diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 5cf22b08f79..7a95654d343 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 6efe5f33dcb..3409effaf21 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -507,6 +507,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) { @@ -540,6 +543,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; @@ -827,14 +836,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"); @@ -898,7 +907,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; } }