From a256a9266ee1e5e9c185d1cfe99c9f0dd8cd429a Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 14 May 2021 14:00:00 +0200 Subject: [PATCH] vkd3d: Rewrite descriptor QA. Adds support for GPU-assisted validation of descriptor usage in the CBV_SRV_UAV heap. Signed-off-by: Hans-Kristian Arntzen --- libs/vkd3d/command.c | 4 +- libs/vkd3d/descriptor_debug.c | 383 +++++++++++++++++++++++++--- libs/vkd3d/device.c | 16 +- libs/vkd3d/memory.c | 12 +- libs/vkd3d/raytracing_pipeline.c | 4 + libs/vkd3d/resource.c | 137 ++++++---- libs/vkd3d/state.c | 32 +++ libs/vkd3d/vkd3d_descriptor_debug.h | 75 +++++- libs/vkd3d/vkd3d_private.h | 18 +- 9 files changed, 562 insertions(+), 119 deletions(-) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index eefd5bca..46ea9d4e 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -21,6 +21,7 @@ #include "vkd3d_private.h" #include "vkd3d_swapchain_factory.h" +#include "vkd3d_descriptor_debug.h" #ifdef VKD3D_ENABLE_RENDERDOC #include "vkd3d_renderdoc.h" #endif @@ -312,9 +313,10 @@ static void vkd3d_wait_for_gpu_timeline_semaphore(struct vkd3d_fence_worker *wor return; } - /* This is a good time to kick the debug ring thread into action. */ + /* This is a good time to kick the debug threads into action. */ if (device->debug_ring.active) pthread_cond_signal(&device->debug_ring.ring_cond); + vkd3d_descriptor_debug_kick_qa_check(device->descriptor_qa_global_info); TRACE("Signaling fence %p value %#"PRIx64".\n", fence->fence, fence->value); if (FAILED(hr = d3d12_fence_signal(fence->fence, fence->value))) diff --git a/libs/vkd3d/descriptor_debug.c b/libs/vkd3d/descriptor_debug.c index c40f171f..1b226668 100644 --- a/libs/vkd3d/descriptor_debug.c +++ b/libs/vkd3d/descriptor_debug.c @@ -26,19 +26,73 @@ static pthread_once_t debug_once = PTHREAD_ONCE_INIT; static pthread_mutex_t debug_lock = PTHREAD_MUTEX_INITIALIZER; -static bool descriptor_debug_active; +static bool descriptor_debug_active_qa_checks; +static bool descriptor_debug_active_log; static FILE *descriptor_debug_file; +struct vkd3d_descriptor_qa_global_info +{ + struct vkd3d_descriptor_qa_global_buffer_data *data; + VkDescriptorBufferInfo descriptor; + VkBuffer vk_buffer; + VkDeviceMemory vk_memory; + unsigned int num_cookies; + + pthread_t ring_thread; + pthread_mutex_t ring_lock; + pthread_cond_t ring_cond; + bool active; +}; + +static const char *debug_descriptor_type(vkd3d_descriptor_qa_flags type_flags) +{ + bool has_raw_va = !!(type_flags & VKD3D_DESCRIPTOR_QA_TYPE_RAW_VA_BIT); + + switch (type_flags & ~VKD3D_DESCRIPTOR_QA_TYPE_RAW_VA_BIT) + { + case VKD3D_DESCRIPTOR_QA_TYPE_SAMPLER_BIT: return "SAMPLER"; + case VKD3D_DESCRIPTOR_QA_TYPE_SAMPLED_IMAGE_BIT: return "SAMPLED_IMAGE"; + case VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_IMAGE_BIT: return "STORAGE_IMAGE"; + case VKD3D_DESCRIPTOR_QA_TYPE_UNIFORM_BUFFER_BIT: return "UNIFORM_BUFFER"; + case VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_BUFFER_BIT: return "STORAGE_BUFFER"; + case VKD3D_DESCRIPTOR_QA_TYPE_UNIFORM_TEXEL_BUFFER_BIT: return "UNIFORM_TEXEL_BUFFER"; + case VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_TEXEL_BUFFER_BIT: return "STORAGE_TEXEL_BUFFER"; + + case VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_TEXEL_BUFFER_BIT | VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_BUFFER_BIT: + return has_raw_va ? "STORAGE_TEXEL_BUFFER / STORAGE_BUFFER (w/ counter)" : "STORAGE_TEXEL_BUFFER / STORAGE_BUFFER"; + + case VKD3D_DESCRIPTOR_QA_TYPE_UNIFORM_TEXEL_BUFFER_BIT | VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_BUFFER_BIT: + return has_raw_va ? "UNIFORM_TEXEL_BUFFER / STORAGE_BUFFER (w/ counter)" : "UNIFORM_TEXEL_BUFFER / STORAGE_BUFFER"; + + case VKD3D_DESCRIPTOR_QA_TYPE_RT_ACCELERATION_STRUCTURE_BIT: + return "RTAS"; + + case 0: + return "NONE"; + + default: return "?"; + } +} + static void vkd3d_descriptor_debug_init_once(void) { - const char *env = getenv("VKD3D_DESCRIPTOR_QA_LOG"); + const char *env; + + env = getenv("VKD3D_DESCRIPTOR_QA_LOG"); if (env) { + INFO("Enabling VKD3D_DESCRIPTOR_QA_LOG\n"); descriptor_debug_file = fopen(env, "w"); if (!descriptor_debug_file) ERR("Failed to open file: %s.\n", env); else - descriptor_debug_active = true; + descriptor_debug_active_log = true; + } + + if (vkd3d_config_flags & VKD3D_CONFIG_FLAG_DESCRIPTOR_QA_CHECKS) + { + INFO("Enabling descriptor QA checks!\n"); + descriptor_debug_active_qa_checks = true; } } @@ -47,9 +101,196 @@ void vkd3d_descriptor_debug_init(void) pthread_once(&debug_once, vkd3d_descriptor_debug_init_once); } -bool vkd3d_descriptor_debug_active(void) +bool vkd3d_descriptor_debug_active_log(void) { - return descriptor_debug_active; + return descriptor_debug_active_log; +} + +bool vkd3d_descriptor_debug_active_qa_checks(void) +{ + return descriptor_debug_active_qa_checks; +} + +VkDeviceSize vkd3d_descriptor_debug_heap_info_size(unsigned int num_descriptors) +{ + return offsetof(struct vkd3d_descriptor_qa_heap_buffer_data, desc) + num_descriptors * + sizeof(struct vkd3d_descriptor_qa_cookie_descriptor); +} + +static void vkd3d_descriptor_debug_set_live_status_bit( + struct vkd3d_descriptor_qa_global_info *global_info, uint64_t cookie) +{ + if (!global_info || !global_info->active || !global_info->data) + return; + + if (cookie < global_info->num_cookies) + { + vkd3d_atomic_uint32_or(&global_info->data->live_status_table[cookie / 32], + 1u << (cookie & 31), vkd3d_memory_order_relaxed); + } + else + INFO("Cookie index %"PRIu64" is out of range, cannot be tracked.\n", cookie); +} + +static void vkd3d_descriptor_debug_unset_live_status_bit( + struct vkd3d_descriptor_qa_global_info *global_info, uint64_t cookie) +{ + if (!global_info || !global_info->active || !global_info->data) + return; + + if (cookie < global_info->num_cookies) + { + vkd3d_atomic_uint32_and(&global_info->data->live_status_table[cookie / 32], + ~(1u << (cookie & 31)), vkd3d_memory_order_relaxed); + } +} + +static void vkd3d_descriptor_debug_qa_check_report_fault( + struct vkd3d_descriptor_qa_global_info *global_info); + +static void *vkd3d_descriptor_debug_qa_check_entry(void *userdata) +{ + struct vkd3d_descriptor_qa_global_info *global_info = userdata; + bool active = true; + + while (active) + { + /* Don't spin endlessly, this thread is kicked after a successful fence wait. */ + pthread_mutex_lock(&global_info->ring_lock); + pthread_cond_wait(&global_info->ring_cond, &global_info->ring_lock); + active = global_info->active; + pthread_mutex_unlock(&global_info->ring_lock); + + if (global_info->data->fault_type != 0) + { + vkd3d_descriptor_debug_qa_check_report_fault(global_info); + ERR("Num failed checks: %u\n", global_info->data->fault_atomic); + + /* Reset the latch so we can get more reports. */ + vkd3d_atomic_uint32_store_explicit(&global_info->data->fault_type, 0, vkd3d_memory_order_relaxed); + vkd3d_atomic_uint32_store_explicit(&global_info->data->fault_atomic, 0, vkd3d_memory_order_release); + } + } + + return NULL; +} + +void vkd3d_descriptor_debug_kick_qa_check(struct vkd3d_descriptor_qa_global_info *global_info) +{ + if (global_info && global_info->active) + pthread_cond_signal(&global_info->ring_cond); +} + +const VkDescriptorBufferInfo *vkd3d_descriptor_debug_get_global_info_descriptor( + struct vkd3d_descriptor_qa_global_info *global_info) +{ + if (global_info) + return &global_info->descriptor; + else + return NULL; +} + +HRESULT vkd3d_descriptor_debug_alloc_global_info( + struct vkd3d_descriptor_qa_global_info **out_global_info, unsigned int num_cookies, + struct d3d12_device *device) +{ + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + struct vkd3d_descriptor_qa_global_info *global_info; + D3D12_RESOURCE_DESC buffer_desc; + D3D12_HEAP_PROPERTIES heap_info; + D3D12_HEAP_FLAGS heap_flags; + VkResult vr; + HRESULT hr; + + global_info = vkd3d_calloc(1, sizeof(*global_info)); + if (!global_info) + return E_OUTOFMEMORY; + + memset(&buffer_desc, 0, sizeof(buffer_desc)); + buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + buffer_desc.Width = sizeof(uint32_t) * ((num_cookies + 31) / 32) + + offsetof(struct vkd3d_descriptor_qa_global_buffer_data, live_status_table); + buffer_desc.Height = 1; + buffer_desc.DepthOrArraySize = 1; + buffer_desc.MipLevels = 1; + buffer_desc.SampleDesc.Count = 1; + buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + buffer_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + /* host-visible device memory */ + memset(&heap_info, 0, sizeof(heap_info)); + heap_info.Type = D3D12_HEAP_TYPE_UPLOAD; + + heap_flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS; + + if (FAILED(hr = vkd3d_create_buffer(device, &heap_info, heap_flags, &buffer_desc, &global_info->vk_buffer))) + { + vkd3d_descriptor_debug_free_global_info(global_info, device); + return hr; + } + + if (FAILED(hr = vkd3d_allocate_buffer_memory(device, global_info->vk_buffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &global_info->vk_memory))) + { + vkd3d_descriptor_debug_free_global_info(global_info, device); + return hr; + } + + if ((vr = VK_CALL(vkMapMemory(device->vk_device, global_info->vk_memory, + 0, VK_WHOLE_SIZE, 0, (void**)&global_info->data)))) + { + ERR("Failed to map buffer, vr %d.\n", vr); + vkd3d_descriptor_debug_free_global_info(global_info, device); + return hresult_from_vk_result(vr); + } + + memset(global_info->data, 0, buffer_desc.Width); + + /* The NULL descriptor has cookie 0, and is always considered live. */ + global_info->data->live_status_table[0] = 1u << 0; + + global_info->descriptor.buffer = global_info->vk_buffer; + global_info->descriptor.offset = 0; + global_info->descriptor.range = buffer_desc.Width; + global_info->num_cookies = num_cookies; + + pthread_mutex_init(&global_info->ring_lock, NULL); + pthread_cond_init(&global_info->ring_cond, NULL); + global_info->active = true; + if (pthread_create(&global_info->ring_thread, NULL, vkd3d_descriptor_debug_qa_check_entry, global_info) != 0) + { + vkd3d_descriptor_debug_free_global_info(global_info, device); + return E_OUTOFMEMORY; + } + + *out_global_info = global_info; + return S_OK; +} + +void vkd3d_descriptor_debug_free_global_info( + struct vkd3d_descriptor_qa_global_info *global_info, + struct d3d12_device *device) +{ + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + + if (!global_info) + return; + + if (global_info->active) + { + pthread_mutex_lock(&global_info->ring_lock); + global_info->active = false; + pthread_cond_signal(&global_info->ring_cond); + pthread_mutex_unlock(&global_info->ring_lock); + pthread_join(global_info->ring_thread, NULL); + pthread_mutex_destroy(&global_info->ring_lock); + pthread_cond_destroy(&global_info->ring_cond); + } + + VK_CALL(vkFreeMemory(device->vk_device, global_info->vk_memory, NULL)); + VK_CALL(vkDestroyBuffer(device->vk_device, global_info->vk_buffer, NULL)); + vkd3d_free(global_info); } #define DECL_BUFFER() \ @@ -67,13 +308,52 @@ bool vkd3d_descriptor_debug_active(void) #define APPEND_SNPRINTF(...) do { ptr += strlen(ptr); snprintf(ptr, (buffer + ARRAY_SIZE(buffer)) - ptr, __VA_ARGS__); } while(0) -void vkd3d_descriptor_debug_register_heap(void *heap, const D3D12_DESCRIPTOR_HEAP_DESC *desc) +static void vkd3d_descriptor_debug_qa_check_report_fault( + struct vkd3d_descriptor_qa_global_info *global_info) { DECL_BUFFER(); - if (!vkd3d_descriptor_debug_active()) + + if (global_info->data->fault_type & VKD3D_DESCRIPTOR_FAULT_TYPE_HEAP_OF_OF_RANGE) + APPEND_SNPRINTF("Fault type: HEAP_OUT_OF_RANGE\n"); + if (global_info->data->fault_type & VKD3D_DESCRIPTOR_FAULT_TYPE_MISMATCH_DESCRIPTOR_TYPE) + APPEND_SNPRINTF("Fault type: MISMATCH_DESCRIPTOR_TYPE\n"); + if (global_info->data->fault_type & VKD3D_DESCRIPTOR_FAULT_TYPE_DESTROYED_RESOURCE) + APPEND_SNPRINTF("Fault type: DESTROYED_RESOURCE\n"); + + APPEND_SNPRINTF("CBV_SRV_UAV heap cookie: %u\n", global_info->data->failed_heap); + APPEND_SNPRINTF("Shader hash and instruction: %"PRIx64" (%u)\n", + global_info->data->failed_hash, global_info->data->failed_instruction); + APPEND_SNPRINTF("Accessed resource/view cookie: %u\n", global_info->data->failed_cookie); + APPEND_SNPRINTF("Shader desired descriptor type: %u (%s)\n", + global_info->data->failed_descriptor_type_mask, + debug_descriptor_type(global_info->data->failed_descriptor_type_mask)); + APPEND_SNPRINTF("Found descriptor type in heap: %u (%s)\n", + global_info->data->actual_descriptor_type_mask, + debug_descriptor_type(global_info->data->actual_descriptor_type_mask)); + APPEND_SNPRINTF("Failed heap index: %u\n", global_info->data->failed_offset); + ERR("\n============\n%s==========\n", buffer); + if (!vkd3d_descriptor_debug_active_log()) + return; + FLUSH_BUFFER(); +} + +void vkd3d_descriptor_debug_register_heap( + struct vkd3d_descriptor_qa_heap_buffer_data *heap, uint64_t cookie, + const D3D12_DESCRIPTOR_HEAP_DESC *desc) +{ + DECL_BUFFER(); + + if (heap) + { + heap->num_descriptors = desc->NumDescriptors; + heap->heap_index = cookie <= UINT32_MAX ? (uint32_t)cookie : 0u; + memset(heap->desc, 0, desc->NumDescriptors * sizeof(*heap->desc)); + } + + if (!vkd3d_descriptor_debug_active_log()) return; - APPEND_SNPRINTF("REGISTER HEAP %p || COUNT = %u", heap, desc->NumDescriptors); + APPEND_SNPRINTF("REGISTER HEAP %"PRIu64" || COUNT = %u", cookie, desc->NumDescriptors); if (desc->Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) APPEND_SNPRINTF(" || SHADER"); @@ -103,21 +383,25 @@ void vkd3d_descriptor_debug_register_heap(void *heap, const D3D12_DESCRIPTOR_HEA FLUSH_BUFFER(); } -void vkd3d_descriptor_debug_unregister_heap(void *heap) +void vkd3d_descriptor_debug_unregister_heap(uint64_t cookie) { DECL_BUFFER(); - if (!vkd3d_descriptor_debug_active()) + if (!vkd3d_descriptor_debug_active_log()) return; - APPEND_SNPRINTF("DESTROY HEAP %p", heap); + APPEND_SNPRINTF("DESTROY HEAP %"PRIu64, cookie); FLUSH_BUFFER(); } -void vkd3d_descriptor_debug_register_resource_cookie(uint64_t cookie, const D3D12_RESOURCE_DESC *desc) +void vkd3d_descriptor_debug_register_resource_cookie(struct vkd3d_descriptor_qa_global_info *global_info, + uint64_t cookie, const D3D12_RESOURCE_DESC *desc) { const char *fmt; DECL_BUFFER(); - if (!vkd3d_descriptor_debug_active()) + + vkd3d_descriptor_debug_set_live_status_bit(global_info, cookie); + + if (!vkd3d_descriptor_debug_active_log()) return; APPEND_SNPRINTF("RESOURCE CREATE #%"PRIu64" || ", cookie); @@ -164,67 +448,82 @@ void vkd3d_descriptor_debug_register_resource_cookie(uint64_t cookie, const D3D1 FLUSH_BUFFER(); } -void vkd3d_descriptor_debug_register_allocation_cookie(uint64_t cookie, const struct vkd3d_allocate_memory_info *info) +void vkd3d_descriptor_debug_register_allocation_cookie( + struct vkd3d_descriptor_qa_global_info *global_info, + uint64_t cookie, const struct vkd3d_allocate_memory_info *info) { D3D12_RESOURCE_DESC desc; memset(&desc, 0, sizeof(desc)); desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Width = info->memory_requirements.size; - vkd3d_descriptor_debug_register_resource_cookie(cookie, &desc); + vkd3d_descriptor_debug_register_resource_cookie(global_info, cookie, &desc); } -void vkd3d_descriptor_debug_register_view_cookie(uint64_t cookie, uint64_t resource_cookie) +void vkd3d_descriptor_debug_register_view_cookie( + struct vkd3d_descriptor_qa_global_info *global_info, + uint64_t cookie, uint64_t resource_cookie) { DECL_BUFFER(); - if (!vkd3d_descriptor_debug_active()) + + vkd3d_descriptor_debug_set_live_status_bit(global_info, cookie); + + if (!vkd3d_descriptor_debug_active_log()) return; APPEND_SNPRINTF("VIEW CREATE #%"PRIu64" <- RESOURCE #%"PRIu64, cookie, resource_cookie); FLUSH_BUFFER(); } -void vkd3d_descriptor_debug_unregister_cookie(uint64_t cookie) +void vkd3d_descriptor_debug_unregister_cookie( + struct vkd3d_descriptor_qa_global_info *global_info, + uint64_t cookie) { DECL_BUFFER(); - if (!vkd3d_descriptor_debug_active()) + + /* Don't unset the null descriptor by mistake. */ + if (cookie != 0) + vkd3d_descriptor_debug_unset_live_status_bit(global_info, cookie); + + if (!vkd3d_descriptor_debug_active_log()) return; APPEND_SNPRINTF("COOKIE DESTROY #%"PRIu64, cookie); FLUSH_BUFFER(); } -static const char *debug_descriptor_type(VkDescriptorType type) +void vkd3d_descriptor_debug_write_descriptor(struct vkd3d_descriptor_qa_heap_buffer_data *heap, uint64_t heap_cookie, + uint32_t offset, vkd3d_descriptor_qa_flags type_flags, uint64_t cookie) { - switch (type) + DECL_BUFFER(); + + if (heap && offset < heap->num_descriptors) { - case VK_DESCRIPTOR_TYPE_SAMPLER: return "SAMPLER"; - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: return "SAMPLED_IMAGE"; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: return "STORAGE_IMAGE"; - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: return "UNIFORM_BUFFER"; - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: return "STORAGE_BUFFER"; - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: return "UNIFORM_TEXEL_BUFFER"; - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: return "STORAGE_TEXEL_BUFFER"; - default: return "?"; + /* Should never overflow here except if game is literally spamming allocations every frame and we + * wait around for hours/days. + * This case will trigger warnings either way. */ + heap->desc[offset].cookie = cookie <= UINT32_MAX ? (uint32_t)cookie : 0u; + heap->desc[offset].descriptor_type = type_flags; } -} -void vkd3d_descriptor_debug_write_descriptor(void *heap, uint32_t offset, VkDescriptorType type, uint64_t cookie) -{ - DECL_BUFFER(); - if (!vkd3d_descriptor_debug_active()) + if (!vkd3d_descriptor_debug_active_log()) return; - APPEND_SNPRINTF("WRITE %p || OFFSET = %u || TYPE = %s || COOKIE = #%"PRIu64, - heap, offset, debug_descriptor_type(type), cookie); + APPEND_SNPRINTF("WRITE HEAP %"PRIu64" || OFFSET = %u || TYPE = %s || COOKIE = #%"PRIu64, + heap_cookie, offset, debug_descriptor_type(type_flags), cookie); FLUSH_BUFFER(); } -void vkd3d_descriptor_debug_copy_descriptor(void *dst_heap, uint32_t dst_offset, - void *src_heap, uint32_t src_offset, - uint64_t cookie) +void vkd3d_descriptor_debug_copy_descriptor( + struct vkd3d_descriptor_qa_heap_buffer_data *dst_heap, uint64_t dst_heap_cookie, uint32_t dst_offset, + struct vkd3d_descriptor_qa_heap_buffer_data *src_heap, uint64_t src_heap_cookie, uint32_t src_offset, + uint64_t cookie) { DECL_BUFFER(); - if (!vkd3d_descriptor_debug_active()) + + if (dst_heap && src_heap && dst_offset < dst_heap->num_descriptors && src_offset < src_heap->num_descriptors) + dst_heap->desc[dst_offset] = src_heap->desc[src_offset]; + + if (!vkd3d_descriptor_debug_active_log()) return; - APPEND_SNPRINTF("COPY %p || DST OFFSET = %u || COOKIE = #%"PRIu64" || SRC %p || SRC OFFSET = %u", - dst_heap, dst_offset, cookie, src_heap, src_offset); + APPEND_SNPRINTF("COPY DST HEAP %"PRIu64" || DST OFFSET = %u || COOKIE = #%"PRIu64" || SRC HEAP %"PRIu64" || SRC OFFSET = %u", + dst_heap_cookie, dst_offset, cookie, src_heap_cookie, src_offset); FLUSH_BUFFER(); } diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 524532cb..b6e3e129 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -20,15 +20,12 @@ #include "vkd3d_private.h" #include "vkd3d_sonames.h" +#include "vkd3d_descriptor_debug.h" #ifdef VKD3D_ENABLE_RENDERDOC #include "vkd3d_renderdoc.h" #endif -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA -#include "vkd3d_descriptor_debug.h" -#endif - static uint32_t vkd3d_get_vk_version(void) { int major, minor, patch; @@ -2416,6 +2413,8 @@ static void d3d12_device_destroy(struct d3d12_device *device) vkd3d_render_pass_cache_cleanup(&device->render_pass_cache, device); d3d12_device_destroy_vkd3d_queues(device); vkd3d_memory_allocator_cleanup(&device->memory_allocator, device); + /* Tear down descriptor global info late, so we catch last minute faults after we drain the queues. */ + vkd3d_descriptor_debug_free_global_info(device->descriptor_qa_global_info, device); VK_CALL(vkDestroyDevice(device->vk_device, NULL)); pthread_mutex_destroy(&device->mutex); if (device->parent) @@ -5050,6 +5049,13 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, if (FAILED(hr = vkd3d_shader_debug_ring_init(&device->debug_ring, device))) goto out_cleanup_meta_ops; + if (vkd3d_descriptor_debug_active_qa_checks()) + { + if (FAILED(hr = vkd3d_descriptor_debug_alloc_global_info(&device->descriptor_qa_global_info, + VKD3D_DESCRIPTOR_DEBUG_DEFAULT_NUM_COOKIES, device))) + goto out_cleanup_debug_ring; + } + vkd3d_render_pass_cache_init(&device->render_pass_cache); if ((device->parent = create_info->parent)) @@ -5058,6 +5064,8 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, d3d12_device_caps_init(device); return S_OK; +out_cleanup_debug_ring: + vkd3d_shader_debug_ring_cleanup(&device->debug_ring, device); out_cleanup_meta_ops: vkd3d_meta_ops_cleanup(&device->meta_ops, device); out_cleanup_sampler_state: diff --git a/libs/vkd3d/memory.c b/libs/vkd3d/memory.c index 72dc49d7..c3e9116e 100644 --- a/libs/vkd3d/memory.c +++ b/libs/vkd3d/memory.c @@ -19,10 +19,7 @@ #define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API #include "vkd3d_private.h" - -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA #include "vkd3d_descriptor_debug.h" -#endif static void vkd3d_memory_allocator_wait_allocation(struct vkd3d_memory_allocator *allocator, struct d3d12_device *device, const struct vkd3d_memory_allocation *allocation); @@ -334,9 +331,7 @@ static void vkd3d_memory_allocation_free(const struct vkd3d_memory_allocation *a TRACE("allocation %p, device %p, allocator %p.\n", allocation, device, allocator); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_unregister_cookie(allocation->resource.cookie); -#endif + vkd3d_descriptor_debug_unregister_cookie(device->descriptor_qa_global_info, allocation->resource.cookie); if (allocation->flags & VKD3D_ALLOCATION_FLAG_ALLOW_WRITE_WATCH) vkd3d_free_write_watch_pointer(allocation->cpu_address); @@ -493,9 +488,8 @@ static HRESULT vkd3d_memory_allocation_init(struct vkd3d_memory_allocation *allo } allocation->resource.cookie = vkd3d_allocate_cookie(); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_register_allocation_cookie(allocation->resource.cookie, info); -#endif + vkd3d_descriptor_debug_register_allocation_cookie(device->descriptor_qa_global_info, + allocation->resource.cookie, info); TRACE("Created allocation %p on memory type %u (%"PRIu64" bytes).\n", allocation, allocation->vk_memory_type, allocation->resource.size); diff --git a/libs/vkd3d/raytracing_pipeline.c b/libs/vkd3d/raytracing_pipeline.c index 40d857d0..83b4cbe7 100644 --- a/libs/vkd3d/raytracing_pipeline.c +++ b/libs/vkd3d/raytracing_pipeline.c @@ -890,6 +890,10 @@ static HRESULT d3d12_state_object_compile_pipeline(struct d3d12_state_object *ob shader_interface_info.push_constant_buffer_count = global_signature->root_constant_count; shader_interface_info.push_constant_ubo_binding = &global_signature->push_constant_ubo_binding; shader_interface_info.offset_buffer_binding = &global_signature->offset_buffer_binding; +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + shader_interface_info.descriptor_qa_global_binding = &global_signature->descriptor_qa_global_info; + shader_interface_info.descriptor_qa_heap_binding = &global_signature->descriptor_qa_heap_binding; +#endif } shader_interface_local_info.descriptor_size = sizeof(struct d3d12_desc); diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 4f59fdf8..75161832 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -23,11 +23,8 @@ #include "vkd3d_private.h" #include "vkd3d_rw_spinlock.h" -#include "hashmap.h" - -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA #include "vkd3d_descriptor_debug.h" -#endif +#include "hashmap.h" #define VKD3D_NULL_SRV_FORMAT DXGI_FORMAT_R8G8B8A8_UNORM #define VKD3D_NULL_UAV_FORMAT DXGI_FORMAT_R32_UINT @@ -822,9 +819,8 @@ struct vkd3d_view *vkd3d_view_map_create_view(struct vkd3d_view_map *view_map, if (!success) return NULL; -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_register_view_cookie(view->cookie, view_map->resource_cookie); -#endif + vkd3d_descriptor_debug_register_view_cookie(device->descriptor_qa_global_info, + view->cookie, view_map->resource_cookie); entry.key = *key; entry.view = view; @@ -2264,9 +2260,7 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12 vkd3d_view_map_destroy(&resource->view_map, resource->device); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_unregister_cookie(resource->res.cookie); -#endif + vkd3d_descriptor_debug_unregister_cookie(device->descriptor_qa_global_info, resource->res.cookie); if (resource->flags & VKD3D_RESOURCE_EXTERNAL) return; @@ -2370,6 +2364,9 @@ static HRESULT d3d12_resource_create(struct d3d12_device *device, uint32_t flags object->flags = flags; object->format = vkd3d_format_from_d3d12_resource_desc(device, desc, 0); object->res.cookie = vkd3d_allocate_cookie(); +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + object->view_map.resource_cookie = object->res.cookie; +#endif /* RTAS are "special" buffers. They can never transition out of this state. */ if (initial_state == D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE) @@ -2381,9 +2378,8 @@ static HRESULT d3d12_resource_create(struct d3d12_device *device, uint32_t flags d3d12_device_add_ref(device); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_register_resource_cookie(object->res.cookie, desc); -#endif + vkd3d_descriptor_debug_register_resource_cookie(device->descriptor_qa_global_info, + object->res.cookie, desc); *resource = object; return S_OK; @@ -2723,9 +2719,7 @@ static void vkd3d_view_destroy(struct vkd3d_view *view, struct d3d12_device *dev TRACE("Destroying view %p.\n", view); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_unregister_cookie(view->cookie); -#endif + vkd3d_descriptor_debug_unregister_cookie(device->descriptor_qa_global_info, view->cookie); switch (view->type) { @@ -2932,8 +2926,8 @@ void d3d12_desc_copy(struct d3d12_desc *dst, struct d3d12_desc *src, for (i = 0; i < count; i++) { vkd3d_descriptor_debug_copy_descriptor( - dst[i].heap, dst[i].heap_offset, - src[i].heap, src[i].heap_offset, + dst[i].heap->descriptor_heap_info.host_ptr, dst[i].heap->cookie, dst[i].heap_offset, + src[i].heap->descriptor_heap_info.host_ptr, src[i].heap->cookie, src[i].heap_offset, src[i].metadata.cookie); } #endif @@ -3449,9 +3443,10 @@ void d3d12_desc_create_cbv(struct d3d12_desc *descriptor, vkd3d_bindless_state_binding_from_info_index(&device->bindless_state, info_index), vk_descriptor_type, &descriptor_info); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_write_descriptor(descriptor->heap, descriptor->heap_offset, vk_write.descriptorType, descriptor->metadata.cookie); -#endif + vkd3d_descriptor_debug_write_descriptor(descriptor->heap->descriptor_heap_info.host_ptr, + descriptor->heap->cookie, + descriptor->heap_offset, + VKD3D_DESCRIPTOR_QA_TYPE_UNIFORM_BUFFER_BIT, descriptor->metadata.cookie); VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, &vk_write, 0, NULL)); } @@ -3586,6 +3581,7 @@ static void vkd3d_create_buffer_srv(struct d3d12_desc *descriptor, { struct vkd3d_null_resources *null_resources = &device->null_resources; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + VKD3D_UNUSED vkd3d_descriptor_qa_flags descriptor_qa_flags = 0; struct vkd3d_bound_buffer_range bound_range = { 0, 0, 0, 0 }; union vkd3d_descriptor_info descriptor_info[2]; VkDescriptorType vk_descriptor_type; @@ -3617,6 +3613,11 @@ static void vkd3d_create_buffer_srv(struct d3d12_desc *descriptor, else WARN("Using CreateSRV for RTAS without RT support?\n"); + vkd3d_descriptor_debug_write_descriptor(descriptor->heap->descriptor_heap_info.host_ptr, + descriptor->heap->cookie, descriptor->heap_offset, + VKD3D_DESCRIPTOR_QA_TYPE_RT_ACCELERATION_STRUCTURE_BIT | VKD3D_DESCRIPTOR_QA_TYPE_RAW_VA_BIT, + descriptor->metadata.cookie); + return; } @@ -3651,6 +3652,7 @@ static void vkd3d_create_buffer_srv(struct d3d12_desc *descriptor, descriptor->metadata.flags |= VKD3D_DESCRIPTOR_FLAG_BUFFER_OFFSET; vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_qa_flags |= VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_BUFFER_BIT; vkd3d_init_write_descriptor_set(&vk_write[vk_write_count], descriptor, vkd3d_bindless_state_binding_from_info_index(&device->bindless_state, info_index), vk_descriptor_type, &descriptor_info[vk_write_count]); @@ -3694,6 +3696,7 @@ static void vkd3d_create_buffer_srv(struct d3d12_desc *descriptor, descriptor->metadata.flags |= VKD3D_DESCRIPTOR_FLAG_BUFFER_OFFSET; vk_descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + descriptor_qa_flags |= VKD3D_DESCRIPTOR_QA_TYPE_UNIFORM_TEXEL_BUFFER_BIT; vkd3d_init_write_descriptor_set(&vk_write[vk_write_count], descriptor, vkd3d_bindless_state_binding_from_info_index(&device->bindless_state, info_index), @@ -3706,9 +3709,8 @@ static void vkd3d_create_buffer_srv(struct d3d12_desc *descriptor, buffer_ranges[descriptor->heap_offset] = bound_range; } -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_write_descriptor(descriptor->heap, descriptor->heap_offset, vk_descriptor_type, descriptor->metadata.cookie); -#endif + vkd3d_descriptor_debug_write_descriptor(descriptor->heap->descriptor_heap_info.host_ptr, + descriptor->heap->cookie, descriptor->heap_offset, descriptor_qa_flags, descriptor->metadata.cookie); if (vk_write_count) VK_CALL(vkUpdateDescriptorSets(device->vk_device, vk_write_count, vk_write, 0, NULL)); @@ -3876,9 +3878,9 @@ static void vkd3d_create_texture_srv(struct d3d12_desc *descriptor, vkd3d_bindless_state_binding_from_info_index(&device->bindless_state, info_index), VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &descriptor_info); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_write_descriptor(descriptor->heap, descriptor->heap_offset, vk_write.descriptorType, descriptor->metadata.cookie); -#endif + vkd3d_descriptor_debug_write_descriptor(descriptor->heap->descriptor_heap_info.host_ptr, + descriptor->heap->cookie, descriptor->heap_offset, + VKD3D_DESCRIPTOR_QA_TYPE_SAMPLED_IMAGE_BIT, descriptor->metadata.cookie); VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, &vk_write, 0, NULL)); } @@ -3950,6 +3952,7 @@ static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_ { struct vkd3d_null_resources *null_resources = &device->null_resources; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + VKD3D_UNUSED vkd3d_descriptor_qa_flags descriptor_qa_flags = 0; struct vkd3d_bound_buffer_range bound_range = { 0, 0, 0, 0 }; union vkd3d_descriptor_info descriptor_info[3]; unsigned int flags, vk_write_count = 0; @@ -4003,6 +4006,7 @@ static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_ descriptor->metadata.flags |= VKD3D_DESCRIPTOR_FLAG_BUFFER_OFFSET; vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_qa_flags |= VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_BUFFER_BIT; vkd3d_init_write_descriptor_set(&vk_write[vk_write_count], descriptor, vkd3d_bindless_state_binding_from_info_index(&device->bindless_state, info_index), @@ -4046,6 +4050,7 @@ static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_ descriptor_info[vk_write_count].buffer_view = view ? view->vk_buffer_view : VK_NULL_HANDLE; vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + descriptor_qa_flags |= VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_TEXEL_BUFFER_BIT; vkd3d_init_write_descriptor_set(&vk_write[vk_write_count], descriptor, vkd3d_bindless_state_binding_from_info_index(&device->bindless_state, info_index), @@ -4058,10 +4063,6 @@ static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_ buffer_ranges[descriptor->heap_offset] = bound_range; } -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_write_descriptor(descriptor->heap, descriptor->heap_offset, vk_descriptor_type, descriptor->metadata.cookie); -#endif - /* Handle UAV counter */ uav_counter_view = VK_NULL_HANDLE; uav_counter_address = 0; @@ -4086,6 +4087,9 @@ static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_ uav_counter_view = view->vk_buffer_view; } + + /* This is used to denote that a counter descriptor is present, irrespective of underlying descriptor type. */ + descriptor_qa_flags |= VKD3D_DESCRIPTOR_QA_TYPE_RAW_VA_BIT; } else if (!device->device_info.robustness2_features.nullDescriptor) uav_counter_view = device->null_resources.vk_storage_buffer_view; @@ -4108,6 +4112,10 @@ static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_ vk_write_count++; } + vkd3d_descriptor_debug_write_descriptor(descriptor->heap->descriptor_heap_info.host_ptr, + descriptor->heap->cookie, descriptor->heap_offset, + descriptor_qa_flags, descriptor->metadata.cookie); + VK_CALL(vkUpdateDescriptorSets(device->vk_device, vk_write_count, vk_write, 0, NULL)); } @@ -4236,9 +4244,9 @@ static void vkd3d_create_texture_uav(struct d3d12_desc *descriptor, vkd3d_bindless_state_binding_from_info_index(&device->bindless_state, info_index), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptor_info); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_write_descriptor(descriptor->heap, descriptor->heap_offset, vk_write.descriptorType, descriptor->metadata.cookie); -#endif + vkd3d_descriptor_debug_write_descriptor(descriptor->heap->descriptor_heap_info.host_ptr, + descriptor->heap->cookie, descriptor->heap_offset, + VKD3D_DESCRIPTOR_QA_TYPE_STORAGE_IMAGE_BIT, descriptor->metadata.cookie); VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, &vk_write, 0, NULL)); } @@ -4528,9 +4536,7 @@ void d3d12_desc_create_sampler(struct d3d12_desc *sampler, if (!(view = vkd3d_view_map_create_view(&device->sampler_map, device, &key))) return; -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_register_view_cookie(view->cookie, 0); -#endif + vkd3d_descriptor_debug_register_view_cookie(device->descriptor_qa_global_info, view->cookie, 0); info_index = vkd3d_bindless_state_find_set_info_index(&device->bindless_state, VKD3D_BINDLESS_SET_SAMPLER); @@ -4547,9 +4553,9 @@ void d3d12_desc_create_sampler(struct d3d12_desc *sampler, vkd3d_bindless_state_binding_from_info_index(&device->bindless_state, info_index), VK_DESCRIPTOR_TYPE_SAMPLER, &descriptor_info); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_write_descriptor(sampler->heap, sampler->heap_offset, vk_write.descriptorType, sampler->metadata.cookie); -#endif + vkd3d_descriptor_debug_write_descriptor(sampler->heap->descriptor_heap_info.host_ptr, + sampler->heap->cookie, sampler->heap_offset, + VKD3D_DESCRIPTOR_QA_TYPE_SAMPLER_BIT, sampler->metadata.cookie); VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, &vk_write, 0, NULL)); } @@ -4651,9 +4657,7 @@ void d3d12_rtv_desc_create_rtv(struct d3d12_rtv_desc *rtv_desc, struct d3d12_dev if (!(view = vkd3d_view_map_create_view(&resource->view_map, device, &key))) return; -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_register_view_cookie(view->cookie, resource->res.cookie); -#endif + vkd3d_descriptor_debug_register_view_cookie(device->descriptor_qa_global_info, view->cookie, resource->res.cookie); rtv_desc->sample_count = vk_samples_from_dxgi_sample_desc(&resource->desc.SampleDesc); rtv_desc->format = key.u.texture.format; @@ -4765,9 +4769,7 @@ void d3d12_rtv_desc_create_dsv(struct d3d12_rtv_desc *dsv_desc, struct d3d12_dev if (!(view = vkd3d_view_map_create_view(&resource->view_map, device, &key))) return; -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_register_view_cookie(view->cookie, resource->res.cookie); -#endif + vkd3d_descriptor_debug_register_view_cookie(device->descriptor_qa_global_info, view->cookie, resource->res.cookie); dsv_desc->sample_count = vk_samples_from_dxgi_sample_desc(&resource->desc.SampleDesc); dsv_desc->format = key.u.texture.format; @@ -4961,6 +4963,12 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_pool(struct d3d12_descrip vk_pool_size->type = set_info->vk_descriptor_type; vk_pool_size->descriptorCount = descriptor_heap->desc.NumDescriptors; + if (vkd3d_descriptor_debug_active_qa_checks() && + descriptor_heap->desc.Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) + { + vk_pool_size->descriptorCount += VKD3D_DESCRIPTOR_DEBUG_NUM_PAD_DESCRIPTORS; + } + if (set_info->vk_descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ssbo_pool = vk_pool_size; } @@ -5076,6 +5084,9 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_set(struct d3d12_descript VkDescriptorSetAllocateInfo vk_set_info; VkResult vr; + if (vkd3d_descriptor_debug_active_qa_checks() && descriptor_heap->desc.Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) + descriptor_count += VKD3D_DESCRIPTOR_DEBUG_NUM_PAD_DESCRIPTORS; + vk_variable_count_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT; vk_variable_count_info.pNext = NULL; vk_variable_count_info.descriptorSetCount = 1; @@ -5135,6 +5146,7 @@ static HRESULT d3d12_descriptor_heap_init_data_buffer(struct d3d12_descriptor_he VkDeviceSize alignment = max(device->device_info.properties2.properties.limits.minStorageBufferOffsetAlignment, device->device_info.properties2.properties.limits.nonCoherentAtomSize); VkDeviceSize raw_va_buffer_size = 0, offset_buffer_size = 0; + VKD3D_UNUSED VkDeviceSize descriptor_heap_info_size = 0; VkDeviceSize buffer_size, offset; D3D12_HEAP_PROPERTIES heap_info; D3D12_RESOURCE_DESC buffer_desc; @@ -5142,16 +5154,25 @@ static HRESULT d3d12_descriptor_heap_init_data_buffer(struct d3d12_descriptor_he VkResult vr; HRESULT hr; + if (desc->Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) { if (device->bindless_state.flags & VKD3D_RAW_VA_AUX_BUFFER) + { raw_va_buffer_size = align(desc->NumDescriptors * sizeof(VkDeviceAddress), alignment); + if (vkd3d_descriptor_debug_active_qa_checks()) + raw_va_buffer_size += align(VKD3D_DESCRIPTOR_DEBUG_NUM_PAD_DESCRIPTORS * sizeof(VkDeviceAddress), alignment); + } if (device->bindless_state.flags & (VKD3D_SSBO_OFFSET_BUFFER | VKD3D_TYPED_OFFSET_BUFFER)) offset_buffer_size = align(desc->NumDescriptors * sizeof(struct vkd3d_bound_buffer_range), alignment); + + if (vkd3d_descriptor_debug_active_qa_checks()) + descriptor_heap_info_size = align(vkd3d_descriptor_debug_heap_info_size(desc->NumDescriptors), alignment); } buffer_size = raw_va_buffer_size + offset_buffer_size; + buffer_size += descriptor_heap_info_size; if (!buffer_size) return S_OK; @@ -5200,6 +5221,11 @@ static HRESULT d3d12_descriptor_heap_init_data_buffer(struct d3d12_descriptor_he d3d12_descriptor_heap_get_buffer_range(descriptor_heap, &offset, raw_va_buffer_size, &descriptor_heap->raw_va_aux_buffer); d3d12_descriptor_heap_get_buffer_range(descriptor_heap, &offset, offset_buffer_size, &descriptor_heap->buffer_ranges); +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + d3d12_descriptor_heap_get_buffer_range(descriptor_heap, &offset, + descriptor_heap_info_size, + &descriptor_heap->descriptor_heap_info); +#endif return S_OK; } @@ -5249,8 +5275,18 @@ static void d3d12_descriptor_heap_update_extra_bindings(struct d3d12_descriptor_ *vk_buffer = descriptor_heap->buffer_ranges.descriptor; break; +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + case VKD3D_BINDLESS_SET_EXTRA_GLOBAL_HEAP_INFO_BUFFER: + *vk_buffer = *vkd3d_descriptor_debug_get_global_info_descriptor(device->descriptor_qa_global_info); + break; + + case VKD3D_BINDLESS_SET_EXTRA_DESCRIPTOR_HEAP_INFO_BUFFER: + *vk_buffer = descriptor_heap->descriptor_heap_info.descriptor; + break; +#endif + default: - ERR("Unsupported etra flags %#x.\n", flag); + ERR("Unsupported extra flags %#x.\n", flag); continue; } @@ -5389,7 +5425,8 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device, TRACE("Created descriptor heap %p.\n", object); #ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_register_heap(object, desc); + object->cookie = vkd3d_allocate_cookie(); + vkd3d_descriptor_debug_register_heap(object->descriptor_heap_info.host_ptr, object->cookie, desc); #endif *descriptor_heap = object; @@ -5413,9 +5450,7 @@ void d3d12_descriptor_heap_cleanup(struct d3d12_descriptor_heap *descriptor_heap VK_CALL(vkDestroyDescriptorPool(device->vk_device, descriptor_heap->vk_descriptor_pool, NULL)); -#ifdef VKD3D_ENABLE_DESCRIPTOR_QA - vkd3d_descriptor_debug_unregister_heap(descriptor_heap); -#endif + vkd3d_descriptor_debug_unregister_heap(descriptor_heap->cookie); } static void d3d12_query_heap_set_name(struct d3d12_query_heap *heap, const char *name) diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c index 381677ba..81b71259 100644 --- a/libs/vkd3d/state.c +++ b/libs/vkd3d/state.c @@ -20,6 +20,7 @@ #define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API #include "vkd3d_private.h" +#include "vkd3d_descriptor_debug.h" #include /* ID3D12RootSignature */ @@ -768,6 +769,18 @@ static void d3d12_root_signature_init_extra_bindings(struct d3d12_root_signature VKD3D_BINDLESS_SET_EXTRA_OFFSET_BUFFER, &root_signature->offset_buffer_binding); } + +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + if (vkd3d_descriptor_debug_active_qa_checks()) + { + vkd3d_bindless_state_find_binding(&root_signature->device->bindless_state, + VKD3D_BINDLESS_SET_EXTRA_DESCRIPTOR_HEAP_INFO_BUFFER, + &root_signature->descriptor_qa_heap_binding); + vkd3d_bindless_state_find_binding(&root_signature->device->bindless_state, + VKD3D_BINDLESS_SET_EXTRA_GLOBAL_HEAP_INFO_BUFFER, + &root_signature->descriptor_qa_global_info); + } +#endif } static HRESULT d3d12_root_signature_init_shader_record_descriptors( @@ -1332,6 +1345,9 @@ unsigned int d3d12_root_signature_get_shader_interface_flags(const struct d3d12_ if (root_signature->device->bindless_state.flags & VKD3D_BINDLESS_CBV_AS_SSBO) flags |= VKD3D_SHADER_INTERFACE_BINDLESS_CBV_AS_STORAGE_BUFFER; + if (vkd3d_descriptor_debug_active_qa_checks()) + flags |= VKD3D_SHADER_INTERFACE_DESCRIPTOR_QA_BUFFER; + return flags; } @@ -2156,6 +2172,10 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st shader_interface.offset_buffer_binding = &root_signature->offset_buffer_binding; shader_interface.stage = VK_SHADER_STAGE_COMPUTE_BIT; shader_interface.xfb_info = NULL; +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + shader_interface.descriptor_qa_global_binding = &root_signature->descriptor_qa_global_info; + shader_interface.descriptor_qa_heap_binding = &root_signature->descriptor_qa_heap_binding; +#endif if ((hr = vkd3d_create_pipeline_cache_from_d3d12_desc(device, &desc->cached_pso, &state->vk_pso_cache)) < 0) { @@ -3033,6 +3053,10 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s shader_interface.push_constant_buffer_count = root_signature->root_constant_count; shader_interface.push_constant_ubo_binding = &root_signature->push_constant_ubo_binding; shader_interface.offset_buffer_binding = &root_signature->offset_buffer_binding; +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + shader_interface.descriptor_qa_global_binding = &root_signature->descriptor_qa_global_info; + shader_interface.descriptor_qa_heap_binding = &root_signature->descriptor_qa_heap_binding; +#endif graphics->patch_vertex_count = 0; @@ -3883,6 +3907,8 @@ static uint32_t d3d12_max_descriptor_count_from_heap_type(D3D12_DESCRIPTOR_HEAP_ switch (heap_type) { case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: + if (vkd3d_descriptor_debug_active_qa_checks()) + return 1000000 + VKD3D_DESCRIPTOR_DEBUG_NUM_PAD_DESCRIPTORS; return 1000000; case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: @@ -4213,6 +4239,12 @@ HRESULT vkd3d_bindless_state_init(struct vkd3d_bindless_state *bindless_state, if (bindless_state->flags & (VKD3D_SSBO_OFFSET_BUFFER | VKD3D_TYPED_OFFSET_BUFFER)) extra_bindings |= VKD3D_BINDLESS_SET_EXTRA_OFFSET_BUFFER; + if (vkd3d_descriptor_debug_active_qa_checks()) + { + extra_bindings |= VKD3D_BINDLESS_SET_EXTRA_GLOBAL_HEAP_INFO_BUFFER | + VKD3D_BINDLESS_SET_EXTRA_DESCRIPTOR_HEAP_INFO_BUFFER; + } + if (FAILED(hr = vkd3d_bindless_state_add_binding(bindless_state, device, VKD3D_BINDLESS_SET_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLER))) goto fail; diff --git a/libs/vkd3d/vkd3d_descriptor_debug.h b/libs/vkd3d/vkd3d_descriptor_debug.h index a58f9e13..4f992ad8 100644 --- a/libs/vkd3d/vkd3d_descriptor_debug.h +++ b/libs/vkd3d/vkd3d_descriptor_debug.h @@ -20,20 +20,75 @@ #define __VKD3D_DESCRIPTOR_DEBUG_H #include "vkd3d_private.h" +#include "vkd3d_descriptor_qa_data.h" + +/* Cost is 1 bit per cookie, and spending 256 MB of host memory on this is reasonable, + * and overflowing this pool should never happen. */ +#define VKD3D_DESCRIPTOR_DEBUG_DEFAULT_NUM_COOKIES (2 * 1000 * 1000 * 1000) +#define VKD3D_DESCRIPTOR_DEBUG_NUM_PAD_DESCRIPTORS 1 + +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA +HRESULT vkd3d_descriptor_debug_alloc_global_info( + struct vkd3d_descriptor_qa_global_info **global_info, + unsigned int num_cookies, + struct d3d12_device *device); +void vkd3d_descriptor_debug_free_global_info( + struct vkd3d_descriptor_qa_global_info *global_info, + struct d3d12_device *device); + +void vkd3d_descriptor_debug_kick_qa_check(struct vkd3d_descriptor_qa_global_info *global_info); + +const VkDescriptorBufferInfo *vkd3d_descriptor_debug_get_global_info_descriptor( + struct vkd3d_descriptor_qa_global_info *global_info); void vkd3d_descriptor_debug_init(void); -bool vkd3d_descriptor_debug_active(void); +bool vkd3d_descriptor_debug_active_log(void); +bool vkd3d_descriptor_debug_active_qa_checks(void); -void vkd3d_descriptor_debug_register_heap(void *heap, const D3D12_DESCRIPTOR_HEAP_DESC *desc); -void vkd3d_descriptor_debug_unregister_heap(void *heap); +void vkd3d_descriptor_debug_register_heap( + struct vkd3d_descriptor_qa_heap_buffer_data *heap, uint64_t cookie, + const D3D12_DESCRIPTOR_HEAP_DESC *desc); +void vkd3d_descriptor_debug_unregister_heap(uint64_t cookie); -void vkd3d_descriptor_debug_register_resource_cookie(uint64_t cookie, const D3D12_RESOURCE_DESC *desc); -void vkd3d_descriptor_debug_register_allocation_cookie(uint64_t cookie, const struct vkd3d_allocate_memory_info *info); -void vkd3d_descriptor_debug_register_view_cookie(uint64_t cookie, uint64_t resource_cookie); -void vkd3d_descriptor_debug_unregister_cookie(uint64_t cookie); +void vkd3d_descriptor_debug_register_resource_cookie( + struct vkd3d_descriptor_qa_global_info *global_info, + uint64_t cookie, const D3D12_RESOURCE_DESC *desc); +void vkd3d_descriptor_debug_register_allocation_cookie( + struct vkd3d_descriptor_qa_global_info *global_info, + uint64_t cookie, const struct vkd3d_allocate_memory_info *info); +void vkd3d_descriptor_debug_register_view_cookie( + struct vkd3d_descriptor_qa_global_info *global_info, + uint64_t cookie, uint64_t resource_cookie); +void vkd3d_descriptor_debug_unregister_cookie( + struct vkd3d_descriptor_qa_global_info *global_info, + uint64_t cookie); -void vkd3d_descriptor_debug_write_descriptor(void *heap, uint32_t offset, VkDescriptorType type, uint64_t cookie); -void vkd3d_descriptor_debug_copy_descriptor(void *dst_heap, uint32_t dst_offset, - void *src_heap, uint32_t src_offset, uint64_t cookie); +void vkd3d_descriptor_debug_write_descriptor( + struct vkd3d_descriptor_qa_heap_buffer_data *heap, uint64_t heap_cookie, uint32_t offset, + vkd3d_descriptor_qa_flags type_flags, uint64_t cookie); +void vkd3d_descriptor_debug_copy_descriptor( + struct vkd3d_descriptor_qa_heap_buffer_data *dst_heap, uint64_t dst_heap_cookie, uint32_t dst_offset, + struct vkd3d_descriptor_qa_heap_buffer_data *src_heap, uint64_t src_heap_cookie, uint32_t src_offset, + uint64_t cookie); + +VkDeviceSize vkd3d_descriptor_debug_heap_info_size(unsigned int num_descriptors); +#else +#define vkd3d_descriptor_debug_alloc_global_info(global_info, num_cookies, device) (S_OK) +#define vkd3d_descriptor_debug_free_global_info(global_info, device) ((void)0) +#define vkd3d_descriptor_debug_kick_qa_check(global_info) ((void)0) +#define vkd3d_descriptor_debug_get_global_info_descriptor(global_info) ((const VkDescriptorBufferInfo *)NULL) +#define vkd3d_descriptor_debug_init() ((void)0) +#define vkd3d_descriptor_debug_active_log() ((void)0) +#define vkd3d_descriptor_debug_active_qa_checks() (false) +#define vkd3d_descriptor_debug_register_heap(heap, cookie, desc) ((void)0) +#define vkd3d_descriptor_debug_unregister_heap(cookie) ((void)0) +#define vkd3d_descriptor_debug_register_resource_cookie(global_info, cookie, desc) ((void)0) +#define vkd3d_descriptor_debug_register_allocation_cookie(global_info, cookie, info) ((void)0) +#define vkd3d_descriptor_debug_register_view_cookie(global_info, cookie, resource_cookie) ((void)0) +#define vkd3d_descriptor_debug_unregister_cookie(global_info, cookie) ((void)0) +#define vkd3d_descriptor_debug_write_descriptor(heap, heap_cookie, offset, type_flags, cookie) ((void)0) +#define vkd3d_descriptor_debug_copy_descriptor(dst_heap, dst_heap_cookie, dst_offset, src_heap, src_heap_cookie, src_offset, cookie) ((void)0) +#define vkd3d_descriptor_debug_heap_info_size(num_descriptors) 0 +#endif #endif diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index c9bc8509..6ec9f2f2 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -1072,6 +1072,10 @@ struct d3d12_descriptor_heap struct vkd3d_host_visible_buffer_range raw_va_aux_buffer; struct vkd3d_host_visible_buffer_range buffer_ranges; +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + struct vkd3d_host_visible_buffer_range descriptor_heap_info; + uint64_t cookie; +#endif struct d3d12_device *device; @@ -1190,6 +1194,10 @@ struct d3d12_root_signature struct vkd3d_shader_descriptor_binding push_constant_ubo_binding; struct vkd3d_shader_descriptor_binding raw_va_aux_buffer_binding; struct vkd3d_shader_descriptor_binding offset_buffer_binding; +#ifdef VKD3D_ENABLE_DESCRIPTOR_QA + struct vkd3d_shader_descriptor_binding descriptor_qa_heap_binding; + struct vkd3d_shader_descriptor_binding descriptor_qa_global_info; +#endif uint32_t descriptor_table_offset; uint32_t descriptor_table_count; @@ -2113,8 +2121,10 @@ enum vkd3d_bindless_set_flag VKD3D_BINDLESS_SET_RAW_SSBO = (1u << 7), VKD3D_BINDLESS_SET_MUTABLE = (1u << 8), - VKD3D_BINDLESS_SET_EXTRA_RAW_VA_AUX_BUFFER = (1u << 24), - VKD3D_BINDLESS_SET_EXTRA_OFFSET_BUFFER = (1u << 25), + VKD3D_BINDLESS_SET_EXTRA_RAW_VA_AUX_BUFFER = (1u << 24), + VKD3D_BINDLESS_SET_EXTRA_OFFSET_BUFFER = (1u << 25), + VKD3D_BINDLESS_SET_EXTRA_GLOBAL_HEAP_INFO_BUFFER = (1u << 26), + VKD3D_BINDLESS_SET_EXTRA_DESCRIPTOR_HEAP_INFO_BUFFER = (1u << 27), VKD3D_BINDLESS_SET_EXTRA_MASK = 0xff000000u }; @@ -2556,6 +2566,9 @@ struct vkd3d_queue_family_info /* ID3D12Device */ typedef ID3D12Device6 d3d12_device_iface; +struct vkd3d_descriptor_qa_global_info; +struct vkd3d_descriptor_qa_heap_buffer_data; + struct d3d12_device { d3d12_device_iface ID3D12Device_iface; @@ -2613,6 +2626,7 @@ struct d3d12_device struct vkd3d_view_map sampler_map; struct vkd3d_sampler_state sampler_state; struct vkd3d_shader_debug_ring debug_ring; + struct vkd3d_descriptor_qa_global_info *descriptor_qa_global_info; }; HRESULT d3d12_device_create(struct vkd3d_instance *instance,