diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index c264a915..fb6b40b2 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, @@ -4852,7 +4858,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); @@ -4876,7 +4882,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); @@ -4968,7 +4974,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; @@ -5171,13 +5177,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; @@ -5189,8 +5196,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; @@ -5303,10 +5311,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; @@ -5314,7 +5323,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) @@ -5328,8 +5339,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; @@ -5345,16 +5356,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); @@ -5373,7 +5385,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..93274bc9 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 size) +{ + cache->head = NULL; + cache->size = size; +} + +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 5b6804f7..b9de98d0 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) +{ + union d3d12_desc_object u; + void *next; + + do + { + u.object = cache->head; + if (!u.object) + return vkd3d_malloc(cache->size); + next = u.header->next; + } + while (!vkd3d_atomic_compare_exchange_pointer(&cache->head, u.object, next)); + + 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 (!vkd3d_atomic_compare_exchange_pointer(&cache->head, head, u.object)); +} + +static struct vkd3d_cbuffer_desc *vkd3d_cbuffer_desc_create(struct d3d12_device *device) +{ + 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; - if ((view = vkd3d_malloc(sizeof(*view)))) - { - view->refcount = 1; - view->type = type; - view->serial_id = InterlockedIncrement64(&object_global_serial_id); - view->vk_counter_view = VK_NULL_HANDLE; - } - return view; -} + assert(magic); -void vkd3d_view_incref(struct vkd3d_view *view) -{ - InterlockedIncrement(&view->refcount); + 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 (vkd3d_atomic_decrement(&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 = vkd3d_atomic_exchange_pointer(&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 = vkd3d_atomic_exchange(&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 = (int)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); + vkd3d_atomic_exchange(&src->next, 0); + continue; } + d3d12_desc_write_vk_heap(descriptor_heap, i, u.object, device); + + vkd3d_view_decref(u.object, device); + vkd3d_atomic_exchange(&src->next, 0); } } @@ -2296,56 +2352,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; + void *object = src->s.u.object; - 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); - - /* 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); } @@ -2407,8 +2433,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; @@ -2417,16 +2444,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; } @@ -2434,7 +2463,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) { @@ -2465,7 +2494,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); } @@ -2693,7 +2722,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; @@ -2726,18 +2755,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; } @@ -2746,6 +2776,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) @@ -2754,13 +2785,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); @@ -2776,8 +2813,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) @@ -2794,7 +2830,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) @@ -2809,15 +2844,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: @@ -2856,20 +2885,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) @@ -2885,15 +2907,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, @@ -2922,7 +2938,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) { @@ -3023,13 +3038,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) @@ -3046,7 +3056,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) @@ -3061,15 +3070,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: @@ -3107,13 +3110,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, @@ -3136,16 +3133,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; @@ -3155,13 +3147,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, @@ -3169,7 +3164,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; @@ -3217,13 +3211,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, @@ -3386,21 +3375,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, @@ -3422,7 +3411,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); @@ -3501,10 +3490,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); @@ -3517,7 +3505,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); @@ -3586,10 +3574,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 2e879ad4..88dc5772 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) @@ -252,6 +250,11 @@ static inline void vkd3d_cond_destroy(struct vkd3d_cond *cond) { } +static inline unsigned int vkd3d_atomic_decrement(unsigned int volatile *x) +{ + return InterlockedDecrement((LONG volatile *)x); +} + static inline bool vkd3d_atomic_compare_exchange(unsigned int volatile *x, unsigned int cmp, unsigned int xchg) { return InterlockedCompareExchange((LONG volatile *)x, xchg, cmp) == cmp; @@ -262,6 +265,16 @@ static inline unsigned int vkd3d_atomic_exchange(unsigned int volatile *x, unsig return InterlockedExchange((LONG volatile *)x, val); } +static inline bool vkd3d_atomic_compare_exchange_pointer(void * volatile *x, void *cmp, void *xchg) +{ + return InterlockedCompareExchangePointer(x, xchg, cmp) == cmp; +} + +static inline void *vkd3d_atomic_exchange_pointer(void * volatile *x, void *val) +{ + return InterlockedExchangePointer(x, val); +} + #else /* _WIN32 */ #include @@ -364,11 +377,25 @@ static inline void vkd3d_cond_destroy(struct vkd3d_cond *cond) ERR("Could not destroy the condition variable, error %d.\n", ret); } +# if HAVE_SYNC_SUB_AND_FETCH +static inline unsigned int vkd3d_atomic_decrement(unsigned int volatile *x) +{ + return __sync_sub_and_fetch(x, 1); +} +# else +# error "vkd3d_atomic_decrement() not implemented for this platform" +# endif /* HAVE_SYNC_ADD_AND_FETCH */ + # if HAVE_SYNC_BOOL_COMPARE_AND_SWAP static inline bool vkd3d_atomic_compare_exchange(unsigned int volatile *x, unsigned int cmp, unsigned int xchg) { return __sync_bool_compare_and_swap(x, cmp, xchg); } + +static inline bool vkd3d_atomic_compare_exchange_pointer(void * volatile *x, void *cmp, void *xchg) +{ + return __sync_bool_compare_and_swap(x, cmp, xchg); +} # else # error "vkd3d_atomic_compare_exchange() not implemented for this platform" # endif @@ -378,6 +405,11 @@ static inline unsigned int vkd3d_atomic_exchange(unsigned int volatile *x, unsig { return __atomic_exchange_n(x, val, __ATOMIC_SEQ_CST); } + +static inline void *vkd3d_atomic_exchange_pointer(void * volatile *x, void *val) +{ + return __atomic_exchange_n(x, val, __ATOMIC_SEQ_CST); +} # elif HAVE_SYNC_BOOL_COMPARE_AND_SWAP static inline unsigned int vkd3d_atomic_exchange(unsigned int volatile *x, unsigned int val) { @@ -388,6 +420,16 @@ static inline unsigned int vkd3d_atomic_exchange(unsigned int volatile *x, unsig } while (!__sync_bool_compare_and_swap(x, i, val)); return i; } + +static inline void *vkd3d_atomic_exchange_pointer(void * volatile *x, void *val) +{ + void *p; + do + { + p = *x; + } while (!__sync_bool_compare_and_swap(x, p, val)); + return p; +} # else # error "vkd3d_atomic_exchange() not implemented for this platform" # endif @@ -700,11 +742,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; @@ -730,9 +770,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; @@ -746,33 +783,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; + unsigned int 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; unsigned int 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; + unsigned int 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 (!vkd3d_atomic_compare_exchange(&h->refcount, refcount, refcount + 1)); + + 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; @@ -807,7 +899,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; @@ -827,7 +918,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; @@ -920,22 +1010,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 { @@ -1523,6 +1597,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 size; +}; + #define VKD3D_DESCRIPTOR_POOL_COUNT 6 /* ID3D12Device */ @@ -1540,7 +1620,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; @@ -1615,19 +1696,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 {