Mesa (master): st/wgl: pseudo-implementation of WGL_EXT_swap_control

Brian Paul brianp at kemper.freedesktop.org
Fri Apr 7 19:51:09 UTC 2017


Module: Mesa
Branch: master
Commit: c78fc70e8c8931c28dfa8be1ea9522fe7b16687b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=c78fc70e8c8931c28dfa8be1ea9522fe7b16687b

Author: Brian Paul <brianp at vmware.com>
Date:   Tue Apr  4 13:11:44 2017 -0600

st/wgl: pseudo-implementation of WGL_EXT_swap_control

This implementation is based on querying the time just before swap/present
and doing a Sleep() if needed.  There is no sync to vblank or actual
coordination with the GPU.  This isn't perfect, but basically works.

We've had some request for this functionality, and it sounds like there
are some Windows GL apps that refuse to start if the driver doesn't
advertise this extension.

Note: NVIDIA's Windows OpenGL driver advertises the WGL_EXT_swap_control
string both with wglGetExtensionsStringEXT() and with
glGetString(GL_EXTENSIONS).  We're only advertising it with the former at
this time.

Tested with asst. Mesa demos, Google Earth, Lightsmark, etc.

VMware bug 1591534.

Reviewed-by: José Fonseca <jfonseca at vmware.com>

---

 src/gallium/state_trackers/wgl/stw_device.c        | 25 +++++++++++++++
 src/gallium/state_trackers/wgl/stw_device.h        |  4 +++
 .../state_trackers/wgl/stw_ext_extensionsstring.c  |  2 +-
 .../state_trackers/wgl/stw_ext_swapinterval.c      | 25 +++++++++------
 src/gallium/state_trackers/wgl/stw_framebuffer.c   | 37 ++++++++++++++++++++++
 src/gallium/state_trackers/wgl/stw_framebuffer.h   |  3 ++
 .../state_trackers/wgl/stw_getprocaddress.c        |  2 +-
 7 files changed, 86 insertions(+), 12 deletions(-)

diff --git a/src/gallium/state_trackers/wgl/stw_device.c b/src/gallium/state_trackers/wgl/stw_device.c
index b57f96f2e8..42a2f0e82f 100644
--- a/src/gallium/state_trackers/wgl/stw_device.c
+++ b/src/gallium/state_trackers/wgl/stw_device.c
@@ -63,6 +63,24 @@ stw_get_param(struct st_manager *smapi,
    }
 }
 
+
+/** Get the refresh rate for the monitor, in Hz */
+static int
+get_refresh_rate(void)
+{
+   DEVMODE devModes;
+
+   if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devModes)) {
+      /* clamp the value, just in case we get garbage */
+      return CLAMP(devModes.dmDisplayFrequency, 30, 120);
+   }
+   else {
+      /* reasonable default */
+      return 60;
+   }
+}
+
+
 boolean
 stw_init(const struct stw_winsys *stw_winsys)
 {
@@ -116,6 +134,13 @@ stw_init(const struct stw_winsys *stw_winsys)
 
    stw_pixelformat_init();
 
+   /* env var override for WGL_EXT_swap_control, useful for testing/debugging */
+   const char *s = os_get_option("SVGA_SWAP_INTERVAL");
+   if (s) {
+      stw_dev->swap_interval = atoi(s);
+   }
+   stw_dev->refresh_rate = get_refresh_rate();
+
    stw_dev->initialized = true;
 
    return TRUE;
diff --git a/src/gallium/state_trackers/wgl/stw_device.h b/src/gallium/state_trackers/wgl/stw_device.h
index ecf212d7cb..766975c292 100644
--- a/src/gallium/state_trackers/wgl/stw_device.h
+++ b/src/gallium/state_trackers/wgl/stw_device.h
@@ -78,6 +78,10 @@ struct stw_device
    unsigned long memdbg_no;
 #endif
 
+   /** WGL_EXT_swap_control */
+   int refresh_rate;
+   int swap_interval;
+
    bool initialized;
 };
 
diff --git a/src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c b/src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c
index 06af8b1e99..996eb586d9 100644
--- a/src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c
+++ b/src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c
@@ -45,7 +45,7 @@ static const char *stw_extension_string =
    "WGL_EXT_create_context_es_profile "
    "WGL_EXT_create_context_es2_profile "
    "WGL_ARB_make_current_read "
-/*   "WGL_EXT_swap_interval " */
+   "WGL_EXT_swap_control "
    "WGL_EXT_extensions_string";
 
 
diff --git a/src/gallium/state_trackers/wgl/stw_ext_swapinterval.c b/src/gallium/state_trackers/wgl/stw_ext_swapinterval.c
index b960913ccb..b2074a73fb 100644
--- a/src/gallium/state_trackers/wgl/stw_ext_swapinterval.c
+++ b/src/gallium/state_trackers/wgl/stw_ext_swapinterval.c
@@ -33,25 +33,30 @@
 #include <GL/gl.h>
 #include <GL/wglext.h>
 #include "util/u_debug.h"
