]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Low latency vsync updates.
authorToni Wilen <twilen@winuae.net>
Sat, 14 Apr 2018 16:04:02 +0000 (19:04 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 14 Apr 2018 16:04:02 +0000 (19:04 +0300)
custom.cpp
od-win32/dxwrap.h
od-win32/win32.cpp
od-win32/win32gfx.cpp

index 5a3042027f19fa0f72b56d8bba70403425fb0933..8d2bcd35d1a9c3c4b8a88a0b9c87e456abaedff4 100644 (file)
@@ -8225,6 +8225,13 @@ STATIC_INLINE bool is_last_line (void)
 
 // low latency vsync
 
+static bool sync_timeout_check(frame_time_t max)
+{
+       frame_time_t rpt = read_processor_time();
+       return (int)rpt - (int)max <= 0;
+}
+
+extern int busywait;
 static void scanlinesleep(int currline, int nextline)
 {
        if (currline < 0)
@@ -8237,16 +8244,20 @@ static void scanlinesleep(int currline, int nextline)
                target_spin(nextline - currline - 1);
                return;
        }
+       if (busywait)
+               return;
        cpu_sleep_millis(1);
 }
 
 static bool linesync_beam_single(void)
 {
+       frame_time_t maxtime = read_processor_time() + 2 * vsynctimebase;
+
        is_syncline = 0;
        maybe_process_pull_audio();
        if (is_last_line()) {
                do_render_slice(-1, 0);
-               while (!currprefs.turbo_emulation) {
+               while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) {
                        maybe_process_pull_audio();
                        target_spin(0);
                        int vp = target_get_display_scanline(-1);
@@ -8254,14 +8265,14 @@ static bool linesync_beam_single(void)
                                break;
                }
                vsync_clear();
-               while (!currprefs.turbo_emulation) {
+               while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) {
                        maybe_process_pull_audio();
                        int vp = target_get_display_scanline(-1);
                        if (vp >= vsync_activeheight - 1 || vp < 0)
                                break;
                        scanlinesleep(vp, vsync_activeheight - 1);
                }
-               while (!currprefs.turbo_emulation) {
+               while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) {
                        maybe_process_pull_audio();
                        target_spin(0);
                        int vp = target_get_display_scanline(-1);
@@ -8284,6 +8295,7 @@ static bool linesync_beam_multi_dual(void)
        static int display_slice_lines;
        static int display_slices;
        static bool display_rendered;
+       frame_time_t maxtime = read_processor_time() + 2 * vsynctimebase;
        bool input_read_done = false;
        bool was_syncline = is_syncline != 0;
 
@@ -8314,7 +8326,7 @@ static bool linesync_beam_multi_dual(void)
                                display_rendered = true;
                        }
                        if (!currprefs.turbo_emulation) {
-                               while (!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;
@@ -8335,7 +8347,7 @@ static bool linesync_beam_multi_dual(void)
                                        do_render_slice(0, display_slice_cnt);
                                        display_rendered = true;
                                }
-                               for (;;) {
+                               while(sync_timeout_check(maxtime)) {
                                        int vp = target_get_display_scanline(-1);
                                        if (vp == -1) {
                                                maybe_process_pull_audio();
@@ -8378,7 +8390,6 @@ static bool linesync_beam_multi_dual(void)
        return input_read_done;
 }
 
-
 static bool linesync_beam_multi(void)
 {
        static int vsyncnextscanline;
@@ -8388,6 +8399,7 @@ static bool linesync_beam_multi(void)
        static int display_slice_lines;
        static int display_slices;
        static bool display_rendered;
+       frame_time_t maxtime = read_processor_time() + 2 * vsynctimebase;
        bool input_read_done = false;
        bool was_syncline = is_syncline != 0;
 
@@ -8417,7 +8429,18 @@ static bool linesync_beam_multi(void)
                        do_render_slice(0, display_slice_cnt);
                        display_rendered = true;
                }
-               while (!currprefs.turbo_emulation) {
+               // if 2 slices: make sure we are out of vblank.
+               if (display_slices <= 2) {
+                       while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) {
+                               int vp = target_get_display_scanline(-1);
+                               if (vp != -1)
+                                       break;
+                               maybe_process_pull_audio();
+                               target_spin(0);
+                       }
+                       vsync_clear();
+               }
+               while (!currprefs.turbo_emulation && sync_timeout_check(maxtime)) {
                        int vp = target_get_display_scanline(-1);
                        if (vp < 0 || vp >= vsyncnextscanline)
                                break;
@@ -8443,7 +8466,7 @@ static bool linesync_beam_multi(void)
                                do_render_slice(1, display_slice_cnt);
                                display_rendered = true;
 
-                               for (;;) {
+                               for(;;) {
                                        frame_time_t rpt = read_processor_time();
                                        if ((int)rpt - (int)vsyncmintime >= 0 || (int)rpt - (int)vsyncmintime < -2 * vsynctimebase)
                                                break;
@@ -8451,15 +8474,6 @@ static bool linesync_beam_multi(void)
                                        target_spin(0);
                                }
                                vsyncmintime = read_processor_time() + vsynctimebase;
-
-                               while (!currprefs.turbo_emulation) {
-                                       maybe_process_pull_audio();
-                                       int vp = target_get_display_scanline(-1);
-                                       if (vp < 0)
-                                               break;
-                                       scanlinesleep(vp, vsync_activeheight - 1);
-                               }
-
                                do_display_slice();
                                display_rendered = false;
                                input_read_done = true;
@@ -8472,7 +8486,7 @@ static bool linesync_beam_multi(void)
                                                display_rendered = true;
                                        }
 
-                                       for (;;) {
+                                       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)
@@ -8499,7 +8513,7 @@ static bool linesync_beam_multi(void)
                                        do_render_slice(0, display_slice_cnt);
                                        display_rendered = true;
                                }
-                               for(;;) {
+                               while (sync_timeout_check(maxtime)) {
                                        int vp = target_get_display_scanline(-1);
                                        if (vp == -1) {
                                                maybe_process_pull_audio();
@@ -8534,7 +8548,7 @@ 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_hblank >= 85 && !currprefs.gfx_variable_sync)
                        linesync_beam_multi_dual();
                else
                        linesync_beam_multi();
index fb3cd4f63f51d6d25bfb79c16b89ae33ed2dd6ce..8727776480eebb28041e5fa5ce068fa049f2e7fe 100644 (file)
@@ -82,6 +82,7 @@ struct MultiDisplay {
        LUID AdapterLuid;
        UINT VidPnSourceId;
        UINT AdapterHandle;
+       bool HasAdapterData;
 };
 extern struct MultiDisplay Displays[MAX_DISPLAYS + 1];
 
index ad1cfab536ec2f6ea449c6478fde47995a798a06..9a8386379992146e4ee641412b3a2df9e5d54af7 100644 (file)
@@ -125,6 +125,7 @@ int uaelib_debug;
 int pissoff_value = 15000 * CYCLE_UNIT;
 unsigned int fpucontrol;
 int extraframewait, extraframewait2;
+int busywait;
 
 extern FILE *debugfile;
 extern int console_logging;
@@ -250,21 +251,35 @@ void target_calibrate_spin(void)
        spincount = 0;
        if (!ap->gfx_vsyncmode)
                return;
+       if (busywait) {
+               write_log(_T("target_calibrate_spin() skipped\n"));
+               return;
+       }
+       write_log(_T("target_calibrate_spin() start\n"));
        spincount = 0x800000000000;
        for (int i = 0; i < 50; i++) {
                for (;;) {
                        vp = target_get_display_scanline(-1);
+                       if (vp <= -10)
+                               goto fail;
                        if (vp >= 1 && vp < vsync_activeheight - 10)
                                break;
                }
+               int vp3 = target_get_display_scanline(-1);
                for (;;) {
                        int vp2 = target_get_display_scanline(-1);
+                       if (vp2 <= -10)
+                               goto fail;
                        if (vp2 == vp + 1)
                                break;
+                       if (vp2 != vp)
+                               goto trynext;
                }
                uae_u64 v1 = __rdtsc();
                for (;;) {
                        int vp2 = target_get_display_scanline(-1);
+                       if (vp2 <= -10)
+                               goto fail;
                        if (vp2 == vp + 2) {
                                uae_u64 sc = __rdtsc() - v1;
                                if (spincount > sc)
@@ -273,6 +288,7 @@ void target_calibrate_spin(void)
                        if (vp2 != vp + 1)
                                break;
                }
+trynext:;
        }
        if (spincount == 0x800000000000) {
                write_log(_T("Spincount calculation error, spinloop not used.\n"), spincount);
@@ -280,6 +296,10 @@ void target_calibrate_spin(void)
        } else {
                write_log(_T("Spincount = %llu\n"), spincount);
        }
+       return;
+fail:
+       write_log(_T("Scanline read failed: %d!\n"), vp);
+       spincount = 0;
 }
 
 int timeend (void)
@@ -442,7 +462,7 @@ int sleep_millis_amiga(int ms)
        return ret;
 }
 
-bool quit_ok()
+bool quit_ok(void)
 {
        if (isfullscreen() > 0)
                return true;
@@ -3860,19 +3880,22 @@ void target_fixup_options (struct uae_prefs *p)
        }
        
        struct MultiDisplay *md = getdisplay (p);
-       for (int i = 0; i < MAX_AMIGADISPLAYS; i++) {
-               if (p->gfx_monitor[i].gfx_size_fs.special == WH_NATIVE) {
+       for (int j = 0; j < MAX_AMIGADISPLAYS; j++) {
+               if (p->gfx_monitor[j].gfx_size_fs.special == WH_NATIVE) {
                        int i;
                        for (i = 0; md->DisplayModes[i].depth >= 0; i++) {
                                if (md->DisplayModes[i].res.width == md->rect.right - md->rect.left &&
                                        md->DisplayModes[i].res.height == md->rect.bottom - md->rect.top) {
-                                       p->gfx_monitor[i].gfx_size_fs.width = md->DisplayModes[i].res.width;
-                                       p->gfx_monitor[i].gfx_size_fs.height = md->DisplayModes[i].res.height;
+                                       p->gfx_monitor[j].gfx_size_fs.width = md->DisplayModes[i].res.width;
+                                       p->gfx_monitor[j].gfx_size_fs.height = md->DisplayModes[i].res.height;
+                                       write_log(_T("Native resolution: %dx%d\n"), p->gfx_monitor[j].gfx_size_fs.width, p->gfx_monitor[j].gfx_size_fs.height);
                                        break;
                                }
                        }
-                       if (md->DisplayModes[i].depth < 0)
-                               p->gfx_monitor[i].gfx_size_fs.special = 0;
+                       if (md->DisplayModes[i].depth < 0) {
+                               p->gfx_monitor[j].gfx_size_fs.special = 0;
+                               write_log(_T("Native resolution not found.\n"));
+                       }
                }
        }
        /* switch from 32 to 16 or vice versa if mode does not exist */
@@ -6205,6 +6228,10 @@ static int parseargs(const TCHAR *argx, const TCHAR *np, const TCHAR *np2)
                floppy_writemode = -1;
                return 1;
        }
+       if (!_tcscmp(arg, _T("busywait"))) {
+               busywait = 1;
+               return 1;
+       }
 
        if (!np)
                return 0;
index a0c6922e8e8849e69a2fe2a067bed8687c0349ff..de8f8c7b9a71b8350073ca8baa15142e3f4bc182 100644 (file)
@@ -170,15 +170,17 @@ static uae_u8 *scrlinebuf;
 static struct MultiDisplay *getdisplay2(struct uae_prefs *p, int index)
 {
        struct AmigaMonitor *mon = &AMonitors[0];
-       int max;
+       static int max;
        int display = index < 0 ? p->gfx_apmode[mon->screen_is_picasso ? APMODE_RTG : APMODE_NATIVE].gfx_display - 1 : index;
 
-       max = 0;
-       while (Displays[max].monitorname)
-               max++;
-       if (max == 0) {
-               gui_message (_T("no display adapters! Exiting"));
-               exit (0);
+       if (!max || (max > 0 && Displays[max].monitorname != NULL)) {
+               max = 0;
+               while (Displays[max].monitorname)
+                       max++;
+               if (max == 0) {
+                       gui_message(_T("no display adapters! Exiting"));
+                       exit(0);
+               }
        }
        if (index >= 0 && display >= max)
                return NULL;
@@ -190,7 +192,7 @@ static struct MultiDisplay *getdisplay2(struct uae_prefs *p, int index)
 }
 struct MultiDisplay *getdisplay (struct uae_prefs *p)
 {
-       return getdisplay2 (p, -1);
+       return getdisplay2(p, -1);
 }
 
 void desktop_coords(int monid, int *dw, int *dh, int *ax, int *ay, int *aw, int *ah)
@@ -334,17 +336,24 @@ static D3DKMTWAITFORVERTICALBLANKEVENT pD3DKMTWaitForVerticalBlankEvent;
 int target_get_display_scanline(int displayindex)
 {
        if (!pD3DKMTGetScanLine)
-               return -2;
+               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;
-       if (pD3DKMTGetScanLine(&sl) == STATUS_SUCCESS) {
+       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 -2;
+       return -12;
 }
 
 typedef LONG(CALLBACK* QUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO*, UINT32*, DISPLAYCONFIG_MODE_INFO*, DISPLAYCONFIG_TOPOLOGY_ID*);
@@ -446,8 +455,6 @@ static void display_param_init(struct AmigaMonitor *mon)
        struct amigadisplay *ad = &adisplays[mon->monitor_id];
        struct apmode *ap = ad->picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
 
-       wait_vblank_display = getdisplay(&currprefs);
-
        vsync_activeheight = mon->currentmode.current_height;
        vsync_totalheight = vsync_activeheight * 1125 / 1080;
        vsync_vblank = 0;
@@ -460,7 +467,12 @@ static void display_param_init(struct AmigaMonitor *mon)
                vsync_activeheight = mon->currentmode.current_height;
        }
 
-       if (ap->gfx_vsyncmode && pD3DKMTWaitForVerticalBlankEvent) {
+       wait_vblank_display = getdisplay(&currprefs);
+       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;
@@ -1026,10 +1038,12 @@ static bool enumeratedisplays2 (bool selectall)
                                if (hdc != NULL) {
                                        D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = { 0 };
                                        OpenAdapterData.hDc = hdc;
-                                       if (pD3DKMTOpenAdapterFromHdc(&OpenAdapterData) == STATUS_SUCCESS) {
+                                       NTSTATUS status = pD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
+                                       if (status == STATUS_SUCCESS) {
                                                md->AdapterLuid = OpenAdapterData.AdapterLuid;
                                                md->VidPnSourceId = OpenAdapterData.VidPnSourceId;
                                                md->AdapterHandle = OpenAdapterData.hAdapter;
+                                               md->HasAdapterData = true;
                                        }
                                        DeleteDC(hdc);
                                }
@@ -2891,7 +2905,8 @@ bool vsync_switchmode(int monid, int hz)
 void vsync_clear(void)
 {
        vsync_active = false;
-       ResetEvent(waitvblankevent);
+       if (waitvblankevent)
+               ResetEvent(waitvblankevent);
 }
 
 int vsync_isdone(frame_time_t *dt)