ddraw: Support using an application-provided surface pointer.
diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index bd13d56..44fe5a0 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -1790,13 +1790,6 @@
}
}
- /* Get the surface parameters */
- if ( pDDSD->dwFlags & DDSD_LPSURFACE)
- {
- ERR("(%p) Using a passed surface pointer is not yet supported\n", This);
- assert(0);
- }
-
/* Get the correct wined3d usage */
if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
DDSCAPS_BACKBUFFER |
@@ -1995,6 +1988,16 @@
DDCKEY_SRCBLT,
&pDDSD->ddckCKSrcBlt);
}
+ if ( pDDSD->dwFlags & DDSD_LPSURFACE)
+ {
+ hr = IWineD3DSurface_SetMem((*ppSurf)->WineD3DSurface, pDDSD->lpSurface);
+ if(hr != WINED3D_OK)
+ {
+ /* No need for a trace here, wined3d does that for us */
+ IDirectDrawSurface7_Release(ICOM_INTERFACE((*ppSurf), IDirectDrawSurface7));
+ return hr;
+ }
+ }
return DD_OK;
}
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index a9086d2..587a3e9 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -1933,6 +1933,15 @@
DDCKEY_SRCBLT,
&DDSD->ddckCKSrcBlt);
}
+ if (DDSD->dwFlags & DDSD_LPSURFACE)
+ {
+ hr = IWineD3DSurface_SetMem(This->WineD3DSurface, DDSD->lpSurface);
+ if(hr != WINED3D_OK)
+ {
+ /* No need for a trace here, wined3d does that for us */
+ return hr;
+ }
+ }
This->surface_desc = *DDSD;
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 9c2ed60..df35fc6 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -102,6 +102,7 @@
This->dib.bitmap_data = NULL;
This->resource.allocatedMemory = NULL;
}
+ IWineD3DSurface_SetMem(iface, NULL);
IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
if(iface == device->ddraw_primary)
@@ -1161,6 +1162,11 @@
TRACE("(%p)->(%p)\n",This,pHDC);
+ if(This->Flags & SFLAG_USERPTR) {
+ ERR("Not supported on surfaces with an application-provided surfaces\n");
+ return DDERR_NODC;
+ }
+
/* Give more detailed info for ddraw */
if (This->Flags & SFLAG_DCINUSE)
return DDERR_DCALREADYCREATED;
@@ -2104,6 +2110,49 @@
return WINED3D_OK;
}
+HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
+ IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
+
+ /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
+ if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
+ ERR("Not supported on render targets\n");
+ return WINED3DERR_INVALIDCALL;
+ }
+
+ if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
+ WARN("Surface is locked or the HDC is in use\n");
+ return WINED3DERR_INVALIDCALL;
+ }
+
+ if(Mem && Mem != This->resource.allocatedMemory) {
+
+ /* Do I have to copy the old surface content? */
+ if(This->Flags & SFLAG_DIBSECTION) {
+ /* Release the DC. No need to hold the critical section for the update
+ * Thread because this thread runs only on front buffers, but this method
+ * fails for render targets in the check above.
+ */
+ SelectObject(This->hDC, This->dib.holdbitmap);
+ DeleteDC(This->hDC);
+ /* Release the DIB section */
+ DeleteObject(This->dib.DIBsection);
+ This->dib.bitmap_data = NULL;
+ This->resource.allocatedMemory = NULL;
+ This->hDC = NULL;
+ This->Flags &= ~SFLAG_DIBSECTION;
+ } else if(!(This->Flags & SFLAG_USERPTR)) {
+ HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
+ }
+ This->resource.allocatedMemory = Mem;
+ This->Flags |= SFLAG_USERPTR;
+ } else if(This->Flags & SFLAG_USERPTR) {
+ /* Lockrect and GetDC will re-create the dib section and allocated memory */
+ This->resource.allocatedMemory = NULL;
+ This->Flags &= ~SFLAG_USERPTR;
+ }
+ return WINED3D_OK;
+}
+
/* TODO: replace this function with context management routines */
HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
@@ -2975,6 +3024,7 @@
IWineD3DSurfaceImpl_RealizePalette,
IWineD3DSurfaceImpl_SetColorKey,
IWineD3DSurfaceImpl_GetPitch,
+ IWineD3DSurfaceImpl_SetMem,
/* Internal use: */
IWineD3DSurfaceImpl_CleanDirtyRect,
IWineD3DSurfaceImpl_AddDirtyRect,
diff --git a/dlls/wined3d/surface_gdi.c b/dlls/wined3d/surface_gdi.c
index bb07afa..9609ebd 100644
--- a/dlls/wined3d/surface_gdi.c
+++ b/dlls/wined3d/surface_gdi.c
@@ -178,6 +178,18 @@
TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n",
This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
+ if(!This->resource.allocatedMemory) {
+ HDC hdc;
+ HRESULT hr;
+ /* This happens on gdi surfaces if the application set a user pointer and resets it.
+ * Recreate the DIB section
+ */
+ hr = IWineD3DSurface_GetDC(iface, &hdc); /* will recursively call lockrect, do not set the LOCKED flag to this line */
+ if(hr != WINED3D_OK) return hr;
+ hr = IWineD3DSurface_ReleaseDC(iface, hdc);
+ if(hr != WINED3D_OK) return hr;
+ }
+
pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
if (NULL == pRect)
@@ -1570,6 +1582,7 @@
IWineD3DSurfaceImpl_RealizePalette,
IWineD3DSurfaceImpl_SetColorKey,
IWineD3DSurfaceImpl_GetPitch,
+ IWineD3DSurfaceImpl_SetMem,
/* Internal use: */
IWineD3DSurfaceImpl_CleanDirtyRect,
IWineD3DSurfaceImpl_AddDirtyRect,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 1f51e3b..d0fb485 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -929,6 +929,7 @@
HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC);
DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface);
HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface);
+HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem);
/* Surface flags: */
#define SFLAG_OVERSIZE 0x00000001 /* Surface is bigger than gl size, blts only */
@@ -948,7 +949,7 @@
#define SFLAG_GLDIRTY 0x00004000 /* The opengl texture is more up to date than the surface mem */
#define SFLAG_LOST 0x00008000 /* Surface lost flag for DDraw */
#define SFLAG_FORCELOAD 0x00010000 /* To force PreLoading of a scratch cursor */
-
+#define SFLAG_USERPTR 0x00020000 /* The application allocated the memory for this surface */
/* In some conditions the surface memory must not be freed:
* SFLAG_OVERSIZE: Not all data can be kept in GL
@@ -967,7 +968,8 @@
SFLAG_LOCKED | \
SFLAG_ACTIVELOCK | \
SFLAG_DYNLOCK | \
- SFLAG_DYNCHANGE )
+ SFLAG_DYNCHANGE | \
+ SFLAG_USERPTR)
BOOL CalculateTexRect(IWineD3DSurfaceImpl *This, RECT *Rect, float glTexCoord[4]);
diff --git a/include/wine/wined3d_interface.h b/include/wine/wined3d_interface.h
index 1c97114..2104aaa 100644
--- a/include/wine/wined3d_interface.h
+++ b/include/wine/wined3d_interface.h
@@ -1130,6 +1130,7 @@
STDMETHOD(RealizePalette)(THIS) PURE;
STDMETHOD(SetColorKey)(THIS_ DWORD Flags, DDCOLORKEY *CKey) PURE;
STDMETHOD_(DWORD,GetPitch)(THIS) PURE;
+ STDMETHOD(SetMem)(THIS_ void *mem) PURE;
/* Internally used methods */
STDMETHOD(CleanDirtyRect)(THIS) PURE;
STDMETHOD(AddDirtyRect)(THIS_ CONST RECT* pRect) PURE;
@@ -1181,6 +1182,7 @@
#define IWineD3DSurface_RealizePalette(p) (p)->lpVtbl->RealizePalette(p)
#define IWineD3DSurface_SetColorKey(p, a, b) (p)->lpVtbl->SetColorKey(p, a, b)
#define IWineD3DSurface_GetPitch(p) (p)->lpVtbl->GetPitch(p)
+#define IWineD3DSurface_SetMem(p, a) (p)->lpVtbl->SetMem(p, a)
/*** IWineD3DSurface (Internal, no d3d mapping) methods ***/
#define IWineD3DSurface_CleanDirtyRect(p) (p)->lpVtbl->CleanDirtyRect(p)
#define IWineD3DSurface_AddDirtyRect(p,a) (p)->lpVtbl->AddDirtyRect(p,a)