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;