Commit da6c9e4c authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

ddrawex: Implement a GetDC special behavior Internet Explorer depends on.

Tests show that in ddrawex.dll it is legal to create a surface with both DDSCAPS_VIDEOMEMORY and DDSCAPS_SYSTEMMEMORY flag set. A surface created that way shows different behavior in IDirectDrawSurface::GetDC.
parent 0d80130a
......@@ -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;
}
......
......@@ -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 */
......@@ -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;
}
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment