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>
}
}
+
+/** 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)
{
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;
unsigned long memdbg_no;
#endif
+ /** WGL_EXT_swap_control */
+ int refresh_rate;
+ int swap_interval;
+
bool initialized;
};
"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";
#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;
}
-
-
#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"
}
+/**
+ * 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)
{
}
}
+ if (stw_dev->swap_interval != 0) {
+ wait_swap_interval(fb);
+ }
+
return stw_st_swap_framebuffer_locked(hdc, fb->stfb);
}
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.
*
/* WGL_EXT_extensions_string */
STW_EXTENSION_ENTRY( wglGetExtensionsStringEXT ),
- /* WGL_EXT_swap_interval */
+ /* WGL_EXT_swap_control */
STW_EXTENSION_ENTRY( wglGetSwapIntervalEXT ),
STW_EXTENSION_ENTRY( wglSwapIntervalEXT ),