From e8360b8eaa802c8854cf357479f33b7e3d4b4dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Fri, 6 Jan 2017 10:33:54 +0100 Subject: [PATCH] d3d9: Do not create render target view while surface refcount is equal to 0. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a regression introduced by commit b005ad6f905dc0051b17ea45b3690e0662e48481. A render target view has to be created when a surface is referenced. Otherwise the render target view reference count would be inconsistent with the surface reference count. Signed-off-by: Józef Kucia Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- dlls/d3d9/d3d9_private.h | 4 +++- dlls/d3d9/device.c | 18 ++++++++++++------ dlls/d3d9/surface.c | 15 ++++++++++++++- dlls/d3d9/tests/visual.c | 9 ++++----- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h index 20c4c5c37c9..fef0133cf0e 100644 --- a/dlls/d3d9/d3d9_private.h +++ b/dlls/d3d9/d3d9_private.h @@ -230,8 +230,10 @@ struct d3d9_surface struct d3d9_texture *texture; }; +struct wined3d_rendertarget_view *d3d9_surface_acquire_rendertarget_view(struct d3d9_surface *surface) DECLSPEC_HIDDEN; struct d3d9_device *d3d9_surface_get_device(const struct d3d9_surface *surface) DECLSPEC_HIDDEN; -struct wined3d_rendertarget_view *d3d9_surface_get_rendertarget_view(struct d3d9_surface *surface) DECLSPEC_HIDDEN; +void d3d9_surface_release_rendertarget_view(struct d3d9_surface *surface, + struct wined3d_rendertarget_view *rtv) DECLSPEC_HIDDEN; void surface_init(struct d3d9_surface *surface, struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx, const struct wined3d_parent_ops **parent_ops) DECLSPEC_HIDDEN; struct d3d9_surface *unsafe_impl_from_IDirect3DSurface9(IDirect3DSurface9 *iface) DECLSPEC_HIDDEN; diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index d47c705bb95..e6ddaf42eb5 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -1421,6 +1421,7 @@ static HRESULT WINAPI d3d9_device_ColorFill(IDirect3DDevice9Ex *iface, struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface); struct d3d9_surface *surface_impl = unsafe_impl_from_IDirect3DSurface9(surface); struct wined3d_sub_resource_desc desc; + struct wined3d_rendertarget_view *rtv; HRESULT hr; TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, surface, rect, color); @@ -1453,9 +1454,10 @@ static HRESULT WINAPI d3d9_device_ColorFill(IDirect3DDevice9Ex *iface, return D3DERR_INVALIDCALL; } + rtv = d3d9_surface_acquire_rendertarget_view(surface_impl); hr = wined3d_device_clear_rendertarget_view(device->wined3d_device, - d3d9_surface_get_rendertarget_view(surface_impl), rect, - WINED3DCLEAR_TARGET, &c, 0.0f, 0); + rtv, rect, WINED3DCLEAR_TARGET, &c, 0.0f, 0); + d3d9_surface_release_rendertarget_view(surface_impl, rtv); wined3d_mutex_unlock(); @@ -1511,6 +1513,7 @@ static HRESULT WINAPI d3d9_device_SetRenderTarget(IDirect3DDevice9Ex *iface, DWO { struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface); struct d3d9_surface *surface_impl = unsafe_impl_from_IDirect3DSurface9(surface); + struct wined3d_rendertarget_view *rtv; HRESULT hr; TRACE("iface %p, idx %u, surface %p.\n", iface, idx, surface); @@ -1534,8 +1537,9 @@ static HRESULT WINAPI d3d9_device_SetRenderTarget(IDirect3DDevice9Ex *iface, DWO } wined3d_mutex_lock(); - hr = wined3d_device_set_rendertarget_view(device->wined3d_device, idx, - surface_impl ? d3d9_surface_get_rendertarget_view(surface_impl) : NULL, TRUE); + rtv = surface_impl ? d3d9_surface_acquire_rendertarget_view(surface_impl) : NULL; + hr = wined3d_device_set_rendertarget_view(device->wined3d_device, idx, rtv, TRUE); + d3d9_surface_release_rendertarget_view(surface_impl, rtv); wined3d_mutex_unlock(); return hr; @@ -1582,12 +1586,14 @@ static HRESULT WINAPI d3d9_device_SetDepthStencilSurface(IDirect3DDevice9Ex *ifa { struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface); struct d3d9_surface *ds_impl = unsafe_impl_from_IDirect3DSurface9(depth_stencil); + struct wined3d_rendertarget_view *rtv; TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil); wined3d_mutex_lock(); - wined3d_device_set_depth_stencil_view(device->wined3d_device, - ds_impl ? d3d9_surface_get_rendertarget_view(ds_impl) : NULL); + rtv = ds_impl ? d3d9_surface_acquire_rendertarget_view(ds_impl) : NULL; + wined3d_device_set_depth_stencil_view(device->wined3d_device, rtv); + d3d9_surface_release_rendertarget_view(ds_impl, rtv); wined3d_mutex_unlock(); return D3D_OK; diff --git a/dlls/d3d9/surface.c b/dlls/d3d9/surface.c index 12e0f397c77..2f8d44759ac 100644 --- a/dlls/d3d9/surface.c +++ b/dlls/d3d9/surface.c @@ -396,10 +396,15 @@ struct d3d9_device *d3d9_surface_get_device(const struct d3d9_surface *surface) return impl_from_IDirect3DDevice9Ex(device); } -struct wined3d_rendertarget_view *d3d9_surface_get_rendertarget_view(struct d3d9_surface *surface) +struct wined3d_rendertarget_view *d3d9_surface_acquire_rendertarget_view(struct d3d9_surface *surface) { HRESULT hr; + /* The surface reference count can be equal to 0 when this function is + * called. In order to properly manage the render target view reference + * count, we temporarily increment the surface reference count. */ + d3d9_surface_AddRef(&surface->IDirect3DSurface9_iface); + if (surface->wined3d_rtv) return surface->wined3d_rtv; @@ -407,6 +412,7 @@ struct wined3d_rendertarget_view *d3d9_surface_get_rendertarget_view(struct d3d9 surface->sub_resource_idx, surface, &d3d9_view_wined3d_parent_ops, &surface->wined3d_rtv))) { ERR("Failed to create rendertarget view, hr %#x.\n", hr); + d3d9_surface_Release(&surface->IDirect3DSurface9_iface); return NULL; } @@ -416,6 +422,13 @@ struct wined3d_rendertarget_view *d3d9_surface_get_rendertarget_view(struct d3d9 return surface->wined3d_rtv; } +void d3d9_surface_release_rendertarget_view(struct d3d9_surface *surface, + struct wined3d_rendertarget_view *rtv) +{ + if (rtv) + d3d9_surface_Release(&surface->IDirect3DSurface9_iface); +} + struct d3d9_surface *unsafe_impl_from_IDirect3DSurface9(IDirect3DSurface9 *iface) { if (!iface) diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index d23be175c84..43c0cbc3a71 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -22223,7 +22223,6 @@ static void test_max_index16(void) DestroyWindow(window); } -/* This test exercises a regression in Wine d3d9 implementation. */ static void test_backbuffer_resize(void) { D3DPRESENT_PARAMETERS present_parameters = {0}; @@ -22257,8 +22256,8 @@ static void test_backbuffer_resize(void) goto done; } - /* In order to exercise the regression the backbuffer surface has to be - * unreferenced when SetRenderTarget() is called. */ + /* Wine d3d9 implementation had a bug which was triggered by a + * SetRenderTarget() call with an unreferenced surface. */ hr = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); ok(SUCCEEDED(hr), "Failed to get backbuffer, hr %#x.\n", hr); refcount = IDirect3DSurface9_Release(backbuffer); @@ -22304,7 +22303,7 @@ static void test_backbuffer_resize(void) color = getPixelColor(device, 1, 1); ok(color == 0x00ffff00, "Got unexpected color 0x%08x.\n", color); color = getPixelColor(device, 700, 500); - todo_wine ok(color == 0x00ffff00, "Got unexpected color 0x%08x.\n", color); + ok(color == 0x00ffff00, "Got unexpected color 0x%08x.\n", color); hr = IDirect3DDevice9_BeginScene(device); ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); @@ -22315,7 +22314,7 @@ static void test_backbuffer_resize(void) color = getPixelColor(device, 1, 1); ok(color == 0x0000ff00, "Got unexpected color 0x%08x.\n", color); color = getPixelColor(device, 700, 500); - todo_wine ok(color == 0x0000ff00, "Got unexpected color 0x%08x.\n", color); + ok(color == 0x0000ff00, "Got unexpected color 0x%08x.\n", color); refcount = IDirect3DDevice9_Release(device); ok(!refcount, "Device has %u references left.\n", refcount);