]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
New low latency vsync updates.
authorToni Wilen <twilen@winuae.net>
Wed, 18 Apr 2018 14:45:18 +0000 (17:45 +0300)
committerToni Wilen <twilen@winuae.net>
Wed, 18 Apr 2018 14:45:18 +0000 (17:45 +0300)
custom.cpp
include/uae.h
newcpu.cpp
od-win32/direct3d.cpp
od-win32/direct3d.h
od-win32/direct3d11.cpp
od-win32/win32gfx.cpp

index 8d2bcd35d1a9c3c4b8a88a0b9c87e456abaedff4..b520ca694944007014d107c0bb6c451a783b0937 100644 (file)
@@ -143,7 +143,7 @@ static bool lof_lace;
 static bool bplcon0_interlace_seen;
 static int scandoubled_line;
 static bool vsync_rendered, frame_rendered, frame_shown;
-static float vsynctimeperline;
+static int vsynctimeperline;
 static int frameskiptime;
 static bool genlockhtoggle;
 static bool genlockvtoggle;
@@ -4346,7 +4346,7 @@ void compute_framesync(void)
 
        compute_vsynctime ();
 
-       hblank_hz = (double)(currprefs.ntscmode ? CHIPSET_CLOCK_NTSC : CHIPSET_CLOCK_PAL) / (maxhpos + (islinetoggle() ? 0.5 : 0));
+       hblank_hz = (currprefs.ntscmode ? CHIPSET_CLOCK_NTSC : CHIPSET_CLOCK_PAL) / (maxhpos + (islinetoggle() ? 0.5 : 0));
 
        write_log (_T("%s mode%s%s V=%.4fHz H=%0.4fHz (%dx%d+%d) IDX=%d (%s) D=%d RTG=%d/%d\n"),
                isntsc ? _T("NTSC") : _T("PAL"),
@@ -7476,7 +7476,7 @@ static bool framewait (void)
                        vsynctimeperline = 1;
 
                if (0 || (log_vsync & 2)) {
-                       write_log (_T("%06d %.2f/%06d %03d%%\n"), t, vsynctimeperline, vsynctimebase, t * 100 / vsynctimebase);
+                       write_log (_T("%06d %06d/%06d %03d%%\n"), t, vsynctimeperline, vsynctimebase, t * 100 / vsynctimebase);
                }
 
                frame_shown = true;
@@ -7538,7 +7538,7 @@ static bool framewait (void)
                vsyncmaxtime = curr_time + max;
 
                if (0)
-                       write_log (_T("%06d:%06d/%06d\n"), adjust, vsynctimeperline, vstb);
+                       write_log (_T("%06d:%06d/%06d %d %d\n"), adjust, vsynctimeperline, vstb, max, maxvpos_display);
        
        } else {
 
@@ -8225,10 +8225,16 @@ STATIC_INLINE bool is_last_line (void)
 
 // low latency vsync
 
+#define LLV_DEBUG 0
+
 static bool sync_timeout_check(frame_time_t max)
 {
+#if LLV_DEBUG
+       return true;
+#else
        frame_time_t rpt = read_processor_time();
        return (int)rpt - (int)max <= 0;
+#endif
 }
 
 extern int busywait;
@@ -8240,7 +8246,7 @@ static void scanlinesleep(int currline, int nextline)
                return;
        int diff = vsync_hblank / (nextline - currline);
        int us = 1000000 / diff;
-       if (us < 2100) { // less than 2ms
+       if (us < 1300) { // spin if less than 1.3ms
                target_spin(nextline - currline - 1);
                return;
        }
@@ -8249,6 +8255,12 @@ static void scanlinesleep(int currline, int nextline)
        cpu_sleep_millis(1);
 }
 
+static void linesync_first_last_line(int *first, int *last)
+{
+       *first = minfirstline;
+       *last = maxvpos_display;
+}
+
 static bool linesync_beam_single(void)
 {
        frame_time_t maxtime = read_processor_time() + 2 * vsynctimebase;
@@ -8300,14 +8312,17 @@ static bool linesync_beam_multi_dual(void)
        bool was_syncline = is_syncline != 0;
 
        is_syncline = 0;
-       if (vpos == 0 && !was_syncline) {
+       if (vpos == 0) {
+               int firstline, lastline;
+               linesync_first_last_line(&firstline, &lastline);
+
                display_slices = currprefs.gfx_display_sections;
                if (display_slices <= 0)
                        display_slices = 1;
                display_slice_cnt = 0;
                vsyncnextscanline = vsync_activeheight / display_slices + 1;
-               display_slice_lines = (maxvpos_display - minfirstline) / display_slices + 1;
-               nextwaitvpos = minfirstline + display_slice_lines;
+               display_slice_lines = (lastline - firstline) / display_slices + 1;
+               nextwaitvpos = firstline + display_slice_lines;
                if (display_slices <= 1)
                        nextwaitvpos = maxvpos_display + 1;
                if (display_slices <= 2 && vsyncnextscanline > vsync_activeheight * 2 / 3)
@@ -8317,6 +8332,9 @@ static bool linesync_beam_multi_dual(void)
                frame_shown = true;
        }
 
+       if (!display_slices)
+               return false;
+
        if (vpos >= nextwaitvpos || is_last_line()) {
 
                if (display_slice_cnt == 0) {
@@ -8405,16 +8423,19 @@ static bool linesync_beam_multi(void)
 
        is_syncline = 0;
        if (vpos == 0 && !was_syncline) {
+               int firstline, lastline;
+               linesync_first_last_line(&firstline, &lastline);
+
                display_slices = currprefs.gfx_display_sections;
                if (!display_slices)
                        display_slices = 1;
                display_slice_cnt = 0;
                vsyncnextscanline = vsync_activeheight / display_slices + 1;
                vsyncnextscanline_add = vsync_activeheight / display_slices;
-               display_slice_lines = (maxvpos_display - minfirstline) / display_slices + 1;
-               nextwaitvpos = minfirstline + display_slice_lines + display_slice_lines / 2;
+               display_slice_lines = (lastline - firstline) / display_slices + 1;
+               nextwaitvpos = firstline + display_slice_lines + display_slice_lines / 2;
                if (display_slices <= 1)
-                       nextwaitvpos = maxvpos_display + 1;
+                       nextwaitvpos = lastline + 1;
                if (display_slices <= 2 && vsyncnextscanline > vsync_activeheight * 2 / 3)
                        vsyncnextscanline = vsync_activeheight * 2 / 3;
 
@@ -8423,6 +8444,9 @@ static bool linesync_beam_multi(void)
                frame_shown = true;
        }
 
+       if (!display_slices)
+               return false;
+
        if (is_last_line()) {
 
                if (!was_syncline && !display_rendered) {
@@ -8450,11 +8474,17 @@ static bool linesync_beam_multi(void)
                                return 0;
                        }
                        scanlinesleep(vp, vsyncnextscanline);
+#if LLV_DEBUG
+                       write_log(_T("1:%d:%d:%d:%d."), vpos, vp, nextwaitvpos, vsyncnextscanline);
+#endif
                }
                do_display_slice();
                input_read_done = true;
                display_slice_cnt = -1;
                display_rendered = false;
+#if LLV_DEBUG
+               write_log("\n");
+#endif
 
        } else if (vpos >= nextwaitvpos) {
 
@@ -8496,6 +8526,9 @@ static bool linesync_beam_multi(void)
                                                        return 0;
                                                }
                                                target_spin(0);
+#if LLV_DEBUG
+                                               write_log(_T("2:%d:%d:%d:%d."), vpos, vp, nextwaitvpos, vsyncnextscanline);
+#endif
                                        }
                                        do_display_slice();
                                        display_rendered = false;
@@ -8518,6 +8551,9 @@ static bool linesync_beam_multi(void)
                                        if (vp == -1) {
                                                maybe_process_pull_audio();
                                                target_spin(0);
+#if LLV_DEBUG
+                                               write_log(_T("3:%d:%d:%d:%d."), vpos, vp, nextwaitvpos, vsyncnextscanline);
+#endif
                                                continue;
                                        }
                                        if (vp < 0 || vp >= vsyncnextscanline)
@@ -8528,6 +8564,9 @@ static bool linesync_beam_multi(void)
                                                return 0;
                                        }
                                        scanlinesleep(vp, vsyncnextscanline);
+#if LLV_DEBUG
+                                       write_log(_T("4:%d:%d:%d:%d."), vpos, vp, nextwaitvpos, vsyncnextscanline);
+#endif
                                }
                                do_display_slice();
                                input_read_done = true;
@@ -8538,7 +8577,11 @@ static bool linesync_beam_multi(void)
                }
                nextwaitvpos += display_slice_lines;
                display_slice_cnt++;
