ddraw: Create the wined3d swapchain when setting the cooperative level.
This commit is contained in:
parent
392785965f
commit
0f10ac9358
|
@ -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;
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ struct IDirectDrawImpl
|
|||
DWORD orig_bpp;
|
||||
|
||||
/* D3D things */
|
||||
IDirectDrawSurfaceImpl *d3d_target;
|
||||
HWND d3d_window;
|
||||
IDirect3DDeviceImpl *d3ddevice;
|
||||
int d3dversion;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue