From: Zebediah Figura zfigura@codeweavers.com
--- dlls/wined3d/swapchain.c | 97 ++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 44 deletions(-)
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index e6938ea14dc..4bbf464e58e 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -1429,15 +1429,63 @@ static HRESULT wined3d_swapchain_state_init(struct wined3d_swapchain_state *stat return hr; }
+static HRESULT swapchain_create_texture(struct wined3d_swapchain *swapchain, + bool front, bool depth, struct wined3d_texture **texture) +{ + const struct wined3d_swapchain_desc *swapchain_desc = &swapchain->state.desc; + struct wined3d_device *device = swapchain->device; + struct wined3d_resource_desc texture_desc; + uint32_t texture_flags = 0; + HRESULT hr; + + texture_desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + texture_desc.format = depth ? swapchain_desc->auto_depth_stencil_format : swapchain_desc->backbuffer_format; + texture_desc.multisample_type = swapchain_desc->multisample_type; + texture_desc.multisample_quality = swapchain_desc->multisample_quality; + texture_desc.usage = 0; + if (!depth && (device->wined3d->flags & WINED3D_NO3D)) + texture_desc.usage |= WINED3DUSAGE_OWNDC; + if (device->wined3d->flags & WINED3D_NO3D) + texture_desc.access = WINED3D_RESOURCE_ACCESS_CPU; + else + texture_desc.access = WINED3D_RESOURCE_ACCESS_GPU; + if (!depth && (swapchain_desc->flags & WINED3D_SWAPCHAIN_LOCKABLE_BACKBUFFER)) + texture_desc.access |= WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W; + texture_desc.width = swapchain_desc->backbuffer_width; + texture_desc.height = swapchain_desc->backbuffer_height; + texture_desc.depth = 1; + texture_desc.size = 0; + + if (front) + texture_desc.bind_flags = 0; + else if (depth) + texture_desc.bind_flags = WINED3D_BIND_DEPTH_STENCIL; + else + texture_desc.bind_flags = swapchain_desc->backbuffer_bind_flags; + + if (swapchain_desc->flags & WINED3D_SWAPCHAIN_GDI_COMPATIBLE) + texture_flags |= WINED3D_TEXTURE_CREATE_GET_DC; + + if (FAILED(hr = wined3d_texture_create(device, &texture_desc, 1, 1, + texture_flags, NULL, NULL, &wined3d_null_parent_ops, texture))) + { + WARN("Failed to create texture, hr %#lx.\n", hr); + return hr; + } + + if (!depth) + wined3d_texture_set_swapchain(*texture, swapchain); + + return S_OK; +} + static HRESULT wined3d_swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device, struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent, void *parent, const struct wined3d_parent_ops *parent_ops, const struct wined3d_swapchain_ops *swapchain_ops) { - struct wined3d_resource_desc texture_desc; struct wined3d_output_desc output_desc; BOOL displaymode_set = FALSE; - DWORD texture_flags = 0; HRESULT hr = E_FAIL; RECT client_rect; unsigned int i; @@ -1519,36 +1567,12 @@ static HRESULT wined3d_swapchain_init(struct wined3d_swapchain *swapchain, struc
TRACE("Creating front buffer.\n");
- texture_desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; - texture_desc.format = swapchain->state.desc.backbuffer_format; - texture_desc.multisample_type = swapchain->state.desc.multisample_type; - texture_desc.multisample_quality = swapchain->state.desc.multisample_quality; - texture_desc.usage = 0; - if (device->wined3d->flags & WINED3D_NO3D) - texture_desc.usage |= WINED3DUSAGE_OWNDC; - texture_desc.bind_flags = 0; - if (device->wined3d->flags & WINED3D_NO3D) - texture_desc.access = WINED3D_RESOURCE_ACCESS_CPU; - else - texture_desc.access = WINED3D_RESOURCE_ACCESS_GPU; - if (swapchain->state.desc.flags & WINED3D_SWAPCHAIN_LOCKABLE_BACKBUFFER) - texture_desc.access |= WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W; - texture_desc.width = swapchain->state.desc.backbuffer_width; - texture_desc.height = swapchain->state.desc.backbuffer_height; - texture_desc.depth = 1; - texture_desc.size = 0; - - if (swapchain->state.desc.flags & WINED3D_SWAPCHAIN_GDI_COMPATIBLE) - texture_flags |= WINED3D_TEXTURE_CREATE_GET_DC; - - if (FAILED(hr = wined3d_texture_create(device, &texture_desc, 1, 1, texture_flags, - NULL, NULL, &wined3d_null_parent_ops, &swapchain->front_buffer))) + if (FAILED(hr = swapchain_create_texture(swapchain, true, false, &swapchain->front_buffer))) { WARN("Failed to create front buffer, hr %#lx.\n", hr); goto err; }
- wined3d_texture_set_swapchain(swapchain->front_buffer, swapchain); if (!(device->wined3d->flags & WINED3D_NO3D)) { wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE); @@ -1580,21 +1604,15 @@ static HRESULT wined3d_swapchain_init(struct wined3d_swapchain *swapchain, struc goto err; }
- texture_desc.bind_flags = swapchain->state.desc.backbuffer_bind_flags; - texture_desc.usage = 0; - if (device->wined3d->flags & WINED3D_NO3D) - texture_desc.usage |= WINED3DUSAGE_OWNDC; for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i) { TRACE("Creating back buffer %u.\n", i); - if (FAILED(hr = wined3d_texture_create(device, &texture_desc, 1, 1, texture_flags, - NULL, NULL, &wined3d_null_parent_ops, &swapchain->back_buffers[i]))) + if (FAILED(hr = swapchain_create_texture(swapchain, false, false, &swapchain->back_buffers[i]))) { WARN("Failed to create back buffer %u, hr %#lx.\n", i, hr); swapchain->state.desc.backbuffer_count = i; goto err; } - wined3d_texture_set_swapchain(swapchain->back_buffers[i], swapchain); } }
@@ -1607,16 +1625,7 @@ static HRESULT wined3d_swapchain_init(struct wined3d_swapchain *swapchain, struc struct wined3d_view_desc desc; struct wined3d_texture *ds;
- texture_desc.format = swapchain->state.desc.auto_depth_stencil_format; - texture_desc.usage = 0; - texture_desc.bind_flags = WINED3D_BIND_DEPTH_STENCIL; - if (device->wined3d->flags & WINED3D_NO3D) - texture_desc.access = WINED3D_RESOURCE_ACCESS_CPU; - else - texture_desc.access = WINED3D_RESOURCE_ACCESS_GPU; - - if (FAILED(hr = wined3d_texture_create(device, &texture_desc, 1, 1, 0, - NULL, NULL, &wined3d_null_parent_ops, &ds))) + if (FAILED(hr = swapchain_create_texture(swapchain, false, true, &ds))) { WARN("Failed to create the auto depth/stencil surface, hr %#lx.\n", hr); goto err;
From: Zebediah Figura zfigura@codeweavers.com
--- dlls/dxgi/dxgi_private.h | 1 + dlls/dxgi/swapchain.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/dlls/dxgi/dxgi_private.h b/dlls/dxgi/dxgi_private.h index fa704d28b0f..e3ea0e52036 100644 --- a/dlls/dxgi/dxgi_private.h +++ b/dlls/dxgi/dxgi_private.h @@ -180,6 +180,7 @@ struct d3d11_swapchain struct wined3d_swapchain_state_parent state_parent; IWineDXGIDevice *device; IWineDXGIFactory *factory; + bool implicit;
IDXGIOutput *target; LONG present_count; diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 0ba9db96108..9aa76f9e97a 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -231,15 +231,17 @@ static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface) if (!refcount) { IWineDXGIDevice *device = swapchain->device; + bool implicit = swapchain->implicit; + if (swapchain->target) { WARN("Releasing fullscreen swapchain.\n"); IDXGIOutput_Release(swapchain->target); } - if (swapchain->factory) + if (!implicit) IWineDXGIFactory_Release(swapchain->factory); wined3d_swapchain_decref(swapchain->wined3d_swapchain); - if (device) + if (!implicit) IWineDXGIDevice_Release(device); }
@@ -302,7 +304,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDevice(IDXGISwapChain1 *ifac
TRACE("iface %p, riid %s, device %p.\n", iface, debugstr_guid(riid), device);
- if (!swapchain->device) + if (swapchain->implicit) { ERR("Implicit swapchain does not store reference to device.\n"); *device = NULL; @@ -889,6 +891,8 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi BOOL fullscreen; HRESULT hr;
+ swapchain->device = &device->IWineDXGIDevice_iface; + /* A reference to the implicit swapchain is held by the wined3d device. In * order to avoid circular references we do not keep a reference to the * device in the implicit swapchain. */ @@ -903,11 +907,10 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi WARN("Failed to get adapter parent, hr %#lx.\n", hr); return hr; } - IWineDXGIDevice_AddRef(swapchain->device = &device->IWineDXGIDevice_iface); + IWineDXGIDevice_AddRef(swapchain->device); } else { - swapchain->device = NULL; swapchain->factory = NULL; }
@@ -969,10 +972,11 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi cleanup: wined3d_private_store_cleanup(&swapchain->private_store); wined3d_mutex_unlock(); - if (swapchain->factory) + if (!swapchain->implicit) + { IWineDXGIFactory_Release(swapchain->factory); - if (swapchain->device) IWineDXGIDevice_Release(swapchain->device); + } return hr; }
From: Zebediah Figura zfigura@codeweavers.com
Instead of using wined3d_texture_update_desc(). This is safe, because:
* ddraw never exposes wined3d textures directly, and always retrieves them directly from wined3d when rendering.
* d3d8 and d3d9 (non-extended) will only resize buffers during a reset, and resetting is forbidden if the application holds any references to the backbuffers. RTVs are also replaced during a reset, so there is no concern about retrieving the old RTVs from the device state.
* d3d9ex allows resetting while holding references to the backbuffers, but tests (fixed by this patch) show that the backbuffers should in fact be recreated.
* dxgi forbids holding references to back buffers during ResizeBuffers(), including indirect references via command lists or device contexts. --- dlls/d3d8/device.c | 23 ++++++++++-- dlls/d3d9/device.c | 78 ++++++++++++++++++++++++++++++++++++++-- dlls/d3d9/tests/d3d9ex.c | 19 ++++------ dlls/dxgi/swapchain.c | 15 ++++++-- dlls/wined3d/swapchain.c | 32 +++++++++++------ 5 files changed, 137 insertions(+), 30 deletions(-)
diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 3727ad3e4eb..b8a4252cc78 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -940,8 +940,8 @@ static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource) static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface, D3DPRESENT_PARAMETERS *present_parameters) { + struct wined3d_swapchain_desc swapchain_desc, old_swapchain_desc; struct d3d8_device *device = impl_from_IDirect3DDevice8(iface); - struct wined3d_swapchain_desc swapchain_desc; struct d3d8_swapchain *implicit_swapchain; unsigned int output_idx; HRESULT hr; @@ -964,16 +964,26 @@ static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface, wined3d_streaming_buffer_cleanup(&device->vertex_buffer); wined3d_streaming_buffer_cleanup(&device->index_buffer);
+ wined3d_swapchain_get_desc(device->implicit_swapchain, &old_swapchain_desc); + if (device->recording) wined3d_stateblock_decref(device->recording); device->recording = NULL; device->update_state = device->state; wined3d_stateblock_reset(device->state);
+ /* wined3d_device_reset() may recreate swapchain textures. + * We do not need to remove the reference to the wined3d swapchain from the + * old d3d8 surfaces: we will fail the reset if they have 0 references, + * and therefore they are not actually holding a reference to the wined3d + * swapchain, and will not do anything with it when they are destroyed. */ + if (SUCCEEDED(hr = wined3d_device_reset(device->wined3d_device, &swapchain_desc, NULL, reset_enum_callback, TRUE))) { struct wined3d_rendertarget_view *rtv; + struct d3d8_surface *surface; + unsigned int i;
present_parameters->BackBufferCount = swapchain_desc.backbuffer_count; implicit_swapchain = wined3d_swapchain_get_parent(device->implicit_swapchain); @@ -984,10 +994,19 @@ static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface, !!swapchain_desc.enable_auto_depth_stencil); device_reset_viewport_state(device);
+ /* FIXME: This should be the new backbuffer count, but we don't support + * changing the backbuffer count in wined3d yet. */ + for (i = 0; i < old_swapchain_desc.backbuffer_count; ++i) + { + struct wined3d_texture *backbuffer = wined3d_swapchain_get_back_buffer(device->implicit_swapchain, i); + + if ((surface = d3d8_surface_create(backbuffer, 0, (IUnknown *)&device->IDirect3DDevice8_iface))) + surface->parent_device = &device->IDirect3DDevice8_iface; + } + if ((rtv = wined3d_device_context_get_depth_stencil_view(device->immediate_context))) { struct wined3d_resource *resource = wined3d_rendertarget_view_get_resource(rtv); - struct d3d8_surface *surface;
if ((surface = d3d8_surface_create(wined3d_texture_from_resource(resource), 0, (IUnknown *)&device->IDirect3DDevice8_iface))) diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 35ba241c23a..7dc9c69dd58 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -1045,8 +1045,9 @@ static HRESULT d3d9_device_get_swapchains(struct d3d9_device *device) static HRESULT d3d9_device_reset(struct d3d9_device *device, D3DPRESENT_PARAMETERS *present_parameters, D3DDISPLAYMODEEX *mode) { + struct wined3d_swapchain_desc swapchain_desc, old_swapchain_desc; + struct d3d9_surface **old_backbuffers = NULL; BOOL extended = device->d3d_parent->extended; - struct wined3d_swapchain_desc swapchain_desc; struct wined3d_display_mode wined3d_mode; struct wined3d_rendertarget_view *rtv; struct d3d9_swapchain *d3d9_swapchain; @@ -1089,9 +1090,53 @@ static HRESULT d3d9_device_reset(struct d3d9_device *device, wined3d_stateblock_reset(device->state); }
+ if (FAILED(hr = d3d9_device_get_swapchains(device))) + { + wined3d_mutex_unlock(); + return hr; + } + d3d9_swapchain = wined3d_swapchain_get_parent(device->implicit_swapchains[0]); + + wined3d_swapchain_get_desc(d3d9_swapchain->wined3d_swapchain, &old_swapchain_desc); + + /* wined3d_device_reset() may recreate swapchain textures. + * + * If the device is not extended, we don't need to remove the reference to + * the wined3d swapchain from the old d3d9 surfaces: we will fail the reset + * if they have 0 references, and therefore they are not actually holding a + * reference to the wined3d swapchain, and will not do anything with it when + * they are destroyed. + * + * If the device is extended, those swapchain textures can survive the + * reset, and need to be detached from the implicit swapchain here. To add + * some complexity, we need to add a temporary reference, but we can only do + * that in the extended case, otherwise we'll try to validate that there are + * 0 reference and fail. */ + + if (extended) + { + if (!(old_backbuffers = malloc(old_swapchain_desc.backbuffer_count * sizeof(*old_backbuffers)))) + { + wined3d_mutex_unlock(); + return hr; + } + + for (i = 0; i < old_swapchain_desc.backbuffer_count; ++i) + { + old_backbuffers[i] = wined3d_texture_get_sub_resource_parent( + wined3d_swapchain_get_back_buffer(d3d9_swapchain->wined3d_swapchain, i), 0); + /* Resetting might drop the last reference, so grab an extra one here. + * This also lets us always decref the swapchain, without needing to + * worry about whether it's externally referenced. */ + IDirect3DSurface9_AddRef(&old_backbuffers[i]->IDirect3DSurface9_iface); + } + } + if (SUCCEEDED(hr = wined3d_device_reset(device->wined3d_device, &swapchain_desc, mode ? &wined3d_mode : NULL, reset_enum_callback, !extended))) { + struct d3d9_surface *surface; + heap_free(device->implicit_swapchains);
if (!extended) @@ -1117,6 +1162,29 @@ static HRESULT d3d9_device_reset(struct d3d9_device *device, present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(swapchain_desc.backbuffer_format); present_parameters->BackBufferCount = swapchain_desc.backbuffer_count;
+ if (extended) + { + for (i = 0; i < old_swapchain_desc.backbuffer_count; ++i) + { + surface = old_backbuffers[i]; + /* We have a reference to this surface, so we can assert that it's + * currently holding a reference to the swapchain. */ + wined3d_swapchain_decref(surface->swapchain); + surface->swapchain = NULL; + surface->container = (IUnknown *)&device->IDirect3DDevice9Ex_iface; + } + } + + /* FIXME: This should be the new backbuffer count, but we don't support + * changing the backbuffer count in wined3d yet. */ + for (i = 0; i < old_swapchain_desc.backbuffer_count; ++i) + { + struct wined3d_texture *backbuffer = wined3d_swapchain_get_back_buffer(d3d9_swapchain->wined3d_swapchain, i); + + if ((surface = d3d9_surface_create(backbuffer, 0, (IUnknown *)&device->IDirect3DDevice9Ex_iface))) + surface->parent_device = &device->IDirect3DDevice9Ex_iface; + } + device->device_state = D3D9_DEVICE_STATE_OK;
if (extended) @@ -1146,7 +1214,6 @@ static HRESULT d3d9_device_reset(struct d3d9_device *device, if ((rtv = wined3d_device_context_get_depth_stencil_view(device->immediate_context))) { struct wined3d_resource *resource = wined3d_rendertarget_view_get_resource(rtv); - struct d3d9_surface *surface;
if ((surface = d3d9_surface_create(wined3d_texture_from_resource(resource), 0, (IUnknown *)&device->IDirect3DDevice9Ex_iface))) @@ -1158,6 +1225,13 @@ static HRESULT d3d9_device_reset(struct d3d9_device *device, device->device_state = D3D9_DEVICE_STATE_NOT_RESET; }
+ if (extended) + { + for (i = 0; i < old_swapchain_desc.backbuffer_count; ++i) + IDirect3DSurface9_Release(&old_backbuffers[i]->IDirect3DSurface9_iface); + free(old_backbuffers); + } + wined3d_mutex_unlock();
return hr; diff --git a/dlls/d3d9/tests/d3d9ex.c b/dlls/d3d9/tests/d3d9ex.c index 0915d50107f..2056117f4d7 100644 --- a/dlls/d3d9/tests/d3d9ex.c +++ b/dlls/d3d9/tests/d3d9ex.c @@ -3887,8 +3887,8 @@ static void test_backbuffer_resize(void) old_backbuffer = backbuffer; hr = IDirect3DSurface9_GetDesc(old_backbuffer, &surface_desc); ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#lx.\n", hr); - todo_wine ok(surface_desc.Width == 640, "Got unexpected width %u.\n", surface_desc.Width); - todo_wine ok(surface_desc.Height == 480, "Got unexpected height %u.\n", surface_desc.Height); + ok(surface_desc.Width == 640, "Got unexpected width %u.\n", surface_desc.Width); + ok(surface_desc.Height == 480, "Got unexpected height %u.\n", surface_desc.Height);
hr = IDirect3DDevice9_GetSwapChain(device, 0, &swapchain); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -3897,25 +3897,20 @@ static void test_backbuffer_resize(void) IDirect3DSwapChain9_Release(old_swapchain);
hr = IDirect3DSurface9_GetContainer(old_backbuffer, &IID_IDirect3DSwapChain9, (void **)&swapchain); - todo_wine ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); - if (hr == S_OK) - IDirect3DSwapChain9_Release(swapchain); + ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); hr = IDirect3DSurface9_GetContainer(old_backbuffer, &IID_IDirect3DBaseTexture9, (void **)&texture); ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr); hr = IDirect3DSurface9_GetContainer(old_backbuffer, &IID_IDirect3DDevice9, (void **)&device2); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(device2 == device, "Devices didn't match.\n"); - IDirect3DDevice9_Release(device2); - } + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(device2 == device, "Devices didn't match.\n"); + IDirect3DDevice9_Release(device2);
refcount = IDirect3DSurface9_Release(old_backbuffer); ok(!refcount, "Surface has %lu references left.\n", refcount);
hr = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); ok(SUCCEEDED(hr), "Failed to get backbuffer, hr %#lx.\n", hr); - todo_wine ok(backbuffer != old_backbuffer, "Expected new backbuffer surface.\n"); + ok(backbuffer != old_backbuffer, "Expected new backbuffer surface.\n");
hr = IDirect3DDevice9_SetRenderTarget(device, 0, backbuffer); ok(SUCCEEDED(hr), "Failed to set render target, hr %#lx.\n", hr); diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 9aa76f9e97a..3c70d329474 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -525,6 +525,9 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDesc(IDXGISwapChain1 *iface, return S_OK; }
+static HRESULT d3d11_swapchain_create_d3d11_textures(struct d3d11_swapchain *swapchain, + IWineDXGIDevice *device, struct wined3d_swapchain_desc *desc); + static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain1 *iface, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags) { @@ -558,6 +561,12 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain1 * wined3d_desc.backbuffer_format = wined3dformat_from_dxgi_format(format); hr = wined3d_swapchain_resize_buffers(swapchain->wined3d_swapchain, buffer_count, width, height, wined3d_desc.backbuffer_format, wined3d_desc.multisample_type, wined3d_desc.multisample_quality); + /* wined3d_swapchain_resize_buffers() may recreate swapchain textures. + * We do not need to remove the reference to the wined3d swapchain from the + * old d3d11 textures: we just validated above that they have 0 references, + * and therefore they are not actually holding a reference to the wined3d + * swapchain, and will not do anything with it when they are destroyed. */ + d3d11_swapchain_create_d3d11_textures(swapchain, swapchain->device, &wined3d_desc); wined3d_mutex_unlock();
return hr; @@ -851,14 +860,14 @@ static const struct wined3d_swapchain_state_parent_ops d3d11_swapchain_state_par };
static HRESULT d3d11_swapchain_create_d3d11_textures(struct d3d11_swapchain *swapchain, - struct dxgi_device *device, struct wined3d_swapchain_desc *desc) + IWineDXGIDevice *device, struct wined3d_swapchain_desc *desc) { IWineDXGIDeviceParent *dxgi_device_parent; unsigned int texture_flags = 0; unsigned int i; HRESULT hr;
- if (FAILED(hr = IWineDXGIDevice_QueryInterface(&device->IWineDXGIDevice_iface, + if (FAILED(hr = IWineDXGIDevice_QueryInterface(device, &IID_IWineDXGIDeviceParent, (void **)&dxgi_device_parent))) { ERR("Device should implement IWineDXGIDeviceParent.\n"); @@ -934,7 +943,7 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi goto cleanup; }
- if (FAILED(hr = d3d11_swapchain_create_d3d11_textures(swapchain, device, desc))) + if (FAILED(hr = d3d11_swapchain_create_d3d11_textures(swapchain, &device->IWineDXGIDevice_iface, desc))) { ERR("Failed to create d3d11 textures, hr %#lx.\n", hr); goto cleanup; diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 4bbf464e58e..cad27d7e7ea 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -1929,7 +1929,7 @@ HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapcha enum wined3d_multisample_type multisample_type, unsigned int multisample_quality) { struct wined3d_swapchain_desc *desc = &swapchain->state.desc; - BOOL update_desc = FALSE; + bool recreate = false;
TRACE("swapchain %p, buffer_count %u, width %u, height %u, format %s, " "multisample_type %#x, multisample_quality %#x.\n", @@ -1968,7 +1968,7 @@ HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapcha { desc->backbuffer_width = width; desc->backbuffer_height = height; - update_desc = TRUE; + recreate = true; }
if (format_id == WINED3DFMT_UNKNOWN) @@ -1981,7 +1981,7 @@ HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapcha if (format_id != desc->backbuffer_format) { desc->backbuffer_format = format_id; - update_desc = TRUE; + recreate = true; }
if (multisample_type != desc->multisample_type @@ -1989,25 +1989,35 @@ HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapcha { desc->multisample_type = multisample_type; desc->multisample_quality = multisample_quality; - update_desc = TRUE; + recreate = true; }
- if (update_desc) + if (recreate) { + struct wined3d_texture *new_texture; HRESULT hr; UINT i;
- if (FAILED(hr = wined3d_texture_update_desc(swapchain->front_buffer, 0, desc->backbuffer_width, - desc->backbuffer_height, desc->backbuffer_format, - desc->multisample_type, desc->multisample_quality, NULL, 0))) + TRACE("Recreating swapchain textures.\n"); + + if (FAILED(hr = swapchain_create_texture(swapchain, true, false, &new_texture))) return hr; + wined3d_texture_set_swapchain(swapchain->front_buffer, NULL); + if (wined3d_texture_decref(swapchain->front_buffer)) + ERR("Something's still holding the front buffer (%p).\n", swapchain->front_buffer); + swapchain->front_buffer = new_texture; + + wined3d_texture_validate_location(swapchain->front_buffer, 0, WINED3D_LOCATION_DRAWABLE); + wined3d_texture_invalidate_location(swapchain->front_buffer, 0, ~WINED3D_LOCATION_DRAWABLE);
for (i = 0; i < desc->backbuffer_count; ++i) { - if (FAILED(hr = wined3d_texture_update_desc(swapchain->back_buffers[i], 0, desc->backbuffer_width, - desc->backbuffer_height, desc->backbuffer_format, - desc->multisample_type, desc->multisample_quality, NULL, 0))) + if (FAILED(hr = swapchain_create_texture(swapchain, false, false, &new_texture))) return hr; + wined3d_texture_set_swapchain(swapchain->back_buffers[i], NULL); + if (wined3d_texture_decref(swapchain->back_buffers[i])) + ERR("Something's still holding back buffer %u (%p).\n", i, swapchain->back_buffers[i]); + swapchain->back_buffers[i] = new_texture; } }
From: Zebediah Figura zfigura@codeweavers.com
Limit it to updating user memory and pitch. --- dlls/d3d9/device.c | 7 +--- dlls/ddraw/surface.c | 14 +++---- dlls/wined3d/texture.c | 81 +++++---------------------------------- dlls/wined3d/wined3d.spec | 2 +- include/wine/wined3d.h | 6 +-- 5 files changed, 19 insertions(+), 91 deletions(-)
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 7dc9c69dd58..b4bf51f9426 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -1419,9 +1419,7 @@ static HRESULT WINAPI d3d9_device_CreateTexture(IDirect3DDevice9Ex *iface, if (set_mem) { wined3d_mutex_lock(); - wined3d_texture_update_desc(object->wined3d_texture, 0, width, height, - wined3dformat_from_d3dformat(format), WINED3D_MULTISAMPLE_NONE, 0, - *shared_handle, 0); + wined3d_texture_update_desc(object->wined3d_texture, 0, *shared_handle, 0); wined3d_mutex_unlock(); }
@@ -1685,8 +1683,7 @@ static HRESULT d3d9_device_create_surface(struct d3d9_device *device, unsigned i IDirect3DSurface9_AddRef(*surface);
if (user_mem) - wined3d_texture_update_desc(texture, 0, width, height, desc.format, - multisample_type, multisample_quality, user_mem, 0); + wined3d_texture_update_desc(texture, 0, user_mem, 0);
wined3d_texture_decref(texture);
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index d28ed240a05..437f97f7491 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -4812,8 +4812,8 @@ static HRESULT WINAPI ddraw_surface7_SetSurfaceDesc(IDirectDrawSurface7 *iface, { /* Updating memory only. */
- if (FAILED(hr = wined3d_texture_update_desc(surface->wined3d_texture, surface->sub_resource_idx, - width, height, format_id, WINED3D_MULTISAMPLE_NONE, 0, DDSD->lpSurface, pitch))) + if (FAILED(hr = wined3d_texture_update_desc(surface->wined3d_texture, + surface->sub_resource_idx, DDSD->lpSurface, pitch))) { WARN("Failed to update surface desc, hr %#lx.\n", hr); wined3d_mutex_unlock(); @@ -4856,8 +4856,7 @@ static HRESULT WINAPI ddraw_surface7_SetSurfaceDesc(IDirectDrawSurface7 *iface, return hr_ddraw_from_wined3d(hr); }
- if (FAILED(hr = wined3d_texture_update_desc(new_texture, 0, width, height, - format_id, WINED3D_MULTISAMPLE_NONE, 0, DDSD->lpSurface, pitch))) + if (FAILED(hr = wined3d_texture_update_desc(new_texture, 0, DDSD->lpSurface, pitch))) { ERR("Failed to set user memory, hr %#lx.\n", hr); wined3d_texture_decref(new_texture); @@ -6154,8 +6153,6 @@ static HRESULT ddraw_surface_reserve_memory(struct wined3d_texture *wined3d_text wined3d_texture_get_pitch(wined3d_texture, i, &pitch, &slice_pitch);
if (FAILED(hr = wined3d_texture_update_desc(wined3d_texture, i, - desc.width, desc.height, resource_desc.format, - desc.multisample_type, desc.multisample_quality, (BYTE *)texture->texture_memory + offset, pitch))) { heap_free(texture->texture_memory); @@ -6336,9 +6333,8 @@ static HRESULT ddraw_texture_init(struct ddraw_texture *texture, struct ddraw *d return hr; }
- if ((desc->dwFlags & DDSD_LPSURFACE) && FAILED(hr = wined3d_texture_update_desc(wined3d_texture, 0, - wined3d_desc.width, wined3d_desc.height, wined3d_desc.format, - WINED3D_MULTISAMPLE_NONE, 0, desc->lpSurface, pitch))) + if ((desc->dwFlags & DDSD_LPSURFACE) + && FAILED(hr = wined3d_texture_update_desc(wined3d_texture, 0, desc->lpSurface, pitch))) { ERR("Failed to set surface memory, hr %#lx.\n", hr); goto fail; diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 1bf9adf869c..32923349c6b 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -1882,54 +1882,34 @@ void wined3d_texture_gl_set_compatible_renderbuffer(struct wined3d_texture_gl *t checkGLcall("set compatible renderbuffer"); }
-HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, unsigned int sub_resource_idx, - UINT width, UINT height, enum wined3d_format_id format_id, - enum wined3d_multisample_type multisample_type, UINT multisample_quality, void *mem, UINT pitch) +HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, + unsigned int sub_resource_idx, void *mem, unsigned int pitch) { + unsigned int current_row_pitch, current_slice_pitch, width, height; struct wined3d_texture_sub_resource *sub_resource; unsigned int i, level, sub_resource_count; - const struct wined3d_d3d_info *d3d_info; - const struct wined3d_gl_info *gl_info; const struct wined3d_format *format; struct wined3d_device *device; - unsigned int resource_size; unsigned int slice_pitch; bool update_memory_only; bool create_dib = false;
- TRACE("texture %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, " - "mem %p, pitch %u, sub_resource_idx %u.\n", - texture, width, height, debug_d3dformat(format_id), multisample_type, multisample_quality, mem, pitch, - sub_resource_idx); + TRACE("texture %p, sub_resource_idx %u, mem %p, pitch %u.\n", texture, sub_resource_idx, mem, pitch);
device = texture->resource.device; - gl_info = &device->adapter->gl_info; - d3d_info = &device->adapter->d3d_info; - format = wined3d_get_format(device->adapter, format_id, texture->resource.bind_flags); - resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height, 1); + format = texture->resource.format; level = sub_resource_idx % texture->level_count; sub_resource_count = texture->level_count * texture->layer_count;
- update_memory_only = width == wined3d_texture_get_level_width(texture, level) - && height == wined3d_texture_get_level_height(texture, level) - && format_id == texture->resource.format->id && multisample_type == texture->resource.multisample_type - && multisample_quality == texture->resource.multisample_quality; - + width = wined3d_texture_get_level_width(texture, level); + height = wined3d_texture_get_level_height(texture, level); if (pitch) slice_pitch = height * pitch; else wined3d_format_calculate_pitch(format, 1, width, height, &pitch, &slice_pitch);
- if (update_memory_only) - { - unsigned int current_row_pitch, current_slice_pitch; - - wined3d_texture_get_pitch(texture, level, ¤t_row_pitch, ¤t_slice_pitch); - update_memory_only = pitch == current_row_pitch && slice_pitch == current_slice_pitch; - } - - if (!resource_size) - return WINED3DERR_INVALIDCALL; + wined3d_texture_get_pitch(texture, level, ¤t_row_pitch, ¤t_slice_pitch); + update_memory_only = (pitch == current_row_pitch && slice_pitch == current_slice_pitch);
if (sub_resource_count > 1 && !update_memory_only) { @@ -1995,60 +1975,17 @@ HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, unsig texture->row_pitch = pitch; texture->slice_pitch = slice_pitch;
- texture->resource.format = format; - texture->resource.multisample_type = multisample_type; - texture->resource.multisample_quality = multisample_quality; - texture->resource.width = width; - texture->resource.height = height; if (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) && texture->resource.usage & WINED3DUSAGE_VIDMEM_ACCOUNTING) adapter_adjust_memory(device->adapter, (INT64)texture->slice_pitch - texture->resource.size); texture->resource.size = texture->slice_pitch; sub_resource->size = texture->slice_pitch; sub_resource->locations = WINED3D_LOCATION_DISCARDED; - - if (texture->texture_ops == &texture_gl_ops) - { - if (multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE]) - { - wined3d_texture_gl(texture)->target = GL_TEXTURE_2D_MULTISAMPLE; - texture->flags &= ~WINED3D_TEXTURE_DOWNLOADABLE; - } - else - { - wined3d_texture_gl(texture)->target = GL_TEXTURE_2D; - texture->flags |= WINED3D_TEXTURE_DOWNLOADABLE; - } - } - - if (((width & (width - 1)) || (height & (height - 1))) && !d3d_info->texture_npot - && !d3d_info->texture_npot_conditional) - { - texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED; - texture->pow2_width = texture->pow2_height = 1; - while (texture->pow2_width < width) - texture->pow2_width <<= 1; - while (texture->pow2_height < height) - texture->pow2_height <<= 1; - } - else - { - texture->flags &= ~WINED3D_TEXTURE_COND_NP2_EMULATED; - texture->pow2_width = width; - texture->pow2_height = height; - } }
if (!mem && !wined3d_resource_prepare_sysmem(&texture->resource)) ERR("Failed to allocate resource memory.\n");
- /* The format might be changed to a format that needs conversion. - * If the surface didn't use PBOs previously but could now, don't - * change it - whatever made us not use PBOs might come back, e.g. - * color keys. */ - if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER && !wined3d_texture_use_pbo(texture, d3d_info)) - texture->resource.map_binding = WINED3D_LOCATION_SYSMEM; - wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM); wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_SYSMEM);
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index e905684ce23..91d3355830e 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -309,7 +309,7 @@ @ cdecl wined3d_texture_set_lod(ptr long) @ cdecl wined3d_texture_set_overlay_position(ptr long long long) @ cdecl wined3d_texture_set_sub_resource_parent(ptr long ptr ptr) -@ cdecl wined3d_texture_update_desc(ptr long long long long long long ptr long) +@ cdecl wined3d_texture_update_desc(ptr long ptr long) @ cdecl wined3d_texture_update_overlay(ptr long ptr ptr long ptr long)
@ cdecl wined3d_unordered_access_view_create(ptr ptr ptr ptr ptr) diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 71a5d92c301..04e69e67904 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2868,10 +2868,8 @@ HRESULT __cdecl wined3d_texture_set_overlay_position(struct wined3d_texture *tex unsigned int sub_resource_idx, LONG x, LONG y); void __cdecl wined3d_texture_set_sub_resource_parent(struct wined3d_texture *texture, unsigned int sub_resource_idx, void *parent, const struct wined3d_parent_ops *parent_ops); -HRESULT __cdecl wined3d_texture_update_desc(struct wined3d_texture *texture, unsigned int sub_resource_idx, - UINT width, UINT height, enum wined3d_format_id format_id, - enum wined3d_multisample_type multisample_type, UINT multisample_quality, - void *mem, UINT pitch); +HRESULT __cdecl wined3d_texture_update_desc(struct wined3d_texture *texture, + unsigned int sub_resource_idx, void *mem, unsigned int pitch); HRESULT __cdecl wined3d_texture_update_overlay(struct wined3d_texture *texture, unsigned int sub_resource_idx, const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, const RECT *dst_rect, uint32_t flags);
Jan Sikorski (@jsikorski) commented about dlls/dxgi/swapchain.c:
WARN("Failed to get adapter parent, hr %#lx.\n", hr); return hr; }
IWineDXGIDevice_AddRef(swapchain->device = &device->IWineDXGIDevice_iface);
} else {IWineDXGIDevice_AddRef(swapchain->device);
swapchain->device = NULL;
Should we set `swapchan->implicit = true` around here?
On Wed May 17 12:46:02 2023 +0000, Jan Sikorski wrote:
Should we set `swapchan->implicit = true` around here?
Um... yeah, that was my intent. That the tests pass anyway is concerning, though, and suggests that at least we don't have enough. I'll take a closer look.
On Wed May 17 16:34:48 2023 +0000, Zebediah Figura wrote:
Um... yeah, that was my intent. That the tests pass anyway is concerning, though, and suggests that at least we don't have enough. I'll take a closer look.
The tests don't test the implicit swapchain because it's never actually exposed, and only exists I think because of some wined3d reasons probably related to GL.
Not only is the comment about swapchain references incorrect since b15685355c, but currently there's not even any reason to create a dxgi swapchain for the wined3d implicit swapchain, so I've replaced patch 2/4 with a patch that removes that.