[PATCH vkd3d 5/5] libs/vkd3d: Implement internal reference counting for resources.

Józef Kucia joseph.kucia at gmail.com
Wed Jan 24 07:33:37 CST 2018


From: Józef Kucia <jkucia at codeweavers.com>

For swapchain back buffers.

Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---

In Wine, we use wined3d objects to implement internal reference counting
for D3D11. We need internal reference counting for swapchain back
buffers in D3D12. D3D12 swapchains hold internal references to back
buffers, but public/COM reference counts are equal to 0. This patch adds
explicit support for internal reference counting for ID3D12Resources.

---
 include/vkd3d.h            |  9 ++++--
 libs/vkd3d/resource.c      | 49 ++++++++++++++++++++++++++++--
 libs/vkd3d/vkd3d.map       |  2 ++
 libs/vkd3d/vkd3d_private.h |  1 +
 tests/vkd3d_api.c          | 76 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 132 insertions(+), 5 deletions(-)

diff --git a/include/vkd3d.h b/include/vkd3d.h
index de75ee3a3894..8f2c9b52b2a3 100644
--- a/include/vkd3d.h
+++ b/include/vkd3d.h
@@ -83,9 +83,7 @@ VkInstance vkd3d_instance_get_vk_instance(struct vkd3d_instance *instance);
 ULONG vkd3d_instance_incref(struct vkd3d_instance *instance);
 
 HRESULT vkd3d_create_device(const struct vkd3d_device_create_info *create_info,
-        REFIID riid, void **device);
-HRESULT vkd3d_create_image_resource(ID3D12Device *device, const D3D12_RESOURCE_DESC *desc,
-        VkImage vk_image, unsigned int resource_flags, ID3D12Resource **resource);
+        REFIID iid, void **device);
 VkDevice vkd3d_get_vk_device(ID3D12Device *device);
 VkPhysicalDevice vkd3d_get_vk_physical_device(ID3D12Device *device);
 struct vkd3d_instance *vkd3d_instance_from_device(ID3D12Device *device);
@@ -94,6 +92,11 @@ uint32_t vkd3d_get_vk_queue_family_index(ID3D12CommandQueue *queue);
 VkQueue vkd3d_acquire_vk_queue(ID3D12CommandQueue *queue);
 void vkd3d_release_vk_queue(ID3D12CommandQueue *queue);
 
+HRESULT vkd3d_create_image_resource(ID3D12Device *device, const D3D12_RESOURCE_DESC *desc,
+        VkImage vk_image, unsigned int resource_flags, ID3D12Resource **resource);
+ULONG vkd3d_resource_decref(ID3D12Resource *resource);
+ULONG vkd3d_resource_incref(ID3D12Resource *resource);
+
 HRESULT vkd3d_serialize_root_signature(const D3D12_ROOT_SIGNATURE_DESC *root_signature_desc,
         D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob);
 
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c
index 264578bd31a8..712ff9c748f6 100644
--- a/libs/vkd3d/resource.c
+++ b/libs/vkd3d/resource.c
@@ -332,6 +332,30 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12
         VK_CALL(vkFreeMemory(device->vk_device, resource->vk_memory, NULL));
 }
 
