d3d9: Do not create render target view while surface refcount is equal to 0.

This fixes a regression introduced by commit
b005ad6f90.

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 <jkucia@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Józef Kucia 2017-01-06 10:33:54 +01:00 committed by Alexandre Julliard
parent da5a0b7611
commit e8360b8eaa
4 changed files with 33 additions and 13 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -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);