wined3d: Implement vertical refresh sync.
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 2abbeb6..5d14fde 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -1064,6 +1064,10 @@
}
memcpy(ThisExtn, Start, (GLX_Extensions - Start));
TRACE_(d3d_caps)("- %s\n", ThisExtn);
+ if (strstr(ThisExtn, "GLX_SGI_video_sync")) {
+ gl_info->supported[SGI_VIDEO_SYNC] = TRUE;
+ }
+
if (*GLX_Extensions == ' ') GLX_Extensions++;
}
}
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 587f41e..6398e77 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -2355,7 +2355,8 @@
static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
- IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
+ IWineD3DSwapChainImpl *swapchain = NULL;
+ HRESULT hr;
TRACE("(%p)->(%p,%x)\n", This, override, Flags);
/* Flipping is only supported on RenderTargets */
@@ -2369,8 +2370,32 @@
*/
}
+ IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
+ if(!swapchain) {
+ ERR("Flipped surface is not on a swapchain\n");
+ return WINEDDERR_NOTFLIPPABLE;
+ }
+
+ /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
+ * and only d3d8 and d3d9 apps specify the presentation interval
+ */
+ if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
+ /* Most common case first to avoid wasting time on all the other cases */
+ swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
+ } else if(Flags & WINEDDFLIP_NOVSYNC) {
+ swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
+ } else if(Flags & WINEDDFLIP_INTERVAL2) {
+ swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
+ } else if(Flags & WINEDDFLIP_INTERVAL3) {
+ swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
+ } else {
+ swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
+ }
+
/* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
- return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
+ hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *) swapchain, NULL, NULL, 0, NULL, 0);
+ IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
+ return hr;
}
/* Does a direct frame buffer -> texture copy. Stretching is done
@@ -2773,10 +2798,10 @@
*/
dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
+ dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
- IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
- NULL, NULL, 0, NULL);
+ IWineD3DSwapChain_Present((IWineD3DSwapChain *) dstSwapchain, NULL, NULL, 0, NULL, 0);
dstSwapchain->presentParms.SwapEffect = orig_swap;
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 262eb7f..e7a3173 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -53,6 +53,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
WINE_DECLARE_DEBUG_CHANNEL(fps);
+#define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info
/* IDirect3DSwapChain IUnknown parts follow: */
static ULONG WINAPI IWineD3DSwapChainImpl_AddRef(IWineD3DSwapChain *iface) {
@@ -148,6 +149,8 @@
static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
DWORD clear_flags = 0;
+ unsigned int sync;
+ int retval;
ENTER_GL();
@@ -374,6 +377,47 @@
}
}
+ if(This->presentParms.PresentationInterval != WINED3DPRESENT_INTERVAL_IMMEDIATE && GL_SUPPORT(SGI_VIDEO_SYNC)) {
+ retval = GL_EXTCALL(glXGetVideoSyncSGI(&sync));
+ if(retval != 0) {
+ ERR("glXGetVideoSyncSGI failed(retval = %d\n", retval);
+ }
+
+ switch(This->presentParms.PresentationInterval) {
+ case WINED3DPRESENT_INTERVAL_DEFAULT:
+ case WINED3DPRESENT_INTERVAL_ONE:
+ if(sync <= This->vSyncCounter) {
+ retval = GL_EXTCALL(glXWaitVideoSyncSGI(1, 0, &This->vSyncCounter));
+ } else {
+ This->vSyncCounter = sync;
+ }
+ break;
+ case WINED3DPRESENT_INTERVAL_TWO:
+ if(sync <= This->vSyncCounter + 1) {
+ retval = GL_EXTCALL(glXWaitVideoSyncSGI(2, This->vSyncCounter & 0x1, &This->vSyncCounter));
+ } else {
+ This->vSyncCounter = sync;
+ }
+ break;
+ case WINED3DPRESENT_INTERVAL_THREE:
+ if(sync <= This->vSyncCounter + 2) {
+ retval = GL_EXTCALL(glXWaitVideoSyncSGI(3, This->vSyncCounter % 0x3, &This->vSyncCounter));
+ } else {
+ This->vSyncCounter = sync;
+ }
+ break;
+ case WINED3DPRESENT_INTERVAL_FOUR:
+ if(sync <= This->vSyncCounter + 3) {
+ retval = GL_EXTCALL(glXWaitVideoSyncSGI(4, This->vSyncCounter & 0x3, &This->vSyncCounter));
+ } else {
+ This->vSyncCounter = sync;
+ }
+ break;
+ default:
+ FIXME("Unknown presentation interval %08x\n", This->presentParms.PresentationInterval);
+ }
+ }
+
TRACE("returning\n");
return WINED3D_OK;
}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 49081b1..de38042 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1404,6 +1404,7 @@
WINED3DFORMAT orig_fmt;
long prev_time, frames; /* Performance tracking */
+ unsigned int vSyncCounter;
WineD3DContext **context; /* Later a array for multithreading */
unsigned int num_contexts;