st/wgl: pseudo-implementation of WGL_EXT_swap_control
authorBrian Paul <brianp@vmware.com>
Tue, 4 Apr 2017 19:11:44 +0000 (13:11 -0600)
committerBrian Paul <brianp@vmware.com>
Fri, 7 Apr 2017 19:46:43 +0000 (13:46 -0600)
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@vmware.com>
src/gallium/state_trackers/wgl/stw_device.c
src/gallium/state_trackers/wgl/stw_device.h
src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c
src/gallium/state_trackers/wgl/stw_ext_swapinterval.c
src/gallium/state_trackers/wgl/stw_framebuffer.c
src/gallium/state_trackers/wgl/stw_framebuffer.h
src/gallium/state_trackers/wgl/stw_getprocaddress.c

index b57f96f2e872a809f4b05b56004d96b8ec9c1fe3..42a2f0e82f900fdf6705b19c42c9f1a4f3ae8bf2 100644 (file)
@@ -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;
index ecf212d7cb690695f4b863ade01d6edca8d37485..766975c292c7115fbfdf5ef7fc997971c083953e 100644 (file)
@@ -78,6 +78,10 @@ struct stw_device
    unsigned long memdbg_no;
 #endif
 
+   /** WGL_EXT_swap_control */
+   int refresh_rate;
+   int swap_interval;
+
    bool initialized;
 };
 
index 06af8b1e99432f3b4cb03ee7a3e5d6aadb0a79fa..996eb586d941f16354672aebb962d265d677c106 100644 (file)
@@ -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";
 
 
index b960913ccbb7f70865cf004ed1bd62aa46ea73aa..b2074a73fb79ef5854cacafe41d300e7d6e9af82 100644 (file)
 #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;
 }
-
-
index 09b57766dc0b72874d20a7a6f4b58dcdbd7c38a8..321fbb6ea7747b8943ed3cb010d1c8e5ca6ebb4c 100644 (file)
@@ -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);
 }
 
index 029fb9ffa34d42d168e197504790ca416b695e05..d44c3a6634a841ee035ec6fe4ba70e00ded0cc1e 100644 (file)
@@ -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.
     * 
index 9273d103310332cffdf8b5f7a9961109a3cf6f09..c8138f61fa4c191f90beb96535520ca5a355ba79 100644 (file)
@@ -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 ),