+#if LLV_DEBUG
+               write_log("\n");
+#endif
        }
+
        return input_read_done;
 }
 
index c149d86c09dde9913ebdfece0784641f4f28e3a1..476ee9d6ad538c43b0f820082e45cda5589f6e44 100644 (file)
@@ -36,6 +36,7 @@ extern void target_run (void);
 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 bool get_plugin_path (TCHAR *out, int size, const TCHAR *path);
 extern void stripslashes (TCHAR *p);
 extern void fixtrailing (TCHAR *p);
index 6b1f909e0547efa619ae1d196c86b6a44f3d5681..ddbf43237a8195c43fce3e907a9e03141981109f 100644 (file)
@@ -1923,6 +1923,7 @@ static void build_cpufunctbl (void)
        write_log(_T("\n"));
 
        set_cpu_caches (true);
+       target_cpu_speed();
 }
 
 #define CYCLES_DIV 8192
@@ -6441,6 +6442,7 @@ void m68k_go (int may_quit)
                                currprefs.m68k_speed = changed_prefs.m68k_speed;
                                currprefs.m68k_speed_throttle = changed_prefs.m68k_speed_throttle;
                                update_68k_cycles();
+                               target_cpu_speed();
                        }
                        cpu_prefs_changed_flag = 0;
                }