+#include "stw_device.h"
 
-/* A dummy implementation of this extension.
- *
- * Required as some applications retrieve and call these functions
- * regardless of the fact that we don't advertise the extension and
- * further more the results of wglGetProcAddress are NULL.
+
+/**
+ * Note that our implementation of swap intervals is a bit of a hack.
+ * We implement it based on querying the time and Sleep()'ing.  We don't
+ * sync to the vblank.
  */
 WINGDIAPI BOOL APIENTRY
 wglSwapIntervalEXT(int interval)
 {
-   (void) interval;
-   debug_printf("%s: %d\n", __FUNCTION__, interval);
+   if (interval < 0) {
+      SetLastError(ERROR_INVALID_DATA);
+      return FALSE;
+   }
+   if (stw_dev) {
+      stw_dev->swap_interval = interval;
+   }
    return TRUE;
 }
 
+
 WINGDIAPI int APIENTRY
 wglGetSwapIntervalEXT(void)
 {
-   return 0;
+   return stw_dev ? stw_dev->swap_interval : 0;
 }
-
-
diff --git a/src/gallium/state_trackers/wgl/stw_framebuffer.c b/src/gallium/state_trackers/wgl/stw_framebuffer.c
index 09b57766dc..321fbb6ea7 100644
--- a/src/gallium/state_trackers/wgl/stw_framebuffer.c
+++ b/src/gallium/state_trackers/wgl/stw_framebuffer.c
@@ -30,6 +30,7 @@
 #include "pipe/p_screen.h"
 #include "util/u_memory.h"
 #include "hud/hud_context.h"
+#include "os/os_time.h"
 #include "state_tracker/st_api.h"
 
 #include "stw_icd.h"
@@ -580,6 +581,38 @@ stw_framebuffer_present_locked(HDC hdc,
 }
 
 
+/**
+ * This is called just before issuing the buffer swap/present.
+ * We query the current time and determine if we should sleep before
+ * issuing the swap/present.
+ * This is a bit of a hack and is certainly not very accurate but it
+ * basically works.
+ * This is for the WGL_ARB_swap_interval extension.
+ */
+static void
+wait_swap_interval(struct stw_framebuffer *fb)
+{
+   /* Note: all time variables here are in units of microseconds */
+   int64_t cur_time = os_time_get_nano() / 1000;
+
+   if (fb->prev_swap_time != 0) {
+      /* Compute time since previous swap */
+      int64_t delta = cur_time - fb->prev_swap_time;
+      int64_t min_swap_period =
+         1.0e6 / stw_dev->refresh_rate * stw_dev->swap_interval;
+
+      /* if time since last swap is less than wait period, wait */
+      if (delta < min_swap_period) {
+         float fudge = 1.75f;  /* emperical fudge factor */
+         int64_t wait = (min_swap_period - delta) * fudge;
+         os_time_sleep(wait);
+      }
+   }
+
+   fb->prev_swap_time = cur_time;
+}
+
+
 BOOL APIENTRY
 DrvSwapBuffers(HDC hdc)
 {
@@ -615,6 +648,10 @@ DrvSwapBuffers(HDC hdc)
       }
    }
 
+   if (stw_dev->swap_interval != 0) {
+      wait_swap_interval(fb);
+   }
+
    return stw_st_swap_framebuffer_locked(hdc, fb->stfb);
 }
 
diff --git a/src/gallium/state_trackers/wgl/stw_framebuffer.h b/src/gallium/state_trackers/wgl/stw_framebuffer.h
index 029fb9ffa3..d44c3a6634 100644
--- a/src/gallium/state_trackers/wgl/stw_framebuffer.h
+++ b/src/gallium/state_trackers/wgl/stw_framebuffer.h
@@ -108,6 +108,9 @@ struct stw_framebuffer
    HANDLE hSharedSurface;
    struct stw_shared_surface *shared_surface;
 
+   /* For WGL_EXT_swap_control */
+   int64_t prev_swap_time;
+
    /** 
     * This is protected by stw_device::fb_mutex, not the mutex above.
     * 
diff --git a/src/gallium/state_trackers/wgl/stw_getprocaddress.c b/src/gallium/state_trackers/wgl/stw_getprocaddress.c
index 9273d10331..c8138f61fa 100644
--- a/src/gallium/state_trackers/wgl/stw_getprocaddress.c
+++ b/src/gallium/state_trackers/wgl/stw_getprocaddress.c
@@ -67,7 +67,7 @@ static const struct stw_extension_entry stw_extension_entries[] = {
    /* WGL_EXT_extensions_string */
    STW_EXTENSION_ENTRY( wglGetExtensionsStringEXT ),
 
-   /* WGL_EXT_swap_interval */
+   /* WGL_EXT_swap_control */
    STW_EXTENSION_ENTRY( wglGetSwapIntervalEXT ),
    STW_EXTENSION_ENTRY( wglSwapIntervalEXT ),
 




More information about the mesa-commit mailing list