From 0f10ac93580d5a055f0b3f6e7c3d77738135f031 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Mon, 28 Nov 2011 21:30:57 +0100 Subject: [PATCH] ddraw: Create the wined3d swapchain when setting the cooperative level. --- dlls/ddraw/ddraw.c | 280 ++++++++++++++++++------------------- dlls/ddraw/ddraw_private.h | 1 - dlls/ddraw/device.c | 4 +- dlls/ddraw/surface.c | 11 -- dlls/ddraw/tests/d3d.c | 4 +- 5 files changed, 136 insertions(+), 164 deletions(-) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index d7aad8f7d0e..45496f69083 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -445,7 +445,6 @@ void ddraw_destroy_swapchain(IDirectDrawImpl *ddraw) } ddraw->d3d_initialized = FALSE; - ddraw->d3d_target = NULL; } else { @@ -484,16 +483,8 @@ static void ddraw_destroy(IDirectDrawImpl *This) list_remove(&This->ddraw_list_entry); wined3d_mutex_unlock(); - /* This can happen more or less legitimately for ddraw 1 and 2, where - * surfaces don't keep a reference to the ddraw object. The surfaces - * will of course be broken after this, (and on native trying to do - * anything with them in that state results in an access violation), but - * the release of the ddraw object should succeed without crashing. */ if (This->wined3d_swapchain) - { - WARN("DirectDraw object is being destroyed while the swapchain still exists.\n"); ddraw_destroy_swapchain(This); - } wined3d_device_decref(This->wined3d_device); wined3d_decref(This->wineD3D); @@ -625,6 +616,109 @@ static HRESULT ddraw_set_focus_window(IDirectDrawImpl *ddraw, HWND window) return DD_OK; } +static HRESULT ddraw_attach_d3d_device(IDirectDrawImpl *ddraw, + WINED3DPRESENT_PARAMETERS *presentation_parameters) +{ + HWND window = presentation_parameters->hDeviceWindow; + HRESULT hr; + + TRACE("ddraw %p.\n", ddraw); + + if (!window || window == GetDesktopWindow()) + { + window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "Hidden D3D Window", + WS_DISABLED, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), + NULL, NULL, NULL, NULL); + if (!window) + { + ERR("Failed to create window, last error %#x.\n", GetLastError()); + return E_FAIL; + } + + ShowWindow(window, SW_HIDE); /* Just to be sure */ + WARN("No window for the Direct3DDevice, created hidden window %p.\n", window); + + presentation_parameters->hDeviceWindow = window; + } + else + { + TRACE("Using existing window %p for Direct3D rendering.\n", window); + } + ddraw->d3d_window = window; + + /* Set this NOW, otherwise creating the depth stencil surface will cause a + * recursive loop until ram or emulated video memory is full. */ + ddraw->d3d_initialized = TRUE; + hr = wined3d_device_init_3d(ddraw->wined3d_device, presentation_parameters); + if (FAILED(hr)) + { + ddraw->d3d_initialized = FALSE; + return hr; + } + + ddraw->declArraySize = 2; + ddraw->decls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw->decls) * ddraw->declArraySize); + if (!ddraw->decls) + { + ERR("Error allocating an array for the converted vertex decls.\n"); + ddraw->declArraySize = 0; + hr = wined3d_device_uninit_3d(ddraw->wined3d_device); + return E_OUTOFMEMORY; + } + + TRACE("Successfully initialized 3D.\n"); + + return DD_OK; +} + +static HRESULT ddraw_create_swapchain(IDirectDrawImpl *ddraw, HWND window, BOOL windowed) +{ + WINED3DPRESENT_PARAMETERS presentation_parameters; + struct wined3d_display_mode mode; + HRESULT hr = WINED3D_OK; + + /* FIXME: wined3d_get_adapter_display_mode() would be more appropriate + * here, since we don't actually have a swapchain yet, but + * wined3d_device_get_display_mode() has some special handling for color + * depth changes. */ + hr = wined3d_device_get_display_mode(ddraw->wined3d_device, 0, &mode); + if (FAILED(hr)) + { + ERR("Failed to get display mode.\n"); + return hr; + } + + memset(&presentation_parameters, 0, sizeof(presentation_parameters)); + presentation_parameters.BackBufferWidth = mode.width; + presentation_parameters.BackBufferHeight = mode.height; + presentation_parameters.BackBufferFormat = mode.format_id; + presentation_parameters.SwapEffect = WINED3DSWAPEFFECT_COPY; + presentation_parameters.hDeviceWindow = window; + presentation_parameters.Windowed = windowed; + + if (DefaultSurfaceType == SURFACE_OPENGL) + hr = ddraw_attach_d3d_device(ddraw, &presentation_parameters); + else + hr = wined3d_device_init_gdi(ddraw->wined3d_device, &presentation_parameters); + + if (FAILED(hr)) + { + ERR("Failed to create swapchain, hr %#x.\n", hr); + return hr; + } + + if (FAILED(hr = wined3d_device_get_swapchain(ddraw->wined3d_device, 0, &ddraw->wined3d_swapchain))) + { + ERR("Failed to get swapchain, hr %#x.\n", hr); + ddraw->wined3d_swapchain = NULL; + return hr; + } + + ddraw_set_swapchain_window(ddraw, window); + + return DD_OK; +} + /***************************************************************************** * IDirectDraw7::SetCooperativeLevel * @@ -789,6 +883,11 @@ static HRESULT WINAPI ddraw7_SetCooperativeLevel(IDirectDraw7 *iface, HWND hwnd, if (cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED)) wined3d_device_set_multithreaded(This->wined3d_device); + if (This->wined3d_swapchain) + ddraw_destroy_swapchain(This); + if (FAILED(hr = ddraw_create_swapchain(This, This->dest_window, !(cooplevel & DDSCL_FULLSCREEN)))) + ERR("Failed to create swapchain, hr %#x.\n", hr); + /* Unhandled flags */ if(cooplevel & DDSCL_ALLOWREBOOT) WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This); @@ -2522,120 +2621,11 @@ CreateAdditionalSurfaces(IDirectDrawImpl *This, return DD_OK; } -static HRESULT ddraw_attach_d3d_device(IDirectDrawImpl *ddraw, - WINED3DPRESENT_PARAMETERS *presentation_parameters) +HRESULT CDECL ddraw_reset_enum_callback(struct wined3d_resource *resource) { - HWND window = presentation_parameters->hDeviceWindow; - HRESULT hr; - - TRACE("ddraw %p.\n", ddraw); - - if (!window || window == GetDesktopWindow()) - { - window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "Hidden D3D Window", - WS_DISABLED, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), - NULL, NULL, NULL, NULL); - if (!window) - { - ERR("Failed to create window, last error %#x.\n", GetLastError()); - return E_FAIL; - } - - ShowWindow(window, SW_HIDE); /* Just to be sure */ - WARN("No window for the Direct3DDevice, created hidden window %p.\n", window); - - presentation_parameters->hDeviceWindow = window; - } - else - { - TRACE("Using existing window %p for Direct3D rendering.\n", window); - } - ddraw->d3d_window = window; - - /* Set this NOW, otherwise creating the depth stencil surface will cause a - * recursive loop until ram or emulated video memory is full. */ - ddraw->d3d_initialized = TRUE; - hr = wined3d_device_init_3d(ddraw->wined3d_device, presentation_parameters); - if (FAILED(hr)) - { - ddraw->d3d_target = NULL; - ddraw->d3d_initialized = FALSE; - return hr; - } - - ddraw->declArraySize = 2; - ddraw->decls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw->decls) * ddraw->declArraySize); - if (!ddraw->decls) - { - ERR("Error allocating an array for the converted vertex decls.\n"); - ddraw->declArraySize = 0; - hr = wined3d_device_uninit_3d(ddraw->wined3d_device); - return E_OUTOFMEMORY; - } - - TRACE("Successfully initialized 3D.\n"); - return DD_OK; } -static HRESULT ddraw_create_swapchain(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *surface) -{ - WINED3DPRESENT_PARAMETERS presentation_parameters; - struct wined3d_display_mode mode; - HRESULT hr = WINED3D_OK; - - /* FIXME: wined3d_get_adapter_display_mode() would be more appropriate - * here, since we don't actually have a swapchain yet, but - * wined3d_device_get_display_mode() has some special handling for color - * depth changes. */ - hr = wined3d_device_get_display_mode(ddraw->wined3d_device, 0, &mode); - if (FAILED(hr)) - { - ERR("Failed to get display mode.\n"); - return hr; - } - - memset(&presentation_parameters, 0, sizeof(presentation_parameters)); - presentation_parameters.BackBufferWidth = mode.width; - presentation_parameters.BackBufferHeight = mode.height; - presentation_parameters.BackBufferFormat = mode.format_id; - presentation_parameters.SwapEffect = WINED3DSWAPEFFECT_COPY; - presentation_parameters.hDeviceWindow = ddraw->dest_window; - presentation_parameters.Windowed = !(ddraw->cooperative_level & DDSCL_FULLSCREEN); - - /* If the implementation is OpenGL and there's no d3ddevice, attach a - * d3ddevice. But attach the d3ddevice only if the currently created - * surface was a primary surface (2D app in 3D mode) or a 3DDEVICE surface - * (3D app). The only case I can think of where this doesn't apply is when - * a 2D app was configured by the user to run with OpenGL and it didn't - * create the render target as first surface. In this case the render - * target creation will cause the 3D init. */ - if (DefaultSurfaceType == SURFACE_OPENGL) - { - hr = ddraw_attach_d3d_device(ddraw, &presentation_parameters); - } - else if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) - { - hr = wined3d_device_init_gdi(ddraw->wined3d_device, &presentation_parameters); - if (FAILED(hr)) - WARN("Failed to initialize GDI ddraw implementation, hr %#x.\n", hr); - } - - if (SUCCEEDED(hr)) - { - if (FAILED(hr = wined3d_device_get_swapchain(ddraw->wined3d_device, 0, &ddraw->wined3d_swapchain))) - { - ERR("Failed to get swapchain, hr %#x.\n", hr); - ddraw->wined3d_swapchain = NULL; - } - } - - if (SUCCEEDED(hr)) - ddraw_set_swapchain_window(ddraw, ddraw->dest_window); - - return hr; -} - /***************************************************************************** * IDirectDraw7::CreateSurface * @@ -2930,6 +2920,30 @@ static HRESULT CreateSurface(IDirectDrawImpl *ddraw, DDSURFACEDESC2 *DDSD, desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX; } + if ((desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) && (ddraw->cooperative_level & DDSCL_EXCLUSIVE)) + { + WINED3DPRESENT_PARAMETERS presentation_parameters; + + hr = wined3d_swapchain_get_present_parameters(ddraw->wined3d_swapchain, &presentation_parameters); + if (FAILED(hr)) + { + ERR("Failed to get present parameters.\n"); + return hr; + } + + presentation_parameters.BackBufferWidth = mode.width; + presentation_parameters.BackBufferHeight = mode.height; + presentation_parameters.BackBufferFormat = mode.format_id; + + hr = wined3d_device_reset(ddraw->wined3d_device, + &presentation_parameters, ddraw_reset_enum_callback); + if (FAILED(hr)) + { + ERR("Failed to reset device.\n"); + return hr; + } + } + /* Create the first surface */ hr = ddraw_create_surface(ddraw, &desc2, &object, 0, version); if (FAILED(hr)) @@ -2990,34 +3004,6 @@ static HRESULT CreateSurface(IDirectDrawImpl *ddraw, DDSURFACEDESC2 *DDSD, return hr; } - if (!ddraw->d3d_initialized && desc2.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE)) - { - if (FAILED(hr = ddraw_create_swapchain(ddraw, object))) - { - IDirectDrawSurfaceImpl *release_surf; - ERR("Failed to create swapchain, hr %#x.\n", hr); - *Surf = NULL; - - /* The earlier created surface structures are in an incomplete - * state here. Wined3d holds the reference on the parents, and it - * released them on the failure already. So the regular release - * method implementation would fail on the attempt to destroy - * either the parents or the swapchain. So free the surface here. - * The surface structure here is a list, not a tree, because - * onscreen targets cannot be cube textures. */ - while (object) - { - release_surf = object; - object = object->complex_array[0]; - ddraw_surface_destroy(release_surf); - } - return hr; - } - - if (DefaultSurfaceType == SURFACE_OPENGL) - ddraw->d3d_target = ddraw->primary ? ddraw->primary : object; - } - if (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) ddraw->primary = object; diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index f53c93f06bb..a4522b08f66 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -98,7 +98,6 @@ struct IDirectDrawImpl DWORD orig_bpp; /* D3D things */ - IDirectDrawSurfaceImpl *d3d_target; HWND d3d_window; IDirect3DDeviceImpl *d3ddevice; int d3dversion; diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index ccbdb1ac4d0..462f39e5e8c 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -361,12 +361,11 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface) ddraw_handle_table_destroy(&This->handle_table); - TRACE("Releasing target %p %p\n", This->target, This->ddraw->d3d_target); + TRACE("Releasing target %p.\n", This->target); /* Release the render target and the WineD3D render target * (See IDirect3D7::CreateDevice for more comments on this) */ IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface); - IDirectDrawSurface7_Release(&This->ddraw->d3d_target->IDirectDrawSurface7_iface); TRACE("Target release done\n"); This->ddraw->d3ddevice = NULL; @@ -6914,7 +6913,6 @@ HRESULT d3d_device_init(IDirect3DDeviceImpl *device, IDirectDrawImpl *ddraw, IDi * 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(&target->IDirectDrawSurface7_iface); - IDirectDrawSurface7_AddRef(&ddraw->d3d_target->IDirectDrawSurface7_iface); ddraw->d3ddevice = device; diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index c7f92fd78cf..851920c866f 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -453,20 +453,12 @@ void ddraw_surface_destroy(IDirectDrawSurfaceImpl *This) static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface) { - IDirectDrawImpl *ddraw = surface->ddraw; - BOOL destroy_swapchain = FALSE; IDirectDrawSurfaceImpl *surf; IUnknown *ifaceToRelease; UINT i; TRACE("surface %p.\n", surface); - if ((ddraw->d3d_initialized && surface == ddraw->d3d_target - && DefaultSurfaceType == SURFACE_OPENGL) - || ((surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) - && DefaultSurfaceType != SURFACE_OPENGL)) - destroy_swapchain = TRUE; - /* The refcount test shows that the palette is detached when the surface * is destroyed. */ IDirectDrawSurface7_SetPalette(&surface->IDirectDrawSurface7_iface, NULL); @@ -495,9 +487,6 @@ static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface) /* Destroy the root surface. */ ddraw_surface_destroy(surface); - if (ddraw->wined3d_swapchain && destroy_swapchain) - ddraw_destroy_swapchain(ddraw); - /* Reduce the ddraw refcount */ if (ifaceToRelease) IUnknown_Release(ifaceToRelease); diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c index 7ed7575b658..0a42083c7c7 100644 --- a/dlls/ddraw/tests/d3d.c +++ b/dlls/ddraw/tests/d3d.c @@ -3309,7 +3309,7 @@ static void SetRenderTargetTest(void) ok(hr == DD_OK, "IDirect3DDevice7_GetRenderTarget failed, hr=0x%08x\n", hr); refcount = getRefcount((IUnknown*) oldrt); - todo_wine ok(refcount == 3, "Refcount should be 3, returned is %d\n", refcount); + ok(refcount == 3, "Refcount should be 3, returned is %d\n", refcount); refcount = getRefcount((IUnknown*) failrt); ok(refcount == 1, "Refcount should be 1, returned is %d\n", refcount); @@ -3318,7 +3318,7 @@ static void SetRenderTargetTest(void) ok(hr != D3D_OK, "IDirect3DDevice7_SetRenderTarget succeeded\n"); refcount = getRefcount((IUnknown*) oldrt); - todo_wine ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount); + ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount); refcount = getRefcount((IUnknown*) failrt); ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount);