ddraw: Create the wined3d swapchain when setting the cooperative level.

This commit is contained in:
Henri Verbeet 2011-11-28 21:30:57 +01:00 committed by Alexandre Julliard
parent 392785965f
commit 0f10ac9358
5 changed files with 136 additions and 164 deletions

View File

@ -445,7 +445,6 @@ void ddraw_destroy_swapchain(IDirectDrawImpl *ddraw)
} }
ddraw->d3d_initialized = FALSE; ddraw->d3d_initialized = FALSE;
ddraw->d3d_target = NULL;
} }
else else
{ {
@ -484,16 +483,8 @@ static void ddraw_destroy(IDirectDrawImpl *This)
list_remove(&This->ddraw_list_entry); list_remove(&This->ddraw_list_entry);
wined3d_mutex_unlock(); 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) if (This->wined3d_swapchain)
{
WARN("DirectDraw object is being destroyed while the swapchain still exists.\n");
ddraw_destroy_swapchain(This); ddraw_destroy_swapchain(This);
}
wined3d_device_decref(This->wined3d_device); wined3d_device_decref(This->wined3d_device);
wined3d_decref(This->wineD3D); wined3d_decref(This->wineD3D);
@ -625,6 +616,109 @@ static HRESULT ddraw_set_focus_window(IDirectDrawImpl *ddraw, HWND window)
return DD_OK; 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 * IDirectDraw7::SetCooperativeLevel
* *
@ -789,6 +883,11 @@ static HRESULT WINAPI ddraw7_SetCooperativeLevel(IDirectDraw7 *iface, HWND hwnd,
if (cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED)) if (cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED))
wined3d_device_set_multithreaded(This->wined3d_device); 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 */ /* Unhandled flags */
if(cooplevel & DDSCL_ALLOWREBOOT) if(cooplevel & DDSCL_ALLOWREBOOT)
WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This); WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This);
@ -2522,120 +2621,11 @@ CreateAdditionalSurfaces(IDirectDrawImpl *This,
return DD_OK; return DD_OK;
} }
static HRESULT ddraw_attach_d3d_device(IDirectDrawImpl *ddraw, HRESULT CDECL ddraw_reset_enum_callback(struct wined3d_resource *resource)
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_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; 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 * IDirectDraw7::CreateSurface
* *
@ -2930,6 +2920,30 @@ static HRESULT CreateSurface(IDirectDrawImpl *ddraw, DDSURFACEDESC2 *DDSD,
desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX; 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 */ /* Create the first surface */
hr = ddraw_create_surface(ddraw, &desc2, &object, 0, version); hr = ddraw_create_surface(ddraw, &desc2, &object, 0, version);
if (FAILED(hr)) if (FAILED(hr))
@ -2990,34 +3004,6 @@ static HRESULT CreateSurface(IDirectDrawImpl *ddraw, DDSURFACEDESC2 *DDSD,
return hr; 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) if (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
ddraw->primary = object; ddraw->primary = object;

View File

@ -98,7 +98,6 @@ struct IDirectDrawImpl
DWORD orig_bpp; DWORD orig_bpp;
/* D3D things */ /* D3D things */
IDirectDrawSurfaceImpl *d3d_target;
HWND d3d_window; HWND d3d_window;
IDirect3DDeviceImpl *d3ddevice; IDirect3DDeviceImpl *d3ddevice;
int d3dversion; int d3dversion;

View File

@ -361,12 +361,11 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface)
ddraw_handle_table_destroy(&This->handle_table); 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 /* Release the render target and the WineD3D render target
* (See IDirect3D7::CreateDevice for more comments on this) * (See IDirect3D7::CreateDevice for more comments on this)
*/ */
IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface); IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface);
IDirectDrawSurface7_Release(&This->ddraw->d3d_target->IDirectDrawSurface7_iface);
TRACE("Target release done\n"); TRACE("Target release done\n");
This->ddraw->d3ddevice = NULL; 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 * In most cases, those surfaces are the same anyway, but this will simply
* add another ref which is released when the device is destroyed. */ * add another ref which is released when the device is destroyed. */
IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface); IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
IDirectDrawSurface7_AddRef(&ddraw->d3d_target->IDirectDrawSurface7_iface);
ddraw->d3ddevice = device; ddraw->d3ddevice = device;

View File

@ -453,20 +453,12 @@ void ddraw_surface_destroy(IDirectDrawSurfaceImpl *This)
static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface) static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface)
{ {
IDirectDrawImpl *ddraw = surface->ddraw;
BOOL destroy_swapchain = FALSE;
IDirectDrawSurfaceImpl *surf; IDirectDrawSurfaceImpl *surf;
IUnknown *ifaceToRelease; IUnknown *ifaceToRelease;
UINT i; UINT i;
TRACE("surface %p.\n", surface); 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 /* The refcount test shows that the palette is detached when the surface
* is destroyed. */ * is destroyed. */
IDirectDrawSurface7_SetPalette(&surface->IDirectDrawSurface7_iface, NULL); IDirectDrawSurface7_SetPalette(&surface->IDirectDrawSurface7_iface, NULL);
@ -495,9 +487,6 @@ static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface)
/* Destroy the root surface. */ /* Destroy the root surface. */
ddraw_surface_destroy(surface); ddraw_surface_destroy(surface);
if (ddraw->wined3d_swapchain && destroy_swapchain)
ddraw_destroy_swapchain(ddraw);
/* Reduce the ddraw refcount */ /* Reduce the ddraw refcount */
if (ifaceToRelease) if (ifaceToRelease)
IUnknown_Release(ifaceToRelease); IUnknown_Release(ifaceToRelease);

View File

@ -3309,7 +3309,7 @@ static void SetRenderTargetTest(void)
ok(hr == DD_OK, "IDirect3DDevice7_GetRenderTarget failed, hr=0x%08x\n", hr); ok(hr == DD_OK, "IDirect3DDevice7_GetRenderTarget failed, hr=0x%08x\n", hr);
refcount = getRefcount((IUnknown*) oldrt); 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); refcount = getRefcount((IUnknown*) failrt);
ok(refcount == 1, "Refcount should be 1, returned is %d\n", refcount); 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"); ok(hr != D3D_OK, "IDirect3DDevice7_SetRenderTarget succeeded\n");
refcount = getRefcount((IUnknown*) oldrt); 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); refcount = getRefcount((IUnknown*) failrt);
ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount); ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount);