From 558ebcf44fc2ea26a93f154dbd3ee82fee841ec9 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 16 Nov 2019 19:47:41 +0200 Subject: [PATCH] Lagless vsync improvements. --- custom.cpp | 27 ++++++++++++++++--- od-win32/win32.cpp | 5 ++-- od-win32/win32gfx.cpp | 60 ++++++++++++++++++++++++++----------------- 3 files changed, 63 insertions(+), 29 deletions(-) diff --git a/custom.cpp b/custom.cpp index 4bebbf80..1fd09055 100644 --- a/custom.cpp +++ b/custom.cpp @@ -8951,6 +8951,7 @@ static bool linesync_beam_single_single(void) if (vsyncnextstep != 1) { vsyncnextstep = 1; do_render_slice(-1, 0, vpos); + // wait until out of vblank while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) { maybe_process_pull_audio(); vp = target_get_display_scanline(-1); @@ -8966,24 +8967,42 @@ static bool linesync_beam_single_single(void) if (vsyncnextstep != 2) { vsyncnextstep = 2; vsync_clear(); + // wait until second half of display while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) { maybe_process_pull_audio(); vp = target_get_display_scanline(-1); - if (vp >= vsync_activeheight - 1 || vp < 0) + if (vp >= vsync_activeheight / 2) break; if (currprefs.m68k_speed < 0 && !was_syncline) { is_syncline = -2; is_syncline_end = vsync_activeheight - 1; return 0; } - scanlinesleep(vp, vsync_activeheight - 1); + scanlinesleep(vp, vsync_activeheight / 2); } } if (vsyncnextstep != 3) { vsyncnextstep = 3; + // wait until end of display (or start of next field) + while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) { + maybe_process_pull_audio(); + vp = target_get_display_scanline(-1); + if (vp >= vsync_activeheight - 1 || vp < vsync_activeheight / 2) + break; + if (currprefs.m68k_speed < 0 && !was_syncline) { + is_syncline = -2; + is_syncline_end = vsync_activeheight - 1; + return 0; + } + scanlinesleep(vp, vsync_activeheight - 1); + } + } + if (vsyncnextstep != 4) { + vsyncnextstep = 4; do_display_slice(); frame_rendered = true; frame_shown = true; + // wait until first half of display while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) { maybe_process_pull_audio(); vp = target_get_display_scanline(-1); @@ -9013,7 +9032,7 @@ static bool linesync_beam_multi_dual(void) linesync_first_last_line(&firstline, &lastline); display_slices = currprefs.gfx_display_sections; - if (!display_slices) + if (display_slices <= 0) display_slices = 1; display_slice_cnt = 0; vsyncnextscanline = vsync_activeheight / display_slices + 1; @@ -9218,7 +9237,7 @@ static bool linesync_beam_multi_single(void) } // flip slightly early because flip regularly gets delayed if done during vblank - int lastflipline = vsync_activeheight - vsyncnextscanline_add / 3; + int lastflipline = vsync_activeheight - vsyncnextscanline_add / 5; while (sync_timeout_check(maxtime)) { int vp = target_get_display_scanline(-1); maybe_process_pull_audio(); diff --git a/od-win32/win32.cpp b/od-win32/win32.cpp index 9c5d966f..31a6f9f1 100644 --- a/od-win32/win32.cpp +++ b/od-win32/win32.cpp @@ -319,10 +319,11 @@ int target_sleep_nanos(int nanos) } uae_u64 spincount; +extern bool calculated_scanline; void target_spin(int total) { - if (!spincount) + if (!spincount || calculated_scanline) return; if (total > 10) total = 10; @@ -346,7 +347,7 @@ void target_calibrate_spin(void) spincount = 0; if (!ap->gfx_vsyncmode) return; - if (busywait) { + if (busywait || calculated_scanline) { write_log(_T("target_calibrate_spin() skipped\n")); return; } diff --git a/od-win32/win32gfx.cpp b/od-win32/win32gfx.cpp index 78057372..4984b7aa 100644 --- a/od-win32/win32gfx.cpp +++ b/od-win32/win32gfx.cpp @@ -330,6 +330,13 @@ int target_get_display(const TCHAR *name) return -1; } +static volatile int waitvblankthread_mode; +HANDLE waitvblankevent; +static frame_time_t wait_vblank_timestamp; +static MultiDisplay *wait_vblank_display; +static volatile bool vsync_active; +static bool scanlinecalibrating; + typedef NTSTATUS(CALLBACK* D3DKMTOPENADAPTERFROMHDC)(D3DKMT_OPENADAPTERFROMHDC*); static D3DKMTOPENADAPTERFROMHDC pD3DKMTOpenAdapterFromHdc; typedef NTSTATUS(CALLBACK* D3DKMTGETSCANLINE)(D3DKMT_GETSCANLINE*); @@ -371,22 +378,35 @@ static int target_get_display_scanline2(int displayindex) return -13; } -extern uae_u64 spincount;; +extern uae_u64 spincount; +bool calculated_scanline = 1; + int target_get_display_scanline(int displayindex) { - static uae_u64 lastrdtsc; - static int lastvpos; - if (spincount == 0 || currprefs.m68k_speed >= 0) { - lastrdtsc = 0; + if (!scanlinecalibrating && calculated_scanline) { + static int lastline; + float diff = read_processor_time() - wait_vblank_timestamp; + if (diff < 0) + return -1; + int sl = (int)(diff * (vsync_activeheight + (vsync_totalheight - vsync_activeheight) / 10) * vsync_vblank / syncbase); + if (sl < 0) + sl = -1; + return sl; + } else { + static uae_u64 lastrdtsc; + static int lastvpos; + if (spincount == 0 || currprefs.m68k_speed >= 0) { + lastrdtsc = 0; + lastvpos = target_get_display_scanline2(displayindex); + return lastvpos; + } + uae_u64 v = __rdtsc(); + if (lastrdtsc > v) + return lastvpos; lastvpos = target_get_display_scanline2(displayindex); + lastrdtsc = __rdtsc() + spincount * 4; return lastvpos; } - uae_u64 v = __rdtsc(); - if (lastrdtsc > v) - return lastvpos; - lastvpos = target_get_display_scanline2(displayindex); - lastrdtsc = __rdtsc() + spincount * 4; - return lastvpos; } typedef LONG(CALLBACK* QUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO*, UINT32*, DISPLAYCONFIG_MODE_INFO*, DISPLAYCONFIG_TOPOLOGY_ID*); @@ -459,16 +479,10 @@ static bool get_display_vblank_params(int displayindex, int *activeheightp, int return ret; } -static volatile int waitvblankthread_mode; -HANDLE waitvblankevent; -static frame_time_t wait_vblank_timestamp; -static MultiDisplay *wait_vblank_display; -static volatile bool vsync_active; - static unsigned int __stdcall waitvblankthread(void *dummy) { waitvblankthread_mode = 2; - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); while (waitvblankthread_mode) { D3DKMT_WAITFORVERTICALBLANKEVENT e = { 0 }; e.hAdapter = wait_vblank_display->AdapterHandle; @@ -500,19 +514,17 @@ static void display_vblank_thread(struct AmigaMonitor *mon) struct amigadisplay *ad = &adisplays[mon->monitor_id]; struct apmode *ap = ad->picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0]; - if (currprefs.m68k_speed >= 0) { - display_vblank_thread_kill(); - return; - } if (waitvblankthread_mode > 0) return; // It seems some Windows 7 drivers stall if D3DKMTWaitForVerticalBlankEvent() // and D3DKMTGetScanLine() is used simultaneously. - if (os_win8 && ap->gfx_vsyncmode && pD3DKMTWaitForVerticalBlankEvent && wait_vblank_display && wait_vblank_display->HasAdapterData) { + if ((calculated_scanline || os_win8) && ap->gfx_vsyncmode && pD3DKMTWaitForVerticalBlankEvent && wait_vblank_display && wait_vblank_display->HasAdapterData) { waitvblankevent = CreateEvent(NULL, FALSE, FALSE, NULL); waitvblankthread_mode = 1; unsigned int th; _beginthreadex(NULL, 0, waitvblankthread, 0, 0, &th); + } else { + calculated_scanline = 0; } } @@ -546,7 +558,9 @@ static void display_param_init(struct AmigaMonitor *mon) write_log(_T("Selected display mode does not have adapter data!\n")); } Sleep(10); + scanlinecalibrating = true; target_calibrate_spin(); + scanlinecalibrating = false; display_vblank_thread(mon); } -- 2.47.3