vkd3d: Replace the resource count field of struct d3d12_heap with an internal refcount.

When a heap was released at the same time as the last resource on that
heap, it was possible for both to see each other's
refcount/resource_count as 0 and both would try to destroy the heap.

Avoid that by converting "resource_count" to an internal refcount, which
holds an extra +1 if the main refcount is nonzero. The final release
will then be synchronized between the two since both will operate on
"internal_refcount".
This commit is contained in:
Evan Tang
2025-06-13 12:25:15 -05:00
committed by Henri Verbeet
parent 752a48f4ac
commit f4a4e2afec
Notes: Henri Verbeet 2025-06-25 17:09:25 +02:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1602
2 changed files with 15 additions and 14 deletions

View File

@@ -310,6 +310,9 @@ static ULONG STDMETHODCALLTYPE d3d12_heap_AddRef(ID3D12Heap *iface)
struct d3d12_heap *heap = impl_from_ID3D12Heap(iface); struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
unsigned int refcount = vkd3d_atomic_increment_u32(&heap->refcount); unsigned int refcount = vkd3d_atomic_increment_u32(&heap->refcount);
if (refcount == 1)
vkd3d_atomic_increment_u32(&heap->internal_refcount);
TRACE("%p increasing refcount to %u.\n", heap, refcount); TRACE("%p increasing refcount to %u.\n", heap, refcount);
VKD3D_ASSERT(!heap->is_private); VKD3D_ASSERT(!heap->is_private);
@@ -342,6 +345,12 @@ static void d3d12_heap_destroy(struct d3d12_heap *heap)
d3d12_device_release(device); d3d12_device_release(device);
} }
static void d3d12_heap_decref(struct d3d12_heap *heap)
{
if (!vkd3d_atomic_decrement_u32(&heap->internal_refcount))
d3d12_heap_destroy(heap);
}
static ULONG STDMETHODCALLTYPE d3d12_heap_Release(ID3D12Heap *iface) static ULONG STDMETHODCALLTYPE d3d12_heap_Release(ID3D12Heap *iface)
{ {
struct d3d12_heap *heap = impl_from_ID3D12Heap(iface); struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
@@ -350,18 +359,12 @@ static ULONG STDMETHODCALLTYPE d3d12_heap_Release(ID3D12Heap *iface)
TRACE("%p decreasing refcount to %u.\n", heap, refcount); TRACE("%p decreasing refcount to %u.\n", heap, refcount);
/* A heap must not be destroyed until all contained resources are destroyed. */ /* A heap must not be destroyed until all contained resources are destroyed. */
if (!refcount && !heap->resource_count) if (!refcount)
d3d12_heap_destroy(heap); d3d12_heap_decref(heap);
return refcount; return refcount;
} }
static void d3d12_heap_resource_destroyed(struct d3d12_heap *heap)
{
if (!vkd3d_atomic_decrement_u32(&heap->resource_count) && (!heap->refcount || heap->is_private))
d3d12_heap_destroy(heap);
}
static HRESULT STDMETHODCALLTYPE d3d12_heap_GetPrivateData(ID3D12Heap *iface, static HRESULT STDMETHODCALLTYPE d3d12_heap_GetPrivateData(ID3D12Heap *iface,
REFGUID guid, UINT *data_size, void *data) REFGUID guid, UINT *data_size, void *data)
{ {
@@ -487,7 +490,7 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap,
heap->ID3D12Heap_iface.lpVtbl = &d3d12_heap_vtbl; heap->ID3D12Heap_iface.lpVtbl = &d3d12_heap_vtbl;
heap->refcount = 1; heap->refcount = 1;
heap->resource_count = 0; heap->internal_refcount = 1;
heap->is_private = !!resource; heap->is_private = !!resource;
@@ -555,8 +558,6 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap,
heap->device = device; heap->device = device;
if (!heap->is_private) if (!heap->is_private)
d3d12_device_add_ref(heap->device); d3d12_device_add_ref(heap->device);
else
heap->resource_count = 1;
if (d3d12_heap_get_memory_property_flags(heap) & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) if (d3d12_heap_get_memory_property_flags(heap) & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
{ {
@@ -998,7 +999,7 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12
d3d12_resource_tile_info_cleanup(resource); d3d12_resource_tile_info_cleanup(resource);
if (resource->heap) if (resource->heap)
d3d12_heap_resource_destroyed(resource->heap); d3d12_heap_decref(resource->heap);
} }
static ULONG d3d12_resource_incref(struct d3d12_resource *resource) static ULONG d3d12_resource_incref(struct d3d12_resource *resource)
@@ -2200,7 +2201,7 @@ static HRESULT vkd3d_bind_heap_memory(struct d3d12_device *device,
{ {
resource->heap = heap; resource->heap = heap;
resource->heap_offset = heap_offset; resource->heap_offset = heap_offset;
vkd3d_atomic_increment_u32(&heap->resource_count); vkd3d_atomic_increment_u32(&heap->internal_refcount);
} }
else else
{ {

View File

@@ -436,7 +436,7 @@ struct d3d12_heap
{ {
ID3D12Heap ID3D12Heap_iface; ID3D12Heap ID3D12Heap_iface;
unsigned int refcount; unsigned int refcount;
unsigned int resource_count; unsigned int internal_refcount;
bool is_private; bool is_private;
D3D12_HEAP_DESC desc; D3D12_HEAP_DESC desc;