int vsync_do_vsync(struct video_canvas_s *c, int been_skipped) { static long skip_counter = 0; static int num_skipped_frames = 0; static int frame_counter = 0; int skip_next_frame = 0; vsync_hook(); set_timer_speed(); if (been_skipped) { num_skipped_frames++; } if (timer_patch > 0) { timer_patch--; asm volatile ("cli"); elapsed_frames++; asm volatile ("sti"); }
/* This is called at the end of each screen frame. It flushes the audio buffer and keeps control of the emulation speed. */ int vsync_do_vsync(struct video_canvas_s *c, int been_skipped) { static unsigned long next_frame_start = 0; unsigned long network_hook_time = 0; /* * these are the counters to show how many frames are skipped * since the last vsync_display_speed */ static int frame_counter = 0; static int skipped_frames = 0; /* * This are the frames which are skipped in a row */ static int skipped_redraw = 0; /* Adjustment of frame output frequency. */ static unsigned long adjust_start; static int frames_adjust; static signed long avg_sdelay, prev_sdelay; double sound_delay; int skip_next_frame; signed long delay; long frame_ticks_remainder, frame_ticks_integer, compval; #if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI) float refresh_cmp; int refresh_div; #endif #ifdef HAVE_NETWORK /* check if someone wants to connect remotely to the monitor */ monitor_check_remote(); #endif vsync_frame_counter++; /* * process everything wich should be done before the synchronisation * e.g. OS/2: exit the programm if trigger_shutdown set */ vsyncarch_presync(); /* Run vsync jobs. */ if (network_connected()) { network_hook_time = vsyncarch_gettime(); } vsync_hook(); if (network_connected()) { network_hook_time = vsyncarch_gettime() - network_hook_time; if (network_hook_time > (unsigned long)frame_ticks) { next_frame_start += network_hook_time; now += network_hook_time; } } #ifdef DEBUG /* switch between recording and playback in history debug mode */ debug_check_autoplay_mode(); #endif /* * Update display every two second (pc system time) * This has some reasons: * - we have a better statistic in case of a fastly running emulator * - we don't slow down fast emulations by updating this value * too often (eg more then 10 times a second) * - I don't want to have a value jumping around for example * between 99% and 101% if the user chooses 100% (s.above) * - We need some statistict to get an avarage number for the * frame-rate without staticstics it would also jump around */ frame_counter++; if (!speed_eval_suspended && (signed long)(now - display_start) >= 2 * vsyncarch_freq) { display_speed(frame_counter - skipped_frames); display_start = now; frame_counter = 0; skipped_frames = 0; } if (been_skipped) { skipped_frames++; } /* Flush sound buffer, get delay in seconds. */ sound_delay = sound_flush(); /* Get current time, directly after getting the sound delay. */ now = vsyncarch_gettime(); /* Start afresh after pause in frame output. */ if (speed_eval_suspended) { speed_eval_suspended = 0; speed_eval_prev_clk = maincpu_clk; display_start = now; frame_counter = 0; skipped_frames = 0; next_frame_start = now; skipped_redraw = 0; } /* Start afresh after "out of sync" cases. */ if (sync_reset) { sync_reset = 0; adjust_start = now; frames_adjust = 0; avg_sdelay = 0; prev_sdelay = 0; frame_ticks = (frame_ticks_orig + frame_ticks) / 2; } /* This is the time between the start of the next frame and now. */ delay = (signed long)(now - next_frame_start); #if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI) refresh_cmp = (float)(c->refreshrate / refresh_frequency); refresh_div = (int)(refresh_cmp + 0.5f); refresh_cmp /= (float)refresh_div; if ((timer_speed == 100) && (!warp_mode_enabled) && vsyncarch_vbl_sync_enabled() && (refresh_cmp <= 1.02f) && (refresh_cmp > 0.98f) && (refresh_div == 1)) { vsyncarch_verticalblank(c, c->refreshrate, refresh_div); skip_next_frame = 0; skipped_redraw = 0; } else { #endif /* * We sleep until the start of the next frame, if: * - warp_mode is disabled * - a limiting speed is given * - we have not reached next_frame_start yet * * We could optimize by sleeping only if a frame is to be output. */ /*log_debug("vsync_do_vsync: sound_delay=%f frame_ticks=%d delay=%d", sound_delay, frame_ticks, delay);*/ if (!warp_mode_enabled && timer_speed && delay < 0) { vsyncarch_sleep(-delay); } #if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI) vsyncarch_prepare_vbl(); #endif /* * Check whether we should skip the next frame or not. * Allow delay of up to one frame before skipping frames. * Frames are skipped: * - only if maximum skipped frames are not reached * - if warp_mode enabled * - if speed is not limited or we are too slow and * refresh rate is automatic or fixed and needs correction * * Remark: The time_deviation should be the equivalent of two * frames and must be scaled to make sure, that we * don't start skipping frames before the CPU reaches 100%. * If we are becoming faster a small deviation because of * threading results in a frame rate correction suddenly. */ frame_ticks_remainder = frame_ticks % 100; frame_ticks_integer = frame_ticks / 100; compval = frame_ticks_integer * 3 * timer_speed + frame_ticks_remainder * 3 * timer_speed / 100; if (skipped_redraw < MAX_SKIPPED_FRAMES && (warp_mode_enabled || (skipped_redraw < refresh_rate - 1) || ((!timer_speed || delay > compval) && !refresh_rate ) ) ) { skip_next_frame = 1; skipped_redraw++; } else { skip_next_frame = 0; skipped_redraw = 0; } #if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI) } #endif /* * Check whether the hardware can keep up. * Allow up to 0,25 second error before forcing a correction. */ if ((signed long)(now - next_frame_start) >= vsyncarch_freq / 8) { #if !defined(__OS2__) && !defined(DEBUG) if (!warp_mode_enabled && relative_speed) { log_warning(LOG_DEFAULT, "Your machine is too slow for current settings!"); } #endif vsync_sync_reset(); next_frame_start = now; } /* Adjust frame output frequency to match sound speed. This only kicks in for cycle based sound and SOUND_ADJUST_EXACT. */ if (frames_adjust < INT_MAX) { frames_adjust++; } /* Adjust audio-video sync */ if (!network_connected() && (signed long)(now - adjust_start) >= vsyncarch_freq / 5) { signed long adjust; avg_sdelay /= frames_adjust; /* Account for both relative and absolute delay. */ adjust = (avg_sdelay - prev_sdelay + avg_sdelay / 8) / frames_adjust; /* Maximum adjustment step 1%. */ if (labs(adjust) > frame_ticks / 100) { adjust = adjust / labs(adjust) * frame_ticks / 100; } frame_ticks -= adjust; frames_adjust = 0; prev_sdelay = avg_sdelay; avg_sdelay = 0; adjust_start = now; } else { /* Actual sound delay is sound delay minus vsync delay. */ signed long sdelay = (signed long)(sound_delay * vsyncarch_freq); avg_sdelay += sdelay; } next_frame_start += frame_ticks; vsyncarch_postsync(); #if 0 FILE *fd = fopen("latencylog.txt", "a"); fprintf(fd, "%d %ld %ld %lf\n", vsync_frame_counter, frame_ticks, delay, sound_delay * 1000000); fclose(fd); #endif return skip_next_frame; }
/* This is called at the end of each screen frame. It flushes the audio buffer and keeps control of the emulation speed. */ int vsync_do_vsync(int been_skipped) { static unsigned short frame_counter = USHRT_MAX; static unsigned short num_skipped_frames; static int skip_counter; int skip_next_frame = 0; vsync_hook(); if (been_skipped) num_skipped_frames++; if (timer_speed != relative_speed) { frame_counter = USHRT_MAX; if (set_timer_speed(relative_speed) < 0) { log_error(LOG_DEFAULT, "Trouble setting timers... giving up."); /* FIXME: Hm, maybe we should be smarter. But this is should never happen.*/ exit(-1); } } if (warp_mode_enabled) { /* "Warp Mode". Just skip as many frames as possible and do not limit the maximum speed at all. */ if (skip_counter < MAX_SKIPPED_FRAMES) { skip_next_frame = 1; skip_counter++; } else skip_counter = elapsed_frames = 0; sound_flush(0); } else if (refresh_rate != 0) { update_elapsed_frames(0); /* Fixed refresh rate. */ if (timer_speed && skip_counter >= elapsed_frames) timer_sleep(); if (skip_counter < refresh_rate - 1) { skip_next_frame = 1; skip_counter++; } else skip_counter = elapsed_frames = 0; patch_timer(sound_flush(relative_speed)); } else { /* Dynamically adjusted refresh rate. */ update_elapsed_frames(0); if (skip_counter >= elapsed_frames) { elapsed_frames = -1; timer_sleep(); skip_counter = 0; } else if (skip_counter < MAX_SKIPPED_FRAMES) { skip_next_frame = 1; skip_counter++; } else skip_counter = elapsed_frames = 0; patch_timer(sound_flush(relative_speed)); } if (frame_counter >= refresh_frequency * 2) { display_speed(frame_counter + 1 - num_skipped_frames); num_skipped_frames = 0; frame_counter = 0; } else frame_counter++; kbdbuf_flush(); #ifdef HAS_JOYSTICK joystick_update(); #endif return skip_next_frame; }
int vsync_do_vsync(struct video_canvas_s *canvas, int been_skipped) { int skip_next_frame = 0; int frame_delay; int now, dopoll; /* this can happen in some rare cases; make sure emulation stops then */ while (EmuPaused != 0) { ui_poll(1); } if (FullScreenMode != 0) { EmuWindowHasInputFocus = 1; } else { RO_Caret caret; Wimp_GetCaretPosition(&caret); /* This will be used by keyboard and joystick code */ EmuWindowHasInputFocus = (canvas_for_handle(caret.WHandle) == NULL) ? 0 : 1; } now = OS_ReadMonotonicTime(); if (warp_mode_enabled) { if (skip_counter < MaxSkippedFrames) { skip_next_frame = 1; skip_counter++; } else { skip_counter = 0; } } else if (refresh_rate != 0) { if (skip_counter < refresh_rate - 1) { skip_next_frame = 1; skip_counter++; } else { skip_counter = 0; } } else { /* Use NumberOfFrames+1 because this frame isn't counted yet */ if ((VSYNC_TIME_DELTA(now, NumberOfFrames+1) < 0) && (skip_counter < MaxSkippedFrames)) { skip_next_frame = 1; skip_counter++; } else { skip_counter = 0; } } /* always pass the actual speed unless in reSID mode */ frame_delay = sound_flush(); if (frame_counter >= refresh_frequency * 2) { num_skipped_frames = 0; frame_counter = 0; } else { frame_counter++; } if (skip_next_frame == 0) { NumberOfRefreshes++; } vsync_hook(); joystick(); mousedrv_sync(); NumberOfFrames += 1 - frame_delay; /* Speed limiter? Wait */ if ((CurrentSpeedLimit != 0) && (warp_mode_enabled == 0)) { while (VSYNC_TIME_DELTA(now, NumberOfFrames) > 0) { now = OS_ReadMonotonicTime(); } } LastFrame = now; if (speed_eval_suspended) { vsync_resync_speed(); speed_eval_suspended = 0; } else { if ((now - LastSpeed) >= SpeedEvery) { int val; RelativeSpeed = (10000 * NumberOfFrames) / (FramesPerSecond * (now - LastSpeed)); ui_display_speed(RelativeSpeed, (100 * NumberOfRefreshes) / (now - LastSpeed), 0); LastSpeed = now; NumberOfFrames = 0; NumberOfRefreshes = 0; resources_get_int("MachineVideoStandard", &val); FramesPerSecond = (val == MACHINE_SYNC_PAL) ? 50 : 60; } } dopoll = 0; if ((now - LastPoll) >= PollEvery) { dopoll = 1; LastPoll = now; } ui_poll(dopoll); video_full_screen_plot_status(); kbdbuf_flush(); return skip_next_frame; }