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/d3d9/tests/d3d9ex.c | 6 ++--- dlls/wined3d/swapchain.c | 55 ++++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 14 deletions(-)
diff --git a/dlls/d3d9/tests/d3d9ex.c b/dlls/d3d9/tests/d3d9ex.c index 41f930a2408..3cb21f1ff38 100644 --- a/dlls/d3d9/tests/d3d9ex.c +++ b/dlls/d3d9/tests/d3d9ex.c @@ -3875,14 +3875,14 @@ 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); 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/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index c280c42e582..5638c80b538 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -1911,12 +1911,46 @@ void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activa wined3d_filter_messages(window, filter); }
+static HRESULT recreate_texture(struct wined3d_texture **texture_ptr, struct wined3d_swapchain *swapchain) +{ + const struct wined3d_swapchain_desc *swapchain_desc = &swapchain->state.desc; + struct wined3d_texture *old_texture = *texture_ptr; + struct wined3d_device *device = swapchain->device; + struct wined3d_resource_desc texture_desc; + struct wined3d_texture *new_texture; + unsigned int texture_flags = 0; + HRESULT hr; + + wined3d_resource_get_desc(&old_texture->resource, &texture_desc); + + texture_desc.width = swapchain_desc->backbuffer_width; + texture_desc.height = swapchain_desc->backbuffer_height; + texture_desc.format = swapchain_desc->backbuffer_format; + texture_desc.multisample_type = swapchain_desc->multisample_type; + texture_desc.multisample_quality = swapchain_desc->multisample_quality; + + if (swapchain_desc->flags & WINED3D_SWAPCHAIN_GDI_COMPATIBLE) + texture_flags |= WINED3D_TEXTURE_CREATE_GET_DC; + + if (FAILED(hr = device->device_parent->ops->create_swapchain_texture(device->device_parent, swapchain->parent, + &texture_desc, texture_flags, &new_texture))) + { + ERR("Failed to recreate swapchain texture, hr %#lx.\n", hr); + return hr; + } + + wined3d_texture_set_swapchain(new_texture, swapchain); + *texture_ptr = new_texture; + + return S_OK; +} + HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count, unsigned int width, unsigned int height, enum wined3d_format_id format_id, 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", @@ -1955,7 +1989,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) @@ -1968,7 +2002,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 @@ -1976,24 +2010,23 @@ 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) { 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))) + if (FAILED(hr = recreate_texture(&swapchain->front_buffer, swapchain))) return hr;
+ 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 = recreate_texture(&swapchain->back_buffers[i], swapchain))) return hr; } }