summaryrefslogtreecommitdiff
path: root/src/microsoft/vulkan/dzn_descriptor_set.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microsoft/vulkan/dzn_descriptor_set.c')
-rw-r--r--src/microsoft/vulkan/dzn_descriptor_set.c1818
1 files changed, 1818 insertions, 0 deletions
diff --git a/src/microsoft/vulkan/dzn_descriptor_set.c b/src/microsoft/vulkan/dzn_descriptor_set.c
new file mode 100644
index 00000000000..b19da113a33
--- /dev/null
+++ b/src/microsoft/vulkan/dzn_descriptor_set.c
@@ -0,0 +1,1818 @@
+/*
+ * Copyright © Microsoft Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "dzn_private.h"
+
+#include "vk_alloc.h"
+#include "vk_descriptors.h"
+#include "vk_util.h"
+
+static D3D12_SHADER_VISIBILITY
+translate_desc_visibility(VkShaderStageFlags in)
+{
+ switch (in) {
+ case VK_SHADER_STAGE_VERTEX_BIT: return D3D12_SHADER_VISIBILITY_VERTEX;
+ case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return D3D12_SHADER_VISIBILITY_HULL;
+ case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return D3D12_SHADER_VISIBILITY_DOMAIN;
+ case VK_SHADER_STAGE_GEOMETRY_BIT: return D3D12_SHADER_VISIBILITY_GEOMETRY;
+ case VK_SHADER_STAGE_FRAGMENT_BIT: return D3D12_SHADER_VISIBILITY_PIXEL;
+ default: return D3D12_SHADER_VISIBILITY_ALL;
+ }
+}
+
+static D3D12_DESCRIPTOR_RANGE_TYPE
+desc_type_to_range_type(VkDescriptorType in, bool writeable)
+{
+ switch (in) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ return D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ return D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ return D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ return writeable ? D3D12_DESCRIPTOR_RANGE_TYPE_UAV : D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ default:
+ unreachable("Unsupported desc type");
+ }
+}
+
+static bool
+is_dynamic_desc_type(VkDescriptorType desc_type)
+{
+ return (desc_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
+ desc_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
+}
+
+static bool
+dzn_descriptor_type_depends_on_shader_usage(VkDescriptorType type)
+{
+ return type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER ||
+ type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
+ type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
+ type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
+}
+
+static uint32_t
+num_descs_for_type(VkDescriptorType type, bool static_sampler)
+{
+ unsigned num_descs = 1;
+
+ /* Some type map to an SRV or UAV depending on how the shaders is using the
+ * resource (NONWRITEABLE flag set or not), in that case we need to reserve
+ * slots for both the UAV and SRV descs.
+ */
+ if (dzn_descriptor_type_depends_on_shader_usage(type))
+ num_descs++;
+
+ /* There's no combined SRV+SAMPLER type in d3d12, we need an descriptor
+ * for the sampler.
+ */
+ if (type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+ num_descs++;
+
+ /* Don't count immutable samplers, they have their own descriptor. */
+ if (static_sampler &&
+ (type == VK_DESCRIPTOR_TYPE_SAMPLER ||
+ type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
+ num_descs--;
+
+ return num_descs;
+}
+
+static void
+dzn_descriptor_set_layout_destroy(struct dzn_descriptor_set_layout *set_layout,
+ const VkAllocationCallbacks *pAllocator)
+{
+ if (!set_layout)
+ return;
+
+ struct dzn_device *device = container_of(set_layout->base.device, struct dzn_device, vk);
+
+ vk_object_base_finish(&set_layout->base);
+ vk_free2(&device->vk.alloc, pAllocator, set_layout);
+}
+
+static VkResult
+dzn_descriptor_set_layout_create(struct dzn_device *device,
+ const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkDescriptorSetLayout *out)
+{
+ const VkDescriptorSetLayoutBinding *bindings = pCreateInfo->pBindings;
+ uint32_t binding_count = 0, static_sampler_count = 0, total_ranges = 0;
+ uint32_t dynamic_ranges_offset = 0, immutable_sampler_count = 0;
+ uint32_t range_count[MAX_SHADER_VISIBILITIES][NUM_POOL_TYPES] = { 0 };
+
+ for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
+ binding_count = MAX2(binding_count, bindings[i].binding + 1);
+
+ if (!bindings[i].descriptorCount)
+ continue;
+
+ D3D12_SHADER_VISIBILITY visibility =
+ translate_desc_visibility(bindings[i].stageFlags);
+ VkDescriptorType desc_type = bindings[i].descriptorType;
+ bool has_sampler =
+ desc_type == VK_DESCRIPTOR_TYPE_SAMPLER ||
+ desc_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+
+ /* From the Vulkan 1.1.97 spec for VkDescriptorSetLayoutBinding:
+ *
+ * "If descriptorType specifies a VK_DESCRIPTOR_TYPE_SAMPLER or
+ * VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER type descriptor, then
+ * pImmutableSamplers can be used to initialize a set of immutable
+ * samplers. [...] If descriptorType is not one of these descriptor
+ * types, then pImmutableSamplers is ignored.
+ *
+ * We need to be careful here and only parse pImmutableSamplers if we
+ * have one of the right descriptor types.
+ */
+ bool immutable_samplers =
+ has_sampler &&
+ bindings[i].pImmutableSamplers != NULL;
+ bool static_sampler = false;
+
+ if (immutable_samplers && bindings[i].descriptorCount == 1) {
+ VK_FROM_HANDLE(dzn_sampler, sampler, bindings[i].pImmutableSamplers[0]);
+
+ if (sampler->static_border_color != -1)
+ static_sampler = true;
+ }
+
+ if (static_sampler) {
+ static_sampler_count += bindings[i].descriptorCount;
+ } else if (has_sampler) {
+ range_count[visibility][D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER]++;
+ total_ranges++;
+
+ if (immutable_samplers)
+ immutable_sampler_count += bindings[i].descriptorCount;
+ }
+
+ if (desc_type != VK_DESCRIPTOR_TYPE_SAMPLER) {
+ range_count[visibility][D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV]++;
+ total_ranges++;
+
+ if (dzn_descriptor_type_depends_on_shader_usage(desc_type)) {
+ range_count[visibility][D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV]++;
+ total_ranges++;
+ }
+
+ if (!is_dynamic_desc_type(desc_type)) {
+ uint32_t factor =
+ dzn_descriptor_type_depends_on_shader_usage(desc_type) ? 2 : 1;
+ dynamic_ranges_offset += bindings[i].descriptorCount * factor;
+ }
+ }
+ }
+
+ /* We need to allocate decriptor set layouts off the device allocator
+ * with DEVICE scope because they are reference counted and may not be
+ * destroyed when vkDestroyDescriptorSetLayout is called.
+ */
+ VK_MULTIALLOC(ma);
+ VK_MULTIALLOC_DECL(&ma, struct dzn_descriptor_set_layout, set_layout, 1);
+ VK_MULTIALLOC_DECL(&ma, D3D12_DESCRIPTOR_RANGE1,
+ ranges, total_ranges);
+ VK_MULTIALLOC_DECL(&ma, D3D12_STATIC_SAMPLER_DESC, static_samplers,
+ static_sampler_count);
+ VK_MULTIALLOC_DECL(&ma, const struct dzn_sampler *, immutable_samplers,
+ immutable_sampler_count);
+ VK_MULTIALLOC_DECL(&ma, struct dzn_descriptor_set_layout_binding, binfos,
+ binding_count);
+
+ if (!vk_multialloc_zalloc2(&ma, &device->vk.alloc, pAllocator,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT))
+ return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ vk_object_base_init(&device->vk, &set_layout->base, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT);
+ set_layout->static_samplers = static_samplers;
+ set_layout->static_sampler_count = static_sampler_count;
+ set_layout->immutable_samplers = immutable_samplers;
+ set_layout->immutable_sampler_count = immutable_sampler_count;
+ set_layout->bindings = binfos;
+ set_layout->binding_count = binding_count;
+ set_layout->dynamic_buffers.range_offset = dynamic_ranges_offset;
+
+ for (uint32_t i = 0; i < MAX_SHADER_VISIBILITIES; i++) {
+ dzn_foreach_pool_type (type) {
+ if (range_count[i][type]) {
+ set_layout->ranges[i][type] = ranges;
+ set_layout->range_count[i][type] = range_count[i][type];
+ ranges += range_count[i][type];
+ }
+ }
+ }
+
+ VkDescriptorSetLayoutBinding *ordered_bindings;
+ VkResult ret =
+ vk_create_sorted_bindings(pCreateInfo->pBindings,
+ pCreateInfo->bindingCount,
+ &ordered_bindings);
+ if (ret != VK_SUCCESS)
+ return ret;
+
+ assert(binding_count ==
+ (pCreateInfo->bindingCount ?
+ (ordered_bindings[pCreateInfo->bindingCount - 1].binding + 1) : 0));
+
+ uint32_t range_idx[MAX_SHADER_VISIBILITIES][NUM_POOL_TYPES] = { 0 };
+ uint32_t static_sampler_idx = 0, immutable_sampler_idx = 0;
+ uint32_t dynamic_buffer_idx = 0;
+ uint32_t base_register = 0;
+
+ for (uint32_t i = 0; i < binding_count; i++) {
+ binfos[i].static_sampler_idx = ~0;
+ binfos[i].immutable_sampler_idx = ~0;
+ binfos[i].dynamic_buffer_idx = ~0;
+ dzn_foreach_pool_type (type)
+ binfos[i].range_idx[type] = ~0;
+ }
+
+ for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
+ VkDescriptorType desc_type = ordered_bindings[i].descriptorType;
+ uint32_t binding = ordered_bindings[i].binding;
+ uint32_t desc_count = ordered_bindings[i].descriptorCount;
+ bool has_sampler =
+ desc_type == VK_DESCRIPTOR_TYPE_SAMPLER ||
+ desc_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ bool has_immutable_samplers =
+ has_sampler &&
+ ordered_bindings[i].pImmutableSamplers != NULL;
+ bool has_static_sampler = has_immutable_samplers && desc_count == 1;
+ bool is_dynamic = is_dynamic_desc_type(desc_type);
+
+ D3D12_SHADER_VISIBILITY visibility =
+ translate_desc_visibility(ordered_bindings[i].stageFlags);
+ binfos[binding].type = desc_type;
+ binfos[binding].visibility = visibility;
+ binfos[binding].base_shader_register = base_register;
+ assert(base_register + desc_count >= base_register);
+ base_register += desc_count;
+
+ if (has_static_sampler) {
+ VK_FROM_HANDLE(dzn_sampler, sampler, ordered_bindings[i].pImmutableSamplers[0]);
+
+ /* Not all border colors are supported. */
+ if (sampler->static_border_color != -1) {
+ binfos[binding].static_sampler_idx = static_sampler_idx;
+ D3D12_STATIC_SAMPLER_DESC *desc = (D3D12_STATIC_SAMPLER_DESC *)
+ &static_samplers[static_sampler_idx];
+
+ desc->Filter = sampler->desc.Filter;
+ desc->AddressU = sampler->desc.AddressU;
+ desc->AddressV = sampler->desc.AddressV;
+ desc->AddressW = sampler->desc.AddressW;
+ desc->MipLODBias = sampler->desc.MipLODBias;
+ desc->MaxAnisotropy = sampler->desc.MaxAnisotropy;
+ desc->ComparisonFunc = sampler->desc.ComparisonFunc;
+ desc->BorderColor = sampler->static_border_color;
+ desc->MinLOD = sampler->desc.MinLOD;
+ desc->MaxLOD = sampler->desc.MaxLOD;
+ desc->ShaderRegister = binfos[binding].base_shader_register;
+ desc->ShaderVisibility = translate_desc_visibility(ordered_bindings[i].stageFlags);
+ static_sampler_idx++;
+ } else {
+ has_static_sampler = false;
+ }
+ }
+
+ if (has_immutable_samplers && !has_static_sampler) {
+ binfos[binding].immutable_sampler_idx = immutable_sampler_idx;
+ for (uint32_t s = 0; s < desc_count; s++) {
+ VK_FROM_HANDLE(dzn_sampler, sampler, ordered_bindings[i].pImmutableSamplers[s]);
+
+ immutable_samplers[immutable_sampler_idx++] = sampler;
+ }
+ }
+
+ if (is_dynamic) {
+ binfos[binding].dynamic_buffer_idx = dynamic_buffer_idx;
+ for (uint32_t d = 0; d < desc_count; d++)
+ set_layout->dynamic_buffers.bindings[dynamic_buffer_idx + d] = binding;
+ dynamic_buffer_idx += desc_count;
+ assert(dynamic_buffer_idx <= MAX_DYNAMIC_BUFFERS);
+ }
+
+ if (!ordered_bindings[i].descriptorCount)
+ continue;
+
+ unsigned num_descs =
+ num_descs_for_type(desc_type, has_static_sampler);
+ if (!num_descs) continue;
+
+ assert(visibility < ARRAY_SIZE(set_layout->ranges));
+
+ bool has_range[NUM_POOL_TYPES] = { 0 };
+ has_range[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER] =
+ has_sampler && !has_static_sampler;
+ has_range[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] =
+ desc_type != VK_DESCRIPTOR_TYPE_SAMPLER;
+
+ dzn_foreach_pool_type (type) {
+ if (!has_range[type]) continue;
+
+ uint32_t idx = range_idx[visibility][type]++;
+ assert(idx < range_count[visibility][type]);
+
+ binfos[binding].range_idx[type] = idx;
+ D3D12_DESCRIPTOR_RANGE1 *range = (D3D12_DESCRIPTOR_RANGE1 *)
+ &set_layout->ranges[visibility][type][idx];
+ VkDescriptorType range_type = desc_type;
+ if (desc_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
+ range_type = type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ?
+ VK_DESCRIPTOR_TYPE_SAMPLER :
+ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+ }
+ range->RangeType = desc_type_to_range_type(range_type, false);
+ range->NumDescriptors = desc_count;
+ range->BaseShaderRegister = binfos[binding].base_shader_register;
+ range->Flags = type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ?
+ D3D12_DESCRIPTOR_RANGE_FLAG_NONE :
+ D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS;
+ if (is_dynamic) {
+ range->OffsetInDescriptorsFromTableStart =
+ set_layout->dynamic_buffers.range_offset +
+ set_layout->dynamic_buffers.desc_count;
+ set_layout->dynamic_buffers.count += range->NumDescriptors;
+ set_layout->dynamic_buffers.desc_count += range->NumDescriptors;
+ } else {
+ range->OffsetInDescriptorsFromTableStart = set_layout->range_desc_count[type];
+ set_layout->range_desc_count[type] += range->NumDescriptors;
+ }
+
+ if (!dzn_descriptor_type_depends_on_shader_usage(desc_type))
+ continue;
+
+ assert(idx + 1 < range_count[visibility][type]);
+ range_idx[visibility][type]++;
+ range[1] = range[0];
+ range++;
+ range->RangeType = desc_type_to_range_type(range_type, true);
+ if (is_dynamic) {
+ range->OffsetInDescriptorsFromTableStart =
+ set_layout->dynamic_buffers.range_offset +
+ set_layout->dynamic_buffers.desc_count;
+ set_layout->dynamic_buffers.desc_count += range->NumDescriptors;
+ } else {
+ range->OffsetInDescriptorsFromTableStart = set_layout->range_desc_count[type];
+ set_layout->range_desc_count[type] += range->NumDescriptors;
+ }
+ }
+ }
+
+ free(ordered_bindings);
+
+ *out = dzn_descriptor_set_layout_to_handle(set_layout);
+ return VK_SUCCESS;
+}
+
+static uint32_t
+dzn_descriptor_set_layout_get_heap_offset(const struct dzn_descriptor_set_layout *layout,
+ uint32_t b,
+ D3D12_DESCRIPTOR_HEAP_TYPE type,
+ bool writeable)
+{
+ assert(b < layout->binding_count);
+ D3D12_SHADER_VISIBILITY visibility = layout->bindings[b].visibility;
+ assert(visibility < ARRAY_SIZE(layout->ranges));
+ assert(type < NUM_POOL_TYPES);
+
+ uint32_t range_idx = layout->bindings[b].range_idx[type];
+
+ if (range_idx == ~0)
+ return ~0;
+
+ if (writeable &&
+ !dzn_descriptor_type_depends_on_shader_usage(layout->bindings[b].type))
+ return ~0;
+
+ if (writeable)
+ range_idx++;
+
+ assert(range_idx < layout->range_count[visibility][type]);
+ return layout->ranges[visibility][type][range_idx].OffsetInDescriptorsFromTableStart;
+}
+
+static uint32_t
+dzn_descriptor_set_layout_get_desc_count(const struct dzn_descriptor_set_layout *layout,
+ uint32_t b)
+{
+ D3D12_SHADER_VISIBILITY visibility = layout->bindings[b].visibility;
+ assert(visibility < ARRAY_SIZE(layout->ranges));
+
+ dzn_foreach_pool_type (type) {
+ uint32_t range_idx = layout->bindings[b].range_idx[type];
+ assert(range_idx == ~0 || range_idx < layout->range_count[visibility][type]);
+
+ if (range_idx != ~0)
+ return layout->ranges[visibility][type][range_idx].NumDescriptors;
+ }
+
+ return 0;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+dzn_CreateDescriptorSetLayout(VkDevice device,
+ const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkDescriptorSetLayout *pSetLayout)
+{
+ return dzn_descriptor_set_layout_create(dzn_device_from_handle(device),
+ pCreateInfo, pAllocator, pSetLayout);
+}
+
+VKAPI_ATTR void VKAPI_CALL
+dzn_DestroyDescriptorSetLayout(VkDevice device,
+ VkDescriptorSetLayout descriptorSetLayout,
+ const VkAllocationCallbacks *pAllocator)
+{
+ dzn_descriptor_set_layout_destroy(dzn_descriptor_set_layout_from_handle(descriptorSetLayout),
+ pAllocator);
+}
+
+static void
+dzn_pipeline_layout_destroy(struct dzn_pipeline_layout *layout)
+{
+ struct dzn_device *device = container_of(layout->base.device, struct dzn_device, vk);
+
+ if (layout->root.sig)
+ ID3D12RootSignature_Release(layout->root.sig);
+
+ vk_free(&device->vk.alloc, layout);
+}
+
+// Reserve two root parameters for the push constants and sysvals CBVs.
+#define MAX_INTERNAL_ROOT_PARAMS 2
+
+// One root parameter for samplers and the other one for views, multiplied by
+// the number of visibility combinations, plus the internal root parameters.
+#define MAX_ROOT_PARAMS ((MAX_SHADER_VISIBILITIES * 2) + MAX_INTERNAL_ROOT_PARAMS)
+
+// Maximum number of DWORDS (32-bit words) that can be used for a root signature
+#define MAX_ROOT_DWORDS 64
+
+static VkResult
+dzn_pipeline_layout_create(struct dzn_device *device,
+ const VkPipelineLayoutCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkPipelineLayout *out)
+{
+ uint32_t binding_count = 0;
+
+ for (uint32_t s = 0; s < pCreateInfo->setLayoutCount; s++) {
+ VK_FROM_HANDLE(dzn_descriptor_set_layout, set_layout, pCreateInfo->pSetLayouts[s]);
+
+ if (!set_layout)
+ continue;
+
+ binding_count += set_layout->binding_count;
+ }
+
+ VK_MULTIALLOC(ma);
+ VK_MULTIALLOC_DECL(&ma, struct dzn_pipeline_layout, layout, 1);
+ VK_MULTIALLOC_DECL(&ma, struct dxil_spirv_vulkan_binding,
+ bindings, binding_count);
+
+ if (!vk_multialloc_zalloc(&ma, &device->vk.alloc,
+ VK_SYSTEM_ALLOCATION_SCOPE_DEVICE))
+ return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ vk_object_base_init(&device->vk, &layout->base, VK_OBJECT_TYPE_PIPELINE_LAYOUT);
+
+ for (uint32_t s = 0; s < pCreateInfo->setLayoutCount; s++) {
+ VK_FROM_HANDLE(dzn_descriptor_set_layout, set_layout, pCreateInfo->pSetLayouts[s]);
+
+ if (!set_layout || !set_layout->binding_count)
+ continue;
+
+ layout->binding_translation[s].bindings = bindings;
+ bindings += set_layout->binding_count;
+ }
+
+ uint32_t range_count = 0, static_sampler_count = 0;
+
+ p_atomic_set(&layout->refcount, 1);
+
+ layout->root.param_count = 0;
+ dzn_foreach_pool_type (type)
+ layout->desc_count[type] = 0;
+
+ layout->set_count = pCreateInfo->setLayoutCount;
+ for (uint32_t j = 0; j < layout->set_count; j++) {
+ VK_FROM_HANDLE(dzn_descriptor_set_layout, set_layout, pCreateInfo->pSetLayouts[j]);
+ struct dxil_spirv_vulkan_binding *bindings = layout->binding_translation[j].bindings;
+
+ layout->sets[j].dynamic_buffer_count = set_layout->dynamic_buffers.count;
+ memcpy(layout->sets[j].range_desc_count, set_layout->range_desc_count,
+ sizeof(layout->sets[j].range_desc_count));
+ layout->binding_translation[j].binding_count = set_layout->binding_count;
+ for (uint32_t b = 0; b < set_layout->binding_count; b++)
+ bindings[b].base_register = set_layout->bindings[b].base_shader_register;
+
+ static_sampler_count += set_layout->static_sampler_count;
+ dzn_foreach_pool_type (type) {
+ layout->sets[j].heap_offsets[type] = layout->desc_count[type];
+ layout->desc_count[type] += set_layout->range_desc_count[type];
+ for (uint32_t i = 0; i < MAX_SHADER_VISIBILITIES; i++)
+ range_count += set_layout->range_count[i][type];
+ }
+
+ layout->desc_count[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] +=
+ set_layout->dynamic_buffers.desc_count;
+ for (uint32_t o = 0, elem = 0; o < set_layout->dynamic_buffers.count; o++, elem++) {
+ uint32_t b = set_layout->dynamic_buffers.bindings[o];
+
+ if (o > 0 && set_layout->dynamic_buffers.bindings[o - 1] != b)
+ elem = 0;
+
+ uint32_t srv =
+ dzn_descriptor_set_layout_get_heap_offset(set_layout, b, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, false);
+ uint32_t uav =
+ dzn_descriptor_set_layout_get_heap_offset(set_layout, b, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, true);
+
+ layout->sets[j].dynamic_buffer_heap_offsets[o].srv = srv != ~0 ? srv + elem : ~0;
+ layout->sets[j].dynamic_buffer_heap_offsets[o].uav = uav != ~0 ? uav + elem : ~0;
+ }
+ }
+
+ D3D12_DESCRIPTOR_RANGE1 *ranges = (D3D12_DESCRIPTOR_RANGE1 *)
+ vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*ranges) * range_count, 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (range_count && !ranges) {
+ dzn_pipeline_layout_destroy(layout);
+ return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+ }
+
+ D3D12_STATIC_SAMPLER_DESC *static_sampler_descs = (D3D12_STATIC_SAMPLER_DESC *)
+ vk_alloc2(&device->vk.alloc, pAllocator,
+ sizeof(*static_sampler_descs) * static_sampler_count, 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (static_sampler_count && !static_sampler_descs) {
+ vk_free2(&device->vk.alloc, pAllocator, ranges);
+ dzn_pipeline_layout_destroy(layout);
+ return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+ }
+
+
+ D3D12_ROOT_PARAMETER1 root_params[MAX_ROOT_PARAMS] = { 0 };
+ D3D12_DESCRIPTOR_RANGE1 *range_ptr = ranges;
+ D3D12_ROOT_PARAMETER1 *root_param;
+ uint32_t root_dwords = 0;
+
+ for (uint32_t i = 0; i < MAX_SHADER_VISIBILITIES; i++) {
+ dzn_foreach_pool_type (type) {
+ root_param = &root_params[layout->root.param_count];
+ root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ root_param->DescriptorTable.pDescriptorRanges = range_ptr;
+ root_param->DescriptorTable.NumDescriptorRanges = 0;
+ root_param->ShaderVisibility = (D3D12_SHADER_VISIBILITY)i;
+
+ for (uint32_t j = 0; j < pCreateInfo->setLayoutCount; j++) {
+ VK_FROM_HANDLE(dzn_descriptor_set_layout, set_layout, pCreateInfo->pSetLayouts[j]);
+ uint32_t range_count = set_layout->range_count[i][type];
+
+ memcpy(range_ptr, set_layout->ranges[i][type],
+ range_count * sizeof(D3D12_DESCRIPTOR_RANGE1));
+ for (uint32_t k = 0; k < range_count; k++) {
+ range_ptr[k].RegisterSpace = j;
+ range_ptr[k].OffsetInDescriptorsFromTableStart +=
+ layout->sets[j].heap_offsets[type];
+ }
+ root_param->DescriptorTable.NumDescriptorRanges += range_count;
+ range_ptr += range_count;
+ }
+
+ if (root_param->DescriptorTable.NumDescriptorRanges) {
+ layout->root.type[layout->root.param_count++] = (D3D12_DESCRIPTOR_HEAP_TYPE)type;
+ root_dwords++;
+ }
+ }
+ }
+
+ layout->root.sets_param_count = layout->root.param_count;
+
+ /* Add our sysval CBV, and make it visible to all shaders */
+ layout->root.sysval_cbv_param_idx = layout->root.param_count;
+ root_param = &root_params[layout->root.param_count++];
+ root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+ root_param->Descriptor.RegisterSpace = DZN_REGISTER_SPACE_SYSVALS;
+ root_param->Constants.ShaderRegister = 0;
+ root_param->Constants.Num32BitValues =
+ DIV_ROUND_UP(MAX2(sizeof(struct dxil_spirv_vertex_runtime_data),
+ sizeof(struct dxil_spirv_compute_runtime_data)),
+ 4);
+ root_param->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ root_dwords += root_param->Constants.Num32BitValues;
+
+ D3D12_STATIC_SAMPLER_DESC *static_sampler_ptr = static_sampler_descs;
+ for (uint32_t j = 0; j < pCreateInfo->setLayoutCount; j++) {
+ VK_FROM_HANDLE(dzn_descriptor_set_layout, set_layout, pCreateInfo->pSetLayouts[j]);
+
+ memcpy(static_sampler_ptr, set_layout->static_samplers,
+ set_layout->static_sampler_count * sizeof(*set_layout->static_samplers));
+ if (j > 0) {
+ for (uint32_t k = 0; k < set_layout->static_sampler_count; k++)
+ static_sampler_ptr[k].RegisterSpace = j;
+ }
+ static_sampler_ptr += set_layout->static_sampler_count;
+ }
+
+ uint32_t push_constant_size = 0;
+ uint32_t push_constant_flags = 0;
+ for (uint32_t j = 0; j < pCreateInfo->pushConstantRangeCount; j++) {
+ const VkPushConstantRange* range = pCreateInfo->pPushConstantRanges + j;
+ push_constant_size = MAX2(push_constant_size, range->offset + range->size);
+ push_constant_flags |= range->stageFlags;
+ }
+
+ if (push_constant_size > 0) {
+ layout->root.push_constant_cbv_param_idx = layout->root.param_count;
+ D3D12_ROOT_PARAMETER1 *root_param = &root_params[layout->root.param_count++];
+
+ root_param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+ root_param->Constants.ShaderRegister = 0;
+ root_param->Constants.Num32BitValues = ALIGN(push_constant_size, 4) / 4;
+ root_param->Constants.RegisterSpace = DZN_REGISTER_SPACE_PUSH_CONSTANT;
+ root_param->ShaderVisibility = translate_desc_visibility(push_constant_flags);
+ root_dwords += root_param->Constants.Num32BitValues;
+ }
+
+ assert(layout->root.param_count <= ARRAY_SIZE(root_params));
+ assert(root_dwords <= MAX_ROOT_DWORDS);
+
+ D3D12_VERSIONED_ROOT_SIGNATURE_DESC root_sig_desc = {
+ .Version = D3D_ROOT_SIGNATURE_VERSION_1_1,
+ .Desc_1_1 = {
+ .NumParameters = layout->root.param_count,
+ .pParameters = layout->root.param_count ? root_params : NULL,
+ .NumStaticSamplers =static_sampler_count,
+ .pStaticSamplers = static_sampler_descs,
+ /* TODO Only enable this flag when needed (optimization) */
+ .Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT,
+ },
+ };
+
+ layout->root.sig = dzn_device_create_root_sig(device, &root_sig_desc);
+ vk_free2(&device->vk.alloc, pAllocator, ranges);
+ vk_free2(&device->vk.alloc, pAllocator, static_sampler_descs);
+
+ if (!layout->root.sig) {
+ dzn_pipeline_layout_destroy(layout);
+ return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+ }
+
+ *out = dzn_pipeline_layout_to_handle(layout);
+ return VK_SUCCESS;
+}
+
+struct dzn_pipeline_layout *
+dzn_pipeline_layout_ref(struct dzn_pipeline_layout *layout)
+{
+ if (layout)
+ p_atomic_inc(&layout->refcount);
+
+ return layout;
+}
+
+void
+dzn_pipeline_layout_unref(struct dzn_pipeline_layout *layout)
+{
+ if (layout) {
+ if (p_atomic_dec_zero(&layout->refcount))
+ dzn_pipeline_layout_destroy(layout);
+ }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+dzn_CreatePipelineLayout(VkDevice device,
+ const VkPipelineLayoutCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkPipelineLayout *pPipelineLayout)
+{
+ return dzn_pipeline_layout_create(dzn_device_from_handle(device),
+ pCreateInfo, pAllocator, pPipelineLayout);
+}
+
+VKAPI_ATTR void VKAPI_CALL
+dzn_DestroyPipelineLayout(VkDevice device,
+ VkPipelineLayout layout,
+ const VkAllocationCallbacks *pAllocator)
+{
+ VK_FROM_HANDLE(dzn_pipeline_layout, playout, layout);
+
+ dzn_pipeline_layout_unref(playout);
+}
+
+static D3D12_DESCRIPTOR_HEAP_TYPE
+desc_type_to_heap_type(VkDescriptorType in)
+{
+ switch (in) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ return D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ return D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ default:
+ unreachable("Unsupported desc type");
+ }
+}
+
+static void
+dzn_descriptor_heap_finish(struct dzn_descriptor_heap *heap)
+{
+ if (heap->heap)
+ ID3D12DescriptorHeap_Release(heap->heap);
+
+ if (heap->dev)
+ ID3D12Device_Release(heap->dev);
+}
+
+static VkResult
+dzn_descriptor_heap_init(struct dzn_descriptor_heap *heap,
+ struct dzn_device *device,
+ D3D12_DESCRIPTOR_HEAP_TYPE type,
+ uint32_t desc_count,
+ bool shader_visible)
+{
+ heap->desc_count = desc_count;
+ heap->type = type;
+ heap->dev = device->dev;
+ ID3D12Device1_AddRef(heap->dev);
+ heap->desc_sz = ID3D12Device1_GetDescriptorHandleIncrementSize(device->dev, type);
+
+ D3D12_DESCRIPTOR_HEAP_DESC desc = {
+ .Type = type,
+ .NumDescriptors = desc_count,
+ .Flags = shader_visible ?
+ D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE :
+ D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
+ };
+
+ if (FAILED(ID3D12Device1_CreateDescriptorHeap(device->dev, &desc,
+ &IID_ID3D12DescriptorHeap,
+ &heap->heap))) {
+ return vk_error(device,
+ shader_visible ?
+ VK_ERROR_OUT_OF_DEVICE_MEMORY : VK_ERROR_OUT_OF_HOST_MEMORY);
+ }
+
+ D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle;
+ ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap->heap, &cpu_handle);
+ heap->cpu_base = cpu_handle.ptr;
+ if (shader_visible) {
+ D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle;
+ ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(heap->heap, &gpu_handle);
+ heap->gpu_base = gpu_handle.ptr;
+ }
+
+ return VK_SUCCESS;
+}
+
+D3D12_CPU_DESCRIPTOR_HANDLE
+dzn_descriptor_heap_get_cpu_handle(const struct dzn_descriptor_heap *heap, uint32_t desc_offset)
+{
+ return (D3D12_CPU_DESCRIPTOR_HANDLE) {
+ .ptr = heap->cpu_base + (desc_offset * heap->desc_sz),
+ };
+}
+
+D3D12_GPU_DESCRIPTOR_HANDLE
+dzn_descriptor_heap_get_gpu_handle(const struct dzn_descriptor_heap *heap, uint32_t desc_offset)
+{
+ return (D3D12_GPU_DESCRIPTOR_HANDLE) {
+ .ptr = heap->gpu_base ? heap->gpu_base + (desc_offset * heap->desc_sz) : 0,
+ };
+}
+
+static void
+dzn_descriptor_heap_write_sampler_desc(struct dzn_descriptor_heap *heap,
+ uint32_t desc_offset,
+ const struct dzn_sampler *sampler)
+{
+ ID3D12Device1_CreateSampler(heap->dev, &sampler->desc,
+ dzn_descriptor_heap_get_cpu_handle(heap, desc_offset));
+}
+
+void
+dzn_descriptor_heap_write_image_view_desc(struct dzn_descriptor_heap *heap,
+ uint32_t desc_offset,
+ bool writeable, bool cube_as_2darray,
+ const struct dzn_image_view *iview)
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE view_handle =
+ dzn_descriptor_heap_get_cpu_handle(heap, desc_offset);
+ struct dzn_image *image = container_of(iview->vk.image, struct dzn_image, vk);
+
+ if (writeable) {
+ ID3D12Device1_CreateUnorderedAccessView(heap->dev, image->res, NULL, &iview->uav_desc, view_handle);
+ } else if (cube_as_2darray &&
+ (iview->srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY ||
+ iview->srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE)) {
+ D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = iview->srv_desc;
+ srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
+ srv_desc.Texture2DArray.PlaneSlice = 0;
+ if (iview->srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY) {
+ srv_desc.Texture2DArray.MostDetailedMip =
+ iview->srv_desc.TextureCubeArray.MostDetailedMip;
+ srv_desc.Texture2DArray.MipLevels =
+ iview->srv_desc.TextureCubeArray.MipLevels;
+ srv_desc.Texture2DArray.FirstArraySlice =
+ iview->srv_desc.TextureCubeArray.First2DArrayFace;
+ srv_desc.Texture2DArray.ArraySize =
+ iview->srv_desc.TextureCubeArray.NumCubes * 6;
+ } else {
+ srv_desc.Texture2DArray.MostDetailedMip =
+ iview->srv_desc.TextureCube.MostDetailedMip;
+ srv_desc.Texture2DArray.MipLevels =
+ iview->srv_desc.TextureCube.MipLevels;
+ srv_desc.Texture2DArray.FirstArraySlice = 0;
+ srv_desc.Texture2DArray.ArraySize = 6;
+ }
+
+ ID3D12Device1_CreateShaderResourceView(heap->dev, image->res, &srv_desc, view_handle);
+ } else {
+ ID3D12Device1_CreateShaderResourceView(heap->dev, image->res, &iview->srv_desc, view_handle);
+ }
+}
+
+static void
+dzn_descriptor_heap_write_buffer_view_desc(struct dzn_descriptor_heap *heap,
+ uint32_t desc_offset,
+ bool writeable,
+ const struct dzn_buffer_view *bview)
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE view_handle =
+ dzn_descriptor_heap_get_cpu_handle(heap, desc_offset);
+
+ if (writeable)
+ ID3D12Device1_CreateUnorderedAccessView(heap->dev, bview->buffer->res, NULL, &bview->uav_desc, view_handle);
+ else
+ ID3D12Device1_CreateShaderResourceView(heap->dev, bview->buffer->res, &bview->srv_desc, view_handle);
+}
+
+void
+dzn_descriptor_heap_write_buffer_desc(struct dzn_descriptor_heap *heap,
+ uint32_t desc_offset,
+ bool writeable,
+ const struct dzn_buffer_desc *info)
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE view_handle =
+ dzn_descriptor_heap_get_cpu_handle(heap, desc_offset);
+
+ VkDeviceSize size =
+ info->range == VK_WHOLE_SIZE ?
+ info->buffer->size - info->offset :
+ info->range;
+
+ if (info->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
+ info->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
+ assert(!writeable);
+ D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc = {
+ .BufferLocation = ID3D12Resource_GetGPUVirtualAddress(info->buffer->res) + info->offset,
+ .SizeInBytes = ALIGN_POT(size, 256),
+ };
+ ID3D12Device1_CreateConstantBufferView(heap->dev, &cbv_desc, view_handle);
+ } else if (writeable) {
+ D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {
+ .Format = DXGI_FORMAT_R32_TYPELESS,
+ .ViewDimension = D3D12_UAV_DIMENSION_BUFFER,
+ .Buffer = {
+ .FirstElement = info->offset / sizeof(uint32_t),
+ .NumElements = (UINT)size / sizeof(uint32_t),
+ .Flags = D3D12_BUFFER_UAV_FLAG_RAW,
+ },
+ };
+ ID3D12Device1_CreateUnorderedAccessView(heap->dev, info->buffer->res, NULL, &uav_desc, view_handle);
+ } else {
+ D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {
+ .Format = DXGI_FORMAT_R32_TYPELESS,
+ .ViewDimension = D3D12_SRV_DIMENSION_BUFFER,
+ .Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
+ .Buffer = {
+ .FirstElement = info->offset / sizeof(uint32_t),
+ .NumElements = (UINT)size / sizeof(uint32_t),
+ .Flags = D3D12_BUFFER_SRV_FLAG_RAW,
+ },
+ };
+ ID3D12Device1_CreateShaderResourceView(heap->dev, info->buffer->res, &srv_desc, view_handle);
+ }
+}
+
+void
+dzn_descriptor_heap_copy(struct dzn_descriptor_heap *dst_heap,
+ uint32_t dst_offset,
+ const struct dzn_descriptor_heap *src_heap,
+ uint32_t src_offset,
+ uint32_t desc_count)
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE dst_handle =
+ dzn_descriptor_heap_get_cpu_handle(dst_heap, dst_offset);
+ D3D12_CPU_DESCRIPTOR_HANDLE src_handle =
+ dzn_descriptor_heap_get_cpu_handle(src_heap, src_offset);
+
+ ID3D12Device1_CopyDescriptorsSimple(dst_heap->dev, desc_count,
+ dst_handle,
+ src_handle,
+ dst_heap->type);
+}
+
+struct dzn_descriptor_set_ptr {
+ uint32_t binding, elem;
+};
+
+static void
+dzn_descriptor_set_ptr_validate(const struct dzn_descriptor_set *set,
+ struct dzn_descriptor_set_ptr *ptr)
+{
+
+ if (ptr->binding >= set->layout->binding_count) {
+ ptr->binding = ~0;
+ ptr->elem = ~0;
+ return;
+ }
+
+ uint32_t desc_count =
+ dzn_descriptor_set_layout_get_desc_count(set->layout, ptr->binding);
+ if (ptr->elem >= desc_count) {
+ ptr->binding = ~0;
+ ptr->elem = ~0;
+ }
+}
+
+static void
+dzn_descriptor_set_ptr_init(const struct dzn_descriptor_set *set,
+ struct dzn_descriptor_set_ptr *ptr,
+ uint32_t binding, uint32_t elem)
+{
+ ptr->binding = binding;
+ ptr->elem = elem;
+ dzn_descriptor_set_ptr_validate(set, ptr);
+}
+
+static void
+dzn_descriptor_set_ptr_move(const struct dzn_descriptor_set *set,
+ struct dzn_descriptor_set_ptr *ptr,
+ uint32_t count)
+{
+ if (ptr->binding == ~0)
+ return;
+
+ while (count) {
+ uint32_t desc_count =
+ dzn_descriptor_set_layout_get_desc_count(set->layout, ptr->binding);
+
+ if (count >= desc_count - ptr->elem) {
+ count -= desc_count - ptr->elem;
+ ptr->binding++;
+ ptr->elem = 0;
+ } else {
+ ptr->elem += count;
+ count = 0;
+ }
+ }
+
+ dzn_descriptor_set_ptr_validate(set, ptr);
+}
+
+static bool
+dzn_descriptor_set_ptr_is_valid(const struct dzn_descriptor_set_ptr *ptr)
+{
+ return ptr->binding != ~0 && ptr->elem != ~0;
+}
+
+static uint32_t
+dzn_descriptor_set_remaining_descs_in_binding(const struct dzn_descriptor_set *set,
+ const struct dzn_descriptor_set_ptr *ptr)
+{
+ if (ptr->binding >= set->layout->binding_count)
+ return 0;
+
+ uint32_t desc_count =
+ dzn_descriptor_set_layout_get_desc_count(set->layout, ptr->binding);
+
+ return desc_count >= ptr->elem ? desc_count - ptr->elem : 0;
+}
+
+
+static uint32_t
+dzn_descriptor_set_get_heap_offset(const struct dzn_descriptor_set *set,
+ D3D12_DESCRIPTOR_HEAP_TYPE type,
+ const struct dzn_descriptor_set_ptr *ptr,
+ bool writeable)
+{
+ if (ptr->binding == ~0)
+ return ~0;
+
+ uint32_t base =
+ dzn_descriptor_set_layout_get_heap_offset(set->layout, ptr->binding, type, writeable);
+ if (base == ~0)
+ return ~0;
+
+ return base + ptr->elem;
+}
+
+static void
+dzn_descriptor_set_write_sampler_desc(struct dzn_descriptor_set *set,
+ const struct dzn_descriptor_set_ptr *ptr,
+ const struct dzn_sampler *sampler)
+{
+ D3D12_DESCRIPTOR_HEAP_TYPE type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
+ uint32_t heap_offset =
+ dzn_descriptor_set_get_heap_offset(set, type, ptr, false);
+
+ if (heap_offset != ~0) {
+ mtx_lock(&set->pool->defragment_lock);
+ dzn_descriptor_heap_write_sampler_desc(&set->pool->heaps[type],
+ set->heap_offsets[type] + heap_offset,
+ sampler);
+ mtx_unlock(&set->pool->defragment_lock);
+ }
+}
+
+static uint32_t
+dzn_descriptor_set_get_dynamic_buffer_idx(const struct dzn_descriptor_set *set,
+ const struct dzn_descriptor_set_ptr *ptr)
+{
+ if (ptr->binding == ~0)
+ return ~0;
+
+ uint32_t base = set->layout->bindings[ptr->binding].dynamic_buffer_idx;
+
+ if (base == ~0)
+ return ~0;
+
+ return base + ptr->elem;
+}
+
+static void
+dzn_descriptor_set_write_dynamic_buffer_desc(struct dzn_descriptor_set *set,
+ const struct dzn_descriptor_set_ptr *ptr,
+ const struct dzn_buffer_desc *info)
+{
+ uint32_t dynamic_buffer_idx =
+ dzn_descriptor_set_get_dynamic_buffer_idx(set, ptr);
+ if (dynamic_buffer_idx == ~0)
+ return;
+
+ assert(dynamic_buffer_idx < set->layout->dynamic_buffers.count);
+ set->dynamic_buffers[dynamic_buffer_idx] = *info;
+}
+
+static VkDescriptorType
+dzn_descriptor_set_get_desc_vk_type(const struct dzn_descriptor_set *set,
+ const struct dzn_descriptor_set_ptr *ptr)
+{
+ if (ptr->binding >= set->layout->binding_count)
+ return (VkDescriptorType)~0;
+
+ return set->layout->bindings[ptr->binding].type;
+}
+
+static void
+dzn_descriptor_set_write_image_view_desc(struct dzn_descriptor_set *set,
+ const struct dzn_descriptor_set_ptr *ptr,
+ bool cube_as_2darray,
+ const struct dzn_image_view *iview)
+{
+ D3D12_DESCRIPTOR_HEAP_TYPE type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ uint32_t heap_offset =
+ dzn_descriptor_set_get_heap_offset(set, type, ptr, false);
+ if (heap_offset == ~0)
+ return;
+
+ mtx_lock(&set->pool->defragment_lock);
+ dzn_descriptor_heap_write_image_view_desc(&set->pool->heaps[type],
+ set->heap_offsets[type] + heap_offset,
+ false, cube_as_2darray,
+ iview);
+
+ VkDescriptorType vk_type = dzn_descriptor_set_get_desc_vk_type(set, ptr);
+ if (dzn_descriptor_type_depends_on_shader_usage(vk_type)) {
+ heap_offset =
+ dzn_descriptor_set_get_heap_offset(set, type, ptr, true);
+ assert(heap_offset != ~0);
+ dzn_descriptor_heap_write_image_view_desc(&set->pool->heaps[type],
+ set->heap_offsets[type] + heap_offset,
+ true, cube_as_2darray,
+ iview);
+ }
+ mtx_unlock(&set->pool->defragment_lock);
+}
+
+static void
+dzn_descriptor_set_write_buffer_view_desc(struct dzn_descriptor_set *set,
+ const struct dzn_descriptor_set_ptr *ptr,
+ const struct dzn_buffer_view *bview)
+{
+ D3D12_DESCRIPTOR_HEAP_TYPE type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ uint32_t heap_offset =
+ dzn_descriptor_set_get_heap_offset(set, type, ptr, false);
+ if (heap_offset == ~0)
+ return;
+
+ mtx_lock(&set->pool->defragment_lock);
+ dzn_descriptor_heap_write_buffer_view_desc(&set->pool->heaps[type],
+ set->heap_offsets[type] + heap_offset,
+ false, bview);
+
+ VkDescriptorType vk_type = dzn_descriptor_set_get_desc_vk_type(set, ptr);
+ if (dzn_descriptor_type_depends_on_shader_usage(vk_type)) {
+ heap_offset =
+ dzn_descriptor_set_get_heap_offset(set, type, ptr, true);
+ assert(heap_offset != ~0);
+ dzn_descriptor_heap_write_buffer_view_desc(&set->pool->heaps[type],
+ set->heap_offsets[type] + heap_offset,
+ true, bview);
+ }
+ mtx_unlock(&set->pool->defragment_lock);
+}
+
+static void
+dzn_descriptor_set_write_buffer_desc(struct dzn_descriptor_set *set,
+ const struct dzn_descriptor_set_ptr *ptr,
+ const struct dzn_buffer_desc *bdesc)
+{
+ D3D12_DESCRIPTOR_HEAP_TYPE type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ uint32_t heap_offset =
+ dzn_descriptor_set_get_heap_offset(set, type, ptr, false);
+ if (heap_offset == ~0)
+ return;
+
+ mtx_lock(&set->pool->defragment_lock);
+ dzn_descriptor_heap_write_buffer_desc(&set->pool->heaps[type],
+ set->heap_offsets[type] + heap_offset,
+ false, bdesc);
+
+ VkDescriptorType vk_type = dzn_descriptor_set_get_desc_vk_type(set, ptr);
+ if (dzn_descriptor_type_depends_on_shader_usage(vk_type)) {
+ heap_offset =
+ dzn_descriptor_set_get_heap_offset(set, type, ptr, true);
+ assert(heap_offset != ~0);
+ dzn_descriptor_heap_write_buffer_desc(&set->pool->heaps[type],
+ set->heap_offsets[type] + heap_offset,
+ true, bdesc);
+ }
+ mtx_unlock(&set->pool->defragment_lock);
+}
+
+static void
+dzn_descriptor_set_init(struct dzn_descriptor_set *set,
+ struct dzn_device *device,
+ struct dzn_descriptor_pool *pool,
+ struct dzn_descriptor_set_layout *layout)
+{
+ vk_object_base_init(&device->vk, &set->base, VK_OBJECT_TYPE_DESCRIPTOR_SET);
+
+ set->pool = pool;
+ set->layout = layout;
+
+ mtx_lock(&pool->defragment_lock);
+ dzn_foreach_pool_type(type) {
+ set->heap_offsets[type] = pool->free_offset[type];
+ set->heap_sizes[type] = layout->range_desc_count[type];
+ set->pool->free_offset[type] += layout->range_desc_count[type];
+ }
+ mtx_unlock(&pool->defragment_lock);
+
+ /* Pre-fill the immutable samplers */
+ if (layout->immutable_sampler_count) {
+ for (uint32_t b = 0; b < layout->binding_count; b++) {
+ bool has_samplers =
+ layout->bindings[b].type == VK_DESCRIPTOR_TYPE_SAMPLER ||
+ layout->bindings[b].type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+
+ if (!has_samplers || layout->bindings[b].immutable_sampler_idx == ~0)
+ continue;
+
+ struct dzn_descriptor_set_ptr ptr;
+ const struct dzn_sampler **sampler =
+ &layout->immutable_samplers[layout->bindings[b].immutable_sampler_idx];
+ for (dzn_descriptor_set_ptr_init(set, &ptr, b, 0);
+ dzn_descriptor_set_ptr_is_valid(&ptr);
+ dzn_descriptor_set_ptr_move(set, &ptr, 1)) {
+ dzn_descriptor_set_write_sampler_desc(set, &ptr, *sampler);
+ sampler++;
+ }
+ }
+ }
+}
+
+static void
+dzn_descriptor_set_finish(struct dzn_descriptor_set *set)
+{
+ vk_object_base_finish(&set->base);
+ set->pool = NULL;
+ set->layout = NULL;
+}
+
+static void
+dzn_descriptor_pool_destroy(struct dzn_descriptor_pool *pool,
+ const VkAllocationCallbacks *pAllocator)
+{
+ if (!pool)
+ return;
+
+ struct dzn_device *device = container_of(pool->base.device, struct dzn_device, vk);
+
+ dzn_foreach_pool_type (type) {
+ if (pool->desc_count[type])
+ dzn_descriptor_heap_finish(&pool->heaps[type]);
+ }
+
+ vk_object_base_finish(&pool->base);
+ vk_free2(&device->vk.alloc, pAllocator, pool);
+}
+
+static VkResult
+dzn_descriptor_pool_create(struct dzn_device *device,
+ const VkDescriptorPoolCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkDescriptorPool *out)
+{
+ VK_MULTIALLOC(ma);
+ VK_MULTIALLOC_DECL(&ma, struct dzn_descriptor_pool, pool, 1);
+ VK_MULTIALLOC_DECL(&ma, struct dzn_descriptor_set, sets, pCreateInfo->maxSets);
+
+ if (!vk_multialloc_zalloc2(&ma, &device->vk.alloc, pAllocator,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT))
+ return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ pool->alloc = pAllocator ? *pAllocator : device->vk.alloc;
+ pool->sets = sets;
+ pool->set_count = pCreateInfo->maxSets;
+ mtx_init(&pool->defragment_lock, mtx_plain);
+
+ vk_object_base_init(&device->vk, &pool->base, VK_OBJECT_TYPE_DESCRIPTOR_POOL);
+
+ for (uint32_t p = 0; p < pCreateInfo->poolSizeCount; p++) {
+ VkDescriptorType type = pCreateInfo->pPoolSizes[p].type;
+ uint32_t num_desc = pCreateInfo->pPoolSizes[p].descriptorCount;
+
+ switch (type) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ pool->desc_count[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER] += num_desc;
+ break;
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ pool->desc_count[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] += num_desc;
+ pool->desc_count[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER] += num_desc;
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ pool->desc_count[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] += num_desc;
+ break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ /* Reserve one UAV and one SRV slot for those. */
+ pool->desc_count[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] += num_desc * 2;
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ break;
+ default:
+ unreachable("Unsupported desc type");
+ }
+ }
+
+ dzn_foreach_pool_type (type) {
+ if (!pool->desc_count[type])
+ continue;
+
+ VkResult result =
+ dzn_descriptor_heap_init(&pool->heaps[type], device, type, pool->desc_count[type], false);
+ if (result != VK_SUCCESS) {
+ dzn_descriptor_pool_destroy(pool, pAllocator);
+ return result;
+ }
+ }
+
+ *out = dzn_descriptor_pool_to_handle(pool);
+ return VK_SUCCESS;
+}
+
+static VkResult
+dzn_descriptor_pool_defragment_heap(struct dzn_descriptor_pool *pool,
+ D3D12_DESCRIPTOR_HEAP_TYPE type)
+{
+ struct dzn_device *device = container_of(pool->base.device, struct dzn_device, vk);
+ struct dzn_descriptor_heap new_heap;
+
+ VkResult result =
+ dzn_descriptor_heap_init(&new_heap, device, type,
+ pool->heaps[type].desc_count,
+ false);
+ if (result != VK_SUCCESS)
+ return result;
+
+ mtx_lock(&pool->defragment_lock);
+ uint32_t heap_offset = 0;
+ for (uint32_t s = 0; s < pool->set_count; s++) {
+ if (!pool->sets[s].layout)
+ continue;
+
+ dzn_descriptor_heap_copy(&new_heap, heap_offset,
+ &pool->heaps[type],
+ pool->sets[s].heap_offsets[type],
+ pool->sets[s].heap_sizes[type]);
+ pool->sets[s].heap_offsets[type] = heap_offset;
+ heap_offset += pool->sets[s].heap_sizes[type];
+ }
+ mtx_unlock(&pool->defragment_lock);
+
+ dzn_descriptor_heap_finish(&pool->heaps[type]);
+ pool->heaps[type] = new_heap;
+
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+dzn_CreateDescriptorPool(VkDevice device,
+ const VkDescriptorPoolCreateInfo *pCreateInfo,
+ const VkAllocationCallbacks *pAllocator,
+ VkDescriptorPool *pDescriptorPool)
+{
+ return dzn_descriptor_pool_create(dzn_device_from_handle(device),
+ pCreateInfo, pAllocator, pDescriptorPool);
+}
+
+VKAPI_ATTR void VKAPI_CALL
+dzn_DestroyDescriptorPool(VkDevice device,
+ VkDescriptorPool descriptorPool,
+ const VkAllocationCallbacks *pAllocator)
+{
+ dzn_descriptor_pool_destroy(dzn_descriptor_pool_from_handle(descriptorPool),
+ pAllocator);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+dzn_ResetDescriptorPool(VkDevice device,
+ VkDescriptorPool descriptorPool,
+ VkDescriptorPoolResetFlags flags)
+{
+ VK_FROM_HANDLE(dzn_descriptor_pool, pool, descriptorPool);
+
+ for (uint32_t s = 0; s < pool->set_count; s++)
+ dzn_descriptor_set_finish(&pool->sets[s]);
+
+ dzn_foreach_pool_type(type)
+ pool->free_offset[type] = 0;
+
+ return VK_SUCCESS;
+}
+
+void
+dzn_descriptor_heap_pool_finish(struct dzn_descriptor_heap_pool *pool)
+{
+ list_splicetail(&pool->active_heaps, &pool->free_heaps);
+ list_for_each_entry_safe(struct dzn_descriptor_heap_pool_entry, entry, &pool->free_heaps, link) {
+ list_del(&entry->link);
+ dzn_descriptor_heap_finish(&entry->heap);
+ vk_free(pool->alloc, entry);
+ }
+}
+
+void
+dzn_descriptor_heap_pool_init(struct dzn_descriptor_heap_pool *pool,
+ struct dzn_device *device,
+ D3D12_DESCRIPTOR_HEAP_TYPE type,
+ bool shader_visible,
+ const VkAllocationCallbacks *alloc)
+{
+ assert(!shader_visible ||
+ type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ||
+ type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+
+ pool->alloc = alloc;
+ pool->type = type;
+ pool->shader_visible = shader_visible;
+ list_inithead(&pool->active_heaps);
+ list_inithead(&pool->free_heaps);
+ pool->offset = 0;
+ pool->desc_sz = ID3D12Device1_GetDescriptorHandleIncrementSize(device->dev, type);
+}
+
+VkResult
+dzn_descriptor_heap_pool_alloc_slots(struct dzn_descriptor_heap_pool *pool,
+ struct dzn_device *device, uint32_t desc_count,
+ struct dzn_descriptor_heap **heap,
+ uint32_t *first_slot)
+{
+ struct dzn_descriptor_heap *last_heap =
+ list_is_empty(&pool->active_heaps) ?
+ NULL :
+ &(list_last_entry(&pool->active_heaps, struct dzn_descriptor_heap_pool_entry, link)->heap);
+ uint32_t last_heap_desc_count =
+ last_heap ? last_heap->desc_count : 0;
+
+ if (pool->offset + desc_count > last_heap_desc_count) {
+ uint32_t granularity =
+ (pool->type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ||
+ pool->type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) ?
+ 64 * 1024 : 4 * 1024;
+ uint32_t alloc_step = ALIGN_POT(desc_count * pool->desc_sz, granularity);
+ uint32_t heap_desc_count = MAX2(alloc_step / pool->desc_sz, 16);
+
+ /* Maximum of 2048 samplers per heap when shader_visible is true. */
+ if (pool->shader_visible &&
+ pool->type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) {
+ assert(desc_count <= 2048);
+ heap_desc_count = MIN2(heap_desc_count, 2048);
+ }
+
+ struct dzn_descriptor_heap_pool_entry *new_heap = NULL;
+
+ list_for_each_entry_safe(struct dzn_descriptor_heap_pool_entry, entry, &pool->free_heaps, link) {
+ if (entry->heap.desc_count >= heap_desc_count) {
+ new_heap = entry;
+ list_del(&entry->link);
+ break;
+ }
+ }
+
+ if (!new_heap) {
+ new_heap = (struct dzn_descriptor_heap_pool_entry *)
+ vk_zalloc(pool->alloc, sizeof(*new_heap), 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ if (!new_heap)
+ return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ VkResult result =
+ dzn_descriptor_heap_init(&new_heap->heap, device, pool->type,
+ heap_desc_count, pool->shader_visible);
+ if (result != VK_SUCCESS) {
+ vk_free(&device->vk.alloc, new_heap);
+ return result;
+ }
+ }
+
+ list_addtail(&new_heap->link, &pool->active_heaps);
+ pool->offset = 0;
+ last_heap = &new_heap->heap;
+ }
+
+ *heap = last_heap;
+ *first_slot = pool->offset;
+ pool->offset += desc_count;
+ return VK_SUCCESS;
+}
+
+void
+dzn_descriptor_heap_pool_reset(struct dzn_descriptor_heap_pool *pool)
+{
+ pool->offset = 0;
+ list_splicetail(&pool->active_heaps, &pool->free_heaps);
+ list_inithead(&pool->free_heaps);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+dzn_AllocateDescriptorSets(VkDevice dev,
+ const VkDescriptorSetAllocateInfo *pAllocateInfo,
+ VkDescriptorSet *pDescriptorSets)
+{
+ VK_FROM_HANDLE(dzn_descriptor_pool, pool, pAllocateInfo->descriptorPool);
+ VK_FROM_HANDLE(dzn_device, device, dev);
+ VkResult result;
+ unsigned i;
+
+ if (pAllocateInfo->descriptorSetCount > (pool->set_count - pool->used_set_count))
+ return VK_ERROR_OUT_OF_POOL_MEMORY;
+
+ uint32_t set_idx = 0;
+ for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
+ VK_FROM_HANDLE(dzn_descriptor_set_layout, layout, pAllocateInfo->pSetLayouts[i]);
+
+ dzn_foreach_pool_type(type) {
+ if (pool->used_desc_count[type] + layout->range_desc_count[type] > pool->desc_count[type]) {
+ dzn_FreeDescriptorSets(dev, pAllocateInfo->descriptorPool, i, pDescriptorSets);
+ return vk_error(device, VK_ERROR_OUT_OF_POOL_MEMORY);
+ }
+
+ if (pool->free_offset[type] + layout->range_desc_count[type] > pool->desc_count[type]) {
+ result = dzn_descriptor_pool_defragment_heap(pool, type);
+ if (result != VK_SUCCESS) {
+ dzn_FreeDescriptorSets(dev, pAllocateInfo->descriptorPool, i, pDescriptorSets);
+ return vk_error(device, VK_ERROR_FRAGMENTED_POOL);
+ }
+ }
+ }
+
+ struct dzn_descriptor_set *set = NULL;
+ for (; set_idx < pool->set_count; set_idx++) {
+ if (!pool->sets[set_idx].layout) {
+ set = &pool->sets[set_idx];
+ break;
+ }
+ }
+
+ dzn_descriptor_set_init(set, device, pool, layout);
+ pDescriptorSets[i] = dzn_descriptor_set_to_handle(set);
+ }
+
+ return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+dzn_FreeDescriptorSets(VkDevice dev,
+ VkDescriptorPool descriptorPool,
+ uint32_t count,
+ const VkDescriptorSet *pDescriptorSets)
+{
+ VK_FROM_HANDLE(dzn_descriptor_pool, pool, descriptorPool);
+ VK_FROM_HANDLE(dzn_device, device, dev);
+
+ for (uint32_t s = 0; s < count; s++) {
+ VK_FROM_HANDLE(dzn_descriptor_set, set, pDescriptorSets[s]);
+
+ if (!set)
+ continue;
+
+ assert(set->pool == pool);
+
+ dzn_descriptor_set_finish(set);
+ }
+
+ mtx_lock(&pool->defragment_lock);
+ dzn_foreach_pool_type(type)
+ pool->free_offset[type] = 0;
+
+ for (uint32_t s = 0; s < pool->set_count; s++) {
+ const struct dzn_descriptor_set *set = &pool->sets[s];
+
+ if (set->layout) {
+ dzn_foreach_pool_type (type) {
+ pool->free_offset[type] =
+ MAX2(pool->free_offset[type],
+ set->heap_offsets[type] +
+ set->layout->range_desc_count[type]);
+ }
+ }
+ }
+ mtx_unlock(&pool->defragment_lock);
+
+ return VK_SUCCESS;
+}
+
+static void
+dzn_descriptor_set_write(const VkWriteDescriptorSet *pDescriptorWrite)
+{
+ VK_FROM_HANDLE(dzn_descriptor_set, set, pDescriptorWrite->dstSet);
+
+ struct dzn_descriptor_set_ptr ptr;
+
+ dzn_descriptor_set_ptr_init(set, &ptr,
+ pDescriptorWrite->dstBinding,
+ pDescriptorWrite->dstArrayElement);
+ uint32_t desc_count = pDescriptorWrite->descriptorCount;
+
+ uint32_t d = 0;
+ bool cube_as_2darray =
+ pDescriptorWrite->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+
+ switch (pDescriptorWrite->descriptorType) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ for (; dzn_descriptor_set_ptr_is_valid(&ptr) && d < desc_count;
+ dzn_descriptor_set_ptr_move(set, &ptr, 1)) {
+ assert(dzn_descriptor_set_get_desc_vk_type(set, &ptr) == pDescriptorWrite->descriptorType);
+ const VkDescriptorImageInfo *pImageInfo = pDescriptorWrite->pImageInfo + d;
+ VK_FROM_HANDLE(dzn_sampler, sampler, pImageInfo->sampler);
+
+ if (sampler)
+ dzn_descriptor_set_write_sampler_desc(set, &ptr, sampler);
+
+ d++;
+ }
+ break;
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ for (; dzn_descriptor_set_ptr_is_valid(&ptr) && d < desc_count;
+ dzn_descriptor_set_ptr_move(set, &ptr, 1)) {
+ assert(dzn_descriptor_set_get_desc_vk_type(set, &ptr) == pDescriptorWrite->descriptorType);
+ const VkDescriptorImageInfo *pImageInfo = pDescriptorWrite->pImageInfo + d;
+ VK_FROM_HANDLE(dzn_sampler, sampler, pImageInfo->sampler);
+ VK_FROM_HANDLE(dzn_image_view, iview, pImageInfo->imageView);
+
+ if (sampler)
+ dzn_descriptor_set_write_sampler_desc(set, &ptr, sampler);
+
+ if (iview)
+ dzn_descriptor_set_write_image_view_desc(set, &ptr, cube_as_2darray, iview);
+
+ d++;
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ for (; dzn_descriptor_set_ptr_is_valid(&ptr) && d < desc_count;
+ dzn_descriptor_set_ptr_move(set, &ptr, 1)) {
+ assert(dzn_descriptor_set_get_desc_vk_type(set, &ptr) == pDescriptorWrite->descriptorType);
+ const VkDescriptorImageInfo *pImageInfo = pDescriptorWrite->pImageInfo + d;
+ VK_FROM_HANDLE(dzn_image_view, iview, pImageInfo->imageView);
+
+ if (iview)
+ dzn_descriptor_set_write_image_view_desc(set, &ptr, cube_as_2darray, iview);
+
+ d++;
+ }
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ for (; dzn_descriptor_set_ptr_is_valid(&ptr) && d < desc_count;
+ dzn_descriptor_set_ptr_move(set, &ptr, 1)) {
+ assert(dzn_descriptor_set_get_desc_vk_type(set, &ptr) == pDescriptorWrite->descriptorType);
+ const VkDescriptorBufferInfo *binfo = &pDescriptorWrite->pBufferInfo[d];
+ struct dzn_buffer_desc desc = {
+ pDescriptorWrite->descriptorType,
+ dzn_buffer_from_handle(binfo->buffer),
+ binfo->range, binfo->offset
+ };
+
+ if (desc.buffer)
+ dzn_descriptor_set_write_buffer_desc(set, &ptr, &desc);
+
+ d++;
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ for (; dzn_descriptor_set_ptr_is_valid(&ptr) && d < desc_count;
+ dzn_descriptor_set_ptr_move(set, &ptr, 1)) {
+ assert(dzn_descriptor_set_get_desc_vk_type(set, &ptr) == pDescriptorWrite->descriptorType);
+ const VkDescriptorBufferInfo *binfo = &pDescriptorWrite->pBufferInfo[d];
+ struct dzn_buffer_desc desc = {
+ pDescriptorWrite->descriptorType,
+ dzn_buffer_from_handle(binfo->buffer),
+ binfo->range, binfo->offset
+ };
+
+ if (desc.buffer)
+ dzn_descriptor_set_write_dynamic_buffer_desc(set, &ptr, &desc);
+
+ d++;
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ for (; dzn_descriptor_set_ptr_is_valid(&ptr) && d < desc_count;
+ dzn_descriptor_set_ptr_move(set, &ptr, 1)) {
+ assert(dzn_descriptor_set_get_desc_vk_type(set, &ptr) == pDescriptorWrite->descriptorType);
+ VK_FROM_HANDLE(dzn_buffer_view, bview, pDescriptorWrite->pTexelBufferView[d]);
+
+ if (bview)
+ dzn_descriptor_set_write_buffer_view_desc(set, &ptr, bview);
+
+ d++;
+ }
+ break;
+
+ default:
+ unreachable("invalid descriptor type");
+ break;
+ }
+
+ assert(d == pDescriptorWrite->descriptorCount);
+}
+
+static void
+dzn_descriptor_set_copy(const VkCopyDescriptorSet *pDescriptorCopy)
+{
+ VK_FROM_HANDLE(dzn_descriptor_set, src_set, pDescriptorCopy->srcSet);
+ VK_FROM_HANDLE(dzn_descriptor_set, dst_set, pDescriptorCopy->dstSet);
+ struct dzn_descriptor_set_ptr src_ptr, dst_ptr;
+
+ dzn_descriptor_set_ptr_init(src_set, &src_ptr,
+ pDescriptorCopy->srcBinding,
+ pDescriptorCopy->srcArrayElement);
+ dzn_descriptor_set_ptr_init(dst_set, &dst_ptr,
+ pDescriptorCopy->dstBinding,
+ pDescriptorCopy->dstArrayElement);
+
+ uint32_t copied_count = 0;
+
+ while (dzn_descriptor_set_ptr_is_valid(&src_ptr) &&
+ dzn_descriptor_set_ptr_is_valid(&dst_ptr) &&
+ copied_count < pDescriptorCopy->descriptorCount) {
+ VkDescriptorType src_type =
+ dzn_descriptor_set_get_desc_vk_type(src_set, &src_ptr);
+ VkDescriptorType dst_type =
+ dzn_descriptor_set_get_desc_vk_type(dst_set, &dst_ptr);
+
+ assert(src_type == dst_type);
+ uint32_t count =
+ MIN2(dzn_descriptor_set_remaining_descs_in_binding(src_set, &src_ptr),
+ dzn_descriptor_set_remaining_descs_in_binding(dst_set, &dst_ptr));
+
+ if (src_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
+ src_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
+ uint32_t src_idx =
+ dzn_descriptor_set_get_dynamic_buffer_idx(src_set, &src_ptr);
+ uint32_t dst_idx =
+ dzn_descriptor_set_get_dynamic_buffer_idx(dst_set, &dst_ptr);
+
+ memcpy(&dst_set->dynamic_buffers[dst_idx],
+ &src_set->dynamic_buffers[src_idx],
+ sizeof(*dst_set->dynamic_buffers) * count);
+ } else {
+ dzn_foreach_pool_type(type) {
+ uint32_t src_heap_offset =
+ dzn_descriptor_set_get_heap_offset(src_set, type, &src_ptr, false);
+ uint32_t dst_heap_offset =
+ dzn_descriptor_set_get_heap_offset(dst_set, type, &dst_ptr, false);
+
+ if (src_heap_offset == ~0) {
+ assert(dst_heap_offset == ~0);
+ continue;
+ }
+
+ mtx_lock(&src_set->pool->defragment_lock);
+ mtx_lock(&dst_set->pool->defragment_lock);
+ dzn_descriptor_heap_copy(&dst_set->pool->heaps[type],
+ dst_set->heap_offsets[type] + dst_heap_offset,
+ &src_set->pool->heaps[type],
+ src_set->heap_offsets[type] + src_heap_offset,
+ count);
+
+ if (dzn_descriptor_type_depends_on_shader_usage(src_type)) {
+ src_heap_offset =
+ dzn_descriptor_set_get_heap_offset(src_set, type, &src_ptr, true);
+ dst_heap_offset =
+ dzn_descriptor_set_get_heap_offset(dst_set, type, &dst_ptr, true);
+ assert(src_heap_offset != ~0);
+ assert(dst_heap_offset != ~0);
+ dzn_descriptor_heap_copy(&dst_set->pool->heaps[type],
+ dst_set->heap_offsets[type] + dst_heap_offset,
+ &src_set->pool->heaps[type],
+ src_set->heap_offsets[type] + src_heap_offset,
+ count);
+ }
+ mtx_unlock(&dst_set->pool->defragment_lock);
+ mtx_unlock(&src_set->pool->defragment_lock);
+ }
+ }
+
+ dzn_descriptor_set_ptr_move(src_set, &src_ptr, count);
+ dzn_descriptor_set_ptr_move(dst_set, &dst_ptr, count);
+ copied_count += count;
+ }
+
+ assert(copied_count == pDescriptorCopy->descriptorCount);
+}
+
+VKAPI_ATTR void VKAPI_CALL
+dzn_UpdateDescriptorSets(VkDevice _device,
+ uint32_t descriptorWriteCount,
+ const VkWriteDescriptorSet *pDescriptorWrites,
+ uint32_t descriptorCopyCount,
+ const VkCopyDescriptorSet *pDescriptorCopies)
+{
+ VK_FROM_HANDLE(dzn_device, dev, _device);
+
+ for (unsigned i = 0; i < descriptorWriteCount; i++)
+ dzn_descriptor_set_write(&pDescriptorWrites[i]);
+
+ for (unsigned i = 0; i < descriptorCopyCount; i++)
+ dzn_descriptor_set_copy(&pDescriptorCopies[i]);
+}