diff --git a/src/nouveau/vulkan/meson.build b/src/nouveau/vulkan/meson.build index f1057798b98..2cd2358d339 100644 --- a/src/nouveau/vulkan/meson.build +++ b/src/nouveau/vulkan/meson.build @@ -5,6 +5,9 @@ nvk_files = files( 'nvk_buffer.h', 'nvk_cmd_buffer.c', 'nvk_cmd_buffer.h', + 'nvk_descriptor_set.h', + 'nvk_descriptor_set_layout.c', + 'nvk_descriptor_set_layout.h', 'nvk_device.c', 'nvk_device.h', 'nvk_device_memory.c', diff --git a/src/nouveau/vulkan/nvk_descriptor_set.h b/src/nouveau/vulkan/nvk_descriptor_set.h new file mode 100644 index 00000000000..f9a269ed609 --- /dev/null +++ b/src/nouveau/vulkan/nvk_descriptor_set.h @@ -0,0 +1,18 @@ +#ifndef NVK_DESCRIPTOR_SET +#define NVK_DESCRIPTOR_SET 1 + +#include "nvk_private.h" + +struct nvk_image_descriptor { + unsigned image_index:20; + unsigned sampler_index:12; +}; + +/* This has to match nir_address_format_64bit_bounded_global */ +struct nvk_buffer_address { + uint64_t base_addr; + uint32_t size; + uint32_t zero; /* Must be zero! */ +}; + +#endif diff --git a/src/nouveau/vulkan/nvk_descriptor_set_layout.c b/src/nouveau/vulkan/nvk_descriptor_set_layout.c new file mode 100644 index 00000000000..1be1fa9cb82 --- /dev/null +++ b/src/nouveau/vulkan/nvk_descriptor_set_layout.c @@ -0,0 +1,225 @@ +#include "nvk_descriptor_set_layout.h" + +#include "nvk_descriptor_set.h" +#include "nvk_device.h" +#include "nvk_sampler.h" + +#include "util/mesa-sha1.h" + +static bool +binding_has_immutable_samplers(const VkDescriptorSetLayoutBinding *binding) { + switch (binding->descriptorType) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + return binding->pImmutableSamplers != NULL; + + default: + return false; + } +} + +static void descriptor_stride_align_for_type( + VkDescriptorType type, const VkMutableDescriptorTypeListVALVE *type_list, + uint32_t *stride, uint32_t *align) { + switch (type) { + case VK_DESCRIPTOR_TYPE_SAMPLER: + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + /* TODO: How do samplers work? */ + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + *stride = *align = sizeof(struct nvk_image_descriptor); + break; + + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + unreachable("TODO: Implement texel buffers"); + + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + *stride = *align = sizeof(struct nvk_buffer_address); + break; + + case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK: + *stride = 1; /* Array size is bytes */ + *align = NVK_MIN_UBO_ALIGNMENT; + break; + + case VK_DESCRIPTOR_TYPE_MUTABLE_VALVE: + *stride = *align = 0; + for (unsigned i = 0; i < type_list->descriptorTypeCount; i++) { + /* This shouldn't recurse */ + assert(type_list->pDescriptorTypes[i] != + VK_DESCRIPTOR_TYPE_MUTABLE_VALVE); + uint32_t desc_stride, desc_align; + descriptor_stride_align_for_type(type_list->pDescriptorTypes[i], NULL, + &desc_stride, &desc_align); + *stride = MAX2(*stride, desc_stride); + *align = MAX2(*align, desc_align); + } + *stride = ALIGN(*stride, *align); + break; + + default: + unreachable("Invalid descriptor type"); + } +} + +VKAPI_ATTR VkResult VKAPI_CALL nvk_CreateDescriptorSetLayout( + VkDevice _device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDescriptorSetLayout *pSetLayout) { + VK_FROM_HANDLE(nvk_device, device, _device); + + uint32_t num_bindings = 0; + uint32_t immutable_sampler_count = 0; + for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) { + const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[j]; + num_bindings = MAX2(num_bindings, binding->binding + 1); + + /* 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. + */ + if (binding_has_immutable_samplers(binding)) + immutable_sampler_count += binding->descriptorCount; + } + + VK_MULTIALLOC(ma); + VK_MULTIALLOC_DECL(&ma, struct nvk_descriptor_set_layout, layout, 1); + VK_MULTIALLOC_DECL(&ma, struct nvk_descriptor_set_binding_layout, bindings, + num_bindings); + VK_MULTIALLOC_DECL(&ma, struct nvk_sampler *, samplers, + immutable_sampler_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_DESCRIPTOR_SET_LAYOUT); + + p_atomic_set(&layout->ref_cnt, 1); + layout->binding_count = num_bindings; + + for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) { + const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[j]; + uint32_t b = binding->binding; + /* We temporarily store pCreateInfo->pBindings[] index (plus one) in the + * immutable_samplers pointer. This provides us with a quick-and-dirty + * way to sort the bindings by binding number. + */ + layout->binding[b].immutable_samplers = (void *)(uintptr_t)(j + 1); + } + + const VkDescriptorSetLayoutBindingFlagsCreateInfo *binding_flags_info = + vk_find_struct_const(pCreateInfo->pNext, + DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO); + const VkMutableDescriptorTypeCreateInfoVALVE *mutable_info = + vk_find_struct_const(pCreateInfo->pNext, + MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE); + + uint32_t buffer_size = 0; + for (uint32_t b = 0; b < num_bindings; b++) { + /* We stashed the pCreateInfo->pBindings[] index (plus one) in the + * immutable_samplers pointer. Check for NULL (empty binding) and then + * reset it and compute the index. + */ + if (layout->binding[b].immutable_samplers == NULL) + continue; + const uint32_t info_idx = + (uintptr_t)(void *)layout->binding[b].immutable_samplers - 1; + layout->binding[b].immutable_samplers = NULL; + + const VkDescriptorSetLayoutBinding *binding = + &pCreateInfo->pBindings[info_idx]; + + if (binding->descriptorCount == 0) + continue; + + layout->binding[b].type = binding->descriptorType; + + if (binding_flags_info && binding_flags_info->bindingCount > 0) { + assert(binding_flags_info->bindingCount == pCreateInfo->bindingCount); + layout->binding[b].flags = binding_flags_info->pBindingFlags[info_idx]; + } + + layout->binding[b].array_size = binding->descriptorCount; + + const VkMutableDescriptorTypeListVALVE *type_list = NULL; + if (binding->descriptorType == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) { + assert(mutable_info != NULL); + assert(info_idx <= mutable_info->mutableDescriptorTypeListCount); + type_list = &mutable_info->pMutableDescriptorTypeLists[info_idx]; + } + + uint32_t stride, align; + descriptor_stride_align_for_type(binding->descriptorType, type_list, + &stride, &align); + + layout->binding[b].offset = ALIGN_POT(buffer_size, align); + layout->binding[b].stride = stride; + buffer_size += stride * binding->descriptorCount; + + if (binding_has_immutable_samplers(binding)) { + layout->binding[b].immutable_samplers = samplers; + samplers += binding->descriptorCount; + for (uint32_t i = 0; i < binding->descriptorCount; i++) { + VK_FROM_HANDLE(nvk_sampler, sampler, binding->pImmutableSamplers[i]); + layout->binding[b].immutable_samplers[i] = sampler; + } + } + } + + layout->descriptor_buffer_size = buffer_size; + + struct mesa_sha1 sha1_ctx; + _mesa_sha1_init(&sha1_ctx); + +#define SHA1_UPDATE_VALUE(x) _mesa_sha1_update(&sha1_ctx, &(x), sizeof(x)); + SHA1_UPDATE_VALUE(layout->descriptor_buffer_size); + SHA1_UPDATE_VALUE(layout->binding_count); + + for (uint32_t b = 0; b < num_bindings; b++) { + SHA1_UPDATE_VALUE(layout->binding[b].type); + SHA1_UPDATE_VALUE(layout->binding[b].flags); + SHA1_UPDATE_VALUE(layout->binding[b].array_size); + SHA1_UPDATE_VALUE(layout->binding[b].offset); + SHA1_UPDATE_VALUE(layout->binding[b].stride); + /* Immutable samplers are ignored for now */ + } +#undef SHA1_UPDATE_VALUE + + _mesa_sha1_final(&sha1_ctx, layout->sha1); + + *pSetLayout = nvk_descriptor_set_layout_to_handle(layout); + + return VK_SUCCESS; +} + +void nvk_descriptor_set_layout_destroy( + struct nvk_device *device, struct nvk_descriptor_set_layout *layout) { + assert(layout->ref_cnt == 0); + vk_object_free(&device->vk, NULL, layout); +} + +VKAPI_ATTR void VKAPI_CALL nvk_DestroyDescriptorSetLayout( + VkDevice _device, VkDescriptorSetLayout descriptorSetLayout, + const VkAllocationCallbacks *pAllocator) { + VK_FROM_HANDLE(nvk_device, device, _device); + VK_FROM_HANDLE(nvk_descriptor_set_layout, layout, descriptorSetLayout); + + if (!layout) + return; + + nvk_descriptor_set_layout_unref(device, layout); +} diff --git a/src/nouveau/vulkan/nvk_descriptor_set_layout.h b/src/nouveau/vulkan/nvk_descriptor_set_layout.h new file mode 100644 index 00000000000..9adec0d3e13 --- /dev/null +++ b/src/nouveau/vulkan/nvk_descriptor_set_layout.h @@ -0,0 +1,71 @@ +#ifndef NVK_DESCRIPTOR_SET_LAYOUT +#define NVK_DESCRIPTOR_SET_LAYOUT 1 + +#include "nvk_private.h" + +#include "vulkan/runtime/vk_object.h" + +struct nvk_device; +struct nvk_sampler; + +struct nvk_descriptor_set_binding_layout { + /* The type of the descriptors in this binding */ + VkDescriptorType type; + + /* Flags provided when this binding was created */ + VkDescriptorBindingFlags flags; + + /* Number of array elements in this binding (or size in bytes for inline + * uniform data) + */ + uint32_t array_size; + + /* Offset into the descriptor buffer where this descriptor lives */ + uint32_t offset; + + /* Stride between array elements in the descriptor buffer */ + uint32_t stride; + + /* Immutable samplers (or NULL if no immutable samplers) */ + struct nvk_sampler **immutable_samplers; +}; + +struct nvk_descriptor_set_layout { + struct vk_object_base base; + + uint32_t ref_cnt; + + unsigned char sha1[20]; + + /* Size of the descriptor buffer for this descriptor set */ + uint32_t descriptor_buffer_size; + + /* Number of bindings in this descriptor set */ + uint32_t binding_count; + + /* Bindings in this descriptor set */ + struct nvk_descriptor_set_binding_layout binding[0]; +}; + +VK_DEFINE_HANDLE_CASTS(nvk_descriptor_set_layout, base, VkDescriptorSetLayout, + VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT) + +void nvk_descriptor_set_layout_destroy( + struct nvk_device *device, struct nvk_descriptor_set_layout *layout); + +static inline struct nvk_descriptor_set_layout * +nvk_descriptor_set_layout_ref(struct nvk_descriptor_set_layout *layout) { + assert(layout && layout->ref_cnt >= 1); + p_atomic_inc(&layout->ref_cnt); + return layout; +} + +static inline void +nvk_descriptor_set_layout_unref(struct nvk_device *device, + struct nvk_descriptor_set_layout *layout) { + assert(layout && layout->ref_cnt >= 1); + if (p_atomic_dec_zero(&layout->ref_cnt)) + nvk_descriptor_set_layout_destroy(device, layout); +} + +#endif diff --git a/src/nouveau/vulkan/nvk_private.h b/src/nouveau/vulkan/nvk_private.h index 48602b1854c..d0fa48f240d 100644 --- a/src/nouveau/vulkan/nvk_private.h +++ b/src/nouveau/vulkan/nvk_private.h @@ -12,6 +12,8 @@ #include #include +#define NVK_MIN_UBO_ALIGNMENT 16 + /** * Warn on ignored extension structs. *