From: Zebediah Figura zfigura@codeweavers.com
--- dlls/wined3d/texture.c | 42 ++++++++++++++++++++++++++++++++++ dlls/wined3d/utils.c | 1 + dlls/wined3d/view.c | 27 ++++++++++++++++++---- dlls/wined3d/wined3d.spec | 1 + dlls/wined3d/wined3d_private.h | 3 +++ include/wine/wined3d.h | 4 ++++ 6 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 3dfecc949d1..09eea050d9c 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -1648,6 +1648,12 @@ ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture) { bool in_cs_thread = GetCurrentThreadId() == texture->resource.device->cs->thread_id;
+ if (texture->identity_srv) + { + assert(!in_cs_thread); + wined3d_shader_resource_view_destroy(texture->identity_srv); + } + /* This is called from the CS thread to destroy temporary textures. */ if (!in_cs_thread) wined3d_mutex_lock(); @@ -4667,6 +4673,42 @@ void wined3d_texture_update_sub_resource(struct wined3d_texture *texture, unsign wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB); }
+struct wined3d_shader_resource_view * CDECL wined3d_texture_acquire_identity_srv(struct wined3d_texture *texture) +{ + struct wined3d_view_desc desc; + HRESULT hr; + + TRACE("texture %p.\n", texture); + + if (texture->identity_srv) + return texture->identity_srv; + + desc.format_id = texture->resource.format->id; + /* The texture owns a reference to the SRV, so we can't have the SRV hold + * a reference to the texture. + * At the same time, a view must be destroyed before its texture, and we + * need a bound SRV to keep the texture alive even if it doesn't have any + * other references. + * In order to achieve this we have the objects share reference counts. + * This means the view doesn't hold a reference to the resource, but any + * references to the view are forwarded to the resource instead. The view + * is destroyed manually when all references are released. */ + desc.flags = WINED3D_VIEW_FORWARD_REFERENCE; + desc.u.texture.level_idx = 0; + desc.u.texture.level_count = texture->level_count; + desc.u.texture.layer_idx = 0; + desc.u.texture.layer_count = texture->layer_count; + if (FAILED(hr = wined3d_shader_resource_view_create(&desc, &texture->resource, + NULL, &wined3d_null_parent_ops, &texture->identity_srv))) + { + ERR("Failed to create shader resource view, hr %#lx.\n", hr); + return NULL; + } + wined3d_shader_resource_view_decref(texture->identity_srv); + + return texture->identity_srv; +} + static void wined3d_texture_no3d_upload_data(struct wined3d_context *context, const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 05a0ab36af8..e833bdc8d90 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -4918,6 +4918,7 @@ const char *wined3d_debug_view_desc(const struct wined3d_view_desc *d, const str VIEW_FLAG_TO_STR(WINED3D_VIEW_TEXTURE_ARRAY); VIEW_FLAG_TO_STR(WINED3D_VIEW_READ_ONLY_DEPTH); VIEW_FLAG_TO_STR(WINED3D_VIEW_READ_ONLY_STENCIL); + VIEW_FLAG_TO_STR(WINED3D_VIEW_FORWARD_REFERENCE); #undef VIEW_FLAG_TO_STR if (flags) FIXME("Unrecognised view flag(s) %#x.\n", flags); diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c index 76b6e66b82e..5174075cdd2 100644 --- a/dlls/wined3d/view.c +++ b/dlls/wined3d/view.c @@ -959,8 +959,12 @@ HRESULT CDECL wined3d_rendertarget_view_create_from_sub_resource(struct wined3d_
ULONG CDECL wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view) { - unsigned int refcount = InterlockedIncrement(&view->refcount); + unsigned int refcount; + + if (view->desc.flags & WINED3D_VIEW_FORWARD_REFERENCE) + return wined3d_resource_incref(view->resource);
+ refcount = InterlockedIncrement(&view->refcount); TRACE("%p increasing refcount to %u.\n", view, refcount);
return refcount; @@ -971,10 +975,21 @@ void wined3d_shader_resource_view_cleanup(struct wined3d_shader_resource_view *v view->parent_ops->wined3d_object_destroyed(view->parent); }
+void wined3d_shader_resource_view_destroy(struct wined3d_shader_resource_view *view) +{ + wined3d_mutex_lock(); + view->resource->device->adapter->adapter_ops->adapter_destroy_shader_resource_view(view); + wined3d_mutex_unlock(); +} + ULONG CDECL wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view) { - unsigned int refcount = InterlockedDecrement(&view->refcount); + unsigned int refcount; + + if (view->desc.flags & WINED3D_VIEW_FORWARD_REFERENCE) + return wined3d_resource_decref(view->resource);
+ refcount = InterlockedDecrement(&view->refcount); TRACE("%p decreasing refcount to %u.\n", view, refcount);
if (!refcount) @@ -986,9 +1001,7 @@ ULONG CDECL wined3d_shader_resource_view_decref(struct wined3d_shader_resource_v * device, which the resource implicitly provides. * - We shouldn't free buffer resources until after we've removed the * view from its bo_user list. */ - wined3d_mutex_lock(); - resource->device->adapter->adapter_ops->adapter_destroy_shader_resource_view(view); - wined3d_mutex_unlock(); + wined3d_shader_resource_view_destroy(view); wined3d_resource_decref(resource); }
@@ -1091,6 +1104,10 @@ static HRESULT wined3d_shader_resource_view_init(struct wined3d_shader_resource_ return E_INVALIDARG; view->desc = *desc;
+ /* If WINED3D_VIEW_FORWARD_REFERENCE, the view shouldn't take a reference + * to the resource. However, the reference to the view returned by this + * function should translate to a resource reference, so we increment the + * resource's reference count anyway. */ wined3d_resource_incref(view->resource = resource);
return WINED3D_OK; diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 2eaf83160c1..72e0e3fd8fa 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -298,6 +298,7 @@ @ cdecl wined3d_swapchain_state_resize_target(ptr ptr) @ cdecl wined3d_swapchain_state_set_fullscreen(ptr ptr ptr)
+@ cdecl wined3d_texture_acquire_identity_srv(ptr) @ cdecl wined3d_texture_add_dirty_region(ptr long ptr) @ cdecl wined3d_texture_create(ptr ptr long long long ptr ptr ptr ptr) @ cdecl wined3d_texture_decref(ptr) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index bb955873467..429c6632716 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3335,6 +3335,8 @@ struct wined3d_texture unsigned int row_pitch; unsigned int slice_pitch;
+ struct wined3d_shader_resource_view *identity_srv; + /* May only be accessed from the command stream worker thread. */ struct wined3d_texture_async { @@ -3935,6 +3937,7 @@ struct wined3d_shader_resource_view };
void wined3d_shader_resource_view_cleanup(struct wined3d_shader_resource_view *view) DECLSPEC_HIDDEN; +void wined3d_shader_resource_view_destroy(struct wined3d_shader_resource_view *view);
static inline struct wined3d_texture *wined3d_state_get_ffp_texture(const struct wined3d_state *state, unsigned int idx) { diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index c2f7950ad3f..d7a3dd1e0fe 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -1583,6 +1583,9 @@ enum wined3d_memory_segment_group #define WINED3D_VIEW_TEXTURE_ARRAY 0x00000010 #define WINED3D_VIEW_READ_ONLY_DEPTH 0x00000020 #define WINED3D_VIEW_READ_ONLY_STENCIL 0x00000040 +/* The view shares a reference count with its resource. + * See wined3d_texture_acquire_identity_srv(). */ +#define WINED3D_VIEW_FORWARD_REFERENCE 0x00000080
#define WINED3D_MAX_VIEWPORTS 16
@@ -2866,6 +2869,7 @@ HRESULT __cdecl wined3d_swapchain_state_resize_target(struct wined3d_swapchain_s HRESULT __cdecl wined3d_swapchain_state_set_fullscreen(struct wined3d_swapchain_state *state, const struct wined3d_swapchain_desc *desc, const struct wined3d_display_mode *mode);
+struct wined3d_shader_resource_view * __cdecl wined3d_texture_acquire_identity_srv(struct wined3d_texture *texture); HRESULT __cdecl wined3d_texture_add_dirty_region(struct wined3d_texture *texture, UINT layer, const struct wined3d_box *dirty_region); HRESULT __cdecl wined3d_texture_create(struct wined3d_device *device, const struct wined3d_resource_desc *desc,