+static ULONG d3d12_resource_incref(struct d3d12_resource *resource)
+{
+    ULONG refcount = InterlockedIncrement(&resource->internal_refcount);
+
+    TRACE("%p increasing refcount to %u.\n", resource, refcount);
+
+    return refcount;
+}
+
+static ULONG d3d12_resource_decref(struct d3d12_resource *resource)
+{
+    ULONG refcount = InterlockedDecrement(&resource->internal_refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", resource, refcount);
+
+    if (!refcount)
+    {
+        d3d12_resource_destroy(resource, resource->device);
+        vkd3d_free(resource);
+    }
+
+    return refcount;
+}
+
 /* ID3D12Resource */
 static inline struct d3d12_resource *impl_from_ID3D12Resource(ID3D12Resource *iface)
 {
@@ -367,6 +391,14 @@ static ULONG STDMETHODCALLTYPE d3d12_resource_AddRef(ID3D12Resource *iface)
 
     TRACE("%p increasing refcount to %u.\n", resource, refcount);
 
+    if (refcount == 1)
+    {
+        struct d3d12_device *device = resource->device;
+
+        ID3D12Device_AddRef(&device->ID3D12Device_iface);
+        d3d12_resource_incref(resource);
+    }
+
     return refcount;
 }
 
@@ -381,8 +413,7 @@ static ULONG STDMETHODCALLTYPE d3d12_resource_Release(ID3D12Resource *iface)
     {
         struct d3d12_device *device = resource->device;
 
-        d3d12_resource_destroy(resource, device);
-        vkd3d_free(resource);
+        d3d12_resource_decref(resource);
 
         ID3D12Device_Release(&device->ID3D12Device_iface);
     }
@@ -641,6 +672,7 @@ static HRESULT d3d12_committed_resource_init(struct d3d12_resource *resource, st
 
     resource->ID3D12Resource_iface.lpVtbl = &d3d12_resource_vtbl;
     resource->refcount = 1;
+    resource->internal_refcount = 1;
 
     resource->desc = *desc;
 
@@ -773,6 +805,7 @@ HRESULT vkd3d_create_image_resource(ID3D12Device *device, const D3D12_RESOURCE_D
 
     object->ID3D12Resource_iface.lpVtbl = &d3d12_resource_vtbl;
     object->refcount = 1;
+    object->internal_refcount = 1;
     object->desc = *desc;
     object->u.vk_image = vk_image;
     object->vk_memory = VK_NULL_HANDLE;
@@ -793,6 +826,18 @@ HRESULT vkd3d_create_image_resource(ID3D12Device *device, const D3D12_RESOURCE_D
     return S_OK;
 }
 
+ULONG vkd3d_resource_incref(ID3D12Resource *resource)
+{
+    TRACE("resource %p.\n", resource);
+    return d3d12_resource_incref(impl_from_ID3D12Resource(resource));
+}
+
+ULONG vkd3d_resource_decref(ID3D12Resource *resource)
+{
+    TRACE("resource %p.\n", resource);
+    return d3d12_resource_decref(impl_from_ID3D12Resource(resource));
+}
+
 /* CBVs, SRVs, UAVs */
 static struct vkd3d_view *vkd3d_view_create(void)
 {
diff --git a/libs/vkd3d/vkd3d.map b/libs/vkd3d/vkd3d.map
index 9edc3aa5af1c..246275b97a30 100644
--- a/libs/vkd3d/vkd3d.map
+++ b/libs/vkd3d/vkd3d.map
@@ -15,6 +15,8 @@ global:
     vkd3d_instance_get_vk_instance;
     vkd3d_instance_incref;
     vkd3d_release_vk_queue;
+    vkd3d_resource_decref;
+    vkd3d_resource_incref;
     vkd3d_serialize_root_signature;
 
 local: *;
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index a60ee991d1ea..691305158bd7 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -183,6 +183,7 @@ struct d3d12_resource
 {
     ID3D12Resource ID3D12Resource_iface;
     LONG refcount;
+    LONG internal_refcount;
 
     D3D12_RESOURCE_DESC desc;
 
diff --git a/tests/vkd3d_api.c b/tests/vkd3d_api.c
index 4def3b7e53e2..fc8d985981f5 100644
--- a/tests/vkd3d_api.c
+++ b/tests/vkd3d_api.c
@@ -24,6 +24,12 @@
 #include "vkd3d_test.h"
 #include <vkd3d.h>
 
+static ULONG resource_get_internal_refcount(ID3D12Resource *resource)
+{
+    vkd3d_resource_incref(resource);
+    return vkd3d_resource_decref(resource);
+}
+
 static bool signal_event(HANDLE event)
 {
     trace("Signal event %p.\n", event);
@@ -69,6 +75,36 @@ static ID3D12CommandQueue *create_command_queue(ID3D12Device *device,
     return queue;
 }
 
+static ID3D12Resource *create_buffer(ID3D12Device *device, D3D12_HEAP_TYPE heap_type,
+        size_t size, D3D12_RESOURCE_FLAGS resource_flags, D3D12_RESOURCE_STATES initial_resource_state)
+{
+    D3D12_HEAP_PROPERTIES heap_properties;
+    D3D12_RESOURCE_DESC resource_desc;
+    ID3D12Resource *buffer;
+    HRESULT hr;
+
+    memset(&heap_properties, 0, sizeof(heap_properties));
+    heap_properties.Type = heap_type;
+
+    resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+    resource_desc.Alignment = 0;
+    resource_desc.Width = size;
+    resource_desc.Height = 1;
+    resource_desc.DepthOrArraySize = 1;
+    resource_desc.MipLevels = 1;
+    resource_desc.Format = DXGI_FORMAT_UNKNOWN;
+    resource_desc.SampleDesc.Count = 1;
+    resource_desc.SampleDesc.Quality = 0;
+    resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+    resource_desc.Flags = resource_flags;
+
+    hr = ID3D12Device_CreateCommittedResource(device, &heap_properties,
+            D3D12_HEAP_FLAG_NONE, &resource_desc, initial_resource_state,
+            NULL, &IID_ID3D12Resource, (void **)&buffer);
+    ok(hr == S_OK, "Failed to create buffer, hr %#x.\n", hr);
+    return buffer;
+}
+
 static void test_create_instance(void)
 {
     struct vkd3d_instance_create_info create_info;
@@ -567,6 +603,45 @@ static void test_vkd3d_queue(void)
     ok(!refcount, "Device has %u references left.\n", refcount);
 }
 
+static void test_resource_internal_refcount(void)
+{
+    ID3D12Resource *resource;
+    ID3D12Device *device;
+    ULONG refcount;
+
+    device = create_device();
+    ok(device, "Failed to create device.\n");
+
+    resource = create_buffer(device, D3D12_HEAP_TYPE_UPLOAD, 1024,
+            D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_GENERIC_READ);
+    refcount = vkd3d_resource_incref(resource);
+    ok(refcount == 2, "Got refcount %u.\n", refcount);
+    refcount = ID3D12Resource_Release(resource);
+    ok(!refcount, "Got refcount %u.\n", refcount);
+    refcount = resource_get_internal_refcount(resource);
+    ok(refcount == 1, "Got refcount %u.\n", refcount);
+    refcount = vkd3d_resource_decref(resource);
+    ok(!refcount, "Got refcount %u.\n", refcount);
+
+    resource = create_buffer(device, D3D12_HEAP_TYPE_UPLOAD, 1024,
+            D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_GENERIC_READ);
+    refcount = vkd3d_resource_incref(resource);
+    ok(refcount == 2, "Got refcount %u.\n", refcount);
+    refcount = ID3D12Resource_Release(resource);
+    ok(!refcount, "Got refcount %u.\n", refcount);
+    refcount = resource_get_internal_refcount(resource);
+    ok(refcount == 1, "Got refcount %u.\n", refcount);
+    refcount = ID3D12Resource_AddRef(resource);
+    ok(refcount == 1, "Got refcount %u.\n", refcount);
+    refcount = vkd3d_resource_decref(resource);
+    ok(refcount == 1, "Got refcount %u.\n", refcount);
+    refcount = ID3D12Resource_Release(resource);
+    ok(!refcount, "Got refcount %u.\n", refcount);
+
+    refcount = ID3D12Device_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+}
+
 static bool have_d3d12_device(void)
 {
     ID3D12Device *device;
@@ -592,4 +667,5 @@ START_TEST(vkd3d_api)
     run_test(test_physical_device);
     run_test(test_adapter_luid);
     run_test(test_vkd3d_queue);
+    run_test(test_resource_internal_refcount);
 }
-- 
2.13.6




More information about the wine-devel mailing list