void updatescreen(void) { /* update sound */ sound_frame_update(); /* if we're not skipping this frame, draw the screen */ if (!osd_skip_this_frame()) { profiler_mark(PROFILER_VIDEO); draw_screen(); profiler_mark(PROFILER_END); } /* the user interface must be called between vh_update() and osd_update_video_and_audio(), */ /* to allow it to overlay things on the game display. We must call it even */ /* if the frame is skipped, to keep a consistent timing. */ ui_update_and_render(artwork_get_ui_bitmap()); /* update our movie recording state */ if (!mame_is_paused()) record_movie_frame(scrbitmap[0]); /* blit to the screen */ update_video_and_audio(); /* call the end-of-frame callback */ if (Machine->drv->video_eof && !mame_is_paused()) { profiler_mark(PROFILER_VIDEO); (*Machine->drv->video_eof)(); profiler_mark(PROFILER_END); } }
const char *osd_get_fps_text(const performance_info *performance) { static char buffer[1024]; char *dest = buffer; // if we're paused, display less info if (mame_is_paused(Machine)) dest += sprintf(dest, "Paused"); else { dest += sprintf(dest, "%s%2d%4d%%%4d/%d fps", effective_autoframeskip() ? "auto" : "fskp", effective_frameskip(), (int)(performance->game_speed_percent + 0.5), (int)(performance->frames_per_second + 0.5), (int)(Machine->screen[0].refresh + 0.5)); /* for vector games, add the number of vector updates */ if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR) dest += sprintf(dest, "\n %d vector updates", performance->vector_updates_last_second); else if (performance->partial_updates_this_frame > 1) dest += sprintf(dest, "\n %d partial updates", performance->partial_updates_this_frame); } /* return a pointer to the static buffer */ return buffer; }
static void update_autoframeskip(void) { // skip if paused if (mame_is_paused(Machine)) return; // don't adjust frameskip if we're paused or if the debugger was // visible this cycle or if we haven't run yet if (cpu_getcurrentframe() > 2 * FRAMESKIP_LEVELS) { const performance_info *performance = mame_get_performance_info(); // if we're too fast, attempt to increase the frameskip if (performance->game_speed_percent >= 99.5) { frameskipadjust++; // but only after 3 consecutive frames where we are too fast if (frameskipadjust >= 3) { frameskipadjust = 0; if (video_config.frameskip > 0) video_config.frameskip--; } } // if we're too slow, attempt to increase the frameskip else { // if below 80% speed, be more aggressive if (performance->game_speed_percent < 80) frameskipadjust -= (90 - performance->game_speed_percent) / 5; // if we're close, only force it up to frameskip 8 else if (video_config.frameskip < 8) frameskipadjust--; // perform the adjustment while (frameskipadjust <= -2) { frameskipadjust += 2; if (video_config.frameskip < FRAMESKIP_LEVELS - 1) video_config.frameskip++; } } } }
void winwindow_ui_pause_from_main_thread(int pause) { int old_temp_pause = ui_temp_pause; assert(GetCurrentThreadId() == main_threadid); // if we're pausing, increment the pause counter if (pause) { // if we're the first to pause, we have to actually initiate it if (ui_temp_pause++ == 0) { // only call mame_pause if we weren't already paused due to some external reason ui_temp_was_paused = mame_is_paused(Machine); if (!ui_temp_was_paused) { mame_pause(Machine, TRUE); SetEvent(ui_pause_event); } } } // if we're resuming, decrement the pause counter else { // if we're the last to resume, unpause MAME if (--ui_temp_pause == 0) { // but only do it if we were the ones who initiated it if (!ui_temp_was_paused) { mame_pause(Machine, FALSE); ResetEvent(ui_pause_event); } } } if (LOG_TEMP_PAUSE) logerror("winwindow_ui_pause_from_main_thread(): %d --> %d\n", old_temp_pause, ui_temp_pause); }
UINT32 ui_gfx_ui_handler(running_machine *machine, UINT32 uistate) { ui_gfx_state *state = &ui_gfx; /* if we have nothing, implicitly cancel */ if (machine->config->total_colors == 0 && machine->colortable == NULL && machine->gfx[0] == NULL && tilemap_count(machine) == 0) goto cancel; /* if we're not paused, mark the bitmap dirty */ if (!mame_is_paused(machine)) state->bitmap_dirty = TRUE; /* switch off the state to display something */ again: switch (state->mode) { case 0: /* if we have a palette, display it */ if (machine->config->total_colors > 0) { palette_handler(machine, state); break; } /* fall through...*/ state->mode++; case 1: /* if we have graphics sets, display them */ if (machine->gfx[0] != NULL) { gfxset_handler(machine, state); break; } /* fall through...*/ state->mode++; case 2: /* if we have tilemaps, display them */ if (tilemap_count(machine) > 0) { tilemap_handler(machine, state); break; } state->mode = 0; goto again; } /* handle keys */ if (ui_input_pressed(machine, IPT_UI_SELECT)) { state->mode = (state->mode + 1) % 3; state->bitmap_dirty = TRUE; } if (ui_input_pressed(machine, IPT_UI_PAUSE)) mame_pause(machine, !mame_is_paused(machine)); if (ui_input_pressed(machine, IPT_UI_CANCEL) || ui_input_pressed(machine, IPT_UI_SHOW_GFX)) goto cancel; return uistate; cancel: if (!uistate) mame_pause(machine, FALSE); state->bitmap_dirty = TRUE; return UI_HANDLER_CANCEL; }
int winwindow_ui_is_paused(void) { return mame_is_paused(Machine) && ui_temp_was_paused; }
void video_frame_update(void) { int skipped_it = video_skip_this_frame(); int paused = mame_is_paused(Machine); int phase = mame_get_phase(Machine); int livemask; int scrnum; /* only render sound and video if we're in the running phase */ if (phase == MAME_PHASE_RUNNING) { /* update sound */ sound_frame_update(); /* finish updating the screens */ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) if (Machine->drv->screen[scrnum].tag != NULL) video_screen_update_partial(scrnum, Machine->screen[scrnum].visarea.max_y); /* now add the quads for all the screens */ livemask = render_get_live_screens_mask(); for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) { if (livemask & (1 << scrnum)) { internal_screen_info *screen = &scrinfo[scrnum]; /* only update if empty and not a vector game; otherwise assume the driver did it directly */ if (render_container_is_empty(render_container_get_screen(scrnum)) && !(Machine->drv->video_attributes & VIDEO_TYPE_VECTOR)) { mame_bitmap *bitmap = screen->bitmap[screen->curbitmap]; if (!skipping_this_frame && screen->changed) { rectangle fixedvis = Machine->screen[scrnum].visarea; fixedvis.max_x++; fixedvis.max_y++; render_texture_set_bitmap(screen->texture, bitmap, &fixedvis, Machine->drv->screen[scrnum].palette_base, screen->format); screen->curbitmap = 1 - screen->curbitmap; } render_screen_add_quad(scrnum, 0.0f, 0.0f, 1.0f, 1.0f, MAKE_ARGB(0xff,0xff,0xff,0xff), screen->texture, PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1)); } } } /* update our movie recording state */ if (!paused) movie_record_frame(0); /* reset the screen changed flags */ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) scrinfo[scrnum].changed = 0; } /* draw any crosshairs */ crosshair_render(); /* draw the user interface */ ui_update_and_render(); /* call the OSD to update */ skipping_this_frame = osd_update(mame_timer_get_time()); /* empty the containers */ for (scrnum = 0; scrnum < MAX_SCREENS; scrnum++) if (Machine->drv->screen[scrnum].tag != NULL) render_container_empty(render_container_get_screen(scrnum)); /* update FPS */ recompute_fps(skipped_it); /* call the end-of-frame callback */ if (phase == MAME_PHASE_RUNNING) { /* reset partial updates if we're paused or if the debugger is active */ if (paused || mame_debug_is_active()) video_reset_partial_updates(); /* otherwise, call the video EOF callback */ else if (Machine->drv->video_eof != NULL) { profiler_mark(PROFILER_VIDEO); (*Machine->drv->video_eof)(Machine); profiler_mark(PROFILER_END); } } }
static void update_throttle(mame_time emutime) { static double ticks_per_sleep_msec = 0; osd_ticks_t target, curr, cps, diffticks; int allowed_to_sleep; subseconds_t subsecs_per_cycle; int paused = mame_is_paused(Machine); // if we're only syncing to the refresh, bail now if (video_config.syncrefresh) return; // if we're paused, emutime will not advance; explicitly resync and set us backwards // 1/60th of a second if (paused) throttle_realtime = throttle_emutime = sub_subseconds_from_mame_time(emutime, MAX_SUBSECONDS / PAUSED_REFRESH_RATE); // if time moved backwards (reset), or if it's been more than 1 second in emulated time, resync if (compare_mame_times(emutime, throttle_emutime) < 0 || sub_mame_times(emutime, throttle_emutime).seconds > 0) goto resync; // get the current realtime; if it's been more than 1 second realtime, just resync cps = osd_ticks_per_second(); diffticks = osd_ticks() - throttle_last_ticks; throttle_last_ticks += diffticks; if (diffticks >= cps) goto resync; // add the time that has passed to the real time subsecs_per_cycle = MAX_SUBSECONDS / cps; throttle_realtime = add_subseconds_to_mame_time(throttle_realtime, diffticks * subsecs_per_cycle); // update the emulated time throttle_emutime = emutime; // if we're behind, just sync if (compare_mame_times(throttle_emutime, throttle_realtime) <= 0) goto resync; // determine our target ticks value target = throttle_last_ticks + sub_mame_times(throttle_emutime, throttle_realtime).subseconds / subsecs_per_cycle; // initialize the ticks per sleep if (ticks_per_sleep_msec == 0) ticks_per_sleep_msec = (double)(cps / 1000); // this counts as idle time profiler_mark(PROFILER_IDLE); // determine whether or not we are allowed to sleep allowed_to_sleep = video_config.sleep && (!effective_autoframeskip() || effective_frameskip() == 0); // sync for (curr = osd_ticks(); curr - target < 0; curr = osd_ticks()) { // if we have enough time to sleep, do it // ...but not if we're autoframeskipping and we're behind if (paused || (allowed_to_sleep && (target - curr) > (osd_ticks_t)(ticks_per_sleep_msec * 1.1))) { osd_ticks_t next; // keep track of how long we actually slept Sleep(1); next = osd_ticks(); ticks_per_sleep_msec = (ticks_per_sleep_msec * 0.90) + ((double)(next - curr) * 0.10); } } // idle time done profiler_mark(PROFILER_END); // update realtime diffticks = osd_ticks() - throttle_last_ticks; throttle_last_ticks += diffticks; throttle_realtime = add_subseconds_to_mame_time(throttle_realtime, diffticks * subsecs_per_cycle); return; resync: // reset realtime and emutime to the same value throttle_realtime = throttle_emutime = emutime; }
INLINE int effective_throttle(void) { return !video_config.fastforward && (video_config.throttle || mame_is_paused(Machine) || ui_is_menu_active() || ui_is_slider_active()); }
void sound_frame_update(void) { int sample, spknum; VPRINTF(("sound_frame_update\n")); profiler_mark(PROFILER_SOUND); /* reset the mixing streams */ memset(leftmix, 0, samples_this_frame * sizeof(*leftmix)); memset(rightmix, 0, samples_this_frame * sizeof(*rightmix)); /* if we're not paused, keep the sounds going */ if (!mame_is_paused(Machine)) { /* force all the speaker streams to generate the proper number of samples */ for (spknum = 0; spknum < totalspeakers; spknum++) { speaker_info *spk = &speaker[spknum]; stream_sample_t *stream_buf; /* get the output buffer */ if (spk->mixer_stream) { stream_buf = stream_consume_output(spk->mixer_stream, 0, samples_this_frame); #ifdef MAME_DEBUG /* debug version: keep track of the maximum sample */ for (sample = 0; sample < samples_this_frame; sample++) { if (stream_buf[sample] > spk->max_sample) spk->max_sample = stream_buf[sample]; else if (-stream_buf[sample] > spk->max_sample) spk->max_sample = -stream_buf[sample]; if (stream_buf[sample] > 32767 || stream_buf[sample] < -32768) spk->clipped_samples++; spk->total_samples++; } #endif /* mix if sound is enabled */ if (global_sound_enabled && !nosound_mode) { /* if the speaker is centered, send to both left and right */ if (spk->speaker->x == 0) for (sample = 0; sample < samples_this_frame; sample++) { leftmix[sample] += stream_buf[sample]; rightmix[sample] += stream_buf[sample]; } /* if the speaker is to the left, send only to the left */ else if (spk->speaker->x < 0) for (sample = 0; sample < samples_this_frame; sample++) leftmix[sample] += stream_buf[sample]; /* if the speaker is to the right, send only to the right */ else for (sample = 0; sample < samples_this_frame; sample++) rightmix[sample] += stream_buf[sample]; } } } } /* now downmix the final result */ for (sample = 0; sample < samples_this_frame; sample++) { INT32 samp; /* clamp the left side */ samp = leftmix[sample]; if (samp < -32768) samp = -32768; else if (samp > 32767) samp = 32767; finalmix[sample*2+0] = samp; /* clamp the right side */ samp = rightmix[sample]; if (samp < -32768) samp = -32768; else if (samp > 32767) samp = 32767; finalmix[sample*2+1] = samp; } if (wavfile && !mame_is_paused(Machine)) wav_add_data_16(wavfile, finalmix, samples_this_frame * 2); /* play the result */ samples_this_frame = osd_update_audio_stream(finalmix); /* update the streamer */ streams_frame_update(); /* reset the timer to resync for this frame */ mame_timer_adjust(sound_update_timer, time_never, 0, time_never); profiler_mark(PROFILER_END); }