From c9b8a79e0bd61204cfe7b88362617da9a485f0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 3 Jun 2007 13:20:27 +0200 Subject: [PATCH] wined3d: Implement vertical refresh sync. --- dlls/wined3d/directx.c | 4 ++++ dlls/wined3d/surface.c | 33 +++++++++++++++++++++---- dlls/wined3d/swapchain.c | 44 ++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 1 + include/ddraw.h | 4 ++++ include/wine/wined3d_gl.h | 9 +++++++ include/wine/wined3d_types.h | 11 +++++++++ 7 files changed, 102 insertions(+), 4 deletions(-) diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 2abbeb6e3e6..5d14fdee518 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -1064,6 +1064,10 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info, Display* display) { } 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 587f41eb850..6398e777562 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -2355,7 +2355,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) { 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 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DS */ } + 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 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * */ 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 262eb7f24c6..e7a31737bea 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -53,6 +53,7 @@ static inline Display *get_display( HDC hdc ) 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 void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface, D3DCB 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 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO } } + 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 49081b19c35..de38042e141 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1404,6 +1404,7 @@ typedef struct IWineD3DSwapChainImpl WINED3DFORMAT orig_fmt; long prev_time, frames; /* Performance tracking */ + unsigned int vSyncCounter; WineD3DContext **context; /* Later a array for multithreading */ unsigned int num_contexts; diff --git a/include/ddraw.h b/include/ddraw.h index 4572d08ed92..938a19af69e 100644 --- a/include/ddraw.h +++ b/include/ddraw.h @@ -241,6 +241,10 @@ typedef struct IDirectDrawGammaControl *LPDIRECTDRAWGAMMACONTROL; #define DDFLIP_NOVSYNC 0x00000008 #define DDFLIP_STEREO 0x00000010 #define DDFLIP_DONOTWAIT 0x00000020 +#define DDFLIP_INTERVAL2 0x02000000 +#define DDFLIP_INTERVAL3 0x03000000 +#define DDFLIP_INTERVAL4 0x04000000 + /* dwFlags for GetBltStatus */ #define DDGBS_CANBLT 0x00000001 diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h index 1fbbfe8a3b9..24f5faf60ca 100644 --- a/include/wine/wined3d_gl.h +++ b/include/wine/wined3d_gl.h @@ -1225,6 +1225,10 @@ typedef void (APIENTRY * PGLFNTEXBUMPPARAMETERFVATIPROC) (GLenum, GLfloat *); typedef void (APIENTRY * PGLFNGETTEXBUMPPARAMETERIVATIPROC) (GLenum, GLint *); typedef void (APIENTRY * PGLFNGETTEXBUMPPARAMETERFVATIPROC) (GLenum, GLfloat *); +/* GLX_SGI_video_sync */ +typedef int (APIENTRY * PGLXFNGETVIDEOSYNCSGIPROC) (unsigned int *); +typedef int (APIENTRY * PGLXFNWAITVIDEOSYNCSGIPROC) (int, int, unsigned int *); + /* GL_VERSION_2_0 */ #ifndef GL_VERSION_2_0 #define GL_VERSION_2_0 1 @@ -1593,6 +1597,8 @@ typedef enum _GL_SupportedExt { /* APPLE */ APPLE_FENCE, APPLE_CLIENT_STORAGE, + /* SGI */ + SGI_VIDEO_SYNC, OPENGL_SUPPORTED_EXT_END } GL_SupportedExt; @@ -1817,6 +1823,9 @@ typedef enum _GL_SupportedExt { USE_GL_FUNC(PGLFNTEXBUMPPARAMETERFVATIPROC, glTexBumpParameterfvATI); \ USE_GL_FUNC(PGLFNGETTEXBUMPPARAMETERIVATIPROC, glGetTexBumpParameterivATI); \ USE_GL_FUNC(PGLFNGETTEXBUMPPARAMETERFVATIPROC, glGetTexBumpParameterfvATI); \ + /* GLX_SGI_video_sync */ \ + USE_GL_FUNC(PGLXFNGETVIDEOSYNCSGIPROC, glXGetVideoSyncSGI); \ + USE_GL_FUNC(PGLXFNWAITVIDEOSYNCSGIPROC, glXWaitVideoSyncSGI); \ /* OpenGL 2.0 functions */ #define GL2_FUNCS_GEN \ diff --git a/include/wine/wined3d_types.h b/include/wine/wined3d_types.h index 0cbe88017d1..baebdc37f4c 100644 --- a/include/wine/wined3d_types.h +++ b/include/wine/wined3d_types.h @@ -1759,4 +1759,15 @@ typedef struct _WINEDDOVERLAYFX #define WINEDDGFS_CANFLIP 1L #define WINEDDGFS_ISFLIPDONE 2L +/* dwFlags for Flip */ +#define WINEDDFLIP_WAIT 0x00000001 +#define WINEDDFLIP_EVEN 0x00000002 /* only valid for overlay */ +#define WINEDDFLIP_ODD 0x00000004 /* only valid for overlay */ +#define WINEDDFLIP_NOVSYNC 0x00000008 +#define WINEDDFLIP_STEREO 0x00000010 +#define WINEDDFLIP_DONOTWAIT 0x00000020 +#define WINEDDFLIP_INTERVAL2 0x02000000 +#define WINEDDFLIP_INTERVAL3 0x03000000 +#define WINEDDFLIP_INTERVAL4 0x04000000 + #endif