From b005ad6f905dc0051b17ea45b3690e0662e48481 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Thu, 21 Aug 2014 09:55:55 +0200 Subject: [PATCH] wined3d: Use rendertarget views for color output instead of surfaces. --- dlls/d3d10core/d3d10core_private.h | 2 + dlls/d3d10core/view.c | 3 +- dlls/d3d8/d3d8_private.h | 4 ++ dlls/d3d8/device.c | 26 ++++---- dlls/d3d8/surface.c | 47 ++++++++++++++ dlls/d3d8/texture.c | 25 ++++++++ dlls/d3d9/d3d9_private.h | 4 ++ dlls/d3d9/device.c | 12 ++-- dlls/d3d9/surface.c | 47 ++++++++++++++ dlls/d3d9/texture.c | 25 ++++++++ dlls/ddraw/ddraw.c | 20 +++--- dlls/ddraw/ddraw_private.h | 2 + dlls/ddraw/device.c | 10 +-- dlls/ddraw/surface.c | 68 +++++++++++++++++--- dlls/wined3d/arb_program_shader.c | 4 +- dlls/wined3d/context.c | 47 ++++++++------ dlls/wined3d/cs.c | 28 ++++----- dlls/wined3d/device.c | 123 ++++++++++++++++++++++--------------- dlls/wined3d/drawprim.c | 4 +- dlls/wined3d/glsl_shader.c | 2 +- dlls/wined3d/shader.c | 4 +- dlls/wined3d/state.c | 35 +++++------ dlls/wined3d/surface.c | 34 ++++++---- dlls/wined3d/texture.c | 4 +- dlls/wined3d/utils.c | 4 +- dlls/wined3d/view.c | 50 ++++++++++++++- dlls/wined3d/wined3d.spec | 9 ++- dlls/wined3d/wined3d_private.h | 33 ++++++++-- include/wine/wined3d.h | 15 +++-- 29 files changed, 512 insertions(+), 179 deletions(-) diff --git a/dlls/d3d10core/d3d10core_private.h b/dlls/d3d10core/d3d10core_private.h index a697a0ed8ef..8497f3afd26 100644 --- a/dlls/d3d10core/d3d10core_private.h +++ b/dlls/d3d10core/d3d10core_private.h @@ -53,6 +53,8 @@ struct d3d10_shader_info struct wined3d_shader_signature *output_signature; }; +extern const struct wined3d_parent_ops d3d10_null_wined3d_parent_ops DECLSPEC_HIDDEN; + /* TRACE helper functions */ const char *debug_d3d10_primitive_topology(D3D10_PRIMITIVE_TOPOLOGY topology) DECLSPEC_HIDDEN; const char *debug_dxgi_format(DXGI_FORMAT format) DECLSPEC_HIDDEN; diff --git a/dlls/d3d10core/view.c b/dlls/d3d10core/view.c index 73944661a65..fb69f518166 100644 --- a/dlls/d3d10core/view.c +++ b/dlls/d3d10core/view.c @@ -745,7 +745,8 @@ HRESULT d3d10_rendertarget_view_init(struct d3d10_rendertarget_view *view, struc } wined3d_rendertarget_view_desc_from_d3d10core(&wined3d_desc, &view->desc); - if (FAILED(hr = wined3d_rendertarget_view_create(&wined3d_desc, wined3d_resource, view, &view->wined3d_view))) + if (FAILED(hr = wined3d_rendertarget_view_create(&wined3d_desc, wined3d_resource, + view, &d3d10_null_wined3d_parent_ops, &view->wined3d_view))) { WARN("Failed to create a wined3d rendertarget view, hr %#x.\n", hr); return hr; diff --git a/dlls/d3d8/d3d8_private.h b/dlls/d3d8/d3d8_private.h index 74f96efbc40..6283c8d51ea 100644 --- a/dlls/d3d8/d3d8_private.h +++ b/dlls/d3d8/d3d8_private.h @@ -227,11 +227,14 @@ struct d3d8_surface IDirect3DSurface8 IDirect3DSurface8_iface; struct d3d8_resource resource; struct wined3d_surface *wined3d_surface; + struct list rtv_entry; + struct wined3d_rendertarget_view *wined3d_rtv; IDirect3DDevice8 *parent_device; IUnknown *container; struct d3d8_texture *texture; }; +struct wined3d_rendertarget_view *d3d8_surface_get_rendertarget_view(struct d3d8_surface *surface) DECLSPEC_HIDDEN; void surface_init(struct d3d8_surface *surface, IUnknown *container_parent, struct wined3d_surface *wined3d_surface, const struct wined3d_parent_ops **parent_ops) DECLSPEC_HIDDEN; struct d3d8_surface *unsafe_impl_from_IDirect3DSurface8(IDirect3DSurface8 *iface) DECLSPEC_HIDDEN; @@ -268,6 +271,7 @@ struct d3d8_texture struct d3d8_resource resource; struct wined3d_texture *wined3d_texture; IDirect3DDevice8 *parent_device; + struct list rtv_list; }; HRESULT cubetexture_init(struct d3d8_texture *texture, struct d3d8_device *device, diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 845858355dd..3eaa9484a10 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -1136,19 +1136,22 @@ static HRESULT WINAPI d3d8_device_SetRenderTarget(IDirect3DDevice8 *iface, if (ds_impl) { + struct wined3d_rendertarget_view *original_rtv; struct wined3d_resource_desc ds_desc, rt_desc; struct wined3d_resource *wined3d_resource; - struct wined3d_surface *original_rt = NULL; + struct d3d8_surface *original_surface; /* If no render target is passed in check the size against the current RT */ if (!render_target) { - if (!(original_rt = wined3d_device_get_render_target(device->wined3d_device, 0))) + + if (!(original_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0))) { wined3d_mutex_unlock(); return D3DERR_NOTFOUND; } - wined3d_resource = wined3d_surface_get_resource(original_rt); + original_surface = wined3d_rendertarget_view_get_sub_resource_parent(original_rtv); + wined3d_resource = wined3d_surface_get_resource(original_surface->wined3d_surface); } else wined3d_resource = wined3d_surface_get_resource(rt_impl->wined3d_surface); @@ -1167,12 +1170,9 @@ static HRESULT WINAPI d3d8_device_SetRenderTarget(IDirect3DDevice8 *iface, original_ds = wined3d_device_get_depth_stencil(device->wined3d_device); wined3d_device_set_depth_stencil(device->wined3d_device, ds_impl ? ds_impl->wined3d_surface : NULL); - if (render_target) - { - hr = wined3d_device_set_render_target(device->wined3d_device, 0, rt_impl->wined3d_surface, TRUE); - if (FAILED(hr)) - wined3d_device_set_depth_stencil(device->wined3d_device, original_ds); - } + if (render_target && FAILED(hr = wined3d_device_set_rendertarget_view(device->wined3d_device, 0, + d3d8_surface_get_rendertarget_view(rt_impl), TRUE))) + wined3d_device_set_depth_stencil(device->wined3d_device, original_ds); wined3d_mutex_unlock(); @@ -1182,7 +1182,7 @@ static HRESULT WINAPI d3d8_device_SetRenderTarget(IDirect3DDevice8 *iface, static HRESULT WINAPI d3d8_device_GetRenderTarget(IDirect3DDevice8 *iface, IDirect3DSurface8 **render_target) { struct d3d8_device *device = impl_from_IDirect3DDevice8(iface); - struct wined3d_surface *wined3d_surface; + struct wined3d_rendertarget_view *wined3d_rtv; struct d3d8_surface *surface_impl; HRESULT hr; @@ -1192,9 +1192,11 @@ static HRESULT WINAPI d3d8_device_GetRenderTarget(IDirect3DDevice8 *iface, IDire return D3DERR_INVALIDCALL; wined3d_mutex_lock(); - if ((wined3d_surface = wined3d_device_get_render_target(device->wined3d_device, 0))) + if ((wined3d_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0))) { - surface_impl = wined3d_surface_get_parent(wined3d_surface); + /* We want the sub resource parent here, since the view itself may be + * internal to wined3d and may not have a parent. */ + surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_rtv); *render_target = &surface_impl->IDirect3DSurface8_iface; IDirect3DSurface8_AddRef(*render_target); hr = D3D_OK; diff --git a/dlls/d3d8/surface.c b/dlls/d3d8/surface.c index d20d7917ae7..7779a5647fb 100644 --- a/dlls/d3d8/surface.c +++ b/dlls/d3d8/surface.c @@ -68,6 +68,8 @@ static ULONG WINAPI d3d8_surface_AddRef(IDirect3DSurface8 *iface) if (surface->parent_device) IDirect3DDevice8_AddRef(surface->parent_device); wined3d_mutex_lock(); + if (surface->wined3d_rtv) + wined3d_rendertarget_view_incref(surface->wined3d_rtv); wined3d_surface_incref(surface->wined3d_surface); wined3d_mutex_unlock(); } @@ -96,6 +98,8 @@ static ULONG WINAPI d3d8_surface_Release(IDirect3DSurface8 *iface) IDirect3DDevice8 *parent_device = surface->parent_device; wined3d_mutex_lock(); + if (surface->wined3d_rtv) + wined3d_rendertarget_view_decref(surface->wined3d_rtv); wined3d_surface_decref(surface->wined3d_surface); wined3d_mutex_unlock(); @@ -297,6 +301,7 @@ void surface_init(struct d3d8_surface *surface, IUnknown *container_parent, d3d8_resource_init(&surface->resource); surface->resource.refcount = 0; surface->wined3d_surface = wined3d_surface; + list_init(&surface->rtv_entry); surface->container = container_parent; if (container_parent && SUCCEEDED(IUnknown_QueryInterface(container_parent, @@ -309,6 +314,48 @@ void surface_init(struct d3d8_surface *surface, IUnknown *container_parent, *parent_ops = &d3d8_surface_wined3d_parent_ops; } +static void STDMETHODCALLTYPE view_wined3d_object_destroyed(void *parent) +{ + struct d3d8_surface *surface = parent; + + /* If the surface reference count drops to zero, we release our reference + * to the view, but don't clear the pointer yet, in case e.g. a + * GetRenderTarget() call brings the surface back before the view is + * actually destroyed. When the view is destroyed, we need to clear the + * pointer, or a subsequent surface AddRef() would reference it again. + * + * This is safe because as long as the view still has a reference to the + * texture, the surface is also still alive, and we're called before the + * view releases that reference. */ + surface->wined3d_rtv = NULL; + list_remove(&surface->rtv_entry); +} + +static const struct wined3d_parent_ops d3d8_view_wined3d_parent_ops = +{ + view_wined3d_object_destroyed, +}; + +struct wined3d_rendertarget_view *d3d8_surface_get_rendertarget_view(struct d3d8_surface *surface) +{ + HRESULT hr; + + if (surface->wined3d_rtv) + return surface->wined3d_rtv; + + if (FAILED(hr = wined3d_rendertarget_view_create_from_surface(surface->wined3d_surface, + surface, &d3d8_view_wined3d_parent_ops, &surface->wined3d_rtv))) + { + ERR("Failed to create rendertarget view, hr %#x.\n", hr); + return NULL; + } + + if (surface->texture) + list_add_head(&surface->texture->rtv_list, &surface->rtv_entry); + + return surface->wined3d_rtv; +} + struct d3d8_surface *unsafe_impl_from_IDirect3DSurface8(IDirect3DSurface8 *iface) { if (!iface) diff --git a/dlls/d3d8/texture.c b/dlls/d3d8/texture.c index 1cdf97b1350..54944acf617 100644 --- a/dlls/d3d8/texture.c +++ b/dlls/d3d8/texture.c @@ -65,8 +65,14 @@ static ULONG WINAPI d3d8_texture_2d_AddRef(IDirect3DTexture8 *iface) if (ref == 1) { + struct d3d8_surface *surface; + IDirect3DDevice8_AddRef(texture->parent_device); wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d8_surface, rtv_entry) + { + wined3d_rendertarget_view_incref(surface->wined3d_rtv); + } wined3d_texture_incref(texture->wined3d_texture); wined3d_mutex_unlock(); } @@ -84,8 +90,13 @@ static ULONG WINAPI d3d8_texture_2d_Release(IDirect3DTexture8 *iface) if (!ref) { IDirect3DDevice8 *parent_device = texture->parent_device; + struct d3d8_surface *surface; wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d8_surface, rtv_entry) + { + wined3d_rendertarget_view_decref(surface->wined3d_rtv); + } wined3d_texture_decref(texture->wined3d_texture); wined3d_mutex_unlock(); @@ -413,8 +424,14 @@ static ULONG WINAPI d3d8_texture_cube_AddRef(IDirect3DCubeTexture8 *iface) if (ref == 1) { + struct d3d8_surface *surface; + IDirect3DDevice8_AddRef(texture->parent_device); wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d8_surface, rtv_entry) + { + wined3d_rendertarget_view_incref(surface->wined3d_rtv); + } wined3d_texture_incref(texture->wined3d_texture); wined3d_mutex_unlock(); } @@ -432,10 +449,15 @@ static ULONG WINAPI d3d8_texture_cube_Release(IDirect3DCubeTexture8 *iface) if (!ref) { IDirect3DDevice8 *parent_device = texture->parent_device; + struct d3d8_surface *surface; TRACE("Releasing child %p.\n", texture->wined3d_texture); wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d8_surface, rtv_entry) + { + wined3d_rendertarget_view_decref(surface->wined3d_rtv); + } wined3d_texture_decref(texture->wined3d_texture); wined3d_mutex_unlock(); @@ -1133,6 +1155,7 @@ HRESULT texture_init(struct d3d8_texture *texture, struct d3d8_device *device, texture->IDirect3DBaseTexture8_iface.lpVtbl = (const IDirect3DBaseTexture8Vtbl *)&Direct3DTexture8_Vtbl; d3d8_resource_init(&texture->resource); + list_init(&texture->rtv_list); desc.resource_type = WINED3D_RTYPE_TEXTURE; desc.format = wined3dformat_from_d3dformat(format); @@ -1174,6 +1197,7 @@ HRESULT cubetexture_init(struct d3d8_texture *texture, struct d3d8_device *devic texture->IDirect3DBaseTexture8_iface.lpVtbl = (const IDirect3DBaseTexture8Vtbl *)&Direct3DCubeTexture8_Vtbl; d3d8_resource_init(&texture->resource); + list_init(&texture->rtv_list); desc.resource_type = WINED3D_RTYPE_CUBE_TEXTURE; desc.format = wined3dformat_from_d3dformat(format); @@ -1214,6 +1238,7 @@ HRESULT volumetexture_init(struct d3d8_texture *texture, struct d3d8_device *dev texture->IDirect3DBaseTexture8_iface.lpVtbl = (const IDirect3DBaseTexture8Vtbl *)&Direct3DVolumeTexture8_Vtbl; d3d8_resource_init(&texture->resource); + list_init(&texture->rtv_list); desc.resource_type = WINED3D_RTYPE_VOLUME_TEXTURE; desc.format = wined3dformat_from_d3dformat(format); diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h index bde85838dd6..d12805f67db 100644 --- a/dlls/d3d9/d3d9_private.h +++ b/dlls/d3d9/d3d9_private.h @@ -214,12 +214,15 @@ struct d3d9_surface IDirect3DSurface9 IDirect3DSurface9_iface; struct d3d9_resource resource; struct wined3d_surface *wined3d_surface; + struct list rtv_entry; + struct wined3d_rendertarget_view *wined3d_rtv; IDirect3DDevice9Ex *parent_device; IUnknown *container; struct d3d9_texture *texture; BOOL getdc_supported; }; +struct wined3d_rendertarget_view *d3d9_surface_get_rendertarget_view(struct d3d9_surface *surface) DECLSPEC_HIDDEN; void surface_init(struct d3d9_surface *surface, IUnknown *container_parent, struct wined3d_surface *wined3d_surface, const struct wined3d_parent_ops **parent_ops) DECLSPEC_HIDDEN; struct d3d9_surface *unsafe_impl_from_IDirect3DSurface9(IDirect3DSurface9 *iface) DECLSPEC_HIDDEN; @@ -256,6 +259,7 @@ struct d3d9_texture struct d3d9_resource resource; struct wined3d_texture *wined3d_texture; IDirect3DDevice9Ex *parent_device; + struct list rtv_list; }; HRESULT cubetexture_init(struct d3d9_texture *texture, struct d3d9_device *device, diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 7d41e4e11d0..6dfd600760a 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -1345,8 +1345,8 @@ static HRESULT WINAPI d3d9_device_SetRenderTarget(IDirect3DDevice9Ex *iface, DWO } wined3d_mutex_lock(); - hr = wined3d_device_set_render_target(device->wined3d_device, idx, - surface_impl ? surface_impl->wined3d_surface : NULL, TRUE); + hr = wined3d_device_set_rendertarget_view(device->wined3d_device, idx, + surface_impl ? d3d9_surface_get_rendertarget_view(surface_impl) : NULL, TRUE); wined3d_mutex_unlock(); return hr; @@ -1355,7 +1355,7 @@ static HRESULT WINAPI d3d9_device_SetRenderTarget(IDirect3DDevice9Ex *iface, DWO static HRESULT WINAPI d3d9_device_GetRenderTarget(IDirect3DDevice9Ex *iface, DWORD idx, IDirect3DSurface9 **surface) { struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface); - struct wined3d_surface *wined3d_surface; + struct wined3d_rendertarget_view *wined3d_rtv; struct d3d9_surface *surface_impl; HRESULT hr = D3D_OK; @@ -1371,9 +1371,11 @@ static HRESULT WINAPI d3d9_device_GetRenderTarget(IDirect3DDevice9Ex *iface, DWO } wined3d_mutex_lock(); - if ((wined3d_surface = wined3d_device_get_render_target(device->wined3d_device, idx))) + if ((wined3d_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, idx))) { - surface_impl = wined3d_surface_get_parent(wined3d_surface); + /* We want the sub resource parent here, since the view itself may be + * internal to wined3d and may not have a parent. */ + surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_rtv); *surface = &surface_impl->IDirect3DSurface9_iface; IDirect3DSurface9_AddRef(*surface); } diff --git a/dlls/d3d9/surface.c b/dlls/d3d9/surface.c index 17f2ace5ef3..e5eb11f3fa4 100644 --- a/dlls/d3d9/surface.c +++ b/dlls/d3d9/surface.c @@ -69,6 +69,8 @@ static ULONG WINAPI d3d9_surface_AddRef(IDirect3DSurface9 *iface) if (surface->parent_device) IDirect3DDevice9Ex_AddRef(surface->parent_device); wined3d_mutex_lock(); + if (surface->wined3d_rtv) + wined3d_rendertarget_view_incref(surface->wined3d_rtv); wined3d_surface_incref(surface->wined3d_surface); wined3d_mutex_unlock(); } @@ -97,6 +99,8 @@ static ULONG WINAPI d3d9_surface_Release(IDirect3DSurface9 *iface) IDirect3DDevice9Ex *parent_device = surface->parent_device; wined3d_mutex_lock(); + if (surface->wined3d_rtv) + wined3d_rendertarget_view_decref(surface->wined3d_rtv); wined3d_surface_decref(surface->wined3d_surface); wined3d_mutex_unlock(); @@ -351,6 +355,7 @@ void surface_init(struct d3d9_surface *surface, IUnknown *container_parent, d3d9_resource_init(&surface->resource); surface->resource.refcount = 0; surface->wined3d_surface = wined3d_surface; + list_init(&surface->rtv_entry); surface->container = container_parent; if (container_parent && SUCCEEDED(IUnknown_QueryInterface(container_parent, @@ -380,6 +385,48 @@ void surface_init(struct d3d9_surface *surface, IUnknown *container_parent, *parent_ops = &d3d9_surface_wined3d_parent_ops; } +static void STDMETHODCALLTYPE view_wined3d_object_destroyed(void *parent) +{ + struct d3d9_surface *surface = parent; + + /* If the surface reference count drops to zero, we release our reference + * to the view, but don't clear the pointer yet, in case e.g. a + * GetRenderTarget() call brings the surface back before the view is + * actually destroyed. When the view is destroyed, we need to clear the + * pointer, or a subsequent surface AddRef() would reference it again. + * + * This is safe because as long as the view still has a reference to the + * texture, the surface is also still alive, and we're called before the + * view releases that reference. */ + surface->wined3d_rtv = NULL; + list_remove(&surface->rtv_entry); +} + +static const struct wined3d_parent_ops d3d9_view_wined3d_parent_ops = +{ + view_wined3d_object_destroyed, +}; + +struct wined3d_rendertarget_view *d3d9_surface_get_rendertarget_view(struct d3d9_surface *surface) +{ + HRESULT hr; + + if (surface->wined3d_rtv) + return surface->wined3d_rtv; + + if (FAILED(hr = wined3d_rendertarget_view_create_from_surface(surface->wined3d_surface, + surface, &d3d9_view_wined3d_parent_ops, &surface->wined3d_rtv))) + { + ERR("Failed to create rendertarget view, hr %#x.\n", hr); + return NULL; + } + + if (surface->texture) + list_add_head(&surface->texture->rtv_list, &surface->rtv_entry); + + return surface->wined3d_rtv; +} + struct d3d9_surface *unsafe_impl_from_IDirect3DSurface9(IDirect3DSurface9 *iface) { if (!iface) diff --git a/dlls/d3d9/texture.c b/dlls/d3d9/texture.c index a57ecb13fb4..432d248a929 100644 --- a/dlls/d3d9/texture.c +++ b/dlls/d3d9/texture.c @@ -67,8 +67,14 @@ static ULONG WINAPI d3d9_texture_2d_AddRef(IDirect3DTexture9 *iface) if (ref == 1) { + struct d3d9_surface *surface; + IDirect3DDevice9Ex_AddRef(texture->parent_device); wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d9_surface, rtv_entry) + { + wined3d_rendertarget_view_incref(surface->wined3d_rtv); + } wined3d_texture_incref(texture->wined3d_texture); wined3d_mutex_unlock(); } @@ -86,8 +92,13 @@ static ULONG WINAPI d3d9_texture_2d_Release(IDirect3DTexture9 *iface) if (!ref) { IDirect3DDevice9Ex *parent_device = texture->parent_device; + struct d3d9_surface *surface; wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d9_surface, rtv_entry) + { + wined3d_rendertarget_view_decref(surface->wined3d_rtv); + } wined3d_texture_decref(texture->wined3d_texture); wined3d_mutex_unlock(); @@ -458,8 +469,14 @@ static ULONG WINAPI d3d9_texture_cube_AddRef(IDirect3DCubeTexture9 *iface) if (ref == 1) { + struct d3d9_surface *surface; + IDirect3DDevice9Ex_AddRef(texture->parent_device); wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d9_surface, rtv_entry) + { + wined3d_rendertarget_view_decref(surface->wined3d_rtv); + } wined3d_texture_incref(texture->wined3d_texture); wined3d_mutex_unlock(); } @@ -477,10 +494,15 @@ static ULONG WINAPI d3d9_texture_cube_Release(IDirect3DCubeTexture9 *iface) if (!ref) { IDirect3DDevice9Ex *parent_device = texture->parent_device; + struct d3d9_surface *surface; TRACE("Releasing child %p.\n", texture->wined3d_texture); wined3d_mutex_lock(); + LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d9_surface, rtv_entry) + { + wined3d_rendertarget_view_decref(surface->wined3d_rtv); + } wined3d_texture_decref(texture->wined3d_texture); wined3d_mutex_unlock(); @@ -1257,6 +1279,7 @@ HRESULT texture_init(struct d3d9_texture *texture, struct d3d9_device *device, texture->IDirect3DBaseTexture9_iface.lpVtbl = (const IDirect3DBaseTexture9Vtbl *)&d3d9_texture_2d_vtbl; d3d9_resource_init(&texture->resource); + list_init(&texture->rtv_list); desc.resource_type = WINED3D_RTYPE_TEXTURE; desc.format = wined3dformat_from_d3dformat(format); @@ -1298,6 +1321,7 @@ HRESULT cubetexture_init(struct d3d9_texture *texture, struct d3d9_device *devic texture->IDirect3DBaseTexture9_iface.lpVtbl = (const IDirect3DBaseTexture9Vtbl *)&d3d9_texture_cube_vtbl; d3d9_resource_init(&texture->resource); + list_init(&texture->rtv_list); desc.resource_type = WINED3D_RTYPE_CUBE_TEXTURE; desc.format = wined3dformat_from_d3dformat(format); @@ -1338,6 +1362,7 @@ HRESULT volumetexture_init(struct d3d9_texture *texture, struct d3d9_device *dev texture->IDirect3DBaseTexture9_iface.lpVtbl = (const IDirect3DBaseTexture9Vtbl *)&d3d9_texture_3d_vtbl; d3d9_resource_init(&texture->resource); + list_init(&texture->rtv_list); desc.resource_type = WINED3D_RTYPE_VOLUME_TEXTURE; desc.format = wined3dformat_from_d3dformat(format); diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index 5f0070a5b69..0af90d848c8 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -767,8 +767,9 @@ static HRESULT WINAPI ddraw1_RestoreDisplayMode(IDirectDraw *iface) static HRESULT ddraw_set_cooperative_level(struct ddraw *ddraw, HWND window, DWORD cooplevel, BOOL restore_mode_on_normal) { - struct wined3d_surface *rt = NULL, *ds = NULL; + struct wined3d_rendertarget_view *rtv = NULL; struct wined3d_stateblock *stateblock; + struct wined3d_surface *ds = NULL; BOOL restore_state = FALSE; HRESULT hr; @@ -918,11 +919,12 @@ static HRESULT ddraw_set_cooperative_level(struct ddraw *ddraw, HWND window, } wined3d_stateblock_capture(stateblock); - rt = wined3d_device_get_render_target(ddraw->wined3d_device, 0); - if (rt == ddraw->wined3d_frontbuffer) - rt = NULL; - else if (rt) - wined3d_surface_incref(rt); + rtv = wined3d_device_get_rendertarget_view(ddraw->wined3d_device, 0); + /* Rendering to ddraw->wined3d_frontbuffer. */ + if (rtv && !wined3d_rendertarget_view_get_sub_resource_parent(rtv)) + rtv = NULL; + else if (rtv) + wined3d_rendertarget_view_incref(rtv); if ((ds = wined3d_device_get_depth_stencil(ddraw->wined3d_device))) wined3d_surface_incref(ds); @@ -942,10 +944,10 @@ static HRESULT ddraw_set_cooperative_level(struct ddraw *ddraw, HWND window, wined3d_surface_decref(ds); } - if (rt) + if (rtv) { - wined3d_device_set_render_target(ddraw->wined3d_device, 0, rt, FALSE); - wined3d_surface_decref(rt); + wined3d_device_set_rendertarget_view(ddraw->wined3d_device, 0, rtv, FALSE); + wined3d_rendertarget_view_decref(rtv); } wined3d_stateblock_apply(stateblock); diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 374c273a0a8..7d028dd3e6e 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -158,6 +158,7 @@ struct ddraw_surface struct ddraw *ddraw; struct wined3d_surface *wined3d_surface; struct wined3d_texture *wined3d_texture; + struct wined3d_rendertarget_view *wined3d_rtv; struct wined3d_private_store private_store; struct d3d_device *device1; @@ -205,6 +206,7 @@ struct ddraw_texture HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_desc, struct ddraw_surface **surface, IUnknown *outer_unknown, unsigned int version) DECLSPEC_HIDDEN; +struct wined3d_rendertarget_view *ddraw_surface_get_rendertarget_view(struct ddraw_surface *surface) DECLSPEC_HIDDEN; HRESULT ddraw_surface_init(struct ddraw_surface *surface, struct ddraw *ddraw, struct ddraw_texture *texture, struct wined3d_surface *wined3d_surface, const struct wined3d_parent_ops **parent_ops) DECLSPEC_HIDDEN; ULONG ddraw_surface_release_iface(struct ddraw_surface *This) DECLSPEC_HIDDEN; diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index 4f270fd44ca..456e7e865dc 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -246,7 +246,7 @@ static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface) if (This->vertex_buffer) wined3d_buffer_decref(This->vertex_buffer); - wined3d_device_set_render_target(This->wined3d_device, 0, NULL, FALSE); + wined3d_device_set_rendertarget_view(This->wined3d_device, 0, NULL, FALSE); /* Release the wined3d device. This won't destroy it. */ if (!wined3d_device_decref(This->wined3d_device)) @@ -1818,8 +1818,8 @@ static HRESULT d3d_device_set_render_target(struct d3d_device *device, return DDERR_INVALIDPARAMS; } - if (FAILED(hr = wined3d_device_set_render_target(device->wined3d_device, - 0, target->wined3d_surface, FALSE))) + if (FAILED(hr = wined3d_device_set_rendertarget_view(device->wined3d_device, + 0, ddraw_surface_get_rendertarget_view(target), FALSE))) return hr; IUnknown_AddRef(rt_iface); @@ -6818,8 +6818,8 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw, wined3d_device_incref(ddraw->wined3d_device); /* Render to the back buffer */ - hr = wined3d_device_set_render_target(ddraw->wined3d_device, 0, target->wined3d_surface, TRUE); - if (FAILED(hr)) + if (FAILED(hr = wined3d_device_set_rendertarget_view(ddraw->wined3d_device, + 0, ddraw_surface_get_rendertarget_view(target), TRUE))) { ERR("Failed to set render target, hr %#x.\n", hr); ddraw_handle_table_destroy(&device->handle_table); diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index 63be3ae9b2f..0214a7f1e35 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -322,6 +322,8 @@ static void ddraw_surface_add_iface(struct ddraw_surface *surface) if (surface->ifaceToRelease) IUnknown_AddRef(surface->ifaceToRelease); wined3d_mutex_lock(); + if (surface->wined3d_rtv) + wined3d_rendertarget_view_incref(surface->wined3d_rtv); if (surface->wined3d_surface) wined3d_surface_incref(surface->wined3d_surface); if (surface->wined3d_texture) @@ -526,6 +528,8 @@ static void ddraw_surface_cleanup(struct ddraw_surface *surface) surface, surface->ref7, surface->ref4, surface->ref3, surface->ref2, surface->ref1); } + if (surface->wined3d_rtv) + wined3d_rendertarget_view_decref(surface->wined3d_rtv); if (surface->wined3d_texture) wined3d_texture_decref(surface->wined3d_texture); if (surface->wined3d_surface) @@ -1208,11 +1212,12 @@ static HRESULT WINAPI ddraw_surface7_Flip(IDirectDrawSurface7 *iface, IDirectDra { struct ddraw_surface *dst_impl = impl_from_IDirectDrawSurface7(iface); struct ddraw_surface *src_impl = unsafe_impl_from_IDirectDrawSurface7(src); + struct wined3d_rendertarget_view *tmp_rtv, *src_rtv, *rtv; struct ddraw_texture *ddraw_texture, *prev_ddraw_texture; DDSCAPS2 caps = {DDSCAPS_FLIP, 0, 0, 0}; - struct wined3d_surface *tmp, *rt; struct wined3d_texture *texture; IDirectDrawSurface7 *current; + struct wined3d_surface *tmp; HRESULT hr; TRACE("iface %p, src %p, flags %#x.\n", iface, src, flags); @@ -1225,9 +1230,10 @@ static HRESULT WINAPI ddraw_surface7_Flip(IDirectDrawSurface7 *iface, IDirectDra wined3d_mutex_lock(); + tmp_rtv = ddraw_surface_get_rendertarget_view(dst_impl); tmp = dst_impl->wined3d_surface; texture = dst_impl->wined3d_texture; - rt = wined3d_device_get_render_target(dst_impl->ddraw->wined3d_device, 0); + rtv = wined3d_device_get_rendertarget_view(dst_impl->ddraw->wined3d_device, 0); ddraw_texture = wined3d_texture_get_parent(dst_impl->wined3d_texture); if (src_impl) @@ -1249,8 +1255,11 @@ static HRESULT WINAPI ddraw_surface7_Flip(IDirectDrawSurface7 *iface, IDirectDra } } - if (rt == dst_impl->wined3d_surface) - wined3d_device_set_render_target(dst_impl->ddraw->wined3d_device, 0, src_impl->wined3d_surface, FALSE); + src_rtv = ddraw_surface_get_rendertarget_view(src_impl); + if (rtv == dst_impl->wined3d_rtv) + wined3d_device_set_rendertarget_view(dst_impl->ddraw->wined3d_device, 0, src_rtv, FALSE); + wined3d_rendertarget_view_set_parent(src_rtv, dst_impl); + dst_impl->wined3d_rtv = src_rtv; wined3d_resource_set_parent(wined3d_surface_get_resource(src_impl->wined3d_surface), dst_impl); dst_impl->wined3d_surface = src_impl->wined3d_surface; prev_ddraw_texture = wined3d_texture_get_parent(src_impl->wined3d_texture); @@ -1276,8 +1285,11 @@ static HRESULT WINAPI ddraw_surface7_Flip(IDirectDrawSurface7 *iface, IDirectDra } src_impl = impl_from_IDirectDrawSurface7(current); - if (rt == dst_impl->wined3d_surface) - wined3d_device_set_render_target(dst_impl->ddraw->wined3d_device, 0, src_impl->wined3d_surface, FALSE); + src_rtv = ddraw_surface_get_rendertarget_view(src_impl); + if (rtv == dst_impl->wined3d_rtv) + wined3d_device_set_rendertarget_view(dst_impl->ddraw->wined3d_device, 0, src_rtv, FALSE); + wined3d_rendertarget_view_set_parent(src_rtv, dst_impl); + dst_impl->wined3d_rtv = src_rtv; wined3d_resource_set_parent(wined3d_surface_get_resource(src_impl->wined3d_surface), dst_impl); dst_impl->wined3d_surface = src_impl->wined3d_surface; prev_ddraw_texture = wined3d_texture_get_parent(src_impl->wined3d_texture); @@ -1290,8 +1302,10 @@ static HRESULT WINAPI ddraw_surface7_Flip(IDirectDrawSurface7 *iface, IDirectDra /* We don't have to worry about potential texture bindings, since * flippable surfaces can never be textures. */ - if (rt == src_impl->wined3d_surface) - wined3d_device_set_render_target(dst_impl->ddraw->wined3d_device, 0, tmp, FALSE); + if (rtv == src_impl->wined3d_rtv) + wined3d_device_set_rendertarget_view(dst_impl->ddraw->wined3d_device, 0, tmp_rtv, FALSE); + wined3d_rendertarget_view_set_parent(tmp_rtv, src_impl); + src_impl->wined3d_rtv = tmp_rtv; wined3d_resource_set_parent(wined3d_surface_get_resource(tmp), src_impl); src_impl->wined3d_surface = tmp; wined3d_resource_set_parent(wined3d_texture_get_resource(texture), ddraw_texture); @@ -6227,3 +6241,41 @@ HRESULT ddraw_surface_init(struct ddraw_surface *surface, struct ddraw *ddraw, s return DD_OK; } + +static void STDMETHODCALLTYPE view_wined3d_object_destroyed(void *parent) +{ + struct ddraw_surface *surface = parent; + + /* If the surface reference count drops to zero, we release our reference + * to the view, but don't clear the pointer yet, in case e.g. a + * GetRenderTarget() call brings the surface back before the view is + * actually destroyed. When the view is destroyed, we need to clear the + * pointer, or a subsequent surface AddRef() would reference it again. + * + * This is safe because as long as the view still has a reference to the + * texture, the surface is also still alive, and we're called before the + * view releases that reference. */ + surface->wined3d_rtv = NULL; +} + +static const struct wined3d_parent_ops ddraw_view_wined3d_parent_ops = +{ + view_wined3d_object_destroyed, +}; + +struct wined3d_rendertarget_view *ddraw_surface_get_rendertarget_view(struct ddraw_surface *surface) +{ + HRESULT hr; + + if (surface->wined3d_rtv) + return surface->wined3d_rtv; + + if (FAILED(hr = wined3d_rendertarget_view_create_from_surface(surface->wined3d_surface, + surface, &ddraw_view_wined3d_parent_ops, &surface->wined3d_rtv))) + { + ERR("Failed to create rendertarget view, hr %#x.\n", hr); + return NULL; + } + + return surface->wined3d_rtv; +} diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 3d3816f41e1..4a61cc8fcae 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -706,7 +706,7 @@ static void shader_arb_load_constants_internal(struct shader_arb_priv *priv, { const struct wined3d_shader *pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL]; const struct arb_ps_compiled_shader *gl_shader = priv->compiled_fprog; - UINT rt_height = state->fb->render_targets[0]->resource.height; + UINT rt_height = state->fb->render_targets[0]->height; /* Load DirectX 9 float constants for pixel shader */ priv->highest_dirty_ps_const = shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB, @@ -4673,7 +4673,7 @@ static void shader_arb_select(void *shader_priv, struct wined3d_context *context } else { - UINT rt_height = state->fb->render_targets[0]->resource.height; + UINT rt_height = state->fb->render_targets[0]->height; shader_arb_ps_local_constants(compiled, context, state, rt_height); } diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index f62b96228d6..b3573ae713e 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -2281,7 +2281,7 @@ void context_apply_blit_state(struct wined3d_context *context, const struct wine } static BOOL context_validate_rt_config(UINT rt_count, - struct wined3d_surface * const *rts, const struct wined3d_surface *ds) + struct wined3d_rendertarget_view * const *rts, const struct wined3d_surface *ds) { unsigned int i; @@ -2289,7 +2289,7 @@ static BOOL context_validate_rt_config(UINT rt_count, for (i = 0; i < rt_count; ++i) { - if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL) + if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL) return TRUE; } @@ -2301,10 +2301,10 @@ static BOOL context_validate_rt_config(UINT rt_count, BOOL context_apply_clear_state(struct wined3d_context *context, const struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb) { + struct wined3d_rendertarget_view **rts = fb->render_targets; const struct wined3d_gl_info *gl_info = context->gl_info; DWORD rt_mask = 0, *cur_mask; UINT i; - struct wined3d_surface **rts = fb->render_targets; if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != &device->fb || rt_count != context->gl_info->limits.buffers) @@ -2316,12 +2316,12 @@ BOOL context_apply_clear_state(struct wined3d_context *context, const struct win { context_validate_onscreen_formats(context, fb->depth_stencil); - if (!rt_count || wined3d_resource_is_offscreen(&rts[0]->resource)) + if (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource)) { for (i = 0; i < rt_count; ++i) { - context->blit_targets[i] = rts[i]; - if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL) + context->blit_targets[i] = wined3d_rendertarget_view_get_surface(rts[i]); + if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL) rt_mask |= (1 << i); } while (i < context->gl_info->limits.buffers) @@ -2330,12 +2330,12 @@ BOOL context_apply_clear_state(struct wined3d_context *context, const struct win ++i; } context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, fb->depth_stencil, - rt_count ? rts[0]->container->resource.draw_binding : WINED3D_LOCATION_TEXTURE_RGB); + rt_count ? rts[0]->resource->draw_binding : WINED3D_LOCATION_TEXTURE_RGB); } else { context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, WINED3D_LOCATION_DRAWABLE); - rt_mask = context_generate_rt_mask_from_surface(rts[0]); + rt_mask = context_generate_rt_mask_from_surface(wined3d_rendertarget_view_get_surface(rts[0])); } /* If the framebuffer is not the device's fb the device's fb has to be reapplied @@ -2345,20 +2345,23 @@ BOOL context_apply_clear_state(struct wined3d_context *context, const struct win } else { - rt_mask = context_generate_rt_mask_no_fbo(device, rt_count ? rts[0] : NULL); + rt_mask = context_generate_rt_mask_no_fbo(device, + rt_count ? wined3d_rendertarget_view_get_surface(rts[0]) : NULL); } } else if (wined3d_settings.offscreen_rendering_mode == ORM_FBO - && (!rt_count || wined3d_resource_is_offscreen(&rts[0]->resource))) + && (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource))) { for (i = 0; i < rt_count; ++i) { - if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL) rt_mask |= (1 << i); + if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL) + rt_mask |= (1 << i); } } else { - rt_mask = context_generate_rt_mask_no_fbo(device, rt_count ? rts[0] : NULL); + rt_mask = context_generate_rt_mask_no_fbo(device, + rt_count ? wined3d_rendertarget_view_get_surface(rts[0]) : NULL); } cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask; @@ -2395,13 +2398,15 @@ BOOL context_apply_clear_state(struct wined3d_context *context, const struct win static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_device *device) { const struct wined3d_state *state = &device->state; - struct wined3d_surface **rts = state->fb->render_targets; + struct wined3d_rendertarget_view **rts = state->fb->render_targets; struct wined3d_shader *ps = state->shader[WINED3D_SHADER_TYPE_PIXEL]; DWORD rt_mask, rt_mask_bits; unsigned int i; - if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return context_generate_rt_mask_no_fbo(device, rts[0]); - else if (!context->render_offscreen) return context_generate_rt_mask_from_surface(rts[0]); + if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) + return context_generate_rt_mask_no_fbo(device, wined3d_rendertarget_view_get_surface(rts[0])); + else if (!context->render_offscreen) + return context_generate_rt_mask_from_surface(wined3d_rendertarget_view_get_surface(rts[0])); rt_mask = ps ? ps->reg_maps.rt_mask : 1; rt_mask &= context->d3d_info->valid_rt_mask; @@ -2410,7 +2415,7 @@ static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const while (rt_mask_bits) { rt_mask_bits &= ~(1 << i); - if (!rts[i] || rts[i]->resource.format->id == WINED3DFMT_NULL) + if (!rts[i] || rts[i]->format->id == WINED3DFMT_NULL) rt_mask &= ~(1 << i); i++; @@ -2435,8 +2440,14 @@ void context_state_fb(struct wined3d_context *context, const struct wined3d_stat } else { - context_apply_fbo_state(context, GL_FRAMEBUFFER, fb->render_targets, fb->depth_stencil, - fb->render_targets[0]->container->resource.draw_binding); + unsigned int i; + + for (i = 0; i < context->gl_info->limits.buffers; ++i) + { + context->blit_targets[i] = wined3d_rendertarget_view_get_surface(fb->render_targets[i]); + } + context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, fb->depth_stencil, + fb->render_targets[0]->resource->draw_binding); } } diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 684ac9f79b0..df1c4e35ea9 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -31,7 +31,7 @@ enum wined3d_cs_op WINED3D_CS_OP_DRAW, WINED3D_CS_OP_SET_VIEWPORT, WINED3D_CS_OP_SET_SCISSOR_RECT, - WINED3D_CS_OP_SET_RENDER_TARGET, + WINED3D_CS_OP_SET_RENDERTARGET_VIEW, WINED3D_CS_OP_SET_DEPTH_STENCIL, WINED3D_CS_OP_SET_VERTEX_DECLARATION, WINED3D_CS_OP_SET_STREAM_SOURCE, @@ -95,11 +95,11 @@ struct wined3d_cs_set_scissor_rect const RECT *rect; }; -struct wined3d_cs_set_render_target +struct wined3d_cs_set_rendertarget_view { enum wined3d_cs_op opcode; - UINT render_target_idx; - struct wined3d_surface *render_target; + unsigned int view_idx; + struct wined3d_rendertarget_view *view; }; struct wined3d_cs_set_depth_stencil @@ -346,23 +346,23 @@ void wined3d_cs_emit_set_scissor_rect(struct wined3d_cs *cs, const RECT *rect) cs->ops->submit(cs); } -static void wined3d_cs_exec_set_render_target(struct wined3d_cs *cs, const void *data) +static void wined3d_cs_exec_set_rendertarget_view(struct wined3d_cs *cs, const void *data) { - const struct wined3d_cs_set_render_target *op = data; + const struct wined3d_cs_set_rendertarget_view *op = data; - cs->state.fb->render_targets[op->render_target_idx] = op->render_target; + cs->state.fb->render_targets[op->view_idx] = op->view; device_invalidate_state(cs->device, STATE_FRAMEBUFFER); } -void wined3d_cs_emit_set_render_target(struct wined3d_cs *cs, UINT render_target_idx, - struct wined3d_surface *render_target) +void wined3d_cs_emit_set_rendertarget_view(struct wined3d_cs *cs, unsigned int view_idx, + struct wined3d_rendertarget_view *view) { - struct wined3d_cs_set_render_target *op; + struct wined3d_cs_set_rendertarget_view *op; op = cs->ops->require_space(cs, sizeof(*op)); - op->opcode = WINED3D_CS_OP_SET_RENDER_TARGET; - op->render_target_idx = render_target_idx; - op->render_target = render_target; + op->opcode = WINED3D_CS_OP_SET_RENDERTARGET_VIEW; + op->view_idx = view_idx; + op->view = view; cs->ops->submit(cs); } @@ -851,7 +851,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void /* WINED3D_CS_OP_DRAW */ wined3d_cs_exec_draw, /* WINED3D_CS_OP_SET_VIEWPORT */ wined3d_cs_exec_set_viewport, /* WINED3D_CS_OP_SET_SCISSOR_RECT */ wined3d_cs_exec_set_scissor_rect, - /* WINED3D_CS_OP_SET_RENDER_TARGET */ wined3d_cs_exec_set_render_target, + /* WINED3D_CS_OP_SET_RENDERTARGET_VIEW */ wined3d_cs_exec_set_rendertarget_view, /* WINED3D_CS_OP_SET_DEPTH_STENCIL */ wined3d_cs_exec_set_depth_stencil, /* WINED3D_CS_OP_SET_VERTEX_DECLARATION */ wined3d_cs_exec_set_vertex_declaration, /* WINED3D_CS_OP_SET_STREAM_SOURCE */ wined3d_cs_exec_set_stream_source, diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 962c9c8da6a..cd5f5f4748f 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -286,8 +286,8 @@ void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, c UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil) { + struct wined3d_surface *target = rt_count ? wined3d_rendertarget_view_get_surface(fb->render_targets[0]) : NULL; const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL; - struct wined3d_surface *target = rt_count ? fb->render_targets[0] : NULL; const struct wined3d_gl_info *gl_info; UINT drawable_width, drawable_height; struct wined3d_context *context; @@ -308,7 +308,7 @@ void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, c { for (i = 0; i < rt_count; ++i) { - struct wined3d_surface *rt = fb->render_targets[i]; + struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(fb->render_targets[i]); if (rt) surface_load_location(rt, rt->container->resource.draw_binding); } @@ -386,7 +386,7 @@ void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, c { for (i = 0; i < rt_count; ++i) { - struct wined3d_surface *rt = fb->render_targets[i]; + struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(fb->render_targets[i]); if (rt) { @@ -851,11 +851,10 @@ static void device_init_swapchain_state(struct wined3d_device *device, struct wi { for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i) { - wined3d_device_set_render_target(device, i, NULL, FALSE); + wined3d_device_set_rendertarget_view(device, i, NULL, FALSE); } - if (swapchain->back_buffers && swapchain->back_buffers[0]) - wined3d_device_set_render_target(device, 0, - surface_from_resource(wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0)), TRUE); + if (device->back_buffer_view) + wined3d_device_set_rendertarget_view(device, 0, device->back_buffer_view, TRUE); } wined3d_device_set_depth_stencil(device, ds_enable ? device->auto_depth_stencil : NULL); @@ -904,6 +903,14 @@ HRESULT CDECL wined3d_device_init_3d(struct wined3d_device *device, goto err_out; } + if (swapchain_desc->backbuffer_count && FAILED(hr = wined3d_rendertarget_view_create_from_surface( + surface_from_resource(wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0)), + NULL, &wined3d_null_parent_ops, &device->back_buffer_view))) + { + ERR("Failed to create rendertarget view, hr %#x.\n", hr); + goto err_out; + } + device->swapchain_count = 1; device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains)); if (!device->swapchains) @@ -964,6 +971,8 @@ err_out: HeapFree(GetProcessHeap(), 0, device->fb.render_targets); HeapFree(GetProcessHeap(), 0, device->swapchains); device->swapchain_count = 0; + if (device->back_buffer_view) + wined3d_rendertarget_view_decref(device->back_buffer_view); if (swapchain) wined3d_swapchain_decref(swapchain); if (device->blit_priv) @@ -1083,7 +1092,12 @@ HRESULT CDECL wined3d_device_uninit_3d(struct wined3d_device *device) for (i = 0; i < gl_info->limits.buffers; ++i) { - wined3d_device_set_render_target(device, i, NULL, FALSE); + wined3d_device_set_rendertarget_view(device, i, NULL, FALSE); + } + if (device->back_buffer_view) + { + wined3d_rendertarget_view_decref(device->back_buffer_view); + device->back_buffer_view = NULL; } context_release(context); @@ -3213,8 +3227,8 @@ HRESULT CDECL wined3d_device_clear(struct wined3d_device *device, DWORD rect_cou } else if (flags & WINED3DCLEAR_TARGET) { - if (ds->resource.width < device->fb.render_targets[0]->resource.width - || ds->resource.height < device->fb.render_targets[0]->resource.height) + if (ds->resource.width < device->fb.render_targets[0]->width + || ds->resource.height < device->fb.render_targets[0]->height) { WARN("Silently ignoring depth and target clear with mismatching sizes\n"); return WINED3D_OK; @@ -3532,11 +3546,10 @@ HRESULT CDECL wined3d_device_validate_device(const struct wined3d_device *device if (state->render_states[WINED3D_RS_ZENABLE] || state->render_states[WINED3D_RS_ZWRITEENABLE] || state->render_states[WINED3D_RS_STENCILENABLE]) { + struct wined3d_rendertarget_view *rt = device->fb.render_targets[0]; struct wined3d_surface *ds = device->fb.depth_stencil; - struct wined3d_surface *target = device->fb.render_targets[0]; - if(ds && target - && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height)) + if(ds && rt && (ds->resource.width < rt->width || ds->resource.height < rt->height)) { WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n"); return WINED3DERR_CONFLICTINGRENDERSTATE; @@ -3769,18 +3782,18 @@ void CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *device, ERR("Color fill failed, hr %#x.\n", hr); } -struct wined3d_surface * CDECL wined3d_device_get_render_target(const struct wined3d_device *device, - UINT render_target_idx) +struct wined3d_rendertarget_view * CDECL wined3d_device_get_rendertarget_view(const struct wined3d_device *device, + unsigned int view_idx) { - TRACE("device %p, render_target_idx %u.\n", device, render_target_idx); + TRACE("device %p, view_idx %u.\n", device, view_idx); - if (render_target_idx >= device->adapter->gl_info.limits.buffers) + if (view_idx >= device->adapter->gl_info.limits.buffers) { WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers); return NULL; } - return device->fb.render_targets[render_target_idx]; + return device->fb.render_targets[view_idx]; } struct wined3d_surface * CDECL wined3d_device_get_depth_stencil(const struct wined3d_device *device) @@ -3790,61 +3803,61 @@ struct wined3d_surface * CDECL wined3d_device_get_depth_stencil(const struct win return device->fb.depth_stencil; } -HRESULT CDECL wined3d_device_set_render_target(struct wined3d_device *device, - UINT render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport) +HRESULT CDECL wined3d_device_set_rendertarget_view(struct wined3d_device *device, + unsigned int view_idx, struct wined3d_rendertarget_view *view, BOOL set_viewport) { - struct wined3d_surface *prev; + struct wined3d_rendertarget_view *prev; - TRACE("device %p, render_target_idx %u, render_target %p, set_viewport %#x.\n", - device, render_target_idx, render_target, set_viewport); + TRACE("device %p, view_idx %u, view %p, set_viewport %#x.\n", + device, view_idx, view, set_viewport); - if (render_target_idx >= device->adapter->gl_info.limits.buffers) + if (view_idx >= device->adapter->gl_info.limits.buffers) { WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers); return WINED3DERR_INVALIDCALL; } - if (render_target && !(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)) + if (view && !(view->resource->usage & WINED3DUSAGE_RENDERTARGET)) { - WARN("Surface %p doesn't have render target usage.\n", render_target); + WARN("View resource %p doesn't have render target usage.\n", view->resource); return WINED3DERR_INVALIDCALL; } /* Set the viewport and scissor rectangles, if requested. Tests show that * stateblock recording is ignored, the change goes directly into the * primary stateblock. */ - if (!render_target_idx && set_viewport) + if (!view_idx && set_viewport) { struct wined3d_state *state = &device->state; state->viewport.x = 0; state->viewport.y = 0; - state->viewport.width = render_target->resource.width; - state->viewport.height = render_target->resource.height; + state->viewport.width = view->width; + state->viewport.height = view->height; state->viewport.min_z = 0.0f; state->viewport.max_z = 1.0f; wined3d_cs_emit_set_viewport(device->cs, &state->viewport); state->scissor_rect.top = 0; state->scissor_rect.left = 0; - state->scissor_rect.right = render_target->resource.width; - state->scissor_rect.bottom = render_target->resource.height; + state->scissor_rect.right = view->width; + state->scissor_rect.bottom = view->height; wined3d_cs_emit_set_scissor_rect(device->cs, &state->scissor_rect); } - prev = device->fb.render_targets[render_target_idx]; - if (render_target == prev) + prev = device->fb.render_targets[view_idx]; + if (view == prev) return WINED3D_OK; - if (render_target) - wined3d_surface_incref(render_target); - device->fb.render_targets[render_target_idx] = render_target; - wined3d_cs_emit_set_render_target(device->cs, render_target_idx, render_target); + if (view) + wined3d_rendertarget_view_incref(view); + device->fb.render_targets[view_idx] = view; + wined3d_cs_emit_set_rendertarget_view(device->cs, view_idx, view); /* Release after the assignment, to prevent device_resource_released() * from seeing the surface as still in use. */ if (prev) - wined3d_surface_decref(prev); + wined3d_rendertarget_view_decref(prev); return WINED3D_OK; } @@ -4242,11 +4255,8 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device, { for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i) { - wined3d_device_set_render_target(device, i, NULL, FALSE); + wined3d_device_set_rendertarget_view(device, i, NULL, FALSE); } - if (swapchain->back_buffers && swapchain->back_buffers[0]) - wined3d_device_set_render_target(device, 0, - surface_from_resource(wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0)), FALSE); } wined3d_device_set_depth_stencil(device, NULL); @@ -4439,6 +4449,19 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device, } } + if (device->back_buffer_view) + { + wined3d_rendertarget_view_decref(device->back_buffer_view); + device->back_buffer_view = NULL; + } + if (swapchain->desc.backbuffer_count && FAILED(hr = wined3d_rendertarget_view_create_from_surface( + surface_from_resource(wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0)), + NULL, &wined3d_null_parent_ops, &device->back_buffer_view))) + { + ERR("Failed to create rendertarget view, hr %#x.\n", hr); + return hr; + } + if (!swapchain_desc->windowed != !swapchain->desc.windowed || DisplayModeChanged) { @@ -4521,22 +4544,24 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device, device_init_swapchain_state(device, swapchain); } - else + else if (device->back_buffer_view) { - struct wined3d_surface *rt = device->fb.render_targets[0]; + struct wined3d_rendertarget_view *view = device->back_buffer_view; struct wined3d_state *state = &device->state; + wined3d_device_set_rendertarget_view(device, 0, view, FALSE); + /* Note the min_z / max_z is not reset. */ state->viewport.x = 0; state->viewport.y = 0; - state->viewport.width = rt->resource.width; - state->viewport.height = rt->resource.height; + state->viewport.width = view->width; + state->viewport.height = view->height; wined3d_cs_emit_set_viewport(device->cs, &state->viewport); state->scissor_rect.top = 0; state->scissor_rect.left = 0; - state->scissor_rect.right = rt->resource.width; - state->scissor_rect.bottom = rt->resource.height; + state->scissor_rect.right = view->width; + state->scissor_rect.bottom = view->height; wined3d_cs_emit_set_scissor_rect(device->cs, &state->scissor_rect); } @@ -4627,7 +4652,7 @@ void device_resource_released(struct wined3d_device *device, struct wined3d_reso for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i) { - if (device->fb.render_targets[i] == surface) + if (wined3d_rendertarget_view_get_surface(device->fb.render_targets[i]) == surface) { ERR("Surface %p is still in use as render target %u.\n", surface, i); device->fb.render_targets[i] = NULL; diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 621e3f219a2..aa9f66110f6 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -613,7 +613,7 @@ void draw_primitive(struct wined3d_device *device, UINT start_idx, UINT index_co /* Invalidate the back buffer memory so LockRect will read it the next time */ for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i) { - struct wined3d_surface *target = device->fb.render_targets[i]; + struct wined3d_surface *target = wined3d_rendertarget_view_get_surface(device->fb.render_targets[i]); if (target) { surface_load_location(target, target->container->resource.draw_binding); @@ -622,7 +622,7 @@ void draw_primitive(struct wined3d_device *device, UINT start_idx, UINT index_co } } - context = context_acquire(device, device->fb.render_targets[0]); + context = context_acquire(device, wined3d_rendertarget_view_get_surface(device->fb.render_targets[0])); if (!context->valid) { context_release(context); diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 1097d87af28..bebcfd43caa 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1257,7 +1257,7 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont { float ycorrection[] = { - context->render_offscreen ? 0.0f : fb->render_targets[0]->resource.height, + context->render_offscreen ? 0.0f : fb->render_targets[0]->height, context->render_offscreen ? 1.0f : -1.0f, 0.0f, 0.0f, diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 06ed09aef7f..1076628643a 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2036,8 +2036,8 @@ void find_ps_compile_args(const struct wined3d_state *state, const struct wined3 memset(args, 0, sizeof(*args)); /* FIXME: Make sure all bits are set. */ if (!gl_info->supported[ARB_FRAMEBUFFER_SRGB] && state->render_states[WINED3D_RS_SRGBWRITEENABLE]) { - const struct wined3d_surface *rt = state->fb->render_targets[0]; - if (rt->resource.format->flags & WINED3DFMT_FLAG_SRGB_WRITE) + const struct wined3d_format *rt_format = state->fb->render_targets[0]->format; + if (rt_format->flags & WINED3DFMT_FLAG_SRGB_WRITE) { static unsigned int warned = 0; diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index fc9c38dbcac..6f0f96feda1 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -381,7 +381,7 @@ static GLenum gl_blend_factor(enum wined3d_blend factor, const struct wined3d_fo static void state_blend(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { - const struct wined3d_surface *target = state->fb->render_targets[0]; + const struct wined3d_format *rt_format = state->fb->render_targets[0]->format; const struct wined3d_gl_info *gl_info = context->gl_info; GLenum srcBlend, dstBlend; enum wined3d_blend d3d_blend; @@ -395,8 +395,7 @@ static void state_blend(struct wined3d_context *context, const struct wined3d_st /* Disable blending in all cases even without pixelshaders. * With blending on we could face a big performance penalty. * The d3d9 visual test confirms the behavior. */ - if (context->render_offscreen - && !(target->resource.format->flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING)) + if (context->render_offscreen && !(rt_format->flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING)) { gl_info->gl_ops.gl.p_glDisable(GL_BLEND); checkGLcall("glDisable GL_BLEND"); @@ -432,9 +431,8 @@ static void state_blend(struct wined3d_context *context, const struct wined3d_st } else { - srcBlend = gl_blend_factor(d3d_blend, target->resource.format); - dstBlend = gl_blend_factor(state->render_states[WINED3D_RS_DESTBLEND], - target->resource.format); + srcBlend = gl_blend_factor(d3d_blend, rt_format); + dstBlend = gl_blend_factor(state->render_states[WINED3D_RS_DESTBLEND], rt_format); } if (state->render_states[WINED3D_RS_EDGEANTIALIAS] @@ -484,9 +482,8 @@ static void state_blend(struct wined3d_context *context, const struct wined3d_st } else { - srcBlendAlpha = gl_blend_factor(d3d_blend, target->resource.format); - dstBlendAlpha = gl_blend_factor(state->render_states[WINED3D_RS_DESTBLENDALPHA], - target->resource.format); + srcBlendAlpha = gl_blend_factor(d3d_blend, rt_format); + dstBlendAlpha = gl_blend_factor(state->render_states[WINED3D_RS_DESTBLENDALPHA], rt_format); } GL_EXTCALL(glBlendFuncSeparateEXT(srcBlend, dstBlend, srcBlendAlpha, dstBlendAlpha)); @@ -4637,14 +4634,14 @@ void vertexdeclaration(struct wined3d_context *context, const struct wined3d_sta static void viewport_miscpart(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { - const struct wined3d_surface *target = state->fb->render_targets[0]; + const struct wined3d_rendertarget_view *target = state->fb->render_targets[0]; const struct wined3d_gl_info *gl_info = context->gl_info; struct wined3d_viewport vp = state->viewport; - if (vp.width > target->resource.width) - vp.width = target->resource.width; - if (vp.height > target->resource.height) - vp.height = target->resource.height; + if (vp.width > target->width) + vp.width = target->width; + if (vp.height > target->height) + vp.height = target->height; gl_info->gl_ops.gl.p_glDepthRange(vp.min_z, vp.max_z); checkGLcall("glDepthRange"); @@ -4658,7 +4655,7 @@ static void viewport_miscpart(struct wined3d_context *context, const struct wine { UINT width, height; - surface_get_drawable_size(target, context, &width, &height); + surface_get_drawable_size(wined3d_rendertarget_view_get_surface(target), context, &width, &height); gl_info->gl_ops.gl.p_glViewport(vp.x, (height - (vp.y + vp.height)), vp.width, vp.height); } @@ -4817,11 +4814,11 @@ static void scissorrect(struct wined3d_context *context, const struct wined3d_st } else { - const struct wined3d_surface *target = state->fb->render_targets[0]; + const struct wined3d_rendertarget_view *target = state->fb->render_targets[0]; UINT height; UINT width; - surface_get_drawable_size(target, context, &width, &height); + surface_get_drawable_size(wined3d_rendertarget_view_get_surface(target), context, &width, &height); gl_info->gl_ops.gl.p_glScissor(r->left, height - r->bottom, r->right - r->left, r->bottom - r->top); } checkGLcall("glScissor"); @@ -4884,13 +4881,13 @@ static void psorigin(struct wined3d_context *context, const struct wined3d_state void state_srgbwrite(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { + const struct wined3d_format *rt_format = state->fb->render_targets[0]->format; const struct wined3d_gl_info *gl_info = context->gl_info; - const struct wined3d_surface *rt = state->fb->render_targets[0]; TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); if (state->render_states[WINED3D_RS_SRGBWRITEENABLE] - && rt->resource.format->flags & WINED3DFMT_FLAG_SRGB_WRITE) + && rt_format->flags & WINED3DFMT_FLAG_SRGB_WRITE) gl_info->gl_ops.gl.p_glEnable(GL_FRAMEBUFFER_SRGB); else gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB); diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 65517ec69b1..b4665242285 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -3977,6 +3977,7 @@ static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RE enum wined3d_texture_filter_type filter) { struct wined3d_device *device = dst_surface->resource.device; + const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]); const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; struct wined3d_swapchain *src_swapchain, *dst_swapchain; @@ -4009,9 +4010,7 @@ static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RE } /* Early sort out of cases where no render target is used */ - if (!dst_swapchain && !src_swapchain - && src_surface != device->fb.render_targets[0] - && dst_surface != device->fb.render_targets[0]) + if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt) { TRACE("No surface is render target, not using hardware blit.\n"); return WINED3DERR_INVALIDCALL; @@ -4040,16 +4039,16 @@ static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RE if (dst_swapchain) { /* Handled with regular texture -> swapchain blit */ - if (src_surface == device->fb.render_targets[0]) + if (src_surface == rt) TRACE("Blit from active render target to a swapchain\n"); } - else if (src_swapchain && dst_surface == device->fb.render_targets[0]) + else if (src_swapchain && dst_surface == rt) { FIXME("Implement blit from a swapchain to the active render target\n"); return WINED3DERR_INVALIDCALL; } - if ((src_swapchain || src_surface == device->fb.render_targets[0]) && !dst_swapchain) + if ((src_swapchain || src_surface == rt) && !dst_swapchain) { /* Blit from render target to texture */ BOOL stretchx; @@ -4899,9 +4898,19 @@ static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d const RECT *dst_rect, const struct wined3d_color *color) { const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height}; - struct wined3d_fb_state fb = {&dst_surface, NULL}; + struct wined3d_rendertarget_view *view; + struct wined3d_fb_state fb = {&view, NULL}; + HRESULT hr; + + if (FAILED(hr = wined3d_rendertarget_view_create_from_surface(dst_surface, + NULL, &wined3d_null_parent_ops, &view))) + { + ERR("Failed to create rendertarget view, hr %#x.\n", hr); + return hr; + } device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0); + wined3d_rendertarget_view_decref(view); return WINED3D_OK; } @@ -5901,7 +5910,7 @@ cpu: } static HRESULT surface_init(struct wined3d_surface *surface, struct wined3d_texture *container, - const struct wined3d_resource_desc *desc, GLenum target, GLint level, DWORD flags) + const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags) { struct wined3d_device *device = container->resource.device; const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; @@ -5983,6 +5992,7 @@ static HRESULT surface_init(struct wined3d_surface *surface, struct wined3d_text surface->resource.map_binding = WINED3D_LOCATION_SYSMEM; surface->texture_target = target; surface->texture_level = level; + surface->texture_layer = layer; /* Call the private setup routine */ if (FAILED(hr = surface->surface_ops->surface_private_setup(surface))) @@ -6010,7 +6020,7 @@ static HRESULT surface_init(struct wined3d_surface *surface, struct wined3d_text } HRESULT wined3d_surface_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc, - GLenum target, GLint level, DWORD flags, struct wined3d_surface **surface) + GLenum target, unsigned int level, unsigned int layer, DWORD flags, struct wined3d_surface **surface) { struct wined3d_device_parent *device_parent = container->resource.device->device_parent; const struct wined3d_parent_ops *parent_ops; @@ -6019,15 +6029,15 @@ HRESULT wined3d_surface_create(struct wined3d_texture *container, const struct w HRESULT hr; TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, " - "multisample_type %#x, multisample_quality %u, target %#x, level %d, flags %#x, surface %p.\n", + "multisample_type %#x, multisample_quality %u, target %#x, level %u, layer %u, flags %#x, surface %p.\n", container, desc->width, desc->height, debug_d3dformat(desc->format), debug_d3dusage(desc->usage), desc->usage, debug_d3dpool(desc->pool), - desc->multisample_type, desc->multisample_quality, target, level, flags, surface); + desc->multisample_type, desc->multisample_quality, target, level, layer, flags, surface); if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) return E_OUTOFMEMORY; - if (FAILED(hr = surface_init(object, container, desc, target, level, flags))) + if (FAILED(hr = surface_init(object, container, desc, target, level, layer, flags))) { WARN("Failed to initialize surface, returning %#x.\n", hr); HeapFree(GetProcessHeap(), 0, object); diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index f595e16739a..1d9b7fb74f0 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -907,7 +907,7 @@ static HRESULT cubetexture_init(struct wined3d_texture *texture, const struct wi struct wined3d_surface *surface; if (FAILED(hr = wined3d_surface_create(texture, &surface_desc, - cube_targets[j], i, surface_flags, &surface))) + cube_targets[j], i, j, surface_flags, &surface))) { WARN("Failed to create surface, hr %#x.\n", hr); wined3d_texture_cleanup(texture); @@ -1061,7 +1061,7 @@ static HRESULT texture_init(struct wined3d_texture *texture, const struct wined3 struct wined3d_surface *surface; if (FAILED(hr = wined3d_surface_create(texture, &surface_desc, - texture->target, i, surface_flags, &surface))) + texture->target, i, 0, surface_flags, &surface))) { WARN("Failed to create surface, hr %#x.\n", hr); wined3d_texture_cleanup(texture); diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 286638affe5..68eb7355d42 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -3213,7 +3213,7 @@ void gen_ffp_frag_op(const struct wined3d_context *context, const struct wined3d unsigned int i; DWORD ttff; DWORD cop, aop, carg0, carg1, carg2, aarg0, aarg1, aarg2; - const struct wined3d_surface *rt = state->fb->render_targets[0]; + const struct wined3d_format *rt_format = state->fb->render_targets[0]->format; const struct wined3d_gl_info *gl_info = context->gl_info; const struct wined3d_d3d_info *d3d_info = context->d3d_info; @@ -3427,7 +3427,7 @@ void gen_ffp_frag_op(const struct wined3d_context *context, const struct wined3d } if (!gl_info->supported[ARB_FRAMEBUFFER_SRGB] && state->render_states[WINED3D_RS_SRGBWRITEENABLE] - && rt->resource.format->flags & WINED3DFMT_FLAG_SRGB_WRITE) + && rt_format->flags & WINED3DFMT_FLAG_SRGB_WRITE) { settings->sRGB_write = 1; } else { diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c index 7d9e742d24a..5ceebdb295b 100644 --- a/dlls/wined3d/view.c +++ b/dlls/wined3d/view.c @@ -41,6 +41,9 @@ ULONG CDECL wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *v if (!refcount) { + /* Call wined3d_object_destroyed() before releasing the resource, + * since releasing the resource may end up destroying the parent. */ + view->parent_ops->wined3d_object_destroyed(view->parent); wined3d_resource_decref(view->resource); HeapFree(GetProcessHeap(), 0, view); } @@ -55,6 +58,29 @@ void * CDECL wined3d_rendertarget_view_get_parent(const struct wined3d_rendertar return view->parent; } +void * CDECL wined3d_rendertarget_view_get_sub_resource_parent(const struct wined3d_rendertarget_view *view) +{ + struct wined3d_resource *sub_resource; + + TRACE("view %p.\n", view); + + if (view->resource->type == WINED3D_RTYPE_BUFFER) + return wined3d_buffer_get_parent(buffer_from_resource(view->resource)); + + if (!(sub_resource = wined3d_texture_get_sub_resource(wined3d_texture_from_resource(view->resource), + view->sub_resource_idx))) + return NULL; + + return wined3d_resource_get_parent(sub_resource); +} + +void CDECL wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent) +{ + TRACE("view %p, parent %p.\n", view, parent); + + view->parent = parent; +} + struct wined3d_resource * CDECL wined3d_rendertarget_view_get_resource(const struct wined3d_rendertarget_view *view) { TRACE("view %p.\n", view); @@ -63,7 +89,8 @@ struct wined3d_resource * CDECL wined3d_rendertarget_view_get_resource(const str } static void wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *view, - const struct wined3d_rendertarget_view_desc *desc, struct wined3d_resource *resource, void *parent) + const struct wined3d_rendertarget_view_desc *desc, struct wined3d_resource *resource, + void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_gl_info *gl_info = &resource->device->adapter->gl_info; @@ -71,6 +98,7 @@ static void wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *vie view->resource = resource; wined3d_resource_incref(resource); view->parent = parent; + view->parent_ops = parent_ops; view->format = wined3d_get_format(gl_info, desc->format_id); if (resource->type == WINED3D_RTYPE_BUFFER) @@ -97,7 +125,8 @@ static void wined3d_rendertarget_view_init(struct wined3d_rendertarget_view *vie } HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_rendertarget_view_desc *desc, - struct wined3d_resource *resource, void *parent, struct wined3d_rendertarget_view **view) + struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, + struct wined3d_rendertarget_view **view) { struct wined3d_rendertarget_view *object; @@ -107,10 +136,25 @@ HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_rendertarget if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) return E_OUTOFMEMORY; - wined3d_rendertarget_view_init(object, desc, resource, parent); + wined3d_rendertarget_view_init(object, desc, resource, parent, parent_ops); TRACE("Created render target view %p.\n", object); *view = object; return WINED3D_OK; } + +HRESULT CDECL wined3d_rendertarget_view_create_from_surface(struct wined3d_surface *surface, + void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_rendertarget_view **view) +{ + struct wined3d_rendertarget_view_desc desc; + + TRACE("surface %p, view %p.\n", surface, view); + + desc.format_id = surface->resource.format->id; + desc.u.texture.level_idx = surface->texture_level; + desc.u.texture.layer_idx = surface->texture_layer; + desc.u.texture.layer_count = 1; + + return wined3d_rendertarget_view_create(&desc, &surface->container->resource, parent, parent_ops, view); +} diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 722ad18f156..bde427f7522 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -75,7 +75,7 @@ @ cdecl wined3d_device_get_ps_sampler(ptr long) @ cdecl wined3d_device_get_raster_status(ptr long ptr) @ cdecl wined3d_device_get_render_state(ptr long) -@ cdecl wined3d_device_get_render_target(ptr long) +@ cdecl wined3d_device_get_rendertarget_view(ptr long) @ cdecl wined3d_device_get_sampler_state(ptr long long) @ cdecl wined3d_device_get_scissor_rect(ptr ptr) @ cdecl wined3d_device_get_software_vertex_processing(ptr) @@ -130,7 +130,7 @@ @ cdecl wined3d_device_set_ps_consts_i(ptr long ptr long) @ cdecl wined3d_device_set_ps_sampler(ptr long ptr) @ cdecl wined3d_device_set_render_state(ptr long long) -@ cdecl wined3d_device_set_render_target(ptr long ptr long) +@ cdecl wined3d_device_set_rendertarget_view(ptr long ptr long) @ cdecl wined3d_device_set_sampler_state(ptr long long long) @ cdecl wined3d_device_set_scissor_rect(ptr ptr) @ cdecl wined3d_device_set_software_vertex_processing(ptr long) @@ -177,11 +177,14 @@ @ cdecl wined3d_resource_set_parent(ptr ptr) @ cdecl wined3d_resource_set_priority(ptr long) -@ cdecl wined3d_rendertarget_view_create(ptr ptr ptr ptr) +@ cdecl wined3d_rendertarget_view_create(ptr ptr ptr ptr ptr) +@ cdecl wined3d_rendertarget_view_create_from_surface(ptr ptr ptr ptr) @ cdecl wined3d_rendertarget_view_decref(ptr) @ cdecl wined3d_rendertarget_view_get_parent(ptr) @ cdecl wined3d_rendertarget_view_get_resource(ptr) +@ cdecl wined3d_rendertarget_view_get_sub_resource_parent(ptr) @ cdecl wined3d_rendertarget_view_incref(ptr) +@ cdecl wined3d_rendertarget_view_set_parent(ptr ptr) @ cdecl wined3d_sampler_create(ptr ptr) @ cdecl wined3d_sampler_decref(ptr) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 81cbb2980a9..5488178657a 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1175,7 +1175,7 @@ struct wined3d_context struct wined3d_fb_state { - struct wined3d_surface **render_targets; + struct wined3d_rendertarget_view **render_targets; struct wined3d_surface *depth_stencil; }; @@ -1945,6 +1945,7 @@ struct wined3d_device struct wined3d_device_creation_parameters create_parms; HWND focus_window; + struct wined3d_rendertarget_view *back_buffer_view; struct wined3d_swapchain **swapchains; UINT swapchain_count; @@ -2262,8 +2263,9 @@ struct wined3d_surface GLuint pbo; GLuint rb_multisample; GLuint rb_resolved; - GLint texture_level; GLenum texture_target; + unsigned int texture_level; + unsigned int texture_layer; RECT lockedRect; int lockCount; @@ -2323,7 +2325,8 @@ HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const P struct wined3d_surface *src_surface, const RECT *src_rect) DECLSPEC_HIDDEN; void surface_validate_location(struct wined3d_surface *surface, DWORD location) DECLSPEC_HIDDEN; HRESULT wined3d_surface_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc, - GLenum target, GLint level, DWORD flags, struct wined3d_surface **surface) DECLSPEC_HIDDEN; + GLenum target, unsigned int level, unsigned int layer, DWORD flags, + struct wined3d_surface **surface) DECLSPEC_HIDDEN; void wined3d_surface_destroy(struct wined3d_surface *surface) DECLSPEC_HIDDEN; void surface_prepare_map_memory(struct wined3d_surface *surface) DECLSPEC_HIDDEN; @@ -2509,8 +2512,8 @@ void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buff void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_material *material) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render_state state, DWORD value) DECLSPEC_HIDDEN; -void wined3d_cs_emit_set_render_target(struct wined3d_cs *cs, UINT render_target_idx, - struct wined3d_surface *render_target) DECLSPEC_HIDDEN; +void wined3d_cs_emit_set_rendertarget_view(struct wined3d_cs *cs, unsigned int view_idx, + struct wined3d_rendertarget_view *view) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type, UINT sampler_idx, struct wined3d_sampler *sampler) DECLSPEC_HIDDEN; void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx, @@ -2617,6 +2620,7 @@ struct wined3d_rendertarget_view struct wined3d_resource *resource; void *parent; + const struct wined3d_parent_ops *parent_ops; const struct wined3d_format *format; unsigned int sub_resource_idx; @@ -2627,6 +2631,25 @@ struct wined3d_rendertarget_view unsigned int depth; }; +static inline struct wined3d_surface *wined3d_rendertarget_view_get_surface( + const struct wined3d_rendertarget_view *view) +{ + struct wined3d_resource *resource; + struct wined3d_texture *texture; + + if (!view) + return NULL; + + if (view->resource->type != WINED3D_RTYPE_TEXTURE && view->resource->type != WINED3D_RTYPE_CUBE_TEXTURE) + return NULL; + + texture = wined3d_texture_from_resource(view->resource); + if (!(resource = wined3d_texture_get_sub_resource(texture, view->sub_resource_idx))) + return NULL; + + return surface_from_resource(resource); +} + struct wined3d_swapchain_ops { void (*swapchain_present)(struct wined3d_swapchain *swapchain, const RECT *src_rect, diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 216e8ab48d6..fe3da57d1e8 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2154,8 +2154,8 @@ struct wined3d_sampler * __cdecl wined3d_device_get_ps_sampler(const struct wine HRESULT __cdecl wined3d_device_get_raster_status(const struct wined3d_device *device, UINT swapchain_idx, struct wined3d_raster_status *raster_status); DWORD __cdecl wined3d_device_get_render_state(const struct wined3d_device *device, enum wined3d_render_state state); -struct wined3d_surface * __cdecl wined3d_device_get_render_target(const struct wined3d_device *device, - UINT render_target_idx); +struct wined3d_rendertarget_view * __cdecl wined3d_device_get_rendertarget_view(const struct wined3d_device *device, + unsigned int view_idx); DWORD __cdecl wined3d_device_get_sampler_state(const struct wined3d_device *device, UINT sampler_idx, enum wined3d_sampler_state state); void __cdecl wined3d_device_get_scissor_rect(const struct wined3d_device *device, RECT *rect); @@ -2238,8 +2238,8 @@ HRESULT __cdecl wined3d_device_set_ps_consts_i(struct wined3d_device *device, void __cdecl wined3d_device_set_ps_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler); void __cdecl wined3d_device_set_render_state(struct wined3d_device *device, enum wined3d_render_state state, DWORD value); -HRESULT __cdecl wined3d_device_set_render_target(struct wined3d_device *device, - UINT render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport); +HRESULT __cdecl wined3d_device_set_rendertarget_view(struct wined3d_device *device, + unsigned int view_idx, struct wined3d_rendertarget_view *view, BOOL set_viewport); void __cdecl wined3d_device_set_sampler_state(struct wined3d_device *device, UINT sampler_idx, enum wined3d_sampler_state state, DWORD value); void __cdecl wined3d_device_set_scissor_rect(struct wined3d_device *device, const RECT *rect); @@ -2377,11 +2377,16 @@ void __cdecl wined3d_resource_set_parent(struct wined3d_resource *resource, void DWORD __cdecl wined3d_resource_set_priority(struct wined3d_resource *resource, DWORD priority); HRESULT __cdecl wined3d_rendertarget_view_create(const struct wined3d_rendertarget_view_desc *desc, - struct wined3d_resource *resource, void *parent, struct wined3d_rendertarget_view **view); + struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops, + struct wined3d_rendertarget_view **view); +HRESULT __cdecl wined3d_rendertarget_view_create_from_surface(struct wined3d_surface *surface, + void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_rendertarget_view **view); ULONG __cdecl wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *view); void * __cdecl wined3d_rendertarget_view_get_parent(const struct wined3d_rendertarget_view *view); struct wined3d_resource * __cdecl wined3d_rendertarget_view_get_resource(const struct wined3d_rendertarget_view *view); +void * __cdecl wined3d_rendertarget_view_get_sub_resource_parent(const struct wined3d_rendertarget_view *view); ULONG __cdecl wined3d_rendertarget_view_incref(struct wined3d_rendertarget_view *view); +void __cdecl wined3d_rendertarget_view_set_parent(struct wined3d_rendertarget_view *view, void *parent); HRESULT __cdecl wined3d_sampler_create(void *parent, struct wined3d_sampler **sampler); ULONG __cdecl wined3d_sampler_decref(struct wined3d_sampler *sampler); -- 2.11.4.GIT