index 091e1e121a57510fa5eec7c17e29250dd9746bfe..70848837a7180356c11640588c59b1194703e82e 100644 (file)
@@ -3764,6 +3764,25 @@ static uae_u8 *xD3D_setcursorsurface(int monid, int *pitch)
        }
 }
 
+bool xD3D_getscanline(int *scanline, bool *invblank)
+{
+       struct d3dstruct *d3d = &d3ddata[0];
+       HRESULT hr;
+       D3DRASTER_STATUS rt;
+
+       if (!isd3d(d3d))
+               return false;
+       if (d3d->d3dswapchain)
+               hr = d3d->d3dswapchain->GetRasterStatus(&rt);
+       else
+               hr = d3d->d3ddev->GetRasterStatus(0, &rt);
+       if (FAILED(hr))
+               return false;
+       *scanline = rt.ScanLine;
+       *invblank = rt.InVBlank != FALSE;
+       return true;
+}
+
 void d3d9_select(void)
 {
        D3D_free = xD3D_free;
@@ -3792,6 +3811,7 @@ void d3d9_select(void)
        D3D_run = NULL;
        D3D_debug = xD3D_debug;
        D3D_led = NULL;
+       D3D_getscanline = xD3D_getscanline;
 }
 
 #endif
index 8c5894e5ca0e5a6bf469d0a3da55291e34530c07..b71f54378e8458ef4b16e6b6bf38cf3595a6308e 100644 (file)
@@ -25,6 +25,7 @@ extern bool(*D3D_getscalerect)(int, float *mx, float *my, float *sx, float *sy);
 extern void(*D3D_run)(int);
 extern int(*D3D_debug)(int, int);
 extern void(*D3D_led)(int, int, int);
+extern bool(*D3D_getscanline)(int*, bool*);
 
 extern LPDIRECT3DSURFACE9 D3D_capture(int, int*,int*,int*);
 extern bool D3D11_capture(int, void**,int*, int*,int*);
index f25bb13a8883cba740a50ee8d9fbba65ef14d158..231a13aeba0728e3c44f83cb8cf9f9a22115e060 100644 (file)
@@ -64,6 +64,7 @@ bool(*D3D_getscalerect)(int, float *mx, float *my, float *sx, float *sy);
 void(*D3D_run)(int);
 int(*D3D_debug)(int, int);
 void(*D3D_led)(int, int, int);
+bool(*D3D_getscanline)(int*, bool*);
 
 static HMODULE hd3d11, hdxgi, hd3dcompiler, dwmapi;
 
@@ -4865,6 +4866,7 @@ void d3d11_select(void)
        D3D_run = xD3D11_run;
        D3D_debug = xD3D11_debug;
        D3D_led = xD3D11_led;
+       D3D_getscanline = NULL;
 }
 
 void d3d_select(struct uae_prefs *p)
