diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 66ce1664c7d..11071f5a0b6 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -232,6 +232,8 @@ struct IDirectDrawSurfaceImpl /* For the ddraw surface list */ IDirectDrawSurfaceImpl *next; IDirectDrawSurfaceImpl *prev; + + DWORD Handle; }; /* VTable declaration. It's located in surface.c / surface_thunks.c */ @@ -264,6 +266,19 @@ const IParentVtbl IParent_Vtbl; /***************************************************************************** * IDirect3DDevice implementation *****************************************************************************/ +typedef enum +{ + DDrawHandle_Unknown = 0, + DDrawHandle_Texture = 1, + DDrawHandle_Material = 2 +} DDrawHandleTypes; + +struct HandleEntry +{ + void *ptr; + DDrawHandleTypes type; +}; + struct IDirect3DDeviceImpl { /* IUnknown */ @@ -296,6 +311,10 @@ struct IDirect3DDeviceImpl LPBYTE vertex_buffer; DWORD vertex_size; DWORD buffer_size; + + /* Handle management */ + struct HandleEntry *Handles; + DWORD numHandles; }; /* Vtables in various versions */ @@ -309,6 +328,7 @@ const GUID IID_D3DDEVICE_WineD3D; /* Helper functions */ HRESULT IDirect3DImpl_GetCaps(IWineD3D *WineD3D, D3DDEVICEDESC *Desc123, D3DDEVICEDESC7 *Desc7); +DWORD IDirect3DDeviceImpl_CreateHandle(IDirect3DDeviceImpl *This); /* Structures */ struct EnumTextureFormatsCBS @@ -443,6 +463,7 @@ struct IDirect3DMaterialImpl IDirect3DDeviceImpl *active_device; D3DMATERIAL mat; + DWORD Handle; void (*activate)(IDirect3DMaterialImpl* this); }; diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index f0eb86cfdb2..8c454f51534 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -286,6 +286,8 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface) if (ref == 0) { IParent *IndexBufferParent; + DWORD i; + /* Free the index buffer */ IWineD3DDevice_SetIndices(This->wineD3DDevice, NULL, @@ -316,6 +318,38 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface) ERR(" (%p) The wineD3D device %p was destroyed unexpectadely. Prepare for trouble\n", This, This->wineD3DDevice); } + /* The texture handles should be unset by now, but there might be some bits + * missing in our reference counting(needs test). Do a sanity check + */ + for(i = 0; i < This->numHandles; i++) + { + if(This->Handles[i].ptr) + { + switch(This->Handles[i].type) + { + case DDrawHandle_Texture: + { + IDirectDrawSurfaceImpl *surf = (IDirectDrawSurfaceImpl *) This->Handles[i].ptr; + FIXME("Texture Handle %ld not unset properly\n", i + 1); + surf->Handle = 0; + } + break; + + case DDrawHandle_Material: + { + IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) This->Handles[i].ptr; + FIXME("Material handle %ld not unset properly\n", i + 1); + mat->Handle = 0; + } + + default: + FIXME("Unknown handle %ld not unset properly\n", i + 1); + } + } + } + + HeapFree(GetProcessHeap(), 0, This->Handles); + /* Release the render target and the WineD3D render target * (See IDirect3D7::CreateDevice for more comments on this) */ @@ -492,22 +526,17 @@ IDirect3DDeviceImpl_2_SwapTextureHandles(IDirect3DDevice2 *iface, IDirect3DTexture2 *Tex2) { ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface); - IWineD3DTexture *tmp; + DWORD swap; IDirectDrawSurfaceImpl *surf1 = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, Tex1); IDirectDrawSurfaceImpl *surf2 = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, Tex2); - FIXME("(%p)->(%p,%p)\n", This, surf1, surf2); + TRACE("(%p)->(%p,%p)\n", This, surf1, surf2); + This->Handles[surf1->Handle - 1].ptr = surf2; + This->Handles[surf2->Handle - 1].ptr = surf1; - /* The texture handle is simply the interface address of the WineD3DTexture - * interface. Swap the interface pointers. - */ - tmp = surf1->wineD3DTexture; - surf1->wineD3DTexture = surf2->wineD3DTexture; - surf2->wineD3DTexture = tmp; - - /* What about the parent? Does it have to change too? This could cause a - * problem when Releasing the surfaces, Therefore the fixme - */ + swap = surf2->Handle; + surf2->Handle = surf1->Handle; + surf1->Handle = swap; return D3D_OK; } @@ -2029,9 +2058,32 @@ IDirect3DDeviceImpl_7_SetRenderState(IDirect3DDevice7 *iface, switch(RenderStateType) { case D3DRENDERSTATE_TEXTUREHANDLE: - return IWineD3DDevice_SetTexture(This->wineD3DDevice, - 0, - (IWineD3DBaseTexture *) Value); + { + if(Value == 0) + { + return IWineD3DDevice_SetTexture(This->wineD3DDevice, + 0, + NULL); + } + + if(Value > This->numHandles) + { + FIXME("Specified handle %ld out of range\n", Value); + return DDERR_INVALIDPARAMS; + } + if(This->Handles[Value - 1].type != DDrawHandle_Texture) + { + FIXME("Handle %ld isn't a texture handle\n", Value); + return DDERR_INVALIDPARAMS; + } + else + { + IDirectDrawSurfaceImpl *surf = (IDirectDrawSurfaceImpl *) This->Handles[Value - 1].ptr; + return IWineD3DDevice_SetTexture(This->wineD3DDevice, + 0, + (IWineD3DBaseTexture *) surf->wineD3DTexture); + } + } case D3DRENDERSTATE_TEXTUREMAG: { @@ -4572,3 +4624,68 @@ const IDirect3DDeviceVtbl IDirect3DDevice1_Vtbl = Thunk_IDirect3DDeviceImpl_1_BeginScene, Thunk_IDirect3DDeviceImpl_1_GetDirect3D }; + +/***************************************************************************** + * IDirect3DDeviceImpl_CreateHandle + * + * Not called from the VTable + * + * Some older interface versions operate with handles, which are basically + * DWORDs which identify an interface, for example + * IDirect3DDevice::SetRenderState with DIRECT3DRENDERSTATE_TEXTUREHANDLE + * + * Those handle could be just casts to the interface pointers or vice versa, + * but that is not 64 bit safe and would mean blindly derefering a DWORD + * passed by the app. Instead there is a dynamic array in the device which + * keeps a DWORD to pointer information and a type for the handle. + * + * Basically this array only grows, when a handle is freed its pointer is + * just set to NULL. There will be much more reads from the array than + * insertion operations, so a dynamic array is fine. + * + * Params: + * This: D3DDevice implementation for which this handle should be created + * + * Returns: + * A free handle on success + * 0 on failure + * + *****************************************************************************/ +DWORD +IDirect3DDeviceImpl_CreateHandle(IDirect3DDeviceImpl *This) +{ + DWORD i; + struct HandleEntry *oldHandles = This->Handles; + + TRACE("(%p)\n", This); + + for(i = 0; i < This->numHandles; i++) + { + if(This->Handles[i].ptr == NULL && + This->Handles[i].type == DDrawHandle_Unknown) + { + TRACE("Reusing freed handle %ld\n", i + 1); + return i + 1; + } + } + + TRACE("Growing the handle array\n"); + + This->numHandles++; + This->Handles = HeapAlloc(GetProcessHeap(), 0, sizeof(struct HandleEntry) * This->numHandles); + if(!This->Handles) + { + ERR("Out of memory\n"); + This->Handles = oldHandles; + This->numHandles--; + return 0; + } + if(oldHandles) + { + memcpy(This->Handles, oldHandles, (This->numHandles - 1) * sizeof(struct HandleEntry)); + HeapFree(GetProcessHeap(), 0, oldHandles); + } + + TRACE("Returning %ld\n", This->numHandles); + return This->numHandles; +} diff --git a/dlls/ddraw/direct3d.c b/dlls/ddraw/direct3d.c index 4691ebf1441..23efef91c03 100644 --- a/dlls/ddraw/direct3d.c +++ b/dlls/ddraw/direct3d.c @@ -729,6 +729,9 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 *iface, object->material = 0; object->target = target; + object->Handles = NULL; + object->numHandles = 0; + /* This is for convenience */ object->wineD3DDevice = This->wineD3DDevice; diff --git a/dlls/ddraw/material.c b/dlls/ddraw/material.c index 36e617d74b4..c2acce14051 100644 --- a/dlls/ddraw/material.c +++ b/dlls/ddraw/material.c @@ -147,9 +147,16 @@ IDirect3DMaterialImpl_Release(IDirect3DMaterial3 *iface) TRACE("(%p)->() decrementing from %lu.\n", This, ref + 1); - if (!ref) { + if (!ref) + { + if(This->Handle) + { + This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL; + This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown; + } + HeapFree(GetProcessHeap(), 0, This); - return 0; + return 0; } return ref; } @@ -301,15 +308,24 @@ IDirect3DMaterialImpl_GetHandle(IDirect3DMaterial3 *iface, D3DMATERIALHANDLE *lpHandle) { ICOM_THIS_FROM(IDirect3DMaterialImpl, IDirect3DMaterial3, iface); - TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpDirect3DDevice3, lpHandle); - - This->active_device = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice3, lpDirect3DDevice3); - *lpHandle = (DWORD) This; /* Warning: this is not 64 bit clean. - Maybe also we need to store this material somewhere in the device ? */ + IDirect3DDeviceImpl *device = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice3, lpDirect3DDevice3); + TRACE("(%p/%p)->(%p,%p)\n", This, iface, device, lpHandle); + if(!This->Handle) + { + This->Handle = IDirect3DDeviceImpl_CreateHandle(device); + if(!This->Handle) + { + ERR("Error creating a handle\n"); + return DDERR_INVALIDPARAMS; /* Unchecked */ + } + device->Handles[This->Handle - 1].ptr = This; + device->Handles[This->Handle - 1].type = DDrawHandle_Material; + } + *lpHandle = This->Handle; TRACE(" returning handle %08lx.\n", *lpHandle); - - return DD_OK; + + return D3D_OK; } static HRESULT WINAPI diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index 5590c809d22..9da19f4b385 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -229,6 +229,13 @@ static void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This) if(This->WineD3DSurface) IWineD3DSurface_Release(This->WineD3DSurface); + /* Having a texture handle set implies that the device still exists */ + if(This->Handle) + { + This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL; + This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown; + } + /* Reduce the ddraw surface count */ InterlockedDecrement(&This->ddraw->surfaces); if(This->prev) diff --git a/dlls/ddraw/texture.c b/dlls/ddraw/texture.c index 07b5edb376b..c3a2717267a 100644 --- a/dlls/ddraw/texture.c +++ b/dlls/ddraw/texture.c @@ -45,6 +45,7 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(d3d7); +WINE_DECLARE_DEBUG_CHANNEL(ddraw_thunk); /***************************************************************************** * IUnknown interfaces. They are thunks to IDirectDrawSurface7 @@ -218,14 +219,16 @@ IDirect3DTextureImpl_GetHandle(IDirect3DTexture2 *iface, TRACE("(%p)->(%p,%p)\n", This, d3d, lpHandle); - /* The handle is the WineD3DTexture interface. SetRenderState depends on this */ - if(This->ddraw->wineD3DDevice) - *lpHandle = (D3DTEXTUREHANDLE) This->wineD3DTexture; - else + if(!This->Handle) { - /* This is to fool applications which create a texture without a D3DDevice */ - *lpHandle = (D3DTEXTUREHANDLE) This; + This->Handle = IDirect3DDeviceImpl_CreateHandle(d3d); + if(This->Handle) + { + d3d->Handles[This->Handle - 1].ptr = This; + d3d->Handles[This->Handle - 1].type = DDrawHandle_Texture; + } } + *lpHandle = This->Handle; TRACE(" returning handle %08lx.\n", *lpHandle); @@ -238,10 +241,11 @@ Thunk_IDirect3DTextureImpl_1_GetHandle(IDirect3DTexture *iface, LPD3DTEXTUREHANDLE lpHandle) { ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface); - TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", This, lpDirect3DDevice, lpHandle); + IDirect3DDeviceImpl *d3d = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice, lpDirect3DDevice); + TRACE_(ddraw_thunk)("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", This, d3d, lpHandle); - return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface), - COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice2, lpDirect3DDevice), + return IDirect3DTexture2_GetHandle(ICOM_INTERFACE(This, IDirect3DTexture2), + ICOM_INTERFACE(d3d, IDirect3DDevice2), lpHandle); } diff --git a/dlls/ddraw/viewport.c b/dlls/ddraw/viewport.c index f1ac9e37e8b..84c17be08ec 100644 --- a/dlls/ddraw/viewport.c +++ b/dlls/ddraw/viewport.c @@ -384,14 +384,33 @@ IDirect3DViewportImpl_SetBackground(IDirect3DViewport3 *iface, D3DMATERIALHANDLE hMat) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); - TRACE("(%p)->(%08lx)\n", This, (DWORD) hMat); - - This->background = (IDirect3DMaterialImpl *) hMat; - TRACE(" setting background color : %f %f %f %f\n", - This->background->mat.u.diffuse.u1.r, - This->background->mat.u.diffuse.u2.g, - This->background->mat.u.diffuse.u3.b, - This->background->mat.u.diffuse.u4.a); + TRACE("(%p)->(%ld)\n", This, (DWORD) hMat); + + if(hMat && hMat > This->ddraw->d3ddevice->numHandles) + { + WARN("Specified Handle %ld out of range\n", hMat); + return DDERR_INVALIDPARAMS; + } + else if(hMat && This->ddraw->d3ddevice->Handles[hMat - 1].type != DDrawHandle_Material) + { + WARN("Handle %ld is not a material handle\n", hMat); + return DDERR_INVALIDPARAMS; + } + + if(hMat) + { + This->background = (IDirect3DMaterialImpl *) This->ddraw->d3ddevice->Handles[hMat - 1].ptr; + TRACE(" setting background color : %f %f %f %f\n", + This->background->mat.u.diffuse.u1.r, + This->background->mat.u.diffuse.u2.g, + This->background->mat.u.diffuse.u3.b, + This->background->mat.u.diffuse.u4.a); + } + else + { + This->background = NULL; + TRACE("Setting background to NULL\n"); + } return D3D_OK; } @@ -406,8 +425,7 @@ IDirect3DViewportImpl_SetBackground(IDirect3DViewport3 *iface, * lpValid: is set to FALSE if no background is set, TRUE if one is set * * Returns: - * D3D_OK, because it's a stub - * (DDERR_INVALIDPARAMS if Mat or Valid is NULL) + * D3D_OK * *****************************************************************************/ static HRESULT WINAPI @@ -416,7 +434,24 @@ IDirect3DViewportImpl_GetBackground(IDirect3DViewport3 *iface, BOOL *lpValid) { ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface); - FIXME("(%p)->(%p,%p): stub!\n", This, lphMat, lpValid); + TRACE("(%p)->(%p,%p)\n", This, lphMat, lpValid); + + if(lpValid) + { + *lpValid = This->background != NULL; + } + if(lphMat) + { + if(This->background) + { + *lphMat = This->background->Handle; + } + else + { + *lphMat = 0; + } + } + return D3D_OK; }