[PATCH 1/5] ddraw: Create the wined3d swapchain when setting the cooperative level.
Henri Verbeet
hverbeet at codeweavers.com
Mon Nov 28 14:30:57 CST 2011
---
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 d7aad8f..45496f6 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 f53c93f..a4522b0 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 ccbdb1a..462f39e 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 c7f92fd..851920c 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 7ed7575..0a42083 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);
--
1.7.3.4
More information about the wine-patches
mailing list