wined3d: Implement IWineD3DSurface::GetDC and IWineD3DSurface::ReleaseDC.
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 9bb0916..bb5d070 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -1,6 +1,7 @@
/*
* IWineD3DSurface Implementation
*
+ * Copyright 2000-2001 TransGaming Technologies Inc.
* Copyright 2002-2005 Jason Edmeades
* Copyright 2002-2003 Raphael Junqueira
* Copyright 2004 Christian Costa
@@ -70,6 +71,17 @@
glDeleteTextures(1, &This->glDescription.textureName);
LEAVE_GL();
}
+
+ if(This->Flags & SFLAG_DIBSECTION) {
+ /* Release the DC */
+ 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;
+ }
+
IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
TRACE("(%p) Released\n", This);
@@ -344,12 +356,15 @@
These resources may be POOL_SYSTEMMEM, so they must not access the device */
TRACE("locking an ordinarary surface\n");
/* Check to see if memory has already been allocated from the surface*/
- if (NULL == This->resource.allocatedMemory) { /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
+ if ((NULL == This->resource.allocatedMemory) ||
+ (This->Flags & SFLAG_NEWDC) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
/* Non-system memory surfaces */
/*Surface has no memory currently allocated to it!*/
TRACE("(%p) Locking rect\n" , This);
- This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
+ if(!This->resource.allocatedMemory) {
+ This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
+ }
if (0 != This->glDescription.textureName) {
/* Now I have to copy thing bits back */
This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
@@ -704,6 +719,22 @@
GLint prev_draw;
GLint prev_rasterpos[4];
+ /* Some drivers(radeon dri, others?) don't like exceptions during
+ * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
+ * after ReleaseDC. Reading it will cause an exception, which x11drv will
+ * catch to put the dib section in InSync mode, which leads to a crash
+ * and a blocked x server on my radeon card.
+ *
+ * The following lines read the dib section so it is put in inSync mode
+ * before glDrawPixels is called and the crash is prevented. There won't
+ * be any interfering gdi accesses, because UnlockRect is called from
+ * ReleaseDC, and the app won't use the dc any more afterwards.
+ */
+ if(This->Flags & SFLAG_DIBSECTION) {
+ volatile BYTE read;
+ read = This->resource.allocatedMemory[0];
+ }
+
ENTER_GL();
glFlush();
@@ -906,14 +937,216 @@
HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
- FIXME("No support for GetDC yet for surface %p\n", This);
- return WINED3DERR_INVALIDCALL;
+ WINED3DLOCKED_RECT lock;
+ UINT usage;
+ BITMAPINFO* b_info;
+ HDC ddc;
+ DWORD *masks;
+ HRESULT hr;
+
+ TRACE("(%p)->(%p)\n",This,pHDC);
+
+ /* Give more detailed info for ddraw */
+ if (This->Flags & SFLAG_DCINUSE)
+ return DDERR_DCALREADYCREATED;
+
+ /* Can't GetDC if the surface is locked */
+ if (This->Flags & SFLAG_LOCKED)
+ return WINED3DERR_INVALIDCALL;
+
+ memset(&lock, 0, sizeof(lock)); /* To be sure */
+
+ /* Create a DIB section if there isn't a hdc yet */
+ if(!This->hDC)
+ {
+ RGBQUAD col[256];
+
+ if(This->Flags & SFLAG_ACTIVELOCK)
+ {
+ ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
+ }
+
+ switch (This->bytesPerPixel)
+ {
+ case 2:
+ case 4:
+ /* Allocate extra space to store the RGB bit masks. */
+ b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
+ break;
+
+ case 3:
+ b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
+ break;
+
+ default:
+ /* Allocate extra space for a palette. */
+ b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(BITMAPINFOHEADER)
+ + sizeof(RGBQUAD)
+ * (1 << (This->bytesPerPixel * 8)));
+ break;
+ }
+
+ b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ b_info->bmiHeader.biWidth = This->pow2Width;
+ b_info->bmiHeader.biHeight = -This->pow2Height;
+ b_info->bmiHeader.biPlanes = 1;
+ b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
+
+ b_info->bmiHeader.biSizeImage = This->resource.size;
+
+ b_info->bmiHeader.biXPelsPerMeter = 0;
+ b_info->bmiHeader.biYPelsPerMeter = 0;
+ b_info->bmiHeader.biClrUsed = 0;
+ b_info->bmiHeader.biClrImportant = 0;
+
+ /* Get the bit masks */
+ masks = (DWORD *) &(b_info->bmiColors);
+ switch (This->resource.format)
+ {
+ case WINED3DFMT_R8G8B8:
+ usage = DIB_RGB_COLORS;
+ b_info->bmiHeader.biCompression = BI_RGB;
+ break;
+
+ case WINED3DFMT_X1R5G5B5:
+ case WINED3DFMT_A1R5G5B5:
+ case WINED3DFMT_A4R4G4B4:
+ case WINED3DFMT_X4R4G4B4:
+ case WINED3DFMT_R3G3B2:
+ case WINED3DFMT_A8R3G3B2:
+ case WINED3DFMT_A2B10G10R10:
+ case WINED3DFMT_A8B8G8R8:
+ case WINED3DFMT_X8B8G8R8:
+ case WINED3DFMT_A2R10G10B10:
+ case WINED3DFMT_R5G6B5:
+ case WINED3DFMT_A16B16G16R16:
+ usage = 0;
+ b_info->bmiHeader.biCompression = BI_BITFIELDS;
+ masks[0] = get_bitmask_red(This->resource.format);
+ masks[1] = get_bitmask_green(This->resource.format);
+ masks[2] = get_bitmask_blue(This->resource.format);
+ break;
+
+ default:
+ /* Don't know palette */
+ b_info->bmiHeader.biCompression = BI_RGB;
+ usage = 0;
+ break;
+ }
+
+ ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
+ if (ddc == 0)
+ {
+ HeapFree(GetProcessHeap(), 0, b_info);
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ TRACE("Creating a DIB section with size %ldx%ldx%d, size=%ld\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
+ This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
+ DeleteDC(ddc);
+
+ if (!This->dib.DIBsection)
+ {
+ ERR("CreateDIBSection failed!\n");
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+ HeapFree(GetProcessHeap(), 0, b_info);
+
+ TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
+
+ /* copy the existing surface to the dib section */
+ if(This->resource.allocatedMemory)
+ {
+ memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
+ /* We won't need that any more */
+ HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
+ }
+
+ /* Use the dib section from now on */
+ This->resource.allocatedMemory = This->dib.bitmap_data;
+
+ /* Now allocate a HDC */
+ This->hDC = CreateCompatibleDC(0);
+ This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
+ TRACE("using wined3d palette %p\n", This->palette);
+ SelectPalette(This->hDC,
+ This->palette ? This->palette->hpal : 0,
+ FALSE);
+
+ if(This->resource.format == WINED3DFMT_P8 ||
+ This->resource.format == WINED3DFMT_A8P8)
+ {
+ unsigned int n;
+ if(This->palette)
+ {
+ PALETTEENTRY ent[256];
+
+ GetPaletteEntries(This->palette->hpal, 0, 256, ent);
+ for (n=0; n<256; n++)
+ {
+ col[n].rgbRed = ent[n].peRed;
+ col[n].rgbGreen = ent[n].peGreen;
+ col[n].rgbBlue = ent[n].peBlue;
+ col[n].rgbReserved = 0;
+ }
+ }
+ else
+ {
+ IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
+
+ for (n=0; n<256; n++)
+ {
+ col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
+ col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
+ col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
+ col[n].rgbReserved = 0;
+ }
+
+ }
+ SetDIBColorTable(This->hDC, 0, 256, col);
+ }
+
+ /* This is to make LockRect read the gl Texture although memory is allocated */
+ This->Flags |= SFLAG_NEWDC;
+
+ This->Flags |= SFLAG_DIBSECTION;
+ }
+
+ /* Lock the surface */
+ hr = IWineD3DSurface_LockRect(iface,
+ &lock,
+ NULL,
+ 0);
+ This->Flags &= ~SFLAG_NEWDC;
+ if(FAILED(hr))
+ {
+ ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
+ /* keep the dib section */
+ return hr;
+ }
+
+ *pHDC = This->hDC;
+ TRACE("returning %p\n",*pHDC);
+ This->Flags |= SFLAG_DCINUSE;
+
+ return WINED3D_OK;
}
HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
- FIXME("No support for ReleaseDC yet for surface %p\n", This);
- return WINED3DERR_INVALIDCALL;
+
+ TRACE("(%p)->(%p)\n",This,hDC);
+
+ if (!(This->Flags & SFLAG_DCINUSE))
+ return D3DERR_INVALIDCALL;
+
+ /* we locked first, so unlock now */
+ IWineD3DSurface_UnlockRect(iface);
+
+ This->Flags &= ~SFLAG_DCINUSE;
+
+ return WINED3D_OK;
}
/* ******************************************************
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index ca76a93..e419c7c 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -2061,3 +2061,184 @@
default: return WINED3DFMT_UNKNOWN;
}
}
+
+LONG get_bitmask_red(WINED3DFORMAT fmt)
+{
+ switch (fmt) {
+ case WINED3DFMT_R8G8B8:
+ case WINED3DFMT_A8R8G8B8:
+ case WINED3DFMT_X8R8G8B8:
+ return 0x00ff0000;
+
+ case WINED3DFMT_X1R5G5B5:
+ case WINED3DFMT_A1R5G5B5:
+ return 0x7C00;
+
+ case WINED3DFMT_A4R4G4B4:
+ case WINED3DFMT_X4R4G4B4:
+ return 0xF00;
+
+ case WINED3DFMT_R3G3B2:
+ case WINED3DFMT_A8R3G3B2:
+ return 0xE0;
+
+ case WINED3DFMT_A2R10G10B10:
+ return 0x3F0000;
+ break;
+
+ case WINED3DFMT_A2B10G10R10:
+ return 0x3FF;
+
+ case WINED3DFMT_A8B8G8R8:
+ case WINED3DFMT_X8B8G8R8:
+ return 0xff;
+
+ case WINED3DFMT_R5G6B5:
+ return 0xF800;
+
+ case WINED3DFMT_P8:
+ /* No fixed mask for this format */
+ return 0;
+
+#if 0
+ case WINED3DFMT_A16B16G16R16:
+ return 0x00000000ffff;
+ break;
+#endif
+
+ default:
+ ERR("Unknown bitmask for format %d\n", fmt);
+ return 0;
+ }
+}
+
+LONG get_bitmask_green(WINED3DFORMAT fmt)
+{
+ switch (fmt) {
+ case WINED3DFMT_R8G8B8:
+ case WINED3DFMT_A8R8G8B8:
+ case WINED3DFMT_X8R8G8B8:
+ return 0x0000ff00;
+
+ case WINED3DFMT_X1R5G5B5:
+ case WINED3DFMT_A1R5G5B5:
+ return 0x3E0;
+
+ case WINED3DFMT_A4R4G4B4:
+ case WINED3DFMT_X4R4G4B4:
+ return 0xF0;
+
+ case WINED3DFMT_R3G3B2:
+ case WINED3DFMT_A8R3G3B2:
+ return 0x1C;
+
+ case WINED3DFMT_A2B10G10R10:
+ return 0xFFC00;
+
+ case WINED3DFMT_A8B8G8R8:
+ case WINED3DFMT_X8B8G8R8:
+ return 0xFF00;
+ break;
+
+ case WINED3DFMT_A2R10G10B10:
+ return 0xFFC00;
+ break;
+
+ case WINED3DFMT_R5G6B5:
+ return 0x7E0;
+
+ case WINED3DFMT_P8:
+ /* No fixed mask for this format */
+ return 0;
+
+#if 0
+ case WINED3DFMT_A16B16G16R16:
+ return 0x0000ffff0000;
+ break;
+#endif
+
+ default:
+ ERR("Unknown bitmask for format %d\n", fmt);
+ return 0;
+ }
+}
+
+LONG get_bitmask_blue(WINED3DFORMAT fmt)
+{
+ switch (fmt) {
+ case WINED3DFMT_R8G8B8:
+ case WINED3DFMT_A8R8G8B8:
+ case WINED3DFMT_X8R8G8B8:
+ return 0x000000ff;
+
+ case WINED3DFMT_X1R5G5B5:
+ case WINED3DFMT_A1R5G5B5:
+ return 0x1f;
+
+ case WINED3DFMT_A4R4G4B4:
+ case WINED3DFMT_X4R4G4B4:
+ return 0xF;
+
+ case WINED3DFMT_R3G3B2:
+ case WINED3DFMT_A8R3G3B2:
+ return 0x3;
+
+ case WINED3DFMT_A2B10G10R10:
+ return 0x3F0000;
+
+ case WINED3DFMT_A8B8G8R8:
+ case WINED3DFMT_X8B8G8R8:
+ return 0xFF0000;
+
+ case WINED3DFMT_A2R10G10B10:
+ return 0x3FF;
+
+ case WINED3DFMT_R5G6B5:
+ return 0x1F;
+
+ case WINED3DFMT_P8:
+ /* No fixed mask for this format */
+ return 0;
+
+#if 0
+ case WINED3DFMT_A16B16G16R16:
+ return 0xffff00000000;
+ break;
+#endif
+
+ default:
+ ERR("Unknown bitmask for format %d\n", fmt);
+ return 0;
+
+ }
+}
+
+LONG get_bitmask_alpha(WINED3DFORMAT fmt)
+{
+ switch (fmt) {
+ case WINED3DFMT_A8R8G8B8:
+ return 0xff000000;
+
+ case WINED3DFMT_A1R5G5B5:
+ return 0x8000;
+
+ case WINED3DFMT_A4R4G4B4:
+ return 0xF000;
+
+ case WINED3DFMT_A8R3G3B2:
+ return 0xff00;
+
+ case WINED3DFMT_A2B10G10R10:
+ return 0xb0000000;
+
+ case WINED3DFMT_A8B8G8R8:
+ return 0xFF000000;
+
+ case WINED3DFMT_A2R10G10B10:
+ return 0xb0000000;
+
+ default:
+ return 0;
+
+ }
+}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 0150820..3997b9c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -786,6 +786,16 @@
} WINED3DSURFACET_DESC;
/*****************************************************************************
+ * Structure for DIB Surfaces (GetDC and GDI surfaces)
+ */
+typedef struct wineD3DSurface_DIB {
+ HBITMAP DIBsection;
+ void* bitmap_data;
+ HGDIOBJ holdbitmap;
+ BOOL client_memory;
+} wineD3DSurface_DIB;
+
+/*****************************************************************************
* IWineD3DSurface implementation structure
*/
struct IWineD3DSurfaceImpl
@@ -819,6 +829,10 @@
RECT dirtyRect;
glDescriptor glDescription;
+
+ /* For GetDC */
+ wineD3DSurface_DIB dib;
+ HDC hDC;
};
extern const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl;
@@ -837,6 +851,8 @@
#define SFLAG_NONPOW2 0x0400 /* Surface sizes are not a power of 2 */
#define SFLAG_DYNLOCK 0x0800 /* Surface is often locked by the app */
#define SFLAG_DYNCHANGE 0x1800 /* Surface contents are changed very often, implies DYNLOCK */
+#define SFLAG_DCINUSE 0x2000 /* Set between GetDC and ReleaseDC calls */
+#define SFLAG_NEWDC 0x4000 /* To inform LockRect about a new dc */
/* In some conditions the surface memory must not be freed:
* SFLAG_OVERSIZE: Not all data can be kept in GL
@@ -1299,5 +1315,9 @@
/* DirectDraw utility functions */
extern WINED3DFORMAT pixelformat_for_depth(DWORD depth);
+LONG get_bitmask_red(WINED3DFORMAT fmt);
+LONG get_bitmask_green(WINED3DFORMAT fmt);
+LONG get_bitmask_blue(WINED3DFORMAT fmt);
+LONG get_bitmask_alpha(WINED3DFORMAT fmt);
#endif