diff --git a/dlls/ddrawex/ddraw.c b/dlls/ddrawex/ddraw.c index 9645a3de6af..9e8066a038d 100644 --- a/dlls/ddrawex/ddraw.c +++ b/dlls/ddrawex/ddraw.c @@ -387,6 +387,8 @@ IDirectDraw4Impl_CreateSurface(IDirectDraw4 *iface, { IDirectDrawImpl *This = impl_from_dd4(iface); HRESULT hr; + const DWORD perm_dc_flags = DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY; + BOOL permanent_dc; TRACE("(%p)(%p, %p, %p)\n", This, DDSD, Surf, UnkOuter); if(UnkOuter != NULL) @@ -395,8 +397,25 @@ IDirectDraw4Impl_CreateSurface(IDirectDraw4 *iface, FIXME("Implement aggregation for ddrawex surfaces\n"); } + /* plain ddraw.dll refuses to create a surface that has both VIDMEM and SYSMEM flags + * set. In ddrawex this succeeds, and the GetDC() call changes the behavior. The DC + * is permanently valid, and the surface can be locked between GetDC() and ReleaseDC() + * calls. GetDC() can be called more than once too + */ + if((DDSD->ddsCaps.dwCaps & perm_dc_flags) == perm_dc_flags) + { + permanent_dc = TRUE; + DDSD->ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; + DDSD->ddsCaps.dwCaps |= DDSCAPS_OWNDC; + } + else + { + permanent_dc = FALSE; + } + hr = IDirectDraw4_CreateSurface(This->parent, DDSD, Surf, UnkOuter); *Surf = dds_get_outer(*Surf); + if(permanent_dc) prepare_permanent_dc(*Surf); return hr; } diff --git a/dlls/ddrawex/ddrawex_private.h b/dlls/ddrawex/ddrawex_private.h index 12d76d5293c..3e7a0e220c8 100644 --- a/dlls/ddrawex/ddrawex_private.h +++ b/dlls/ddrawex/ddrawex_private.h @@ -100,6 +100,9 @@ typedef struct /* The interface we're forwarding to */ IDirectDrawSurface4 *parent; + BOOL permanent_dc; + HDC hdc; + /* An UUID we use to store the outer surface as private data in the inner surface */ #define IID_DDrawexPriv IID_IDirectDrawSurface4 @@ -107,5 +110,6 @@ typedef struct IDirectDrawSurface4 *dds_get_outer(IDirectDrawSurface4 *inner); IDirectDrawSurface4 *dds_get_inner(IDirectDrawSurface4 *outer); +HRESULT prepare_permanent_dc(IDirectDrawSurface4 *iface); #endif /* __WINE_DLLS_DDRAWEX_DDRAWEX_PRIVATE_H */ diff --git a/dlls/ddrawex/surface.c b/dlls/ddrawex/surface.c index 9b16ce51109..106b02756c2 100644 --- a/dlls/ddrawex/surface.c +++ b/dlls/ddrawex/surface.c @@ -563,7 +563,16 @@ IDirectDrawSurface4Impl_GetDC(IDirectDrawSurface4 *iface, { IDirectDrawSurfaceImpl *This = impl_from_dds4(iface); TRACE("(%p)->(%p)\n", This, hdc); - return IDirectDrawSurface4_GetDC(This->parent, hdc); + if(This->permanent_dc) + { + TRACE("Returning stored dc %p\n", This->hdc); + *hdc = This->hdc; + return DD_OK; + } + else + { + return IDirectDrawSurface4_GetDC(This->parent, hdc); + } } static HRESULT WINAPI @@ -654,8 +663,17 @@ IDirectDrawSurface4Impl_GetSurfaceDesc(IDirectDrawSurface4 *iface, DDSURFACEDESC2 *DDSD) { IDirectDrawSurfaceImpl *This = impl_from_dds4(iface); + HRESULT hr; TRACE("(%p)->(%p)\n", This, DDSD); - return IDirectDrawSurface4_GetSurfaceDesc(This->parent, DDSD); + hr = IDirectDrawSurface4_GetSurfaceDesc(This->parent, DDSD); + + if(SUCCEEDED(hr) && This->permanent_dc) + { + DDSD->ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + DDSD->ddsCaps.dwCaps &= ~DDSCAPS_OWNDC; + } + + return hr; } static HRESULT WINAPI @@ -731,8 +749,17 @@ IDirectDrawSurface4Impl_Lock(IDirectDrawSurface4 *iface, HANDLE h) { IDirectDrawSurfaceImpl *This = impl_from_dds4(iface); + HRESULT hr; TRACE("(%p)->(%p,%p,0x%08x,%p)\n", This, Rect, DDSD, Flags, h); - return IDirectDrawSurface4_Lock(This->parent, Rect, DDSD, Flags, h); + hr = IDirectDrawSurface4_Lock(This->parent, Rect, DDSD, Flags, h); + + if(SUCCEEDED(hr) && This->permanent_dc) + { + DDSD->ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + DDSD->ddsCaps.dwCaps &= ~DDSCAPS_OWNDC; + } + + return hr; } static HRESULT WINAPI @@ -759,7 +786,15 @@ IDirectDrawSurface4Impl_ReleaseDC(IDirectDrawSurface4 *iface, { IDirectDrawSurfaceImpl *This = impl_from_dds4(iface); TRACE("(%p)->(%p)\n", This, hdc); - return IDirectDrawSurface4_ReleaseDC(This->parent, hdc); + if(This->permanent_dc) + { + TRACE("Surface has a permanent DC, not doing anything\n"); + return DD_OK; + } + else + { + return IDirectDrawSurface4_ReleaseDC(This->parent, hdc); + } } static HRESULT WINAPI @@ -1259,3 +1294,15 @@ IDirectDrawSurface4 *dds_get_inner(IDirectDrawSurface4 *outer) if(This == NULL) return NULL; return This->parent; } + +HRESULT prepare_permanent_dc(IDirectDrawSurface4 *iface) +{ + IDirectDrawSurfaceImpl *This = impl_from_dds4(iface); + HRESULT hr; + This->permanent_dc = TRUE; + + hr = IDirectDrawSurface4_GetDC(This->parent, &This->hdc); + if(FAILED(hr)) return hr; + hr = IDirectDrawSurface4_ReleaseDC(This->parent, This->hdc); + return hr; +} diff --git a/dlls/ddrawex/tests/surface.c b/dlls/ddrawex/tests/surface.c index b2065bca31c..c8d519ba889 100644 --- a/dlls/ddrawex/tests/surface.c +++ b/dlls/ddrawex/tests/surface.c @@ -161,7 +161,7 @@ static void CapsTest(void) ddsd.dwWidth = 64; ddsd.dwHeight = 64; hr = IDirectDraw_CreateSurface(dd1, &ddsd, &surf, NULL); - todo_wine ok(hr == DD_OK, "Creating a SYSMEM | VIDMEM surface returned 0x%08x, expected DD_OK\n", hr); + ok(hr == DD_OK, "Creating a SYSMEM | VIDMEM surface returned 0x%08x, expected DD_OK\n", hr); if(surf) IDirectDrawSurface_Release(surf); IDirectDraw_Release(dd1);