index de8f8c7b9a71b8350073ca8baa15142e3f4bc182..0733b49e24d48de955a71d7c37adb8b9daf90eaf 100644 (file)
@@ -335,25 +335,35 @@ static D3DKMTWAITFORVERTICALBLANKEVENT pD3DKMTWaitForVerticalBlankEvent;
 
 int target_get_display_scanline(int displayindex)
 {
-       if (!pD3DKMTGetScanLine)
-               return -10;
-       D3DKMT_GETSCANLINE sl = { 0 };
-       struct MultiDisplay *md = displayindex < 0 ? getdisplay(&currprefs) : &Displays[displayindex];
-       if (!md->HasAdapterData)
-               return -11;
-       sl.VidPnSourceId = md->VidPnSourceId;
-       sl.hAdapter = md->AdapterHandle;
-       NTSTATUS status = pD3DKMTGetScanLine(&sl);
-       if (status == STATUS_SUCCESS) {
-               if (sl.InVerticalBlank)
-                       return -1;
-               return sl.ScanLine;
-       } else {
-               if ((int)status > 0)
-                       return -(int)status;
-               return status;
+       if (pD3DKMTGetScanLine) {
+               D3DKMT_GETSCANLINE sl = { 0 };
+               struct MultiDisplay *md = displayindex < 0 ? getdisplay(&currprefs) : &Displays[displayindex];
+               if (!md->HasAdapterData)
+                       return -11;
+               sl.VidPnSourceId = md->VidPnSourceId;
+               sl.hAdapter = md->AdapterHandle;
+               NTSTATUS status = pD3DKMTGetScanLine(&sl);
+               if (status == STATUS_SUCCESS) {
+                       if (sl.InVerticalBlank)
+                               return -1;
+                       return sl.ScanLine;
+               } else {
+                       if ((int)status > 0)
+                               return -(int)status;
+                       return status;
+               }
+               return -12;
+       } else if (D3D_getscanline) {
+               int scanline;
+               bool invblank;
+               if (D3D_getscanline(&scanline, &invblank)) {
+                       if (invblank)
+                               return -1;
+                       return scanline;
+               }
+               return -14;
        }
-       return -12;
+       return -13;
 }
 
 typedef LONG(CALLBACK* QUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO*, UINT32*, DISPLAYCONFIG_MODE_INFO*, DISPLAYCONFIG_TOPOLOGY_ID*);
@@ -449,6 +459,44 @@ static unsigned int __stdcall waitvblankthread(void *dummy)
        return 0;
 }
 
+static void display_vblank_thread_kill(void)
+{
+       if (waitvblankthread_mode == 2) {
+               waitvblankthread_mode = 0;
+               while (waitvblankthread_mode != -1) {
+                       Sleep(10);
+               }
+               waitvblankthread_mode = 0;
+               CloseHandle(waitvblankevent);
+               waitvblankevent = NULL;
+       }
+       wait_vblank_display = NULL;
+}
+
+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;
+       }
+       // It seems some Windows 7 drivers hang if D3DKMTWaitForVerticalBlankEvent()
+       // and D3DKMTGetScanLine() is used simultaneously.
+       if (os_win8 && ap->gfx_vsyncmode && pD3DKMTWaitForVerticalBlankEvent && wait_vblank_display->HasAdapterData) {
+               waitvblankevent = CreateEvent(NULL, FALSE, FALSE, NULL);
+               waitvblankthread_mode = 1;
+               unsigned int th;
+               _beginthreadex(NULL, 0, waitvblankthread, 0, 0, &th);
+       }
+}
+
+void target_cpu_speed(void)
+{
+       display_vblank_thread(&AMonitors[0]);
+}
+
 extern void target_calibrate_spin(void);
 static void display_param_init(struct AmigaMonitor *mon)
 {
@@ -471,29 +519,9 @@ static void display_param_init(struct AmigaMonitor *mon)
        if (!wait_vblank_display || !wait_vblank_display->HasAdapterData) {
                write_log(_T("Selected display mode does not have adapter data!\n"));
        }
-
-       if (ap->gfx_vsyncmode && pD3DKMTWaitForVerticalBlankEvent && wait_vblank_display->HasAdapterData) {
-               waitvblankevent = CreateEvent(NULL, FALSE, FALSE, NULL);
-               waitvblankthread_mode = 1;
-               unsigned int th;
-               _beginthreadex(NULL, 0, waitvblankthread, 0, 0, &th);
-       }
        Sleep(10);
        target_calibrate_spin();
-}
-
-static void display_param_free(void)
-{
-       if (waitvblankthread_mode == 2) {
-               waitvblankthread_mode = 0;
-               while (waitvblankthread_mode != -1) {
-                       Sleep(10);
-               }
-               waitvblankthread_mode = 0;
-               CloseHandle(waitvblankevent);
-               waitvblankevent = NULL;
-       }
-       wait_vblank_display = NULL;
+       display_vblank_thread(mon);
 }
 
 const TCHAR *target_get_display_name (int num, bool friendlyname)
@@ -1815,7 +1843,7 @@ static void close_hwnds(struct AmigaMonitor *mon)
 {
        mon->screen_is_initialized = 0;
        if (!mon->monitor_id) {
-               display_param_free();
+               display_vblank_thread_kill();
 #ifdef AVIOUTPUT
                AVIOutput_Restart();
 #endif