mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 08:39:34 +00:00
wined3d: Recreate swapchain textures in wined3d_swapchain_resize_buffers().
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.
This commit is contained in:
parent
037be380b2
commit
ebaa0a9426
|
@ -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)))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue