diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index 20f31ee9d3e..920a365e1d0 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -4635,7 +4635,6 @@ static HRESULT WINAPI d3d7_CreateDevice(IDirect3D7 *iface, REFCLSID riid, { IDirectDrawSurfaceImpl *target = (IDirectDrawSurfaceImpl *)surface; IDirectDrawImpl *ddraw = ddraw_from_d3d7(iface); - IParentImpl *index_buffer_parent; IDirect3DDeviceImpl *object; HRESULT hr; @@ -4671,122 +4670,18 @@ static HRESULT WINAPI d3d7_CreateDevice(IDirect3D7 *iface, REFCLSID riid, return DDERR_OUTOFMEMORY; } - if (ddraw->cooperative_level & DDSCL_FPUPRESERVE) - object->lpVtbl = &IDirect3DDevice7_FPUPreserve_Vtbl; - else - object->lpVtbl = &IDirect3DDevice7_FPUSetup_Vtbl; - - object->IDirect3DDevice3_vtbl = &IDirect3DDevice3_Vtbl; - object->IDirect3DDevice2_vtbl = &IDirect3DDevice2_Vtbl; - object->IDirect3DDevice_vtbl = &IDirect3DDevice1_Vtbl; - object->ref = 1; - object->ddraw = ddraw; - object->target = target; - - if (!ddraw_handle_table_init(&object->handle_table, 64)) - { - ERR("Failed to initialize handle table.\n"); - HeapFree(GetProcessHeap(), 0, object); - LeaveCriticalSection(&ddraw_cs); - return DDERR_OUTOFMEMORY; - } - - object->legacyTextureBlending = FALSE; - - /* Create an index buffer, it's needed for indexed drawing */ - index_buffer_parent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*index_buffer_parent)); - if (!index_buffer_parent) - { - ERR("Failed to allocate index buffer parent memory.\n"); - ddraw_handle_table_destroy(&object->handle_table); - HeapFree(GetProcessHeap(), 0, object); - LeaveCriticalSection(&ddraw_cs); - return DDERR_OUTOFMEMORY; - } - - ddraw_parent_init(index_buffer_parent); - - /* Create an Index Buffer. WineD3D needs one for Drawing indexed primitives - * Create a (hopefully) long enough buffer, and copy the indices into it - * Ideally, a IWineD3DBuffer::SetData method could be created, which - * takes the pointer and avoids the memcpy. */ - hr = IWineD3DDevice_CreateIndexBuffer(ddraw->wineD3DDevice, 0x40000 /* Length. Don't know how long it should be */, - WINED3DUSAGE_DYNAMIC /* Usage */, WINED3DPOOL_DEFAULT, &object->indexbuffer, - (IUnknown *)index_buffer_parent, &ddraw_null_wined3d_parent_ops); + hr = d3d_device_init(object, ddraw, target); if (FAILED(hr)) { - ERR("Failed to create an index buffer.\n"); - HeapFree(GetProcessHeap(), 0, index_buffer_parent); - ddraw_handle_table_destroy(&object->handle_table); + WARN("Failed to initialize device, hr %#x.\n", hr); HeapFree(GetProcessHeap(), 0, object); LeaveCriticalSection(&ddraw_cs); return hr; } - index_buffer_parent->child = (IUnknown *)object->indexbuffer; - - /* This is for convenience */ - object->wineD3DDevice = ddraw->wineD3DDevice; - IWineD3DDevice_AddRef(ddraw->wineD3DDevice); TRACE("Created device %p.\n", object); *device = (IDirect3DDevice7 *)object; - /* This is for apps which create a non-flip, non-d3d primary surface - * and an offscreen D3DDEVICE surface, then render to the offscreen surface - * and do a Blt from the offscreen to the primary surface. - * - * Set the offscreen D3DDDEVICE surface(=target) as the back buffer, - * and the primary surface(=This->d3d_target) as the front buffer. - * - * This way the app will render to the D3DDEVICE surface and WineD3D - * will catch the Blt was Back Buffer -> Front buffer blt and perform - * a flip instead. This way we don't have to deal with a mixed GL / GDI - * environment. - * - * This should be checked against windowed apps. The only app tested with - * this is moto racer 2 during the loading screen. - */ - TRACE("Is rendertarget: %s, d3d_target %p.\n", - target->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ? "true" : "false", ddraw->d3d_target); - - if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) - && ddraw->d3d_target != target) - { - TRACE("Using %p as front buffer, %p as back buffer.\n", ddraw->d3d_target, target); - - hr = IWineD3DDevice_SetFrontBackBuffers(ddraw->wineD3DDevice, - ddraw->d3d_target->WineD3DSurface, target->WineD3DSurface); - if (FAILED(hr)) - { - ERR("Failed to set front and back buffer, hr %#x.\n", hr); - } - - /* Render to the back buffer */ - IWineD3DDevice_SetRenderTarget(ddraw->wineD3DDevice, 0, target->WineD3DSurface, TRUE); - object->OffScreenTarget = TRUE; - } - else - { - object->OffScreenTarget = FALSE; - } - - /* FIXME: This is broken. The surface AddRef() makes some sense, because - * we store a pointer during initialization, but then that's also where - * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */ - /* AddRef the render target. Also AddRef the render target from ddraw, - * because if it is released before the app releases the D3D device, the - * D3D capabilities of wined3d will be uninitialized, which has bad effects. - * - * In most cases, those surfaces are the same anyway, but this will simply - * add another ref which is released when the device is destroyed. */ - IDirectDrawSurface7_AddRef(surface); - IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)ddraw->d3d_target); - - ddraw->d3ddevice = object; - - IWineD3DDevice_SetRenderState(ddraw->wineD3DDevice, WINED3DRS_ZENABLE, - IDirect3DDeviceImpl_UpdateDepthStencil(object)); - LeaveCriticalSection(&ddraw_cs); return D3D_OK; } diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 6341f3f8c5e..5ed16764158 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -393,12 +393,8 @@ struct IDirect3DDeviceImpl D3DMATRIXHANDLE world, proj, view; }; -/* Vtables in various versions */ -extern const IDirect3DDevice7Vtbl IDirect3DDevice7_FPUSetup_Vtbl DECLSPEC_HIDDEN; -extern const IDirect3DDevice7Vtbl IDirect3DDevice7_FPUPreserve_Vtbl DECLSPEC_HIDDEN; -extern const IDirect3DDevice3Vtbl IDirect3DDevice3_Vtbl DECLSPEC_HIDDEN; -extern const IDirect3DDevice2Vtbl IDirect3DDevice2_Vtbl DECLSPEC_HIDDEN; -extern const IDirect3DDeviceVtbl IDirect3DDevice1_Vtbl DECLSPEC_HIDDEN; +HRESULT d3d_device_init(IDirect3DDeviceImpl *device, IDirectDrawImpl *ddraw, + IDirectDrawSurfaceImpl *target) DECLSPEC_HIDDEN; /* The IID */ extern const GUID IID_D3DDEVICE_WineD3D DECLSPEC_HIDDEN; diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index bb046b430de..931b2045d19 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -6611,7 +6611,7 @@ IDirect3DDeviceImpl_7_GetInfo(IDirect3DDevice7 *iface, * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required * by Sacrifice (game). */ -const IDirect3DDevice7Vtbl IDirect3DDevice7_FPUSetup_Vtbl = +static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl = { /*** IUnknown Methods ***/ IDirect3DDeviceImpl_7_QueryInterface, @@ -6666,7 +6666,7 @@ const IDirect3DDevice7Vtbl IDirect3DDevice7_FPUSetup_Vtbl = IDirect3DDeviceImpl_7_GetInfo }; -const IDirect3DDevice7Vtbl IDirect3DDevice7_FPUPreserve_Vtbl = +static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl = { /*** IUnknown Methods ***/ IDirect3DDeviceImpl_7_QueryInterface, @@ -6721,7 +6721,7 @@ const IDirect3DDevice7Vtbl IDirect3DDevice7_FPUPreserve_Vtbl = IDirect3DDeviceImpl_7_GetInfo }; -const IDirect3DDevice3Vtbl IDirect3DDevice3_Vtbl = +static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl = { /*** IUnknown Methods ***/ Thunk_IDirect3DDeviceImpl_3_QueryInterface, @@ -6769,7 +6769,7 @@ const IDirect3DDevice3Vtbl IDirect3DDevice3_Vtbl = Thunk_IDirect3DDeviceImpl_3_ValidateDevice }; -const IDirect3DDevice2Vtbl IDirect3DDevice2_Vtbl = +static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl = { /*** IUnknown Methods ***/ Thunk_IDirect3DDeviceImpl_2_QueryInterface, @@ -6808,7 +6808,7 @@ const IDirect3DDevice2Vtbl IDirect3DDevice2_Vtbl = Thunk_IDirect3DDeviceImpl_2_GetClipStatus }; -const IDirect3DDeviceVtbl IDirect3DDevice1_Vtbl = +static const struct IDirect3DDeviceVtbl d3d_device1_vtbl = { /*** IUnknown Methods ***/ Thunk_IDirect3DDeviceImpl_1_QueryInterface, @@ -6870,3 +6870,117 @@ IDirect3DDeviceImpl_UpdateDepthStencil(IDirect3DDeviceImpl *This) IDirectDrawSurface7_Release(depthStencil); return WINED3DZB_TRUE; } + +HRESULT d3d_device_init(IDirect3DDeviceImpl *device, IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *target) +{ + IParentImpl *index_buffer_parent; + HRESULT hr; + + if (ddraw->cooperative_level & DDSCL_FPUPRESERVE) + device->lpVtbl = &d3d_device7_fpu_preserve_vtbl; + else + device->lpVtbl = &d3d_device7_fpu_setup_vtbl; + + device->IDirect3DDevice3_vtbl = &d3d_device3_vtbl; + device->IDirect3DDevice2_vtbl = &d3d_device2_vtbl; + device->IDirect3DDevice_vtbl = &d3d_device1_vtbl; + device->ref = 1; + device->ddraw = ddraw; + device->target = target; + + if (!ddraw_handle_table_init(&device->handle_table, 64)) + { + ERR("Failed to initialize handle table.\n"); + return DDERR_OUTOFMEMORY; + } + + device->legacyTextureBlending = FALSE; + + /* Create an index buffer, it's needed for indexed drawing */ + index_buffer_parent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*index_buffer_parent)); + if (!index_buffer_parent) + { + ERR("Failed to allocate index buffer parent memory.\n"); + ddraw_handle_table_destroy(&device->handle_table); + return DDERR_OUTOFMEMORY; + } + + ddraw_parent_init(index_buffer_parent); + + hr = IWineD3DDevice_CreateIndexBuffer(ddraw->wineD3DDevice, 0x40000 /* Length. Don't know how long it should be */, + WINED3DUSAGE_DYNAMIC /* Usage */, WINED3DPOOL_DEFAULT, &device->indexbuffer, + (IUnknown *)index_buffer_parent, &ddraw_null_wined3d_parent_ops); + if (FAILED(hr)) + { + ERR("Failed to create an index buffer, hr %#x.\n", hr); + HeapFree(GetProcessHeap(), 0, index_buffer_parent); + ddraw_handle_table_destroy(&device->handle_table); + return hr; + } + index_buffer_parent->child = (IUnknown *)device->indexbuffer; + + /* This is for convenience. */ + device->wineD3DDevice = ddraw->wineD3DDevice; + IWineD3DDevice_AddRef(ddraw->wineD3DDevice); + + /* This is for apps which create a non-flip, non-d3d primary surface + * and an offscreen D3DDEVICE surface, then render to the offscreen surface + * and do a Blt from the offscreen to the primary surface. + * + * Set the offscreen D3DDDEVICE surface(=target) as the back buffer, + * and the primary surface(=This->d3d_target) as the front buffer. + * + * This way the app will render to the D3DDEVICE surface and WineD3D + * will catch the Blt was Back Buffer -> Front buffer blt and perform + * a flip instead. This way we don't have to deal with a mixed GL / GDI + * environment. + * + * This should be checked against windowed apps. The only app tested with + * this is moto racer 2 during the loading screen. + */ + TRACE("Is rendertarget: %s, d3d_target %p.\n", + target->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ? "true" : "false", ddraw->d3d_target); + + if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) + && ddraw->d3d_target != target) + { + TRACE("Using %p as front buffer, %p as back buffer.\n", ddraw->d3d_target, target); + + hr = IWineD3DDevice_SetFrontBackBuffers(ddraw->wineD3DDevice, + ddraw->d3d_target->WineD3DSurface, target->WineD3DSurface); + if (FAILED(hr)) + { + ERR("Failed to set front and back buffer, hr %#x.\n", hr); + IParent_Release((IParent *)index_buffer_parent); + ddraw_handle_table_destroy(&device->handle_table); + return hr; + } + + /* Render to the back buffer */ + IWineD3DDevice_SetRenderTarget(ddraw->wineD3DDevice, 0, target->WineD3DSurface, TRUE); + device->OffScreenTarget = TRUE; + } + else + { + device->OffScreenTarget = FALSE; + } + + /* FIXME: This is broken. The target AddRef() makes some sense, because + * we store a pointer during initialization, but then that's also where + * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */ + /* AddRef the render target. Also AddRef the render target from ddraw, + * because if it is released before the app releases the D3D device, the + * D3D capabilities of wined3d will be uninitialized, which has bad effects. + * + * In most cases, those surfaces are the same anyway, but this will simply + * add another ref which is released when the device is destroyed. */ + IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)target); + IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)ddraw->d3d_target); + + ddraw->d3ddevice = device; + + IWineD3DDevice_SetRenderState(ddraw->wineD3DDevice, WINED3DRS_ZENABLE, + IDirect3DDeviceImpl_UpdateDepthStencil(device)); + + return D3D_OK; +}