-- v2: vkd3d: Buffer descriptor writes. vkd3d: Use atomic exchange for descriptor writes. vkd3d: Delay writing Vulkan descriptors until submitted to a queue. vkd3d: Ensure descriptors are pointer aligned.
From: Conor McCarthy cmccarthy@codeweavers.com
The descriptor structure contains pointers. --- libs/vkd3d/resource.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index c282f116..c45406c5 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -3984,6 +3984,8 @@ static HRESULT d3d12_descriptor_heap_init(struct d3d12_descriptor_heap *descript return S_OK; }
+STATIC_ASSERT(!(offsetof(struct d3d12_descriptor_heap, descriptors) & (sizeof(void *) - 1))); + HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device, const D3D12_DESCRIPTOR_HEAP_DESC *desc, struct d3d12_descriptor_heap **descriptor_heap) {
From: Conor McCarthy cmccarthy@codeweavers.com
Eliminates vk_sets_mutex. Performance on average may be lower until the descriptor mutexes are replaced and Vulkan writes are buffered to reduce thunk calls. --- configure.ac | 2 + include/private/vkd3d_common.h | 27 +++ libs/vkd3d/command.c | 50 ++++- libs/vkd3d/device.c | 155 +--------------- libs/vkd3d/resource.c | 329 +++++++++++++-------------------- libs/vkd3d/vkd3d_private.h | 14 +- 6 files changed, 210 insertions(+), 367 deletions(-)
diff --git a/configure.ac b/configure.ac index 29225c8c..93c3d585 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,8 @@ VKD3D_CHECK_FUNC([HAVE_BUILTIN_POPCOUNT], [__builtin_popcount], [__builtin_popco VKD3D_CHECK_FUNC([HAVE_BUILTIN_ADD_OVERFLOW], [__builtin_add_overflow], [__builtin_add_overflow(0, 0, (int *)0)]) VKD3D_CHECK_FUNC([HAVE_SYNC_ADD_AND_FETCH], [__sync_add_and_fetch], [__sync_add_and_fetch((int *)0, 0)]) VKD3D_CHECK_FUNC([HAVE_SYNC_SUB_AND_FETCH], [__sync_sub_and_fetch], [__sync_sub_and_fetch((int *)0, 0)]) +VKD3D_CHECK_FUNC([HAVE_SYNC_COMPARE_AND_SWAP], [__sync_val_compare_and_swap], [__sync_val_compare_and_swap((int *)0, 0, 0)]) +VKD3D_CHECK_FUNC([HAVE_ATOMIC_EXCHANGE_N], [__atomic_exchange_n], [__atomic_exchange_n((int *)0, 0)])
dnl Makefiles case $host_os in diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 78a15c19..017f3f41 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -249,6 +249,33 @@ static inline LONG InterlockedDecrement(LONG volatile *x) # else # error "InterlockedDecrement() not implemented for this platform" # endif + +# if HAVE_SYNC_COMPARE_AND_SWAP +static inline LONG InterlockedCompareExchange(LONG volatile *x, LONG xchg, LONG cmp) +{ + return __sync_val_compare_and_swap(x, cmp, xchg); +} +# else +# error "InterlockedCompareExchange() not implemented for this platform" +# endif +# if HAVE_ATOMIC_EXCHANGE_N +static inline LONG InterlockedExchange(LONG volatile *x, LONG val) +{ + return __atomic_exchange_n(x, val, __ATOMIC_SEQ_CST); +} +# elif HAVE_SYNC_COMPARE_AND_SWAP +static inline LONG InterlockedExchange(LONG volatile *x, LONG val) +{ + LONG i; + do + { + i = *x; + } while (__sync_val_compare_and_swap(x, i, val) != i); + return i; +} +# else +# error "InterlockedExchange() not implemented for this platform" +# endif #endif /* _WIN32 */
static inline void vkd3d_parse_version(const char *version, int *major, int *minor) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 6eddcfa2..3ba1f608 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -3177,12 +3177,6 @@ static void d3d12_command_list_bind_descriptor_heap(struct d3d12_command_list *l bindings->sampler_heap_id = heap->serial_id; }
- /* These sets can be shared across multiple command lists, and therefore binding must - * be synchronised. On an experimental branch in which caching of Vk descriptor writes - * greatly increased the chance of multiple threads arriving here at the same time, - * GRID 2019 crashed without the mutex lock. */ - vkd3d_mutex_lock(&heap->vk_sets_mutex); - for (set = 0; set < ARRAY_SIZE(heap->vk_descriptor_sets); ++set) { VkDescriptorSet vk_descriptor_set = heap->vk_descriptor_sets[set].vk_set; @@ -3193,8 +3187,6 @@ static void d3d12_command_list_bind_descriptor_heap(struct d3d12_command_list *l VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point, rs->vk_pipeline_layout, rs->vk_set_count + set, 1, &vk_descriptor_set, 0, NULL)); } - - vkd3d_mutex_unlock(&heap->vk_sets_mutex); }
static void d3d12_command_list_update_heap_descriptors(struct d3d12_command_list *list, @@ -6166,6 +6158,44 @@ static void d3d12_command_queue_submit_locked(struct d3d12_command_queue *queue) } }
+static bool contains_heap(const struct d3d12_descriptor_heap **heap_array, unsigned int count, + const struct d3d12_descriptor_heap *query) +{ + unsigned int i; + + for (i = 0; i < count; ++i) + if (heap_array[i] == query) + return true; + return false; +} + +static void pipeline_bindings_flush_vk_heap_updates(struct vkd3d_pipeline_bindings *bindings, + struct d3d12_device *device) +{ + /* Only two heaps are strictly allowed, but more could be supported with a hack. */ + const struct d3d12_descriptor_heap *heap_array[3]; + struct d3d12_descriptor_heap *descriptor_heap; + unsigned int i, count; + uint64_t mask; + + mask = bindings->descriptor_table_active_mask & bindings->root_signature->descriptor_table_mask; + + for (i = 0, count = 0; i < ARRAY_SIZE(bindings->descriptor_tables); ++i) + { + if (!(mask & (1ull << i)) || !bindings->descriptor_tables[i]) + continue; + + descriptor_heap = d3d12_desc_get_descriptor_heap(bindings->descriptor_tables[i]); + /* Another thread could be writing unused descriptors, so try to check each heap only once. Flushing + * any updates added after the first flush will only delay execution of the command list. */ + if (contains_heap(heap_array, count, descriptor_heap)) + continue; + if (count < ARRAY_SIZE(heap_array)) + heap_array[count++] = descriptor_heap; + d3d12_desc_flush_vk_heap_updates(descriptor_heap, device); + } +} + static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12CommandQueue *iface, UINT command_list_count, ID3D12CommandList * const *command_lists) { @@ -6199,6 +6229,10 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm return; }
+ if (cmd_list->state) + pipeline_bindings_flush_vk_heap_updates(&cmd_list->pipeline_bindings[cmd_list->state->vk_bind_point], + cmd_list->device); + buffers[i] = cmd_list->vk_command_buffer; }
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 39a5ca01..d9555d1d 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -3368,132 +3368,6 @@ static void STDMETHODCALLTYPE d3d12_device_CreateSampler(ID3D12Device *iface, d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device); }
-static void flush_desc_writes(struct d3d12_desc_copy_location locations[][VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE], - struct d3d12_desc_copy_info *infos, struct d3d12_descriptor_heap *descriptor_heap, struct d3d12_device *device) -{ - enum vkd3d_vk_descriptor_set_index set; - for (set = 0; set < VKD3D_SET_INDEX_COUNT; ++set) - { - if (!infos[set].count) - continue; - d3d12_desc_copy_vk_heap_range(locations[set], &infos[set], descriptor_heap, set, device); - infos[set].count = 0; - infos[set].uav_counter = false; - } -} - -static void d3d12_desc_buffered_copy_atomic(struct d3d12_desc *dst, const struct d3d12_desc *src, - struct d3d12_desc_copy_location locations[][VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE], - struct d3d12_desc_copy_info *infos, struct d3d12_descriptor_heap *descriptor_heap, struct d3d12_device *device) -{ - struct d3d12_desc_copy_location *location; - enum vkd3d_vk_descriptor_set_index set; - struct vkd3d_mutex *mutex; - - mutex = d3d12_device_get_descriptor_mutex(device, src); - vkd3d_mutex_lock(mutex); - - if (src->s.magic == VKD3D_DESCRIPTOR_MAGIC_FREE) - { - /* Source must be unlocked first, and therefore can't be used as a null source. */ - static const struct d3d12_desc null = {0}; - vkd3d_mutex_unlock(mutex); - d3d12_desc_write_atomic(dst, &null, device); - return; - } - - set = vkd3d_vk_descriptor_set_index_from_vk_descriptor_type(src->s.vk_descriptor_type); - location = &locations[set][infos[set].count++]; - - location->src.s = src->s; - - if (location->src.s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) - vkd3d_view_incref(location->src.s.u.view_info.view); - - vkd3d_mutex_unlock(mutex); - - infos[set].uav_counter |= (location->src.s.magic == VKD3D_DESCRIPTOR_MAGIC_UAV) - && !!location->src.s.u.view_info.view->vk_counter_view; - location->dst = dst; - - if (infos[set].count == ARRAY_SIZE(locations[0])) - { - d3d12_desc_copy_vk_heap_range(locations[set], &infos[set], descriptor_heap, set, device); - infos[set].count = 0; - infos[set].uav_counter = false; - } -} - -/* Some games, e.g. Control, copy a large number of descriptors per frame, so the - * speed of this function is critical. */ -static void d3d12_device_vk_heaps_copy_descriptors(struct d3d12_device *device, - UINT dst_descriptor_range_count, const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets, - const UINT *dst_descriptor_range_sizes, - UINT src_descriptor_range_count, const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets, - const UINT *src_descriptor_range_sizes) -{ - struct d3d12_desc_copy_location locations[VKD3D_SET_INDEX_COUNT][VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE]; - unsigned int dst_range_idx, dst_idx, src_range_idx, src_idx; - /* The locations array is relatively large, and often mostly empty. Keeping these - * values together in a separate array will likely result in fewer cache misses. */ - struct d3d12_desc_copy_info infos[VKD3D_SET_INDEX_COUNT]; - struct d3d12_descriptor_heap *descriptor_heap = NULL; - const struct d3d12_desc *src, *heap_base, *heap_end; - unsigned int dst_range_size, src_range_size; - struct d3d12_desc *dst; - - descriptor_heap = d3d12_desc_get_descriptor_heap(d3d12_desc_from_cpu_handle(dst_descriptor_range_offsets[0])); - heap_base = (const struct d3d12_desc *)descriptor_heap->descriptors; - heap_end = heap_base + descriptor_heap->desc.NumDescriptors; - - memset(infos, 0, sizeof(infos)); - dst_range_idx = dst_idx = 0; - src_range_idx = src_idx = 0; - while (dst_range_idx < dst_descriptor_range_count && src_range_idx < src_descriptor_range_count) - { - dst_range_size = dst_descriptor_range_sizes ? dst_descriptor_range_sizes[dst_range_idx] : 1; - src_range_size = src_descriptor_range_sizes ? src_descriptor_range_sizes[src_range_idx] : 1; - - dst = d3d12_desc_from_cpu_handle(dst_descriptor_range_offsets[dst_range_idx]); - src = d3d12_desc_from_cpu_handle(src_descriptor_range_offsets[src_range_idx]); - - if (dst < heap_base || dst >= heap_end) - { - flush_desc_writes(locations, infos, descriptor_heap, device); - descriptor_heap = d3d12_desc_get_descriptor_heap(dst); - heap_base = (const struct d3d12_desc *)descriptor_heap->descriptors; - heap_end = heap_base + descriptor_heap->desc.NumDescriptors; - } - - for (; dst_idx < dst_range_size && src_idx < src_range_size; src_idx++, dst_idx++) - { - /* We don't need to lock either descriptor for the identity check. The descriptor - * mutex is only intended to prevent use-after-free of the vkd3d_view caused by a - * race condition in the calling app. It is unnecessary to protect this test as it's - * the app's race condition, not ours. */ - if (dst[dst_idx].s.magic == src[src_idx].s.magic && (dst[dst_idx].s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) - && dst[dst_idx].s.u.view_info.written_serial_id == src[src_idx].s.u.view_info.view->serial_id) - continue; - d3d12_desc_buffered_copy_atomic(&dst[dst_idx], &src[src_idx], locations, infos, descriptor_heap, device); - } - - if (dst_idx >= dst_range_size) - { - ++dst_range_idx; - dst_idx = 0; - } - if (src_idx >= src_range_size) - { - ++src_range_idx; - src_idx = 0; - } - } - - flush_desc_writes(locations, infos, descriptor_heap, device); -} - -#define VKD3D_DESCRIPTOR_OPTIMISED_COPY_MIN_COUNT 8 - static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device *iface, UINT dst_descriptor_range_count, const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets, const UINT *dst_descriptor_range_sizes, @@ -3525,15 +3399,6 @@ static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device *iface, if (!dst_descriptor_range_count) return;
- if (device->use_vk_heaps && (dst_descriptor_range_count > 1 || (dst_descriptor_range_sizes - && dst_descriptor_range_sizes[0] >= VKD3D_DESCRIPTOR_OPTIMISED_COPY_MIN_COUNT))) - { - d3d12_device_vk_heaps_copy_descriptors(device, dst_descriptor_range_count, dst_descriptor_range_offsets, - dst_descriptor_range_sizes, src_descriptor_range_count, src_descriptor_range_offsets, - src_descriptor_range_sizes); - return; - } - dst_range_idx = dst_idx = 0; src_range_idx = src_idx = 0; while (dst_range_idx < dst_descriptor_range_count && src_range_idx < src_descriptor_range_count) @@ -3544,8 +3409,13 @@ static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device *iface, dst = d3d12_desc_from_cpu_handle(dst_descriptor_range_offsets[dst_range_idx]); src = d3d12_desc_from_cpu_handle(src_descriptor_range_offsets[src_range_idx]);
- while (dst_idx < dst_range_size && src_idx < src_range_size) - d3d12_desc_copy(&dst[dst_idx++], &src[src_idx++], device); + for (; dst_idx < dst_range_size && src_idx < src_range_size; ++dst_idx, ++src_idx) + { + if (dst[dst_idx].s.magic == src[src_idx].s.magic && (dst[dst_idx].s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) + && dst[dst_idx].s.u.view_info.written_serial_id == src[src_idx].s.u.view_info.view->serial_id) + continue; + d3d12_desc_copy(&dst[dst_idx], &src[src_idx], device); + }
if (dst_idx >= dst_range_size) { @@ -3570,17 +3440,6 @@ static void STDMETHODCALLTYPE d3d12_device_CopyDescriptorsSimple(ID3D12Device *i iface, descriptor_count, dst_descriptor_range_offset.ptr, src_descriptor_range_offset.ptr, descriptor_heap_type);
- if (descriptor_count >= VKD3D_DESCRIPTOR_OPTIMISED_COPY_MIN_COUNT) - { - struct d3d12_device *device = impl_from_ID3D12Device(iface); - if (device->use_vk_heaps) - { - d3d12_device_vk_heaps_copy_descriptors(device, 1, &dst_descriptor_range_offset, - &descriptor_count, 1, &src_descriptor_range_offset, &descriptor_count); - return; - } - } - d3d12_device_CopyDescriptors(iface, 1, &dst_descriptor_range_offset, &descriptor_count, 1, &src_descriptor_range_offset, &descriptor_count, descriptor_heap_type); } diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index c45406c5..719da18c 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -2097,179 +2097,201 @@ void vkd3d_view_decref(struct vkd3d_view *view, struct d3d12_device *device) vkd3d_view_destroy(view, device); }
-/* TODO: write null descriptors to all applicable sets (invalid behaviour workaround). */ -static void d3d12_descriptor_heap_write_vk_descriptor_range(struct d3d12_descriptor_heap_vk_set *descriptor_set, - struct d3d12_desc_copy_location *locations, unsigned int write_count) -{ - unsigned int i, info_index = 0, write_index = 0; - - switch (locations[0].src.s.vk_descriptor_type) - { - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - for (; write_index < write_count; ++write_index) - { - descriptor_set->vk_descriptor_writes[write_index].pBufferInfo = &descriptor_set->vk_buffer_infos[info_index]; - for (i = 0; i < descriptor_set->vk_descriptor_writes[write_index].descriptorCount; ++i, ++info_index) - descriptor_set->vk_buffer_infos[info_index] = locations[info_index].src.s.u.vk_cbv_info; - } - break; - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - for (; write_index < write_count; ++write_index) - { - descriptor_set->vk_descriptor_writes[write_index].pImageInfo = &descriptor_set->vk_image_infos[info_index]; - for (i = 0; i < descriptor_set->vk_descriptor_writes[write_index].descriptorCount; ++i, ++info_index) - descriptor_set->vk_image_infos[info_index].imageView = locations[info_index].src.s.u.view_info.view->u.vk_image_view; - } - break; - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - for (; write_index < write_count; ++write_index) - { - descriptor_set->vk_descriptor_writes[write_index].pTexelBufferView = &descriptor_set->vk_buffer_views[info_index]; - for (i = 0; i < descriptor_set->vk_descriptor_writes[write_index].descriptorCount; ++i, ++info_index) - descriptor_set->vk_buffer_views[info_index] = locations[info_index].src.s.u.view_info.view->u.vk_buffer_view; - } - break; - case VK_DESCRIPTOR_TYPE_SAMPLER: - for (; write_index < write_count; ++write_index) - { - descriptor_set->vk_descriptor_writes[write_index].pImageInfo = &descriptor_set->vk_image_infos[info_index]; - for (i = 0; i < descriptor_set->vk_descriptor_writes[write_index].descriptorCount; ++i, ++info_index) - descriptor_set->vk_image_infos[info_index].sampler = locations[info_index].src.s.u.view_info.view->u.vk_sampler; - } - break; - default: - ERR("Unhandled descriptor type %#x.\n", locations[0].src.s.vk_descriptor_type); - break; - } -} - static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_heap *descriptor_heap, - uint32_t dst_array_element, const struct d3d12_device *device) + uint32_t dst_array_element, struct d3d12_device *device) { + VkWriteDescriptorSet vk_descriptor_writes[VKD3D_SET_INDEX_STORAGE_IMAGE + 1]; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct d3d12_descriptor_heap_vk_set *descriptor_set; VkBufferView vk_buffer_view = VK_NULL_HANDLE; + VkDescriptorImageInfo vk_image_infos[2]; enum vkd3d_vk_descriptor_set_index i; VkDescriptorBufferInfo vk_cbv_info;
vk_cbv_info.buffer = VK_NULL_HANDLE; vk_cbv_info.offset = 0; vk_cbv_info.range = VK_WHOLE_SIZE; + memset(vk_image_infos, 0, sizeof(vk_image_infos)); + vk_image_infos[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + vk_image_infos[1].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
/* Binding a shader with the wrong null descriptor type works in Windows. * To support that here we must write one to all applicable Vulkan sets. */ for (i = VKD3D_SET_INDEX_UNIFORM_BUFFER; i <= VKD3D_SET_INDEX_STORAGE_IMAGE; ++i) { descriptor_set = &descriptor_heap->vk_descriptor_sets[i]; - descriptor_set->vk_descriptor_writes[0].dstArrayElement = dst_array_element; - descriptor_set->vk_descriptor_writes[0].descriptorCount = 1; + vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + vk_descriptor_writes[i].pNext = NULL; + vk_descriptor_writes[i].dstSet = descriptor_set->vk_set; + vk_descriptor_writes[i].dstBinding = 0; + vk_descriptor_writes[i].dstArrayElement = dst_array_element; + vk_descriptor_writes[i].descriptorCount = 1; + vk_descriptor_writes[i].descriptorType = descriptor_set->vk_type; switch (i) { case VKD3D_SET_INDEX_UNIFORM_BUFFER: - descriptor_set->vk_descriptor_writes[0].pBufferInfo = &vk_cbv_info; + vk_descriptor_writes[i].pImageInfo = NULL; + vk_descriptor_writes[i].pBufferInfo = &vk_cbv_info; + vk_descriptor_writes[i].pTexelBufferView = NULL; break; case VKD3D_SET_INDEX_SAMPLED_IMAGE: case VKD3D_SET_INDEX_STORAGE_IMAGE: - descriptor_set->vk_image_infos[0].imageView = VK_NULL_HANDLE; + vk_descriptor_writes[i].pImageInfo = &vk_image_infos[i == VKD3D_SET_INDEX_STORAGE_IMAGE]; + vk_descriptor_writes[i].pBufferInfo = NULL; + vk_descriptor_writes[i].pTexelBufferView = NULL; break; case VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER: case VKD3D_SET_INDEX_STORAGE_TEXEL_BUFFER: - descriptor_set->vk_descriptor_writes[0].pTexelBufferView = &vk_buffer_view; + vk_descriptor_writes[i].pImageInfo = NULL; + vk_descriptor_writes[i].pBufferInfo = NULL; + vk_descriptor_writes[i].pTexelBufferView = &vk_buffer_view; break; default: assert(false); break; } - VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, descriptor_set->vk_descriptor_writes, 0, NULL)); } + + VK_CALL(vkUpdateDescriptorSets(device->vk_device, i, vk_descriptor_writes, 0, NULL)); }
-/* dst and src contain the same data unless another thread overwrites dst. The array index is - * calculated from dst, and src is thread safe. */ -static void d3d12_desc_write_vk_heap(const struct d3d12_desc *dst, const struct d3d12_desc *src, - struct d3d12_device *device) +static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_heap, unsigned int dst_array_element, + const struct d3d12_desc *src, struct d3d12_device *device) { struct d3d12_descriptor_heap_vk_set *descriptor_set; - struct d3d12_descriptor_heap *descriptor_heap; const struct vkd3d_vk_device_procs *vk_procs; + VkWriteDescriptorSet vk_descriptor_writes[2]; + VkDescriptorImageInfo vk_image_info; + unsigned int count = 1; + VkDescriptorType type; bool is_null = false;
- descriptor_heap = d3d12_desc_get_descriptor_heap(dst); - descriptor_set = &descriptor_heap->vk_descriptor_sets[vkd3d_vk_descriptor_set_index_from_vk_descriptor_type( - src->s.vk_descriptor_type)]; + type = src->s.vk_descriptor_type; + descriptor_set = &descriptor_heap->vk_descriptor_sets[vkd3d_vk_descriptor_set_index_from_vk_descriptor_type(type)]; vk_procs = &device->vk_procs;
- vkd3d_mutex_lock(&descriptor_heap->vk_sets_mutex); - - descriptor_set->vk_descriptor_writes[0].dstArrayElement = dst->index; - descriptor_set->vk_descriptor_writes[0].descriptorCount = 1; - switch (src->s.vk_descriptor_type) + vk_descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + vk_descriptor_writes[0].pNext = NULL; + vk_descriptor_writes[0].dstSet = descriptor_set->vk_set; + vk_descriptor_writes[0].dstBinding = 0; + vk_descriptor_writes[0].dstArrayElement = dst_array_element; + vk_descriptor_writes[0].descriptorCount = 1; + vk_descriptor_writes[0].descriptorType = type; + switch (type) { case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - descriptor_set->vk_descriptor_writes[0].pBufferInfo = &src->s.u.vk_cbv_info; + vk_descriptor_writes[0].pImageInfo = NULL; + vk_descriptor_writes[0].pBufferInfo = &src->s.u.vk_cbv_info; + vk_descriptor_writes[0].pTexelBufferView = NULL; is_null = !src->s.u.vk_cbv_info.buffer; break; case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - is_null = !(descriptor_set->vk_image_infos[0].imageView = src->s.u.view_info.view->u.vk_image_view); + vk_descriptor_writes[0].pImageInfo = &vk_image_info; + vk_descriptor_writes[0].pBufferInfo = NULL; + vk_descriptor_writes[0].pTexelBufferView = NULL; + vk_image_info.sampler = VK_NULL_HANDLE; + is_null = !(vk_image_info.imageView = src->s.u.view_info.view->u.vk_image_view); + vk_image_info.imageLayout = (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) + ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; break; case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - descriptor_set->vk_descriptor_writes[0].pTexelBufferView = &src->s.u.view_info.view->u.vk_buffer_view; + vk_descriptor_writes[0].pImageInfo = NULL; + vk_descriptor_writes[0].pBufferInfo = NULL; + vk_descriptor_writes[0].pTexelBufferView = &src->s.u.view_info.view->u.vk_buffer_view; is_null = !src->s.u.view_info.view->u.vk_buffer_view; break; case VK_DESCRIPTOR_TYPE_SAMPLER: - descriptor_set->vk_image_infos[0].sampler = src->s.u.view_info.view->u.vk_sampler; + vk_descriptor_writes[0].pImageInfo = &vk_image_info; + vk_descriptor_writes[0].pBufferInfo = NULL; + vk_descriptor_writes[0].pTexelBufferView = NULL; + vk_image_info.sampler = src->s.u.view_info.view->u.vk_sampler; + vk_image_info.imageView = VK_NULL_HANDLE; + vk_image_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; break; default: - ERR("Unhandled descriptor type %#x.\n", src->s.vk_descriptor_type); + ERR("Unhandled descriptor type %#x.\n", type); break; } if (is_null && device->vk_info.EXT_robustness2) - { - d3d12_desc_write_vk_heap_null_descriptor(descriptor_heap, - descriptor_set->vk_descriptor_writes[0].dstArrayElement, device); - vkd3d_mutex_unlock(&descriptor_heap->vk_sets_mutex); - return; - } - - VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, descriptor_set->vk_descriptor_writes, 0, NULL)); + return d3d12_desc_write_vk_heap_null_descriptor(descriptor_heap, dst_array_element, device);
if (src->s.magic == VKD3D_DESCRIPTOR_MAGIC_UAV && src->s.u.view_info.view->vk_counter_view) { descriptor_set = &descriptor_heap->vk_descriptor_sets[VKD3D_SET_INDEX_UAV_COUNTER]; - descriptor_set->vk_descriptor_writes[0].dstArrayElement = dst->index; - descriptor_set->vk_descriptor_writes[0].descriptorCount = 1; - descriptor_set->vk_descriptor_writes[0].pTexelBufferView = &src->s.u.view_info.view->vk_counter_view; - VK_CALL(vkUpdateDescriptorSets(device->vk_device, 1, descriptor_set->vk_descriptor_writes, 0, NULL)); + vk_descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + vk_descriptor_writes[1].pNext = NULL; + vk_descriptor_writes[1].dstSet = descriptor_set->vk_set; + vk_descriptor_writes[1].dstBinding = 0; + vk_descriptor_writes[1].dstArrayElement = dst_array_element; + vk_descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + vk_descriptor_writes[1].descriptorCount = 1; + vk_descriptor_writes[1].pImageInfo = NULL; + vk_descriptor_writes[1].pBufferInfo = NULL; + vk_descriptor_writes[1].pTexelBufferView = &src->s.u.view_info.view->vk_counter_view; + ++count; }
- vkd3d_mutex_unlock(&descriptor_heap->vk_sets_mutex); + VK_CALL(vkUpdateDescriptorSets(device->vk_device, count, vk_descriptor_writes, 0, NULL)); }
-static void d3d12_desc_write_atomic_d3d12_only(struct d3d12_desc *dst, const struct d3d12_desc *src, struct d3d12_device *device) +void d3d12_desc_flush_vk_heap_updates(struct d3d12_descriptor_heap *descriptor_heap, struct d3d12_device *device) { - struct vkd3d_view *defunct_view; + struct d3d12_desc *descriptors, *src; struct vkd3d_mutex *mutex; + struct d3d12_desc tmp; + unsigned int i, next;
- mutex = d3d12_device_get_descriptor_mutex(device, dst); - vkd3d_mutex_lock(mutex); + i = InterlockedExchange(&descriptor_heap->dirty_list_head, UINT_MAX); + + descriptors = (struct d3d12_desc *)descriptor_heap->descriptors;
- if (!(dst->s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) || InterlockedDecrement(&dst->s.u.view_info.view->refcount)) + for (; i != UINT_MAX; i = next) { - d3d12_desc_copy_raw(dst, src); + src = &descriptors[i]; + next = src->next >> 1; + + mutex = d3d12_device_get_descriptor_mutex(device, src); + vkd3d_mutex_lock(mutex); + + d3d12_desc_copy_raw(&tmp, src); + + if (tmp.s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) + vkd3d_view_incref(tmp.s.u.view_info.view); + vkd3d_mutex_unlock(mutex); - return; + + if (tmp.s.magic) + { + d3d12_desc_write_vk_heap(descriptor_heap, i, &tmp, device); + if (tmp.s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) + vkd3d_view_decref(tmp.s.u.view_info.view, device); + } + + InterlockedExchange(&src->next, 0); } +}
- defunct_view = dst->s.u.view_info.view; - d3d12_desc_copy_raw(dst, src); - vkd3d_mutex_unlock(mutex); +static void d3d12_desc_mark_as_modified(struct d3d12_desc *dst) +{ + struct d3d12_descriptor_heap *descriptor_heap; + unsigned int i; + LONG head;
- /* Destroy the view after unlocking to reduce wait time. */ - vkd3d_view_destroy(defunct_view, device); + i = dst->index; + descriptor_heap = d3d12_desc_get_descriptor_heap(dst); + head = descriptor_heap->dirty_list_head; + + /* Only one thread can swap the value away from zero. */ + if (InterlockedCompareExchange(&dst->next, (head << 1) | 1, 0)) + return; + /* Now it is safe to modify 'next' to another nonzero value if necessary. */ + while (InterlockedCompareExchange(&descriptor_heap->dirty_list_head, i, head) != head) + { + head = descriptor_heap->dirty_list_head; + InterlockedExchange(&dst->next, (head << 1) | 1); + } }
void d3d12_desc_write_atomic(struct d3d12_desc *dst, const struct d3d12_desc *src, @@ -2294,8 +2316,8 @@ void d3d12_desc_write_atomic(struct d3d12_desc *dst, const struct d3d12_desc *sr if (defunct_view) vkd3d_view_destroy(defunct_view, device);
- if (device->use_vk_heaps && dst->s.magic) - d3d12_desc_write_vk_heap(dst, src, device); + if (device->use_vk_heaps && dst->s.magic && !dst->next) + d3d12_desc_mark_as_modified(dst); }
static void d3d12_desc_destroy(struct d3d12_desc *descriptor, struct d3d12_device *device) @@ -2305,58 +2327,6 @@ static void d3d12_desc_destroy(struct d3d12_desc *descriptor, struct d3d12_devic d3d12_desc_write_atomic(descriptor, &null_desc, device); }
-void d3d12_desc_copy_vk_heap_range(struct d3d12_desc_copy_location *locations, const struct d3d12_desc_copy_info *info, - struct d3d12_descriptor_heap *descriptor_heap, enum vkd3d_vk_descriptor_set_index set, - struct d3d12_device *device) -{ - struct d3d12_descriptor_heap_vk_set *descriptor_set = &descriptor_heap->vk_descriptor_sets[set]; - const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; - unsigned int i, write_count; - - vkd3d_mutex_lock(&descriptor_heap->vk_sets_mutex); - - for (i = 0, write_count = 0; i < info->count; ++i) - { - d3d12_desc_write_atomic_d3d12_only(locations[i].dst, &locations[i].src, device); - - if (i && locations[i].dst == locations[i - 1].dst + 1) - { - ++descriptor_set->vk_descriptor_writes[write_count - 1].descriptorCount; - continue; - } - /* Accessing dst->index will be slow if a cache miss occurs, so calculate instead. */ - descriptor_set->vk_descriptor_writes[write_count].dstArrayElement = locations[i].dst - - (const struct d3d12_desc *)descriptor_heap->descriptors; - descriptor_set->vk_descriptor_writes[write_count++].descriptorCount = 1; - } - d3d12_descriptor_heap_write_vk_descriptor_range(descriptor_set, locations, write_count); - /* We could pass a VkCopyDescriptorSet array instead, but that would require also storing a src array index - * for each location, which means querying the src descriptor heap. Contiguous copies require contiguous src - * descriptors as well as dst, which is less likely to occur. And client race conditions may break it. */ - VK_CALL(vkUpdateDescriptorSets(device->vk_device, write_count, descriptor_set->vk_descriptor_writes, 0, NULL)); - - if (!info->uav_counter) - goto done; - - descriptor_set = &descriptor_heap->vk_descriptor_sets[VKD3D_SET_INDEX_UAV_COUNTER]; - - for (i = 0, write_count = 0; i < info->count; ++i) - { - if (!locations[i].src.s.u.view_info.view->vk_counter_view) - continue; - descriptor_set->vk_buffer_views[write_count] = locations[i].src.s.u.view_info.view->vk_counter_view; - descriptor_set->vk_descriptor_writes[write_count].pTexelBufferView = &descriptor_set->vk_buffer_views[write_count]; - /* Accessing dst->index will be slow if a cache miss occurs, so calculate instead. */ - descriptor_set->vk_descriptor_writes[write_count].dstArrayElement = locations[i].dst - - (const struct d3d12_desc *)descriptor_heap->descriptors; - descriptor_set->vk_descriptor_writes[write_count++].descriptorCount = 1; - } - VK_CALL(vkUpdateDescriptorSets(device->vk_device, write_count, descriptor_set->vk_descriptor_writes, 0, NULL)); - -done: - vkd3d_mutex_unlock(&descriptor_heap->vk_sets_mutex); -} - void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src, struct d3d12_device *device) { @@ -3705,7 +3675,6 @@ static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_Release(ID3D12DescriptorHea }
VK_CALL(vkDestroyDescriptorPool(device->vk_device, heap->vk_descriptor_pool, NULL)); - vkd3d_mutex_destroy(&heap->vk_sets_mutex);
vkd3d_free(heap);
@@ -3866,7 +3835,6 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_set(struct d3d12_descript const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; VkDescriptorSetVariableDescriptorCountAllocateInfoEXT set_size; VkDescriptorSetAllocateInfo set_desc; - unsigned int i; VkResult vr;
set_desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -3880,8 +3848,7 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_set(struct d3d12_descript set_size.pDescriptorCounts = &variable_binding_size; if ((vr = VK_CALL(vkAllocateDescriptorSets(device->vk_device, &set_desc, &descriptor_set->vk_set))) >= 0) { - for (i = 0; i < ARRAY_SIZE(descriptor_set->vk_descriptor_writes); ++i) - descriptor_set->vk_descriptor_writes[i].dstSet = descriptor_set->vk_set; + descriptor_set->vk_type = device->vk_descriptor_heap_layouts[set].type; return S_OK; }
@@ -3897,7 +3864,6 @@ static HRESULT d3d12_descriptor_heap_vk_descriptor_sets_init(struct d3d12_descri
descriptor_heap->vk_descriptor_pool = VK_NULL_HANDLE; memset(descriptor_heap->vk_descriptor_sets, 0, sizeof(descriptor_heap->vk_descriptor_sets)); - vkd3d_mutex_init(&descriptor_heap->vk_sets_mutex);
if (!device->use_vk_heaps || (desc->Type != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && desc->Type != D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)) @@ -3908,53 +3874,6 @@ static HRESULT d3d12_descriptor_heap_vk_descriptor_sets_init(struct d3d12_descri
for (set = 0; set < ARRAY_SIZE(descriptor_heap->vk_descriptor_sets); ++set) { - struct d3d12_descriptor_heap_vk_set *descriptor_set = &descriptor_heap->vk_descriptor_sets[set]; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(descriptor_set->vk_descriptor_writes); ++i) - { - descriptor_set->vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_set->vk_descriptor_writes[i].pNext = NULL; - descriptor_set->vk_descriptor_writes[i].dstBinding = 0; - descriptor_set->vk_descriptor_writes[i].descriptorType = device->vk_descriptor_heap_layouts[set].type; - descriptor_set->vk_descriptor_writes[i].pImageInfo = NULL; - descriptor_set->vk_descriptor_writes[i].pBufferInfo = NULL; - descriptor_set->vk_descriptor_writes[i].pTexelBufferView = NULL; - } - switch (device->vk_descriptor_heap_layouts[set].type) - { - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - break; - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - descriptor_set->vk_descriptor_writes[0].pImageInfo = &descriptor_set->vk_image_infos[0]; - for (i = 0; i < ARRAY_SIZE(descriptor_set->vk_image_infos); ++i) - { - descriptor_set->vk_image_infos[i].sampler = VK_NULL_HANDLE; - descriptor_set->vk_image_infos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - break; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - descriptor_set->vk_descriptor_writes[0].pImageInfo = &descriptor_set->vk_image_infos[0]; - for (i = 0; i < ARRAY_SIZE(descriptor_set->vk_image_infos); ++i) - { - descriptor_set->vk_image_infos[i].sampler = VK_NULL_HANDLE; - descriptor_set->vk_image_infos[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - break; - case VK_DESCRIPTOR_TYPE_SAMPLER: - descriptor_set->vk_descriptor_writes[0].pImageInfo = &descriptor_set->vk_image_infos[0]; - for (i = 0; i < ARRAY_SIZE(descriptor_set->vk_image_infos); ++i) - { - descriptor_set->vk_image_infos[i].imageView = VK_NULL_HANDLE; - descriptor_set->vk_image_infos[i].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - } - break; - default: - ERR("Unhandled descriptor type %#x.\n", device->vk_descriptor_heap_layouts[set].type); - return E_FAIL; - } if (device->vk_descriptor_heap_layouts[set].applicable_heap_type == desc->Type && FAILED(hr = d3d12_descriptor_heap_create_descriptor_set(descriptor_heap, device, set))) return hr; @@ -4032,7 +3951,9 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device, { memset(&dst[i].s, 0, sizeof(dst[i].s)); dst[i].index = i; + dst[i].next = 0; } + object->dirty_list_head = UINT_MAX; } else { diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 1a277a47..24eebf30 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -732,6 +732,7 @@ struct d3d12_desc } u; } s; unsigned int index; + LONG next; };
static inline struct d3d12_desc *d3d12_desc_from_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle) @@ -838,15 +839,10 @@ struct vkd3d_vk_descriptor_heap_layout VkDescriptorSetLayout vk_set_layout; };
-#define VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE 64 - struct d3d12_descriptor_heap_vk_set { VkDescriptorSet vk_set; - VkDescriptorBufferInfo vk_buffer_infos[VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE]; - VkBufferView vk_buffer_views[VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE]; - VkDescriptorImageInfo vk_image_infos[VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE]; - VkWriteDescriptorSet vk_descriptor_writes[VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE]; + VkDescriptorType vk_type; };
/* ID3D12DescriptorHeap */ @@ -864,11 +860,15 @@ struct d3d12_descriptor_heap
VkDescriptorPool vk_descriptor_pool; struct d3d12_descriptor_heap_vk_set vk_descriptor_sets[VKD3D_SET_INDEX_COUNT]; - struct vkd3d_mutex vk_sets_mutex; + + LONG volatile dirty_list_head; + unsigned int padding;
BYTE descriptors[]; };
+void d3d12_desc_flush_vk_heap_updates(struct d3d12_descriptor_heap *descriptor_heap, struct d3d12_device *device); + static inline struct d3d12_descriptor_heap *d3d12_desc_get_descriptor_heap(const struct d3d12_desc *descriptor) { return CONTAINING_RECORD(descriptor - descriptor->index, struct d3d12_descriptor_heap, descriptors);
From: Conor McCarthy cmccarthy@codeweavers.com
The descriptor component of struct d3d12_desc is replaced with a union containing a pointer which can be swapped out using InterlockedExchangePointer(). To make it safe to increment the refcount of such an object it is necessary to cache freed objects. Elimination of the descriptor mutexes on games which use multithreaded descriptor writes nearly doubles framerate on recent hardware. --- include/private/vkd3d_common.h | 17 ++ include/vkd3d_windows.h | 1 + libs/vkd3d/command.c | 77 +++++--- libs/vkd3d/device.c | 31 ++- libs/vkd3d/resource.c | 349 ++++++++++++++++----------------- libs/vkd3d/vkd3d_private.h | 132 ++++++++----- 6 files changed, 332 insertions(+), 275 deletions(-)
diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 017f3f41..5adc8795 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -255,6 +255,10 @@ static inline LONG InterlockedCompareExchange(LONG volatile *x, LONG xchg, LONG { return __sync_val_compare_and_swap(x, cmp, xchg); } +static inline PVOID InterlockedCompareExchangePointer(PVOID volatile *x, PVOID xchg, PVOID cmp) +{ + return __sync_val_compare_and_swap(x, cmp, xchg); +} # else # error "InterlockedCompareExchange() not implemented for this platform" # endif @@ -263,6 +267,10 @@ static inline LONG InterlockedExchange(LONG volatile *x, LONG val) { return __atomic_exchange_n(x, val, __ATOMIC_SEQ_CST); } +static inline PVOID InterlockedExchangePointer(PVOID volatile *x, PVOID val) +{ + return __atomic_exchange_n(x, val, __ATOMIC_SEQ_CST); +} # elif HAVE_SYNC_COMPARE_AND_SWAP static inline LONG InterlockedExchange(LONG volatile *x, LONG val) { @@ -273,6 +281,15 @@ static inline LONG InterlockedExchange(LONG volatile *x, LONG val) } while (__sync_val_compare_and_swap(x, i, val) != i); return i; } +static inline PVOID InterlockedExchangePointer(PVOID volatile *x, PVOID val) +{ + PVOID p; + do + { + p = *x; + } while (__sync_val_compare_and_swap(x, p, val) != p); + return p; +} # else # error "InterlockedExchange() not implemented for this platform" # endif diff --git a/include/vkd3d_windows.h b/include/vkd3d_windows.h index 002ff667..ba52231c 100644 --- a/include/vkd3d_windows.h +++ b/include/vkd3d_windows.h @@ -76,6 +76,7 @@ typedef int LONG; typedef unsigned int ULONG; typedef float FLOAT; typedef LONG BOOL; +typedef void *PVOID;
/* Assuming LP64 model */ typedef char INT8; diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 3ba1f608..00a08253 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -2720,28 +2720,31 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des unsigned int index, bool use_array) { uint32_t descriptor_range_magic = range->descriptor_magic; - const struct vkd3d_view *view = descriptor->s.u.view_info.view; + union d3d12_desc_object u = descriptor->s.u; uint32_t vk_binding = range->binding; + VkDescriptorType vk_descriptor_type; uint32_t set = range->set;
- if (descriptor->s.magic != descriptor_range_magic) + if (!u.header || u.header->magic != descriptor_range_magic) return false;
+ vk_descriptor_type = u.header->vk_descriptor_type; + vk_descriptor_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; vk_descriptor_write->pNext = NULL; vk_descriptor_write->dstSet = vk_descriptor_sets[set]; vk_descriptor_write->dstBinding = use_array ? vk_binding : vk_binding + index; vk_descriptor_write->dstArrayElement = use_array ? index : 0; vk_descriptor_write->descriptorCount = 1; - vk_descriptor_write->descriptorType = descriptor->s.vk_descriptor_type; + vk_descriptor_write->descriptorType = vk_descriptor_type; vk_descriptor_write->pImageInfo = NULL; vk_descriptor_write->pBufferInfo = NULL; vk_descriptor_write->pTexelBufferView = NULL;
- switch (descriptor->s.magic) + switch (u.header->magic) { case VKD3D_DESCRIPTOR_MAGIC_CBV: - vk_descriptor_write->pBufferInfo = &descriptor->s.u.vk_cbv_info; + vk_descriptor_write->pBufferInfo = &u.cb_desc->vk_cbv_info; break;
case VKD3D_DESCRIPTOR_MAGIC_SRV: @@ -2752,8 +2755,8 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des * in pairs in one set. */ if (range->descriptor_count == UINT_MAX) { - if (descriptor->s.vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER - && descriptor->s.vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + if (vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER + && vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { vk_descriptor_write->dstSet = vk_descriptor_sets[set + 1]; vk_descriptor_write->dstBinding = 0; @@ -2763,21 +2766,21 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des { if (!use_array) vk_descriptor_write->dstBinding = vk_binding + 2 * index; - if (descriptor->s.vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER - && descriptor->s.vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + if (vk_descriptor_type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER + && vk_descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) ++vk_descriptor_write->dstBinding; }
- if (descriptor->s.vk_descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER - || descriptor->s.vk_descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) + if (vk_descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER + || vk_descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { - vk_descriptor_write->pTexelBufferView = &view->u.vk_buffer_view; + vk_descriptor_write->pTexelBufferView = &u.view->v.u.vk_buffer_view; } else { vk_image_info->sampler = VK_NULL_HANDLE; - vk_image_info->imageView = view->u.vk_image_view; - vk_image_info->imageLayout = descriptor->s.magic == VKD3D_DESCRIPTOR_MAGIC_SRV + vk_image_info->imageView = u.view->v.u.vk_image_view; + vk_image_info->imageLayout = u.header->magic == VKD3D_DESCRIPTOR_MAGIC_SRV ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
vk_descriptor_write->pImageInfo = vk_image_info; @@ -2785,7 +2788,7 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des break;
case VKD3D_DESCRIPTOR_MAGIC_SAMPLER: - vk_image_info->sampler = view->u.vk_sampler; + vk_image_info->sampler = u.view->v.u.vk_sampler; vk_image_info->imageView = VK_NULL_HANDLE; vk_image_info->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
@@ -2793,7 +2796,7 @@ static bool vk_write_descriptor_set_from_d3d12_desc(VkWriteDescriptorSet *vk_des break;
default: - ERR("Invalid descriptor %#x.\n", descriptor->s.magic); + ERR("Invalid descriptor %#x.\n", u.header->magic); return false; }
@@ -2847,6 +2850,11 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list for (j = 0; j < descriptor_count; ++j, ++descriptor) { unsigned int register_idx = range->base_register_idx + j; + union d3d12_desc_object u = descriptor->s.u; + VkBufferView vk_counter_view; + + vk_counter_view = (u.header && u.header->magic == VKD3D_DESCRIPTOR_MAGIC_UAV) + ? u.view->v.vk_counter_view : VK_NULL_HANDLE;
/* Track UAV counters. */ if (range->descriptor_magic == VKD3D_DESCRIPTOR_MAGIC_UAV) @@ -2856,8 +2864,6 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list if (state->uav_counters.bindings[k].register_space == range->register_space && state->uav_counters.bindings[k].register_index == register_idx) { - VkBufferView vk_counter_view = descriptor->s.magic == VKD3D_DESCRIPTOR_MAGIC_UAV - ? descriptor->s.u.view_info.view->vk_counter_view : VK_NULL_HANDLE; if (bindings->vk_uav_counter_views[k] != vk_counter_view) bindings->uav_counters_dirty = true; bindings->vk_uav_counter_views[k] = vk_counter_view; @@ -2867,7 +2873,7 @@ static void d3d12_command_list_update_descriptor_table(struct d3d12_command_list }
/* Not all descriptors are necessarily populated if the range is unbounded. */ - if (descriptor->s.magic == VKD3D_DESCRIPTOR_MAGIC_FREE) + if (!u.header) continue;
if (!vk_write_descriptor_set_from_d3d12_desc(current_descriptor_write, current_image_info, @@ -4836,7 +4842,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi WARN("Failed to add view.\n"); }
- list->rtvs[i] = view->u.vk_image_view; + list->rtvs[i] = view->v.u.vk_image_view; list->fb_width = max(list->fb_width, rtv_desc->width); list->fb_height = max(list->fb_height, rtv_desc->height); list->fb_layer_count = max(list->fb_layer_count, rtv_desc->layer_count); @@ -4860,7 +4866,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi list->dsv = VK_NULL_HANDLE; }
- list->dsv = view->u.vk_image_view; + list->dsv = view->v.u.vk_image_view; list->fb_width = max(list->fb_width, dsv_desc->width); list->fb_height = max(list->fb_height, dsv_desc->height); list->fb_layer_count = max(list->fb_layer_count, dsv_desc->layer_count); @@ -4952,7 +4958,7 @@ static void d3d12_command_list_clear(struct d3d12_command_list *list, fb_desc.flags = 0; fb_desc.renderPass = vk_render_pass; fb_desc.attachmentCount = 1; - fb_desc.pAttachments = &view->u.vk_image_view; + fb_desc.pAttachments = &view->v.u.vk_image_view; fb_desc.width = width; fb_desc.height = height; fb_desc.layers = layer_count; @@ -5155,13 +5161,14 @@ static void vkd3d_uav_clear_state_get_image_pipeline(const struct vkd3d_uav_clea }
static void d3d12_command_list_clear_uav(struct d3d12_command_list *list, - struct d3d12_resource *resource, struct vkd3d_view *view, const VkClearColorValue *clear_colour, + struct d3d12_resource *resource, struct vkd3d_view *descriptor, const VkClearColorValue *clear_colour, unsigned int rect_count, const D3D12_RECT *rects) { const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; unsigned int i, miplevel_idx, layer_count; struct vkd3d_uav_clear_pipeline pipeline; struct vkd3d_uav_clear_args clear_args; + const struct vkd3d_resource_view *view; VkDescriptorImageInfo image_info; D3D12_RECT full_rect, curr_rect; VkWriteDescriptorSet write_set; @@ -5173,8 +5180,9 @@ static void d3d12_command_list_clear_uav(struct d3d12_command_list *list, d3d12_command_list_invalidate_bindings(list, list->state); d3d12_command_list_invalidate_root_parameters(list, VKD3D_PIPELINE_BIND_POINT_COMPUTE);
- if (!d3d12_command_allocator_add_view(list->allocator, view)) + if (!d3d12_command_allocator_add_view(list->allocator, descriptor)) WARN("Failed to add view.\n"); + view = &descriptor->v;
clear_args.colour = *clear_colour;
@@ -5287,10 +5295,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID const UINT values[4], UINT rect_count, const D3D12_RECT *rects) { struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); + struct vkd3d_view *descriptor, *uint_view = NULL; struct d3d12_device *device = list->device; - struct vkd3d_view *view, *uint_view = NULL; struct vkd3d_texture_view_desc view_desc; const struct vkd3d_format *uint_format; + const struct vkd3d_resource_view *view; struct d3d12_resource *resource_impl; VkClearColorValue colour;
@@ -5298,7 +5307,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID iface, gpu_handle.ptr, cpu_handle.ptr, resource, values, rect_count, rects);
resource_impl = unsafe_impl_from_ID3D12Resource(resource); - view = d3d12_desc_from_cpu_handle(cpu_handle)->s.u.view_info.view; + if (!(descriptor = d3d12_desc_from_cpu_handle(cpu_handle)->s.u.view)) + return; + view = &descriptor->v; memcpy(colour.uint32, values, sizeof(colour.uint32));
if (view->format->type != VKD3D_FORMAT_TYPE_UINT) @@ -5312,8 +5323,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID
if (d3d12_resource_is_buffer(resource_impl)) { - if (!vkd3d_create_buffer_view(device, resource_impl->u.vk_buffer, uint_format, - view->info.buffer.offset, view->info.buffer.size, &uint_view)) + if (!vkd3d_create_buffer_view(device, VKD3D_DESCRIPTOR_MAGIC_UAV, resource_impl->u.vk_buffer, + uint_format, view->info.buffer.offset, view->info.buffer.size, &uint_view)) { ERR("Failed to create buffer view.\n"); return; @@ -5329,16 +5340,17 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID view_desc.layer_idx = view->info.texture.layer_idx; view_desc.layer_count = view->info.texture.layer_count;
- if (!vkd3d_create_texture_view(device, resource_impl->u.vk_image, &view_desc, &uint_view)) + if (!vkd3d_create_texture_view(device, VKD3D_DESCRIPTOR_MAGIC_UAV, resource_impl->u.vk_image, &view_desc, + &uint_view)) { ERR("Failed to create image view.\n"); return; } } - view = uint_view; + descriptor = uint_view; }
- d3d12_command_list_clear_uav(list, resource_impl, view, &colour, rect_count, rects); + d3d12_command_list_clear_uav(list, resource_impl, descriptor, &colour, rect_count, rects);
if (uint_view) vkd3d_view_decref(uint_view, device); @@ -5357,7 +5369,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewFloat(I iface, gpu_handle.ptr, cpu_handle.ptr, resource, values, rect_count, rects);
resource_impl = unsafe_impl_from_ID3D12Resource(resource); - view = d3d12_desc_from_cpu_handle(cpu_handle)->s.u.view_info.view; + if (!(view = d3d12_desc_from_cpu_handle(cpu_handle)->s.u.view)) + return; memcpy(colour.float32, values, sizeof(colour.float32));
d3d12_command_list_clear_uav(list, resource_impl, view, &colour, rect_count, rects); diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index d9555d1d..97844bcd 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -2414,6 +2414,24 @@ static void vkd3d_init_descriptor_pool_sizes(VkDescriptorPoolSize *pool_sizes, VKD3D_MAX_VIRTUAL_HEAP_DESCRIPTORS_PER_TYPE); };
+static void vkd3d_desc_object_cache_init(struct vkd3d_desc_object_cache *cache, size_t stride) +{ + cache->head = NULL; + cache->stride = stride; +} + +static void vkd3d_desc_object_cache_cleanup(struct vkd3d_desc_object_cache *cache) +{ + union d3d12_desc_object u; + void *next; + + for (u.object = cache->head; u.object; u.object = next) + { + next = u.header->next; + vkd3d_free(u.object); + } +} + /* ID3D12Device */ static inline struct d3d12_device *impl_from_ID3D12Device(ID3D12Device *iface) { @@ -2454,7 +2472,6 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface) { struct d3d12_device *device = impl_from_ID3D12Device(iface); ULONG refcount = InterlockedDecrement(&device->refcount); - size_t i;
TRACE("%p decreasing refcount to %u.\n", device, refcount);
@@ -2474,8 +2491,8 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface) vkd3d_render_pass_cache_cleanup(&device->render_pass_cache, device); d3d12_device_destroy_pipeline_cache(device); d3d12_device_destroy_vkd3d_queues(device); - for (i = 0; i < ARRAY_SIZE(device->desc_mutex); ++i) - vkd3d_mutex_destroy(&device->desc_mutex[i]); + vkd3d_desc_object_cache_cleanup(&device->view_desc_cache); + vkd3d_desc_object_cache_cleanup(&device->cbuffer_desc_cache); VK_CALL(vkDestroyDevice(device->vk_device, NULL)); if (device->parent) IUnknown_Release(device->parent); @@ -3411,8 +3428,7 @@ static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device *iface,
for (; dst_idx < dst_range_size && src_idx < src_range_size; ++dst_idx, ++src_idx) { - if (dst[dst_idx].s.magic == src[src_idx].s.magic && (dst[dst_idx].s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) - && dst[dst_idx].s.u.view_info.written_serial_id == src[src_idx].s.u.view_info.view->serial_id) + if (dst[dst_idx].s.u.object == src[src_idx].s.u.object) continue; d3d12_desc_copy(&dst[dst_idx], &src[src_idx], device); } @@ -3939,7 +3955,6 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, { const struct vkd3d_vk_device_procs *vk_procs; HRESULT hr; - size_t i;
device->ID3D12Device_iface.lpVtbl = &d3d12_device_vtbl; device->refcount = 1; @@ -3982,8 +3997,8 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, device->blocked_queue_count = 0; vkd3d_mutex_init(&device->blocked_queues_mutex);
- for (i = 0; i < ARRAY_SIZE(device->desc_mutex); ++i) - vkd3d_mutex_init(&device->desc_mutex[i]); + vkd3d_desc_object_cache_init(&device->view_desc_cache, sizeof(struct vkd3d_view)); + vkd3d_desc_object_cache_init(&device->cbuffer_desc_cache, sizeof(struct vkd3d_cbuffer_desc));
vkd3d_init_descriptor_pool_sizes(device->vk_pool_sizes, &device->vk_info.descriptor_limits);
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 719da18c..b425dedd 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -2044,24 +2044,72 @@ ULONG vkd3d_resource_decref(ID3D12Resource *resource) return d3d12_resource_decref(impl_from_ID3D12Resource(resource)); }
-/* CBVs, SRVs, UAVs */ -static struct vkd3d_view *vkd3d_view_create(enum vkd3d_view_type type) +/* Objects are cached so that vkd3d_view_incref() can safely check the refcount + * of an object freed by another thread. */ +static void *vkd3d_desc_object_cache_get(struct vkd3d_desc_object_cache *cache) { - struct vkd3d_view *view; + union d3d12_desc_object u; + void *next;
- if ((view = vkd3d_malloc(sizeof(*view)))) + do { - view->refcount = 1; - view->type = type; - view->serial_id = InterlockedIncrement64(&object_global_serial_id); - view->vk_counter_view = VK_NULL_HANDLE; + u.object = cache->head; + if (!u.object) + return vkd3d_malloc(cache->stride); + next = u.header->next; } - return view; + while (InterlockedCompareExchangePointer(&cache->head, next, u.object) != u.object); + + return u.object; +} + +static void vkd3d_desc_object_cache_push(struct vkd3d_desc_object_cache *cache, void *object) +{ + union d3d12_desc_object u = {object}; + void *head; + + do + { + head = cache->head; + u.header->next = head; + } + while (InterlockedCompareExchangePointer(&cache->head, u.object, head) != head); }
-void vkd3d_view_incref(struct vkd3d_view *view) +static struct vkd3d_cbuffer_desc *vkd3d_cbuffer_desc_create(struct d3d12_device *device) { - InterlockedIncrement(&view->refcount); + struct vkd3d_cbuffer_desc *desc; + + if (!(desc = vkd3d_desc_object_cache_get(&device->cbuffer_desc_cache))) + return NULL; + + desc->h.magic = VKD3D_DESCRIPTOR_MAGIC_CBV; + desc->h.vk_descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + desc->h.refcount = 1; + + return desc; +} + +static struct vkd3d_view *vkd3d_view_create(uint32_t magic, VkDescriptorType vk_descriptor_type, + enum vkd3d_view_type type, struct d3d12_device *device) +{ + struct vkd3d_view *view; + + assert(magic); + + if (!(view = vkd3d_desc_object_cache_get(&device->view_desc_cache))) + { + ERR("Failed to allocate descriptor object.\n"); + return NULL; + } + + view->h.magic = magic; + view->h.vk_descriptor_type = vk_descriptor_type; + view->h.refcount = 1; + view->v.type = type; + view->v.vk_counter_view = VK_NULL_HANDLE; + + return view; }
static void vkd3d_view_destroy(struct vkd3d_view *view, struct d3d12_device *device) @@ -2070,31 +2118,44 @@ static void vkd3d_view_destroy(struct vkd3d_view *view, struct d3d12_device *dev
TRACE("Destroying view %p.\n", view);
- switch (view->type) + switch (view->v.type) { case VKD3D_VIEW_TYPE_BUFFER: - VK_CALL(vkDestroyBufferView(device->vk_device, view->u.vk_buffer_view, NULL)); + VK_CALL(vkDestroyBufferView(device->vk_device, view->v.u.vk_buffer_view, NULL)); break; case VKD3D_VIEW_TYPE_IMAGE: - VK_CALL(vkDestroyImageView(device->vk_device, view->u.vk_image_view, NULL)); + VK_CALL(vkDestroyImageView(device->vk_device, view->v.u.vk_image_view, NULL)); break; case VKD3D_VIEW_TYPE_SAMPLER: - VK_CALL(vkDestroySampler(device->vk_device, view->u.vk_sampler, NULL)); + VK_CALL(vkDestroySampler(device->vk_device, view->v.u.vk_sampler, NULL)); break; default: - WARN("Unhandled view type %d.\n", view->type); + WARN("Unhandled view type %d.\n", view->v.type); }
- if (view->vk_counter_view) - VK_CALL(vkDestroyBufferView(device->vk_device, view->vk_counter_view, NULL)); + if (view->v.vk_counter_view) + VK_CALL(vkDestroyBufferView(device->vk_device, view->v.vk_counter_view, NULL));
- vkd3d_free(view); + vkd3d_desc_object_cache_push(&device->view_desc_cache, view); }
-void vkd3d_view_decref(struct vkd3d_view *view, struct d3d12_device *device) +void vkd3d_view_decref(void *view, struct d3d12_device *device) { - if (!InterlockedDecrement(&view->refcount)) - vkd3d_view_destroy(view, device); + union d3d12_desc_object u = {view}; + + if (InterlockedDecrement(&u.header->refcount)) + return; + + if (u.header->magic != VKD3D_DESCRIPTOR_MAGIC_CBV) + vkd3d_view_destroy(u.view, device); + else + vkd3d_desc_object_cache_push(&device->cbuffer_desc_cache, u.object); +} + +static inline void d3d12_desc_replace(struct d3d12_desc *dst, void *view, struct d3d12_device *device) +{ + if ((view = InterlockedExchangePointer(&dst->s.u.object, view))) + vkd3d_view_decref(view, device); }
static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_heap *descriptor_heap, @@ -2156,17 +2217,18 @@ static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_hea }
static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_heap, unsigned int dst_array_element, - const struct d3d12_desc *src, struct d3d12_device *device) + void *object, struct d3d12_device *device) { struct d3d12_descriptor_heap_vk_set *descriptor_set; const struct vkd3d_vk_device_procs *vk_procs; VkWriteDescriptorSet vk_descriptor_writes[2]; + union d3d12_desc_object u = {object}; VkDescriptorImageInfo vk_image_info; unsigned int count = 1; VkDescriptorType type; bool is_null = false;
- type = src->s.vk_descriptor_type; + type = u.header->vk_descriptor_type; descriptor_set = &descriptor_heap->vk_descriptor_sets[vkd3d_vk_descriptor_set_index_from_vk_descriptor_type(type)]; vk_procs = &device->vk_procs;
@@ -2181,9 +2243,9 @@ static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_he { case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: vk_descriptor_writes[0].pImageInfo = NULL; - vk_descriptor_writes[0].pBufferInfo = &src->s.u.vk_cbv_info; + vk_descriptor_writes[0].pBufferInfo = &u.cb_desc->vk_cbv_info; vk_descriptor_writes[0].pTexelBufferView = NULL; - is_null = !src->s.u.vk_cbv_info.buffer; + is_null = !u.cb_desc->vk_cbv_info.buffer; break; case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: @@ -2191,7 +2253,7 @@ static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_he vk_descriptor_writes[0].pBufferInfo = NULL; vk_descriptor_writes[0].pTexelBufferView = NULL; vk_image_info.sampler = VK_NULL_HANDLE; - is_null = !(vk_image_info.imageView = src->s.u.view_info.view->u.vk_image_view); + is_null = !(vk_image_info.imageView = u.view->v.u.vk_image_view); vk_image_info.imageLayout = (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; break; @@ -2199,14 +2261,14 @@ static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_he case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: vk_descriptor_writes[0].pImageInfo = NULL; vk_descriptor_writes[0].pBufferInfo = NULL; - vk_descriptor_writes[0].pTexelBufferView = &src->s.u.view_info.view->u.vk_buffer_view; - is_null = !src->s.u.view_info.view->u.vk_buffer_view; + vk_descriptor_writes[0].pTexelBufferView = &u.view->v.u.vk_buffer_view; + is_null = !u.view->v.u.vk_buffer_view; break; case VK_DESCRIPTOR_TYPE_SAMPLER: vk_descriptor_writes[0].pImageInfo = &vk_image_info; vk_descriptor_writes[0].pBufferInfo = NULL; vk_descriptor_writes[0].pTexelBufferView = NULL; - vk_image_info.sampler = src->s.u.view_info.view->u.vk_sampler; + vk_image_info.sampler = u.view->v.u.vk_sampler; vk_image_info.imageView = VK_NULL_HANDLE; vk_image_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; break; @@ -2217,7 +2279,7 @@ static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_he if (is_null && device->vk_info.EXT_robustness2) return d3d12_desc_write_vk_heap_null_descriptor(descriptor_heap, dst_array_element, device);
- if (src->s.magic == VKD3D_DESCRIPTOR_MAGIC_UAV && src->s.u.view_info.view->vk_counter_view) + if (u.header->magic == VKD3D_DESCRIPTOR_MAGIC_UAV && u.view->v.vk_counter_view) { descriptor_set = &descriptor_heap->vk_descriptor_sets[VKD3D_SET_INDEX_UAV_COUNTER]; vk_descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -2229,7 +2291,7 @@ static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_he vk_descriptor_writes[1].descriptorCount = 1; vk_descriptor_writes[1].pImageInfo = NULL; vk_descriptor_writes[1].pBufferInfo = NULL; - vk_descriptor_writes[1].pTexelBufferView = &src->s.u.view_info.view->vk_counter_view; + vk_descriptor_writes[1].pTexelBufferView = &u.view->v.vk_counter_view; ++count; }
@@ -2239,8 +2301,7 @@ static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_he void d3d12_desc_flush_vk_heap_updates(struct d3d12_descriptor_heap *descriptor_heap, struct d3d12_device *device) { struct d3d12_desc *descriptors, *src; - struct vkd3d_mutex *mutex; - struct d3d12_desc tmp; + union d3d12_desc_object u; unsigned int i, next;
i = InterlockedExchange(&descriptor_heap->dirty_list_head, UINT_MAX); @@ -2252,23 +2313,18 @@ void d3d12_desc_flush_vk_heap_updates(struct d3d12_descriptor_heap *descriptor_h src = &descriptors[i]; next = src->next >> 1;
- mutex = d3d12_device_get_descriptor_mutex(device, src); - vkd3d_mutex_lock(mutex); + u.object = d3d12_desc_get_object_ref(src, device);
- d3d12_desc_copy_raw(&tmp, src); - - if (tmp.s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) - vkd3d_view_incref(tmp.s.u.view_info.view); - - vkd3d_mutex_unlock(mutex); - - if (tmp.s.magic) + if (!u.object) { - d3d12_desc_write_vk_heap(descriptor_heap, i, &tmp, device); - if (tmp.s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) - vkd3d_view_decref(tmp.s.u.view_info.view, device); + InterlockedExchange(&src->next, 0); + continue; }
+ d3d12_desc_write_vk_heap(descriptor_heap, i, u.object, device); + + vkd3d_view_decref(u.object, device); + InterlockedExchange(&src->next, 0); } } @@ -2297,56 +2353,26 @@ static void d3d12_desc_mark_as_modified(struct d3d12_desc *dst) void d3d12_desc_write_atomic(struct d3d12_desc *dst, const struct d3d12_desc *src, struct d3d12_device *device) { - struct vkd3d_view *defunct_view = NULL; - struct vkd3d_mutex *mutex; - - mutex = d3d12_device_get_descriptor_mutex(device, dst); - vkd3d_mutex_lock(mutex); - - /* Nothing to do for VKD3D_DESCRIPTOR_MAGIC_CBV. */ - if ((dst->s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) - && !InterlockedDecrement(&dst->s.u.view_info.view->refcount)) - defunct_view = dst->s.u.view_info.view; - - d3d12_desc_copy_raw(dst, src); - - vkd3d_mutex_unlock(mutex); + void *object = src->s.u.object;
- /* Destroy the view after unlocking to reduce wait time. */ - if (defunct_view) - vkd3d_view_destroy(defunct_view, device); - - if (device->use_vk_heaps && dst->s.magic && !dst->next) + d3d12_desc_replace(dst, object, device); + if (device->use_vk_heaps && object && !dst->next) d3d12_desc_mark_as_modified(dst); }
static void d3d12_desc_destroy(struct d3d12_desc *descriptor, struct d3d12_device *device) { - static const struct d3d12_desc null_desc = {0}; - - d3d12_desc_write_atomic(descriptor, &null_desc, device); + d3d12_desc_replace(descriptor, NULL, device); }
void d3d12_desc_copy(struct d3d12_desc *dst, const struct d3d12_desc *src, struct d3d12_device *device) { struct d3d12_desc tmp; - struct vkd3d_mutex *mutex;
assert(dst != src);
- /* Shadow of the Tomb Raider and possibly other titles sometimes destroy - * and rewrite a descriptor in another thread while it is being copied. */ - mutex = d3d12_device_get_descriptor_mutex(device, src); - vkd3d_mutex_lock(mutex); - - if (src->s.magic & VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW) - vkd3d_view_incref(src->s.u.view_info.view); - - d3d12_desc_copy_raw(&tmp, src); - - vkd3d_mutex_unlock(mutex); - + tmp.s.u.object = d3d12_desc_get_object_ref(src, device); d3d12_desc_write_atomic(dst, &tmp, device); }
@@ -2408,8 +2434,9 @@ static bool vkd3d_create_vk_buffer_view(struct d3d12_device *device, return vr == VK_SUCCESS; }
-bool vkd3d_create_buffer_view(struct d3d12_device *device, VkBuffer vk_buffer, const struct vkd3d_format *format, - VkDeviceSize offset, VkDeviceSize size, struct vkd3d_view **view) +bool vkd3d_create_buffer_view(struct d3d12_device *device, uint32_t magic, VkBuffer vk_buffer, + const struct vkd3d_format *format, VkDeviceSize offset, VkDeviceSize size, + struct vkd3d_view **view) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; VkBufferView vk_view = VK_NULL_HANDLE; @@ -2418,16 +2445,18 @@ bool vkd3d_create_buffer_view(struct d3d12_device *device, VkBuffer vk_buffer, c if (vk_buffer && !vkd3d_create_vk_buffer_view(device, vk_buffer, format, offset, size, &vk_view)) return false;
- if (!(object = vkd3d_view_create(VKD3D_VIEW_TYPE_BUFFER))) + if (!(object = vkd3d_view_create(magic, magic == VKD3D_DESCRIPTOR_MAGIC_UAV + ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, + VKD3D_VIEW_TYPE_BUFFER, device))) { VK_CALL(vkDestroyBufferView(device->vk_device, vk_view, NULL)); return false; }
- object->u.vk_buffer_view = vk_view; - object->format = format; - object->info.buffer.offset = offset; - object->info.buffer.size = size; + object->v.u.vk_buffer_view = vk_view; + object->v.format = format; + object->v.info.buffer.offset = offset; + object->v.info.buffer.size = size; *view = object; return true; } @@ -2435,7 +2464,7 @@ bool vkd3d_create_buffer_view(struct d3d12_device *device, VkBuffer vk_buffer, c #define VKD3D_VIEW_RAW_BUFFER 0x1
static bool vkd3d_create_buffer_view_for_resource(struct d3d12_device *device, - struct d3d12_resource *resource, DXGI_FORMAT view_format, + uint32_t magic, struct d3d12_resource *resource, DXGI_FORMAT view_format, unsigned int offset, unsigned int size, unsigned int structure_stride, unsigned int flags, struct vkd3d_view **view) { @@ -2466,7 +2495,7 @@ static bool vkd3d_create_buffer_view_for_resource(struct d3d12_device *device,
assert(d3d12_resource_is_buffer(resource));
- return vkd3d_create_buffer_view(device, resource->u.vk_buffer, + return vkd3d_create_buffer_view(device, magic, resource->u.vk_buffer, format, offset * element_size, size * element_size, view); }
@@ -2694,7 +2723,7 @@ static void vkd3d_texture_view_desc_normalise(struct vkd3d_texture_view_desc *de desc->layer_count = max_layer_count; }
-bool vkd3d_create_texture_view(struct d3d12_device *device, VkImage vk_image, +bool vkd3d_create_texture_view(struct d3d12_device *device, uint32_t magic, VkImage vk_image, const struct vkd3d_texture_view_desc *desc, struct vkd3d_view **view) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; @@ -2727,18 +2756,19 @@ bool vkd3d_create_texture_view(struct d3d12_device *device, VkImage vk_image, } }
- if (!(object = vkd3d_view_create(VKD3D_VIEW_TYPE_IMAGE))) + if (!(object = vkd3d_view_create(magic, magic == VKD3D_DESCRIPTOR_MAGIC_UAV ? VK_DESCRIPTOR_TYPE_STORAGE_IMAGE + : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VKD3D_VIEW_TYPE_IMAGE, device))) { VK_CALL(vkDestroyImageView(device->vk_device, vk_view, NULL)); return false; }
- object->u.vk_image_view = vk_view; - object->format = format; - object->info.texture.vk_view_type = desc->view_type; - object->info.texture.miplevel_idx = desc->miplevel_idx; - object->info.texture.layer_idx = desc->layer_idx; - object->info.texture.layer_count = desc->layer_count; + object->v.u.vk_image_view = vk_view; + object->v.format = format; + object->v.info.texture.vk_view_type = desc->view_type; + object->v.info.texture.miplevel_idx = desc->miplevel_idx; + object->v.info.texture.layer_idx = desc->layer_idx; + object->v.info.texture.layer_count = desc->layer_count; *view = object; return true; } @@ -2747,6 +2777,7 @@ void d3d12_desc_create_cbv(struct d3d12_desc *descriptor, struct d3d12_device *device, const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc) { struct VkDescriptorBufferInfo *buffer_info; + struct vkd3d_cbuffer_desc *cb_desc; struct d3d12_resource *resource;
if (!desc) @@ -2755,13 +2786,19 @@ void d3d12_desc_create_cbv(struct d3d12_desc *descriptor, return; }
+ if (!(cb_desc = vkd3d_cbuffer_desc_create(device))) + { + ERR("Failed to allocate descriptor object.\n"); + return; + } + if (desc->SizeInBytes & (D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1)) { WARN("Size is not %u bytes aligned.\n", D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); return; }
- buffer_info = &descriptor->s.u.vk_cbv_info; + buffer_info = &cb_desc->vk_cbv_info; if (desc->BufferLocation) { resource = vkd3d_gpu_va_allocator_dereference(&device->gpu_va_allocator, desc->BufferLocation); @@ -2777,8 +2814,7 @@ void d3d12_desc_create_cbv(struct d3d12_desc *descriptor, buffer_info->range = VK_WHOLE_SIZE; }
- descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_CBV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor->s.u.cb_desc = cb_desc; }
static unsigned int vkd3d_view_flags_from_d3d12_buffer_srv_flags(D3D12_BUFFER_SRV_FLAGS flags) @@ -2795,7 +2831,6 @@ static void vkd3d_create_null_srv(struct d3d12_desc *descriptor, { struct vkd3d_null_resources *null_resources = &device->null_resources; struct vkd3d_texture_view_desc vkd3d_desc; - struct vkd3d_view *view; VkImage vk_image;
if (!desc) @@ -2810,15 +2845,9 @@ static void vkd3d_create_null_srv(struct d3d12_desc *descriptor, if (!device->vk_info.EXT_robustness2) WARN("Creating NULL buffer SRV %#x.\n", desc->Format);
- if (vkd3d_create_buffer_view(device, null_resources->vk_buffer, + vkd3d_create_buffer_view(device, VKD3D_DESCRIPTOR_MAGIC_SRV, null_resources->vk_buffer, vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false), - 0, VKD3D_NULL_BUFFER_SIZE, &view)) - { - descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_SRV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - descriptor->s.u.view_info.view = view; - descriptor->s.u.view_info.written_serial_id = view->serial_id; - } + 0, VKD3D_NULL_BUFFER_SIZE, &descriptor->s.u.view); return;
case D3D12_SRV_DIMENSION_TEXTURE2D: @@ -2857,20 +2886,13 @@ static void vkd3d_create_null_srv(struct d3d12_desc *descriptor, vkd3d_desc.components.a = VK_COMPONENT_SWIZZLE_ZERO; vkd3d_desc.allowed_swizzle = true;
- if (!vkd3d_create_texture_view(device, vk_image, &vkd3d_desc, &view)) - return; - - descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_SRV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - descriptor->s.u.view_info.view = view; - descriptor->s.u.view_info.written_serial_id = view->serial_id; + vkd3d_create_texture_view(device, VKD3D_DESCRIPTOR_MAGIC_SRV, vk_image, &vkd3d_desc, &descriptor->s.u.view); }
static void vkd3d_create_buffer_srv(struct d3d12_desc *descriptor, struct d3d12_device *device, struct d3d12_resource *resource, const D3D12_SHADER_RESOURCE_VIEW_DESC *desc) { - struct vkd3d_view *view; unsigned int flags;
if (!desc) @@ -2886,15 +2908,9 @@ static void vkd3d_create_buffer_srv(struct d3d12_desc *descriptor, }
flags = vkd3d_view_flags_from_d3d12_buffer_srv_flags(desc->u.Buffer.Flags); - if (!vkd3d_create_buffer_view_for_resource(device, resource, desc->Format, + vkd3d_create_buffer_view_for_resource(device, VKD3D_DESCRIPTOR_MAGIC_SRV, resource, desc->Format, desc->u.Buffer.FirstElement, desc->u.Buffer.NumElements, - desc->u.Buffer.StructureByteStride, flags, &view)) - return; - - descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_SRV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - descriptor->s.u.view_info.view = view; - descriptor->s.u.view_info.written_serial_id = view->serial_id; + desc->u.Buffer.StructureByteStride, flags, &descriptor->s.u.view); }
static VkImageAspectFlags vk_image_aspect_flags_from_d3d12_plane_slice(const struct vkd3d_format *format, @@ -2923,7 +2939,6 @@ void d3d12_desc_create_srv(struct d3d12_desc *descriptor, const D3D12_SHADER_RESOURCE_VIEW_DESC *desc) { struct vkd3d_texture_view_desc vkd3d_desc; - struct vkd3d_view *view;
if (!resource) { @@ -3019,13 +3034,8 @@ void d3d12_desc_create_srv(struct d3d12_desc *descriptor, } }
- if (!vkd3d_create_texture_view(device, resource->u.vk_image, &vkd3d_desc, &view)) - return; - - descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_SRV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - descriptor->s.u.view_info.view = view; - descriptor->s.u.view_info.written_serial_id = view->serial_id; + vkd3d_create_texture_view(device, VKD3D_DESCRIPTOR_MAGIC_SRV, resource->u.vk_image, &vkd3d_desc, + &descriptor->s.u.view); }
static unsigned int vkd3d_view_flags_from_d3d12_buffer_uav_flags(D3D12_BUFFER_UAV_FLAGS flags) @@ -3042,7 +3052,6 @@ static void vkd3d_create_null_uav(struct d3d12_desc *descriptor, { struct vkd3d_null_resources *null_resources = &device->null_resources; struct vkd3d_texture_view_desc vkd3d_desc; - struct vkd3d_view *view; VkImage vk_image;
if (!desc) @@ -3057,15 +3066,9 @@ static void vkd3d_create_null_uav(struct d3d12_desc *descriptor, if (!device->vk_info.EXT_robustness2) WARN("Creating NULL buffer UAV %#x.\n", desc->Format);
- if (vkd3d_create_buffer_view(device, null_resources->vk_storage_buffer, + vkd3d_create_buffer_view(device, VKD3D_DESCRIPTOR_MAGIC_UAV, null_resources->vk_storage_buffer, vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false), - 0, VKD3D_NULL_BUFFER_SIZE, &view)) - { - descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_UAV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - descriptor->s.u.view_info.view = view; - descriptor->s.u.view_info.written_serial_id = view->serial_id; - } + 0, VKD3D_NULL_BUFFER_SIZE, &descriptor->s.u.view); return;
case D3D12_UAV_DIMENSION_TEXTURE2D: @@ -3103,13 +3106,7 @@ static void vkd3d_create_null_uav(struct d3d12_desc *descriptor, vkd3d_desc.components.a = VK_COMPONENT_SWIZZLE_A; vkd3d_desc.allowed_swizzle = false;
- if (!vkd3d_create_texture_view(device, vk_image, &vkd3d_desc, &view)) - return; - - descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_UAV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptor->s.u.view_info.view = view; - descriptor->s.u.view_info.written_serial_id = view->serial_id; + vkd3d_create_texture_view(device, VKD3D_DESCRIPTOR_MAGIC_UAV, vk_image, &vkd3d_desc, &descriptor->s.u.view); }
static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_device *device, @@ -3132,16 +3129,11 @@ static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_ }
flags = vkd3d_view_flags_from_d3d12_buffer_uav_flags(desc->u.Buffer.Flags); - if (!vkd3d_create_buffer_view_for_resource(device, resource, desc->Format, + if (!vkd3d_create_buffer_view_for_resource(device, VKD3D_DESCRIPTOR_MAGIC_UAV, resource, desc->Format, desc->u.Buffer.FirstElement, desc->u.Buffer.NumElements, desc->u.Buffer.StructureByteStride, flags, &view)) return;
- descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_UAV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - descriptor->s.u.view_info.view = view; - descriptor->s.u.view_info.written_serial_id = view->serial_id; - if (counter_resource) { const struct vkd3d_format *format; @@ -3151,13 +3143,16 @@ static void vkd3d_create_buffer_uav(struct d3d12_desc *descriptor, struct d3d12_
format = vkd3d_get_format(device, DXGI_FORMAT_R32_UINT, false); if (!vkd3d_create_vk_buffer_view(device, counter_resource->u.vk_buffer, format, - desc->u.Buffer.CounterOffsetInBytes, sizeof(uint32_t), &view->vk_counter_view)) + desc->u.Buffer.CounterOffsetInBytes, sizeof(uint32_t), &view->v.vk_counter_view)) { WARN("Failed to create counter buffer view.\n"); - view->vk_counter_view = VK_NULL_HANDLE; - d3d12_desc_destroy(descriptor, device); + view->v.vk_counter_view = VK_NULL_HANDLE; + vkd3d_view_decref(view, device); + return; } } + + descriptor->s.u.view = view; }
static void vkd3d_create_texture_uav(struct d3d12_desc *descriptor, @@ -3165,7 +3160,6 @@ static void vkd3d_create_texture_uav(struct d3d12_desc *descriptor, const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc) { struct vkd3d_texture_view_desc vkd3d_desc; - struct vkd3d_view *view;
if (!init_default_texture_view_desc(&vkd3d_desc, resource, desc ? desc->Format : 0)) return; @@ -3210,13 +3204,8 @@ static void vkd3d_create_texture_uav(struct d3d12_desc *descriptor, } }
- if (!vkd3d_create_texture_view(device, resource->u.vk_image, &vkd3d_desc, &view)) - return; - - descriptor->s.magic = VKD3D_DESCRIPTOR_MAGIC_UAV; - descriptor->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptor->s.u.view_info.view = view; - descriptor->s.u.view_info.written_serial_id = view->serial_id; + vkd3d_create_texture_view(device, VKD3D_DESCRIPTOR_MAGIC_UAV, resource->u.vk_image, &vkd3d_desc, + &descriptor->s.u.view); }
void d3d12_desc_create_uav(struct d3d12_desc *descriptor, struct d3d12_device *device, @@ -3365,21 +3354,21 @@ void d3d12_desc_create_sampler(struct d3d12_desc *sampler, FIXME("Ignoring border color {%.8e, %.8e, %.8e, %.8e}.\n", desc->BorderColor[0], desc->BorderColor[1], desc->BorderColor[2], desc->BorderColor[3]);
- if (!(view = vkd3d_view_create(VKD3D_VIEW_TYPE_SAMPLER))) + if (!(view = vkd3d_view_create(VKD3D_DESCRIPTOR_MAGIC_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLER, + VKD3D_VIEW_TYPE_SAMPLER, device))) return; + view->v.u.vk_sampler = VK_NULL_HANDLE; + view->v.format = NULL;
if (d3d12_create_sampler(device, desc->Filter, desc->AddressU, desc->AddressV, desc->AddressW, desc->MipLODBias, desc->MaxAnisotropy, - desc->ComparisonFunc, desc->MinLOD, desc->MaxLOD, &view->u.vk_sampler) < 0) + desc->ComparisonFunc, desc->MinLOD, desc->MaxLOD, &view->v.u.vk_sampler) < 0) { - vkd3d_free(view); + vkd3d_view_decref(view, device); return; }
- sampler->s.magic = VKD3D_DESCRIPTOR_MAGIC_SAMPLER; - sampler->s.vk_descriptor_type = VK_DESCRIPTOR_TYPE_SAMPLER; - sampler->s.u.view_info.view = view; - sampler->s.u.view_info.written_serial_id = view->serial_id; + sampler->s.u.view = view; }
HRESULT vkd3d_create_static_sampler(struct d3d12_device *device, @@ -3401,7 +3390,7 @@ HRESULT vkd3d_create_static_sampler(struct d3d12_device *device, /* RTVs */ static void d3d12_rtv_desc_destroy(struct d3d12_rtv_desc *rtv, struct d3d12_device *device) { - if (rtv->magic != VKD3D_DESCRIPTOR_MAGIC_RTV) + if (!rtv->view) return;
vkd3d_view_decref(rtv->view, device); @@ -3480,10 +3469,9 @@ void d3d12_rtv_desc_create_rtv(struct d3d12_rtv_desc *rtv_desc, struct d3d12_dev
assert(d3d12_resource_is_texture(resource));
- if (!vkd3d_create_texture_view(device, resource->u.vk_image, &vkd3d_desc, &view)) + if (!vkd3d_create_texture_view(device, VKD3D_DESCRIPTOR_MAGIC_RTV, resource->u.vk_image, &vkd3d_desc, &view)) return;
- rtv_desc->magic = VKD3D_DESCRIPTOR_MAGIC_RTV; rtv_desc->sample_count = vk_samples_from_dxgi_sample_desc(&resource->desc.SampleDesc); rtv_desc->format = vkd3d_desc.format; rtv_desc->width = d3d12_resource_desc_get_width(&resource->desc, vkd3d_desc.miplevel_idx); @@ -3496,7 +3484,7 @@ void d3d12_rtv_desc_create_rtv(struct d3d12_rtv_desc *rtv_desc, struct d3d12_dev /* DSVs */ static void d3d12_dsv_desc_destroy(struct d3d12_dsv_desc *dsv, struct d3d12_device *device) { - if (dsv->magic != VKD3D_DESCRIPTOR_MAGIC_DSV) + if (!dsv->view) return;
vkd3d_view_decref(dsv->view, device); @@ -3565,10 +3553,9 @@ void d3d12_dsv_desc_create_dsv(struct d3d12_dsv_desc *dsv_desc, struct d3d12_dev
assert(d3d12_resource_is_texture(resource));
- if (!vkd3d_create_texture_view(device, resource->u.vk_image, &vkd3d_desc, &view)) + if (!vkd3d_create_texture_view(device, VKD3D_DESCRIPTOR_MAGIC_DSV, resource->u.vk_image, &vkd3d_desc, &view)) return;
- dsv_desc->magic = VKD3D_DESCRIPTOR_MAGIC_DSV; dsv_desc->sample_count = vk_samples_from_dxgi_sample_desc(&resource->desc.SampleDesc); dsv_desc->format = vkd3d_desc.format; dsv_desc->width = d3d12_resource_desc_get_width(&resource->desc, vkd3d_desc.miplevel_idx); diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 24eebf30..7869829a 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -44,13 +44,11 @@
#define VK_CALL(f) (vk_procs->f)
-#define VKD3D_DESCRIPTOR_MAGIC_HAS_VIEW 0x01000000u - #define VKD3D_DESCRIPTOR_MAGIC_FREE 0x00000000u #define VKD3D_DESCRIPTOR_MAGIC_CBV VKD3D_MAKE_TAG('C', 'B', 'V', 0) -#define VKD3D_DESCRIPTOR_MAGIC_SRV VKD3D_MAKE_TAG('S', 'R', 'V', 1) -#define VKD3D_DESCRIPTOR_MAGIC_UAV VKD3D_MAKE_TAG('U', 'A', 'V', 1) -#define VKD3D_DESCRIPTOR_MAGIC_SAMPLER VKD3D_MAKE_TAG('S', 'M', 'P', 1) +#define VKD3D_DESCRIPTOR_MAGIC_SRV VKD3D_MAKE_TAG('S', 'R', 'V', 0) +#define VKD3D_DESCRIPTOR_MAGIC_UAV VKD3D_MAKE_TAG('U', 'A', 'V', 0) +#define VKD3D_DESCRIPTOR_MAGIC_SAMPLER VKD3D_MAKE_TAG('S', 'M', 'P', 0) #define VKD3D_DESCRIPTOR_MAGIC_DSV VKD3D_MAKE_TAG('D', 'S', 'V', 0) #define VKD3D_DESCRIPTOR_MAGIC_RTV VKD3D_MAKE_TAG('R', 'T', 'V', 0)
@@ -662,11 +660,9 @@ enum vkd3d_view_type VKD3D_VIEW_TYPE_SAMPLER, };
-struct vkd3d_view +struct vkd3d_resource_view { - LONG refcount; enum vkd3d_view_type type; - uint64_t serial_id; union { VkBufferView vk_buffer_view; @@ -692,9 +688,6 @@ struct vkd3d_view } info; };
-void vkd3d_view_decref(struct vkd3d_view *view, struct d3d12_device *device); -void vkd3d_view_incref(struct vkd3d_view *view); - struct vkd3d_texture_view_desc { VkImageViewType view_type; @@ -708,33 +701,88 @@ struct vkd3d_texture_view_desc bool allowed_swizzle; };
-bool vkd3d_create_buffer_view(struct d3d12_device *device, VkBuffer vk_buffer, const struct vkd3d_format *format, - VkDeviceSize offset, VkDeviceSize size, struct vkd3d_view **view); -bool vkd3d_create_texture_view(struct d3d12_device *device, VkImage vk_image, +struct vkd3d_desc_header +{ + uint32_t magic; + LONG volatile refcount; + void *next; + VkDescriptorType vk_descriptor_type; +}; + +struct vkd3d_view +{ + struct vkd3d_desc_header h; + struct vkd3d_resource_view v; +}; + +bool vkd3d_create_buffer_view(struct d3d12_device *device, uint32_t magic, VkBuffer vk_buffer, + const struct vkd3d_format *format, VkDeviceSize offset, VkDeviceSize size, struct vkd3d_view **view); +bool vkd3d_create_texture_view(struct d3d12_device *device, uint32_t magic, VkImage vk_image, const struct vkd3d_texture_view_desc *desc, struct vkd3d_view **view);
-struct vkd3d_view_info +struct vkd3d_cbuffer_desc { - uint64_t written_serial_id; - struct vkd3d_view *view; + struct vkd3d_desc_header h; + VkDescriptorBufferInfo vk_cbv_info; };
struct d3d12_desc { struct { - uint32_t magic; - VkDescriptorType vk_descriptor_type; - union + union d3d12_desc_object { - VkDescriptorBufferInfo vk_cbv_info; - struct vkd3d_view_info view_info; + struct vkd3d_desc_header *header; + struct vkd3d_view *view; + struct vkd3d_cbuffer_desc *cb_desc; + void *object; } u; } s; unsigned int index; LONG next; };
+void vkd3d_view_decref(void *view, struct d3d12_device *device); + +static inline bool vkd3d_view_incref(void *desc) +{ + struct vkd3d_desc_header *h = desc; + LONG refcount; + + do + { + refcount = h->refcount; + /* Avoid incrementing a freed object. Reading the value is safe because objects are recycled. */ + if (refcount <= 0) + return false; + } + while (InterlockedCompareExchange(&h->refcount, refcount + 1, refcount) != refcount); + + return true; +} + +static inline void *d3d12_desc_get_object_ref(const volatile struct d3d12_desc *src, struct d3d12_device *device) +{ + void *view; + + /* Some games, e.g. Shadow of the Tomb Raider, GRID 2019, and Horizon Zero Dawn, write descriptors + * from multiple threads without syncronisation. This is apparently valid in Windows. */ + for (;;) + { + do + { + view = src->s.u.object; + } while (view && !vkd3d_view_incref(view)); + + /* Check if the object is still in src to handle the case where it was + * already freed and reused elsewhere when the refcount was incremented. */ + if (view == src->s.u.object) + return view; + + vkd3d_view_decref(view, device); + } +} + static inline struct d3d12_desc *d3d12_desc_from_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle) { return (struct d3d12_desc *)cpu_handle.ptr; @@ -769,7 +817,6 @@ HRESULT vkd3d_create_static_sampler(struct d3d12_device *device,
struct d3d12_rtv_desc { - uint32_t magic; VkSampleCountFlagBits sample_count; const struct vkd3d_format *format; uint64_t width; @@ -789,7 +836,6 @@ void d3d12_rtv_desc_create_rtv(struct d3d12_rtv_desc *rtv_desc, struct d3d12_dev
struct d3d12_dsv_desc { - uint32_t magic; VkSampleCountFlagBits sample_count; const struct vkd3d_format *format; uint64_t width; @@ -883,22 +929,6 @@ static inline unsigned int d3d12_desc_heap_range_size(const struct d3d12_desc *d HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device, const D3D12_DESCRIPTOR_HEAP_DESC *desc, struct d3d12_descriptor_heap **descriptor_heap);
-struct d3d12_desc_copy_location -{ - struct d3d12_desc src; - struct d3d12_desc *dst; -}; - -struct d3d12_desc_copy_info -{ - unsigned int count; - bool uav_counter; -}; - -void d3d12_desc_copy_vk_heap_range(struct d3d12_desc_copy_location *locations, const struct d3d12_desc_copy_info *info, - struct d3d12_descriptor_heap *descriptor_heap, enum vkd3d_vk_descriptor_set_index set, - struct d3d12_device *device); - /* ID3D12QueryHeap */ struct d3d12_query_heap { @@ -1486,6 +1516,12 @@ struct vkd3d_uav_clear_state HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d3d12_device *device); void vkd3d_uav_clear_state_cleanup(struct vkd3d_uav_clear_state *state, struct d3d12_device *device);
+struct vkd3d_desc_object_cache +{ + void * volatile head; + size_t stride; +}; + #define VKD3D_DESCRIPTOR_POOL_COUNT 6
/* ID3D12Device */ @@ -1503,7 +1539,8 @@ struct d3d12_device struct vkd3d_gpu_va_allocator gpu_va_allocator;
struct vkd3d_mutex mutex; - struct vkd3d_mutex desc_mutex[8]; + struct vkd3d_desc_object_cache view_desc_cache; + struct vkd3d_desc_object_cache cbuffer_desc_cache; struct vkd3d_render_pass_cache render_pass_cache; VkPipelineCache vk_pipeline_cache;
@@ -1578,19 +1615,6 @@ static inline unsigned int d3d12_device_get_descriptor_handle_increment_size(str return ID3D12Device_GetDescriptorHandleIncrementSize(&device->ID3D12Device_iface, descriptor_type); }
-static inline struct vkd3d_mutex *d3d12_device_get_descriptor_mutex(struct d3d12_device *device, - const struct d3d12_desc *descriptor) -{ - STATIC_ASSERT(!(ARRAY_SIZE(device->desc_mutex) & (ARRAY_SIZE(device->desc_mutex) - 1))); - uintptr_t idx = (uintptr_t)descriptor; - - idx ^= idx >> 12; - idx ^= idx >> 6; - idx ^= idx >> 3; - - return &device->desc_mutex[idx & (ARRAY_SIZE(device->desc_mutex) - 1)]; -} - /* utils */ enum vkd3d_format_type {
From: Conor McCarthy cmccarthy@codeweavers.com
Reduces the cost of calling vkUpdateDescriptorSets() via winevulkan and its thunks. The performance gain can be as high as 20%. --- libs/vkd3d/resource.c | 201 +++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 80 deletions(-)
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index b425dedd..d1090f8e 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -2158,73 +2158,91 @@ static inline void d3d12_desc_replace(struct d3d12_desc *dst, void *view, struct vkd3d_view_decref(view, device); }
+#define VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE 24 + +struct descriptor_writes +{ + VkDescriptorBufferInfo null_vk_cbv_info; + VkBufferView null_vk_buffer_view; + VkDescriptorImageInfo vk_image_infos[VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE]; + VkWriteDescriptorSet vk_descriptor_writes[VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE]; + void *held_refs[VKD3D_DESCRIPTOR_WRITE_BUFFER_SIZE]; + unsigned int count; + unsigned int held_ref_count; +}; + +static void descriptor_writes_free_object_refs(struct descriptor_writes *writes, struct d3d12_device *device) +{ + unsigned int i; + for (i = 0; i < writes->held_ref_count; ++i) + vkd3d_view_decref(writes->held_refs[i], device); + writes->held_ref_count = 0; +} + static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_heap *descriptor_heap, - uint32_t dst_array_element, struct d3d12_device *device) + uint32_t dst_array_element, struct descriptor_writes *writes, struct d3d12_device *device) { - VkWriteDescriptorSet vk_descriptor_writes[VKD3D_SET_INDEX_STORAGE_IMAGE + 1]; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct d3d12_descriptor_heap_vk_set *descriptor_set; - VkBufferView vk_buffer_view = VK_NULL_HANDLE; - VkDescriptorImageInfo vk_image_infos[2]; - enum vkd3d_vk_descriptor_set_index i; - VkDescriptorBufferInfo vk_cbv_info; - - vk_cbv_info.buffer = VK_NULL_HANDLE; - vk_cbv_info.offset = 0; - vk_cbv_info.range = VK_WHOLE_SIZE; - memset(vk_image_infos, 0, sizeof(vk_image_infos)); - vk_image_infos[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - vk_image_infos[1].imageLayout = VK_IMAGE_LAYOUT_GENERAL; + enum vkd3d_vk_descriptor_set_index set; + unsigned int i = writes->count;
/* Binding a shader with the wrong null descriptor type works in Windows. * To support that here we must write one to all applicable Vulkan sets. */ - for (i = VKD3D_SET_INDEX_UNIFORM_BUFFER; i <= VKD3D_SET_INDEX_STORAGE_IMAGE; ++i) - { - descriptor_set = &descriptor_heap->vk_descriptor_sets[i]; - vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - vk_descriptor_writes[i].pNext = NULL; - vk_descriptor_writes[i].dstSet = descriptor_set->vk_set; - vk_descriptor_writes[i].dstBinding = 0; - vk_descriptor_writes[i].dstArrayElement = dst_array_element; - vk_descriptor_writes[i].descriptorCount = 1; - vk_descriptor_writes[i].descriptorType = descriptor_set->vk_type; - switch (i) + for (set = VKD3D_SET_INDEX_UNIFORM_BUFFER; set <= VKD3D_SET_INDEX_STORAGE_IMAGE; ++set) + { + descriptor_set = &descriptor_heap->vk_descriptor_sets[set]; + writes->vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes->vk_descriptor_writes[i].pNext = NULL; + writes->vk_descriptor_writes[i].dstSet = descriptor_set->vk_set; + writes->vk_descriptor_writes[i].dstBinding = 0; + writes->vk_descriptor_writes[i].dstArrayElement = dst_array_element; + writes->vk_descriptor_writes[i].descriptorCount = 1; + writes->vk_descriptor_writes[i].descriptorType = descriptor_set->vk_type; + switch (set) { case VKD3D_SET_INDEX_UNIFORM_BUFFER: - vk_descriptor_writes[i].pImageInfo = NULL; - vk_descriptor_writes[i].pBufferInfo = &vk_cbv_info; - vk_descriptor_writes[i].pTexelBufferView = NULL; + writes->vk_descriptor_writes[i].pImageInfo = NULL; + writes->vk_descriptor_writes[i].pBufferInfo = &writes->null_vk_cbv_info; + writes->vk_descriptor_writes[i].pTexelBufferView = NULL; break; case VKD3D_SET_INDEX_SAMPLED_IMAGE: case VKD3D_SET_INDEX_STORAGE_IMAGE: - vk_descriptor_writes[i].pImageInfo = &vk_image_infos[i == VKD3D_SET_INDEX_STORAGE_IMAGE]; - vk_descriptor_writes[i].pBufferInfo = NULL; - vk_descriptor_writes[i].pTexelBufferView = NULL; + writes->vk_descriptor_writes[i].pImageInfo = &writes->vk_image_infos[i]; + writes->vk_descriptor_writes[i].pBufferInfo = NULL; + writes->vk_descriptor_writes[i].pTexelBufferView = NULL; + writes->vk_image_infos[i].sampler = VK_NULL_HANDLE; + writes->vk_image_infos[i].imageView = VK_NULL_HANDLE; + writes->vk_image_infos[i].imageLayout = (set == VKD3D_SET_INDEX_STORAGE_IMAGE) + ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; break; case VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER: case VKD3D_SET_INDEX_STORAGE_TEXEL_BUFFER: - vk_descriptor_writes[i].pImageInfo = NULL; - vk_descriptor_writes[i].pBufferInfo = NULL; - vk_descriptor_writes[i].pTexelBufferView = &vk_buffer_view; + writes->vk_descriptor_writes[i].pImageInfo = NULL; + writes->vk_descriptor_writes[i].pBufferInfo = NULL; + writes->vk_descriptor_writes[i].pTexelBufferView = &writes->null_vk_buffer_view; break; default: assert(false); break; } + if (++i < ARRAY_SIZE(writes->vk_descriptor_writes) - 1) + continue; + VK_CALL(vkUpdateDescriptorSets(device->vk_device, i, writes->vk_descriptor_writes, 0, NULL)); + descriptor_writes_free_object_refs(writes, device); + i = 0; }
- VK_CALL(vkUpdateDescriptorSets(device->vk_device, i, vk_descriptor_writes, 0, NULL)); + writes->count = i; }
static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_heap, unsigned int dst_array_element, - void *object, struct d3d12_device *device) + struct descriptor_writes *writes, void *object, struct d3d12_device *device) { struct d3d12_descriptor_heap_vk_set *descriptor_set; const struct vkd3d_vk_device_procs *vk_procs; - VkWriteDescriptorSet vk_descriptor_writes[2]; union d3d12_desc_object u = {object}; - VkDescriptorImageInfo vk_image_info; - unsigned int count = 1; + unsigned int i = writes->count; VkDescriptorType type; bool is_null = false;
@@ -2232,79 +2250,98 @@ static void d3d12_desc_write_vk_heap(struct d3d12_descriptor_heap *descriptor_he descriptor_set = &descriptor_heap->vk_descriptor_sets[vkd3d_vk_descriptor_set_index_from_vk_descriptor_type(type)]; vk_procs = &device->vk_procs;
- vk_descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - vk_descriptor_writes[0].pNext = NULL; - vk_descriptor_writes[0].dstSet = descriptor_set->vk_set; - vk_descriptor_writes[0].dstBinding = 0; - vk_descriptor_writes[0].dstArrayElement = dst_array_element; - vk_descriptor_writes[0].descriptorCount = 1; - vk_descriptor_writes[0].descriptorType = type; + writes->vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes->vk_descriptor_writes[i].pNext = NULL; + writes->vk_descriptor_writes[i].dstSet = descriptor_set->vk_set; + writes->vk_descriptor_writes[i].dstBinding = 0; + writes->vk_descriptor_writes[i].dstArrayElement = dst_array_element; + writes->vk_descriptor_writes[i].descriptorCount = 1; + writes->vk_descriptor_writes[i].descriptorType = type; switch (type) { case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - vk_descriptor_writes[0].pImageInfo = NULL; - vk_descriptor_writes[0].pBufferInfo = &u.cb_desc->vk_cbv_info; - vk_descriptor_writes[0].pTexelBufferView = NULL; + writes->vk_descriptor_writes[i].pImageInfo = NULL; + writes->vk_descriptor_writes[i].pBufferInfo = &u.cb_desc->vk_cbv_info; + writes->vk_descriptor_writes[i].pTexelBufferView = NULL; is_null = !u.cb_desc->vk_cbv_info.buffer; break; case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - vk_descriptor_writes[0].pImageInfo = &vk_image_info; - vk_descriptor_writes[0].pBufferInfo = NULL; - vk_descriptor_writes[0].pTexelBufferView = NULL; - vk_image_info.sampler = VK_NULL_HANDLE; - is_null = !(vk_image_info.imageView = u.view->v.u.vk_image_view); - vk_image_info.imageLayout = (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) + writes->vk_descriptor_writes[i].pImageInfo = &writes->vk_image_infos[i]; + writes->vk_descriptor_writes[i].pBufferInfo = NULL; + writes->vk_descriptor_writes[i].pTexelBufferView = NULL; + writes->vk_image_infos[i].sampler = VK_NULL_HANDLE; + is_null = !(writes->vk_image_infos[i].imageView = u.view->v.u.vk_image_view); + writes->vk_image_infos[i].imageLayout = (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; break; case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - vk_descriptor_writes[0].pImageInfo = NULL; - vk_descriptor_writes[0].pBufferInfo = NULL; - vk_descriptor_writes[0].pTexelBufferView = &u.view->v.u.vk_buffer_view; + writes->vk_descriptor_writes[i].pImageInfo = NULL; + writes->vk_descriptor_writes[i].pBufferInfo = NULL; + writes->vk_descriptor_writes[i].pTexelBufferView = &u.view->v.u.vk_buffer_view; is_null = !u.view->v.u.vk_buffer_view; break; case VK_DESCRIPTOR_TYPE_SAMPLER: - vk_descriptor_writes[0].pImageInfo = &vk_image_info; - vk_descriptor_writes[0].pBufferInfo = NULL; - vk_descriptor_writes[0].pTexelBufferView = NULL; - vk_image_info.sampler = u.view->v.u.vk_sampler; - vk_image_info.imageView = VK_NULL_HANDLE; - vk_image_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + writes->vk_descriptor_writes[i].pImageInfo = &writes->vk_image_infos[i]; + writes->vk_descriptor_writes[i].pBufferInfo = NULL; + writes->vk_descriptor_writes[i].pTexelBufferView = NULL; + writes->vk_image_infos[i].sampler = u.view->v.u.vk_sampler; + writes->vk_image_infos[i].imageView = VK_NULL_HANDLE; + writes->vk_image_infos[i].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; break; default: ERR("Unhandled descriptor type %#x.\n", type); break; } if (is_null && device->vk_info.EXT_robustness2) - return d3d12_desc_write_vk_heap_null_descriptor(descriptor_heap, dst_array_element, device); + return d3d12_desc_write_vk_heap_null_descriptor(descriptor_heap, dst_array_element, writes, device);
+ ++i; if (u.header->magic == VKD3D_DESCRIPTOR_MAGIC_UAV && u.view->v.vk_counter_view) { descriptor_set = &descriptor_heap->vk_descriptor_sets[VKD3D_SET_INDEX_UAV_COUNTER]; - vk_descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - vk_descriptor_writes[1].pNext = NULL; - vk_descriptor_writes[1].dstSet = descriptor_set->vk_set; - vk_descriptor_writes[1].dstBinding = 0; - vk_descriptor_writes[1].dstArrayElement = dst_array_element; - vk_descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - vk_descriptor_writes[1].descriptorCount = 1; - vk_descriptor_writes[1].pImageInfo = NULL; - vk_descriptor_writes[1].pBufferInfo = NULL; - vk_descriptor_writes[1].pTexelBufferView = &u.view->v.vk_counter_view; - ++count; + writes->vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes->vk_descriptor_writes[i].pNext = NULL; + writes->vk_descriptor_writes[i].dstSet = descriptor_set->vk_set; + writes->vk_descriptor_writes[i].dstBinding = 0; + writes->vk_descriptor_writes[i].dstArrayElement = dst_array_element; + writes->vk_descriptor_writes[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + writes->vk_descriptor_writes[i].descriptorCount = 1; + writes->vk_descriptor_writes[i].pImageInfo = NULL; + writes->vk_descriptor_writes[i].pBufferInfo = NULL; + writes->vk_descriptor_writes[i++].pTexelBufferView = &u.view->v.vk_counter_view; }
- VK_CALL(vkUpdateDescriptorSets(device->vk_device, count, vk_descriptor_writes, 0, NULL)); + if (i >= ARRAY_SIZE(writes->vk_descriptor_writes) - 1) + { + VK_CALL(vkUpdateDescriptorSets(device->vk_device, i, writes->vk_descriptor_writes, 0, NULL)); + descriptor_writes_free_object_refs(writes, device); + i = 0; + } + + writes->count = i; }
void d3d12_desc_flush_vk_heap_updates(struct d3d12_descriptor_heap *descriptor_heap, struct d3d12_device *device) { + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; struct d3d12_desc *descriptors, *src; + struct descriptor_writes writes; union d3d12_desc_object u; unsigned int i, next;
- i = InterlockedExchange(&descriptor_heap->dirty_list_head, UINT_MAX); + if ((i = InterlockedExchange(&descriptor_heap->dirty_list_head, UINT_MAX)) == UINT_MAX) + return; + + descriptors = (struct d3d12_desc *)descriptor_heap->descriptors; + + writes.null_vk_cbv_info.buffer = VK_NULL_HANDLE; + writes.null_vk_cbv_info.offset = 0; + writes.null_vk_cbv_info.range = VK_WHOLE_SIZE; + writes.null_vk_buffer_view = VK_NULL_HANDLE; + writes.count = 0; + writes.held_ref_count = 0;
descriptors = (struct d3d12_desc *)descriptor_heap->descriptors;
@@ -2321,12 +2358,16 @@ void d3d12_desc_flush_vk_heap_updates(struct d3d12_descriptor_heap *descriptor_h continue; }
- d3d12_desc_write_vk_heap(descriptor_heap, i, u.object, device); - - vkd3d_view_decref(u.object, device); + writes.held_refs[writes.held_ref_count++] = u.object; + d3d12_desc_write_vk_heap(descriptor_heap, i, &writes, u.object, device);
InterlockedExchange(&src->next, 0); } + + /* Avoid thunk calls wherever possible. */ + if (writes.count) + VK_CALL(vkUpdateDescriptorSets(device->vk_device, writes.count, writes.vk_descriptor_writes, 0, NULL)); + descriptor_writes_free_object_refs(&writes, device); }
static void d3d12_desc_mark_as_modified(struct d3d12_desc *dst)
Zebediah Figura (@zfigura) commented about libs/vkd3d/resource.c:
return S_OK;
}
+STATIC_ASSERT(!(offsetof(struct d3d12_descriptor_heap, descriptors) & (sizeof(void *) - 1)));
I think we have DECLSPEC_ALIGN we could use?