From: Toni Wilen Date: Sat, 21 Apr 2018 10:34:40 +0000 (+0300) Subject: Lagless VSYNC updates. X-Git-Tag: 4000~107 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=61e5322953a3f4aa976ca707966594b4624f0b42;p=francis%2Fwinuae.git Lagless VSYNC updates. --- diff --git a/custom.cpp b/custom.cpp index b520ca69..00ccc660 100644 --- a/custom.cpp +++ b/custom.cpp @@ -7487,11 +7487,9 @@ static bool framewait (void) if (!vblank_hz_state) return status != 0; - if (vs < 0) { - frame_shown = true; - status = 1; - return status != 0; - } + frame_shown = true; + status = 1; + return status != 0; } status = 1; @@ -8252,7 +8250,10 @@ static void scanlinesleep(int currline, int nextline) } if (busywait) return; - cpu_sleep_millis(1); + if (currprefs.m68k_speed < 0) + sleep_millis_main(1); + else + target_sleep_nanos(500); } static void linesync_first_last_line(int *first, int *last) @@ -8343,20 +8344,18 @@ static bool linesync_beam_multi_dual(void) do_render_slice(1, display_slice_cnt); display_rendered = true; } - if (!currprefs.turbo_emulation) { - while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) { - frame_time_t rpt = read_processor_time(); - if ((int)rpt - (int)vsyncmintime >= 0 || (int)rpt - (int)vsyncmintime < -vsynctimebase * 2) { - vsyncmintime = rpt + vsynctimebase; - break; - } - maybe_process_pull_audio(); - target_spin(0); + while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) { + frame_time_t rpt = read_processor_time(); + if ((int)rpt - (int)vsyncmintime >= 0 || (int)rpt - (int)vsyncmintime < -vsynctimebase * 2) { + vsyncmintime = rpt + vsynctimebase; + break; } - do_display_slice(); - display_rendered = false; - input_read_done = true; + maybe_process_pull_audio(); + target_spin(0); } + do_display_slice(); + display_rendered = false; + input_read_done = true; } else { @@ -8408,7 +8407,7 @@ static bool linesync_beam_multi_dual(void) return input_read_done; } -static bool linesync_beam_multi(void) +static bool linesync_beam_multi_single(void) { static int vsyncnextscanline; static int vsyncnextscanline_add; @@ -8464,6 +8463,7 @@ static bool linesync_beam_multi(void) } vsync_clear(); } + while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) { int vp = target_get_display_scanline(-1); if (vp < 0 || vp >= vsyncnextscanline) @@ -8488,25 +8488,38 @@ static bool linesync_beam_multi(void) } else if (vpos >= nextwaitvpos) { + // topmost/first slice? if (display_slice_cnt == 0) { - // topmost slice if (currprefs.gfx_variable_sync) { - do_render_slice(1, display_slice_cnt); - display_rendered = true; + if (!currprefs.turbo_emulation) { + if (!was_syncline) { + do_render_slice(1, display_slice_cnt); + display_rendered = true; + } - for(;;) { - frame_time_t rpt = read_processor_time(); - if ((int)rpt - (int)vsyncmintime >= 0 || (int)rpt - (int)vsyncmintime < -2 * vsynctimebase) - break; - maybe_process_pull_audio(); - target_spin(0); + frame_time_t rpt; + for(;;) { + rpt = read_processor_time(); + if ((int)rpt - (int)vsyncmintime >= 0 || (int)rpt - (int)vsyncmintime < -2 * vsynctimebase) + break; + maybe_process_pull_audio(); + if (currprefs.m68k_speed < 0 && !was_syncline) { + is_syncline = -1; + return 0; + } + target_spin(0); + } + do_display_slice(); + if ((int)rpt - (int)vsyncmintime < vsynctimebase && (int)rpt - (int)vsyncmintime > -vsynctimebase) { + vsyncmintime += vsynctimebase; + } else { + vsyncmintime = rpt + vsynctimebase; + } + display_rendered = false; + input_read_done = true; } - vsyncmintime = read_processor_time() + vsynctimebase; - do_display_slice(); - display_rendered = false; - input_read_done = true; } else { @@ -8516,13 +8529,16 @@ static bool linesync_beam_multi(void) display_rendered = true; } + // flip slightly early because flip regularly gets delayed if done during vblank + int lastflipline = vsync_activeheight - vsyncnextscanline_add / 3; while (sync_timeout_check(maxtime)) { int vp = target_get_display_scanline(-1); maybe_process_pull_audio(); - if (vp < 0 || vp < vsync_activeheight / 2 || vp >= vsync_activeheight - 1) + if (vp < vsync_activeheight / 2 || vp >= lastflipline) break; if (currprefs.m68k_speed < 0 && !was_syncline) { - is_syncline = -1; + is_syncline_end = lastflipline; + is_syncline = -2; return 0; } target_spin(0); @@ -8533,6 +8549,21 @@ static bool linesync_beam_multi(void) do_display_slice(); display_rendered = false; input_read_done = true; + +#if 1 + // if flipped before vblank, wait for vblank + while (sync_timeout_check(maxtime)) { + int vp = target_get_display_scanline(-1); + if (vp < vsync_activeheight / 2) + break; + if (currprefs.m68k_speed < 0 && !was_syncline) { + is_syncline = -1; + return 0; + } + maybe_process_pull_audio(); + target_spin(0); + } +#endif } } @@ -8548,7 +8579,8 @@ static bool linesync_beam_multi(void) } while (sync_timeout_check(maxtime)) { int vp = target_get_display_scanline(-1); - if (vp == -1) { + // We are still in vblank and second slice? Poll until vblank ends. + if (display_slice_cnt == 1 && vp == -1) { maybe_process_pull_audio(); target_spin(0); #if LLV_DEBUG @@ -8591,10 +8623,10 @@ void vsync_event_done(void) if (currprefs.gfx_display_sections <= 1) { linesync_beam_single(); } else { - if (vsync_hblank >= 85 && !currprefs.gfx_variable_sync) + if (vsync_vblank >= 85 && !currprefs.gfx_variable_sync) linesync_beam_multi_dual(); else - linesync_beam_multi(); + linesync_beam_multi_single(); } } @@ -8749,10 +8781,10 @@ static void hsync_handler_post (bool onvsync) if (currprefs.gfx_display_sections <= 1) { input_read_done = linesync_beam_single(); } else { - if (vsync_hblank >= 85 && currprefs.gfx_variable_sync) + if (vsync_vblank >= 85 && !currprefs.gfx_variable_sync) input_read_done = linesync_beam_multi_dual(); else - input_read_done = linesync_beam_multi(); + input_read_done = linesync_beam_multi_single(); } } else if (!currprefs.cpu_thread && !cpu_sleepmode && currprefs.m68k_speed < 0 && !currprefs.cpu_memory_cycle_exact) { @@ -10249,7 +10281,7 @@ uae_u8 *restore_custom_extra (uae_u8 *src) //currprefs.a4091rom.enabled = changed_prefs.a4091rom.enabled = RBB; RBB; RBB; - currprefs.cs_cdtvscsi = changed_prefs.cs_cdtvscsi = RBB; + RBB; currprefs.cs_pcmcia = changed_prefs.cs_pcmcia = RBB; currprefs.cs_ciaatod = changed_prefs.cs_ciaatod = RB; @@ -10309,7 +10341,7 @@ uae_u8 *save_custom_extra (int *len, uae_u8 *dstptr) SB (is_board_enabled(&currprefs, ROMTYPE_A2091, 0) ? 1 : 0); SB (is_board_enabled(&currprefs, ROMTYPE_A4091, 0) ? 1 : 0); - SB (currprefs.cs_cdtvscsi ? 1 : 0); + SB (0); SB (currprefs.cs_pcmcia ? 1 : 0); SB (currprefs.cs_ciaatod); diff --git a/events.cpp b/events.cpp index 0c70d0a1..3819b216 100644 --- a/events.cpp +++ b/events.cpp @@ -70,9 +70,37 @@ void do_cycles_slow (unsigned long cycles_to_add) /* Keep only CPU emulation running while waiting for sync point. */ if (is_syncline == -1) { - audio_finish_pull(); + // wait for vblank + audio_finish_pull(); + int done = vsync_isdone(NULL); + if (!done) { +#ifdef WITH_PPC + if (ppc_state) { + if (is_syncline == 1) { + uae_ppc_execute_check(); + } else { + uae_ppc_execute_quick(); + } + } +#endif + if (currprefs.cachesize) + pissoff = pissoff_value; + else + pissoff = pissoff_nojit_value; + return; + } + vsync_clear(); + vsync_event_done(); + + } else if (is_syncline == -2) { + + // wait for vblank or early vblank + audio_finish_pull(); int done = vsync_isdone(NULL); + int vp = target_get_display_scanline(-1); + if (vp < 0 || vp >= is_syncline_end) + done = true; if (!done) { #ifdef WITH_PPC if (ppc_state) { diff --git a/include/events.h b/include/events.h index fb094a9d..42ed4563 100644 --- a/include/events.h +++ b/include/events.h @@ -32,7 +32,6 @@ extern void do_cycles_ce (unsigned long cycles); extern void do_cycles_ce020 (unsigned long cycles); extern void events_schedule (void); extern void do_cycles_slow (unsigned long cycles_to_add); -extern void do_cycles_fast (unsigned long cycles_to_add); extern int is_cycle_ce (void); diff --git a/include/uae.h b/include/uae.h index 476ee9d6..7d1867ce 100644 --- a/include/uae.h +++ b/include/uae.h @@ -37,6 +37,7 @@ extern void target_quit (void); extern void target_restart (void); extern void target_getdate(int *y, int *m, int *d); extern void target_cpu_speed(void); +extern void target_sleep_nanos(int); extern bool get_plugin_path (TCHAR *out, int size, const TCHAR *path); extern void stripslashes (TCHAR *p); extern void fixtrailing (TCHAR *p); diff --git a/od-win32/direct3d11.cpp b/od-win32/direct3d11.cpp index 51edfb92..a1f8f697 100644 --- a/od-win32/direct3d11.cpp +++ b/od-win32/direct3d11.cpp @@ -3115,8 +3115,9 @@ static void do_present(struct d3d11struct *d3d, int black) int vsync = isvsync(); UINT syncinterval = d3d->vblankintervals; - if (d3d->m_tearingSupport && (d3d->swapChainDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)) { - if (1 || apm->gfx_vsyncmode || d3d - d3d11data > 0 || currprefs.turbo_emulation) { + // only if no vsync or low latency vsync + if (d3d->m_tearingSupport && (d3d->swapChainDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) && (!vsync || apm->gfx_vsyncmode)) { + if (apm->gfx_vsyncmode || d3d - d3d11data > 0 || currprefs.turbo_emulation) { presentFlags |= DXGI_PRESENT_ALLOW_TEARING; syncinterval = 0; } @@ -3127,6 +3128,10 @@ static void do_present(struct d3d11struct *d3d, int black) syncinterval = 0; } if (currprefs.turbo_emulation) { + static int skip; + if (--skip > 0) + return; + skip = 10; if (os_win8) presentFlags |= DXGI_PRESENT_DO_NOT_WAIT; syncinterval = 0; @@ -3134,8 +3139,6 @@ static void do_present(struct d3d11struct *d3d, int black) d3d->syncinterval = syncinterval; hr = d3d->m_swapChain->Present(syncinterval, presentFlags); - if (FAILED(hr)) - write_log(_T("%08x\n"), hr); if (currprefs.turbo_emulation && hr == DXGI_ERROR_WAS_STILL_DRAWING) hr = S_OK; if (FAILED(hr) && hr != DXGI_STATUS_OCCLUDED) { diff --git a/od-win32/win32.cpp b/od-win32/win32.cpp index c33f05f8..35cb99a2 100644 --- a/od-win32/win32.cpp +++ b/od-win32/win32.cpp @@ -216,6 +216,11 @@ static int guijoybutton[MAX_JPORTS]; static int guijoyaxis[MAX_JPORTS][4]; static bool guijoychange; +typedef NTSTATUS(CALLBACK* NTDELAYEXECUTION)(BOOL, PLARGE_INTEGER); +typedef NTSTATUS(CALLBACK* ZWSETTIMERRESOLUTION)(ULONG, BOOLEAN, PULONG); +static NTDELAYEXECUTION pNtDelayExecution; +static ZWSETTIMERRESOLUTION pZwSetTimerResolution; + #if TOUCH_SUPPORT typedef BOOL (CALLBACK* REGISTERTOUCHWINDOW)(HWND, ULONG); typedef BOOL (CALLBACK* GETTOUCHINPUTINFO)(HTOUCHINPUT, UINT, PTOUCHINPUT, int); @@ -225,6 +230,50 @@ static GETTOUCHINPUTINFO pGetTouchInputInfo; static CLOSETOUCHINPUTHANDLE pCloseTouchInputHandle; #endif +static ULONG ActualTimerResolution; + +void target_sleep_nanos(int nanos) +{ + static bool init; + if (!init) { + pNtDelayExecution = (NTDELAYEXECUTION)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtDelayExecution"); + pZwSetTimerResolution = (ZWSETTIMERRESOLUTION)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "ZwSetTimerResolution"); + if (pZwSetTimerResolution) { + // 0.5ms + NTSTATUS status = pZwSetTimerResolution((500 * 1000) / 100, TRUE, &ActualTimerResolution); + if (!status) { + LARGE_INTEGER interval; + interval.QuadPart = -(int)ActualTimerResolution; + status = pNtDelayExecution(false, &interval); + if (!status) { + write_log(_T("Using NtDelayExecution. ActualTimerResolution=%u\n"), ActualTimerResolution); + } else { + write_log(_T("NtDelayExecution returned %08x\n"), status); + pNtDelayExecution = NULL; + pZwSetTimerResolution = NULL; + } + } else { + write_log(_T("NtDelayExecution not available\n")); + pNtDelayExecution = NULL; + pZwSetTimerResolution = NULL; + } + } + init = true; + } + if (pNtDelayExecution) { + LARGE_INTEGER interval; + int start = read_processor_time(); + nanos *= 10; + if (nanos < ActualTimerResolution) + nanos = ActualTimerResolution; + interval.QuadPart = -nanos; + pNtDelayExecution(false, &interval); + idletime += read_processor_time() - start; + } else { + sleep_millis_main(1); + } +} + static uae_u64 spincount; void target_spin(int total) diff --git a/od-win32/win32gfx.cpp b/od-win32/win32gfx.cpp index 2db058d1..a72181dd 100644 --- a/od-win32/win32gfx.cpp +++ b/od-win32/win32gfx.cpp @@ -485,7 +485,9 @@ static void display_vblank_thread(struct AmigaMonitor *mon) display_vblank_thread_kill(); return; } - // It seems some Windows 7 drivers hang if D3DKMTWaitForVerticalBlankEvent() + 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->HasAdapterData) { waitvblankevent = CreateEvent(NULL, FALSE, FALSE, NULL);