mesa/src/amd/vulkan/radv_descriptor_set.c
Icenowy Zheng 734b6a8c35
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run
vk: descriptors: sort bindings along with flags
Vulkan spec requires binding flags to be matched with the binding with
the same index, however currently bindings are sorted with flags not
properly sorted, which leads to bindings and flags mismatch.

Resolve this by adding optional flags info to the parameters of
vk_create_sorted_bindings(), and refactoring panvk/pvr (which really
pair bindings and flags instead of only iterating flags) to use sorted
flags.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Ryan Mckeever <ryan.mckeever@collabora.com>
Reviewed-by: Simon Perretta <simon.perretta@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38967>
2026-01-20 15:55:47 +00:00

758 lines
34 KiB
C

/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* SPDX-License-Identifier: MIT
*/
#include "radv_descriptor_set.h"
#include "radv_cmd_buffer.h"
#include "radv_descriptor_pool.h"
#include "radv_descriptors.h"
#include "radv_entrypoints.h"
#include "radv_sampler.h"
#include "sid.h"
#include "vk_descriptors.h"
VKAPI_ATTR VkResult VKAPI_CALL
radv_CreateDescriptorSetLayout(VkDevice _device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout)
{
VK_FROM_HANDLE(radv_device, device, _device);
const struct radv_physical_device *pdev = radv_device_physical(device);
struct radv_descriptor_set_layout *set_layout;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
const VkDescriptorSetLayoutBindingFlagsCreateInfo *variable_flags =
vk_find_struct_const(pCreateInfo->pNext, DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO);
const VkMutableDescriptorTypeCreateInfoEXT *mutable_info =
vk_find_struct_const(pCreateInfo->pNext, MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT);
uint32_t num_bindings = 0;
uint32_t immutable_sampler_count = 0;
uint32_t ycbcr_sampler_count = 0;
for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) {
num_bindings = MAX2(num_bindings, pCreateInfo->pBindings[j].binding + 1);
if ((pCreateInfo->pBindings[j].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
pCreateInfo->pBindings[j].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) &&
pCreateInfo->pBindings[j].pImmutableSamplers) {
immutable_sampler_count += pCreateInfo->pBindings[j].descriptorCount;
bool has_ycbcr_sampler = false;
for (unsigned i = 0; i < pCreateInfo->pBindings[j].descriptorCount; ++i) {
if (radv_sampler_from_handle(pCreateInfo->pBindings[j].pImmutableSamplers[i])->vk.ycbcr_conversion)
has_ycbcr_sampler = true;
}
if (has_ycbcr_sampler)
ycbcr_sampler_count += pCreateInfo->pBindings[j].descriptorCount;
}
}
uint32_t samplers_offset = offsetof(struct radv_descriptor_set_layout, binding[num_bindings]);
size_t size = samplers_offset + immutable_sampler_count * 4 * sizeof(uint32_t);
if (ycbcr_sampler_count > 0) {
/* Store block of offsets first, followed by the conversion descriptors (padded to the struct
* alignment) */
size += num_bindings * sizeof(uint32_t);
size = align_uintptr(size, alignof(struct vk_ycbcr_conversion_state));
size += ycbcr_sampler_count * sizeof(struct vk_ycbcr_conversion_state);
}
/* We need to allocate descriptor set layouts off the device allocator with DEVICE scope because
* they are reference counted and may not be destroyed when vkDestroyDescriptorSetLayout is
* called.
*/
set_layout = vk_descriptor_set_layout_zalloc(&device->vk, size, pCreateInfo);
if (!set_layout)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
set_layout->flags = pCreateInfo->flags;
/* We just allocate all the samplers at the end of the struct */
uint32_t *samplers = (uint32_t *)&set_layout->binding[num_bindings];
struct vk_ycbcr_conversion_state *ycbcr_samplers = NULL;
uint32_t *ycbcr_sampler_offsets = NULL;
if (ycbcr_sampler_count > 0) {
ycbcr_sampler_offsets = samplers + 4 * immutable_sampler_count;
set_layout->ycbcr_sampler_offsets_offset = (char *)ycbcr_sampler_offsets - (char *)set_layout;
uintptr_t first_ycbcr_sampler_offset = (uintptr_t)ycbcr_sampler_offsets + sizeof(uint32_t) * num_bindings;
first_ycbcr_sampler_offset = align_uintptr(first_ycbcr_sampler_offset, alignof(struct vk_ycbcr_conversion_state));
ycbcr_samplers = (struct vk_ycbcr_conversion_state *)first_ycbcr_sampler_offset;
} else
set_layout->ycbcr_sampler_offsets_offset = 0;
VkDescriptorSetLayoutBinding *bindings = NULL;
VkResult result = vk_create_sorted_bindings(pCreateInfo->pBindings, pCreateInfo->bindingCount, &bindings, NULL, NULL);
if (result != VK_SUCCESS) {
vk_descriptor_set_layout_unref(&device->vk, &set_layout->vk);
return vk_error(device, result);
}
set_layout->binding_count = num_bindings;
set_layout->dynamic_shader_stages = 0;
set_layout->has_immutable_samplers = false;
set_layout->size = 0;
uint32_t buffer_count = 0;
uint32_t dynamic_offset_count = 0;
uint32_t first_alignment = 32;
if (pCreateInfo->bindingCount > 0) {
uint32_t last_alignment = radv_descriptor_alignment(bindings[pCreateInfo->bindingCount - 1].descriptorType);
if (bindings[pCreateInfo->bindingCount - 1].descriptorType == VK_DESCRIPTOR_TYPE_MUTABLE_EXT) {
uint64_t mutable_size = 0, mutable_align = 0;
radv_mutable_descriptor_type_size_alignment(
device, &mutable_info->pMutableDescriptorTypeLists[pCreateInfo->bindingCount - 1], &mutable_size,
&mutable_align);
last_alignment = mutable_align;
}
first_alignment = last_alignment == 32 ? 16 : 32;
}
for (unsigned pass = 0; pass < 2; ++pass) {
for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) {
const VkDescriptorSetLayoutBinding *binding = bindings + j;
uint32_t b = binding->binding;
uint32_t alignment = radv_descriptor_alignment(binding->descriptorType);
unsigned binding_buffer_count = radv_descriptor_type_buffer_count(binding->descriptorType);
uint32_t descriptor_count = binding->descriptorCount;
uint32_t max_sampled_image_descriptors = 1;
bool has_ycbcr_sampler = false;
if (binding->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && binding->pImmutableSamplers) {
for (unsigned i = 0; i < binding->descriptorCount; ++i) {
struct vk_ycbcr_conversion *conversion =
radv_sampler_from_handle(binding->pImmutableSamplers[i])->vk.ycbcr_conversion;
if (conversion) {
has_ycbcr_sampler = true;
max_sampled_image_descriptors =
MAX2(max_sampled_image_descriptors, vk_format_get_plane_count(conversion->state.format));
}
}
}
switch (binding->descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
assert(!(pCreateInfo->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT));
set_layout->binding[b].dynamic_offset_count = 1;
set_layout->dynamic_shader_stages |= binding->stageFlags;
if (binding->stageFlags & RADV_RT_STAGE_BITS)
set_layout->dynamic_shader_stages |= VK_SHADER_STAGE_COMPUTE_BIT;
set_layout->binding[b].size = 0;
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
set_layout->binding[b].size = RADV_BUFFER_DESC_SIZE;
break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
set_layout->binding[b].size = RADV_STORAGE_IMAGE_DESC_SIZE;
break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
set_layout->binding[b].size = radv_get_sampled_image_desc_size(pdev);
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
set_layout->binding[b].size =
max_sampled_image_descriptors * radv_get_combined_image_sampler_desc_size(pdev);
break;
case VK_DESCRIPTOR_TYPE_SAMPLER:
set_layout->binding[b].size = RADV_SAMPLER_DESC_SIZE;
break;
case VK_DESCRIPTOR_TYPE_MUTABLE_EXT: {
uint64_t mutable_size = 0, mutable_align = 0;
radv_mutable_descriptor_type_size_alignment(device, &mutable_info->pMutableDescriptorTypeLists[j],
&mutable_size, &mutable_align);
assert(mutable_size && mutable_align);
set_layout->binding[b].size = mutable_size;
alignment = mutable_align;
break;
}
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
set_layout->binding[b].size = descriptor_count;
descriptor_count = 1;
break;
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
set_layout->binding[b].size = RADV_ACCEL_STRUCT_DESC_SIZE;
break;
default:
break;
}
if ((pass == 0 && alignment != first_alignment) || (pass == 1 && alignment == first_alignment))
continue;
set_layout->size = align(set_layout->size, alignment);
set_layout->binding[b].type = binding->descriptorType;
set_layout->binding[b].array_size = descriptor_count;
set_layout->binding[b].offset = set_layout->size;
set_layout->binding[b].buffer_offset = buffer_count;
set_layout->binding[b].dynamic_offset_offset = dynamic_offset_count;
set_layout->binding[b].has_ycbcr_sampler = has_ycbcr_sampler;
if (variable_flags && j < variable_flags->bindingCount &&
(variable_flags->pBindingFlags[j] & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT)) {
assert(!binding->pImmutableSamplers); /* Terribly ill defined how many samplers are valid */
assert(binding->binding == num_bindings - 1);
set_layout->has_variable_descriptors = true;
}
if ((binding->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
binding->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) &&
binding->pImmutableSamplers) {
set_layout->binding[b].immutable_samplers_offset = samplers_offset;
set_layout->has_immutable_samplers = true;
for (uint32_t i = 0; i < binding->descriptorCount; i++)
memcpy(samplers + 4 * i, &radv_sampler_from_handle(binding->pImmutableSamplers[i])->state,
RADV_SAMPLER_DESC_SIZE);
samplers += 4 * binding->descriptorCount;
samplers_offset += 4 * sizeof(uint32_t) * binding->descriptorCount;
if (has_ycbcr_sampler) {
ycbcr_sampler_offsets[b] = (const char *)ycbcr_samplers - (const char *)set_layout;
for (uint32_t i = 0; i < binding->descriptorCount; i++) {
if (radv_sampler_from_handle(binding->pImmutableSamplers[i])->vk.ycbcr_conversion)
ycbcr_samplers[i] =
radv_sampler_from_handle(binding->pImmutableSamplers[i])->vk.ycbcr_conversion->state;
else
ycbcr_samplers[i].format = VK_FORMAT_UNDEFINED;
}
ycbcr_samplers += binding->descriptorCount;
}
}
set_layout->size += descriptor_count * set_layout->binding[b].size;
buffer_count += descriptor_count * binding_buffer_count;
dynamic_offset_count += descriptor_count * set_layout->binding[b].dynamic_offset_count;
}
}
free(bindings);
set_layout->buffer_count = buffer_count;
set_layout->dynamic_offset_count = dynamic_offset_count;
/* Hash the entire set layout except vk_descriptor_set_layout. The rest of the set layout is
* carefully constructed to not have pointers so a full hash instead of a per-field hash
* should be ok.
*/
uint32_t hash_offset = offsetof(struct radv_descriptor_set_layout, hash) + sizeof(set_layout->hash);
_mesa_blake3_compute((const char *)set_layout + hash_offset, size - hash_offset, set_layout->hash);
*pSetLayout = radv_descriptor_set_layout_to_handle(set_layout);
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL
radv_GetDescriptorSetLayoutSupport(VkDevice _device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
VkDescriptorSetLayoutSupport *pSupport)
{
VK_FROM_HANDLE(radv_device, device, _device);
const struct radv_physical_device *pdev = radv_device_physical(device);
VkDescriptorSetLayoutBinding *bindings = NULL;
VkResult result = vk_create_sorted_bindings(pCreateInfo->pBindings, pCreateInfo->bindingCount, &bindings, NULL, NULL);
if (result != VK_SUCCESS) {
pSupport->supported = false;
return;
}
const VkDescriptorSetLayoutBindingFlagsCreateInfo *variable_flags =
vk_find_struct_const(pCreateInfo->pNext, DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO);
VkDescriptorSetVariableDescriptorCountLayoutSupport *variable_count =
vk_find_struct(pSupport->pNext, DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT);
const VkMutableDescriptorTypeCreateInfoEXT *mutable_info =
vk_find_struct_const(pCreateInfo->pNext, MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT);
if (variable_count) {
variable_count->maxVariableDescriptorCount = 0;
}
uint32_t first_alignment = 32;
if (pCreateInfo->bindingCount > 0) {
uint32_t last_alignment = radv_descriptor_alignment(bindings[pCreateInfo->bindingCount - 1].descriptorType);
if (bindings[pCreateInfo->bindingCount - 1].descriptorType == VK_DESCRIPTOR_TYPE_MUTABLE_EXT) {
uint64_t mutable_size = 0, mutable_align = 0;
radv_mutable_descriptor_type_size_alignment(
device, &mutable_info->pMutableDescriptorTypeLists[pCreateInfo->bindingCount - 1], &mutable_size,
&mutable_align);
last_alignment = mutable_align;
}
first_alignment = last_alignment == 32 ? 16 : 32;
}
bool supported = true;
uint64_t size = 0;
for (unsigned pass = 0; pass < 2; ++pass) {
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
const VkDescriptorSetLayoutBinding *binding = bindings + i;
uint64_t descriptor_size = 0;
uint64_t descriptor_alignment = radv_descriptor_alignment(binding->descriptorType);
uint32_t descriptor_count = binding->descriptorCount;
switch (binding->descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
descriptor_size = RADV_BUFFER_DESC_SIZE;
break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
descriptor_size = RADV_STORAGE_IMAGE_DESC_SIZE;
break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
descriptor_size = radv_get_sampled_image_desc_size(pdev);
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
descriptor_size = radv_get_combined_image_sampler_desc_size(pdev);
break;
case VK_DESCRIPTOR_TYPE_SAMPLER:
descriptor_size = RADV_SAMPLER_DESC_SIZE;
break;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
descriptor_size = descriptor_count;
descriptor_count = 1;
break;
case VK_DESCRIPTOR_TYPE_MUTABLE_EXT:
if (!radv_mutable_descriptor_type_size_alignment(device, &mutable_info->pMutableDescriptorTypeLists[i],
&descriptor_size, &descriptor_alignment)) {
supported = false;
}
break;
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
descriptor_size = RADV_ACCEL_STRUCT_DESC_SIZE;
break;
default:
break;
}
if ((pass == 0 && descriptor_alignment != first_alignment) ||
(pass == 1 && descriptor_alignment == first_alignment))
continue;
if (size && !align64(size, descriptor_alignment)) {
supported = false;
}
size = align64(size, descriptor_alignment);
uint64_t max_count = INT32_MAX;
if (binding->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
max_count = MAX_INLINE_UNIFORM_BLOCK_SIZE - size;
else if (descriptor_size)
max_count = (INT32_MAX - size) / descriptor_size;
if (max_count < descriptor_count) {
supported = false;
}
if (variable_flags && i < variable_flags->bindingCount && variable_count &&
(variable_flags->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT)) {
variable_count->maxVariableDescriptorCount = MIN2(UINT32_MAX, max_count);
}
size += descriptor_count * descriptor_size;
}
}
free(bindings);
pSupport->supported = supported;
}
static VkResult
radv_alloc_descriptor_pool_entry(struct radv_device *device, struct radv_descriptor_pool *pool,
struct radv_descriptor_set *set)
{
uint64_t current_offset = pool->current_offset;
if (!pool->host_memory_base) {
if (set->header.size) {
uint64_t pool_vma_offset = util_vma_heap_alloc(&pool->bo_heap, set->header.size, 32);
if (!pool_vma_offset)
return VK_ERROR_FRAGMENTED_POOL;
assert(pool_vma_offset >= RADV_POOL_HEAP_OFFSET && pool_vma_offset <= pool->size + RADV_POOL_HEAP_OFFSET);
set->header.offset = pool_vma_offset - RADV_POOL_HEAP_OFFSET;
current_offset = set->header.offset;
}
} else {
if (current_offset + set->header.size > pool->size)
return VK_ERROR_OUT_OF_POOL_MEMORY;
pool->current_offset += set->header.size;
}
set->header.bo = pool->bo;
set->header.mapped_ptr = (uint32_t *)(pool->mapped_ptr + current_offset);
set->header.va = pool->bo ? (radv_buffer_get_va(set->header.bo) + current_offset) : 0;
list_addtail(&set->link, &pool->sets);
pool->entry_count++;
return VK_SUCCESS;
}
static VkResult
radv_descriptor_set_create(struct radv_device *device, struct radv_descriptor_pool *pool,
struct radv_descriptor_set_layout *layout, const uint32_t variable_count,
struct radv_descriptor_set **out_set)
{
const struct radv_physical_device *pdev = radv_device_physical(device);
VkResult result;
if (pool->entry_count == pool->max_entry_count)
return VK_ERROR_OUT_OF_POOL_MEMORY;
struct radv_descriptor_set *set;
uint32_t buffer_count = layout->buffer_count;
if (variable_count) {
unsigned stride = radv_descriptor_type_buffer_count(layout->binding[layout->binding_count - 1].type);
buffer_count = layout->binding[layout->binding_count - 1].buffer_offset + variable_count * stride;
}
unsigned range_offset =
offsetof(struct radv_descriptor_set, descriptors) + sizeof(struct radeon_winsys_bo *) * buffer_count;
const unsigned dynamic_offset_count = layout->dynamic_offset_count;
unsigned mem_size = range_offset + sizeof(struct radv_descriptor_range) * dynamic_offset_count;
if (pool->host_memory_base) {
if (pool->host_memory_end - pool->host_memory_ptr < mem_size)
return VK_ERROR_OUT_OF_POOL_MEMORY;
set = (struct radv_descriptor_set *)pool->host_memory_ptr;
pool->host_memory_ptr += mem_size;
} else {
set = vk_alloc2(&device->vk.alloc, NULL, mem_size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!set)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
memset(set, 0, mem_size);
vk_object_base_init(&device->vk, &set->header.base, VK_OBJECT_TYPE_DESCRIPTOR_SET);
if (dynamic_offset_count) {
set->header.dynamic_descriptors = (struct radv_descriptor_range *)((uint8_t *)set + range_offset);
}
set->header.layout = layout;
set->header.buffer_count = buffer_count;
uint32_t layout_size = layout->size;
if (variable_count) {
uint32_t stride = layout->binding[layout->binding_count - 1].size;
if (layout->binding[layout->binding_count - 1].type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
stride = 1;
layout_size = layout->binding[layout->binding_count - 1].offset + variable_count * stride;
}
set->header.size = align(layout_size, 32);
result = radv_alloc_descriptor_pool_entry(device, pool, set);
if (result != VK_SUCCESS)
return result;
if (layout->has_immutable_samplers) {
for (unsigned i = 0; i < layout->binding_count; ++i) {
if (!layout->binding[i].immutable_samplers_offset)
continue;
unsigned offset = layout->binding[i].offset / 4;
if (layout->binding[i].type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
offset += radv_get_combined_image_sampler_offset(pdev) / 4;
const uint32_t *samplers =
(const uint32_t *)((const char *)layout + layout->binding[i].immutable_samplers_offset);
for (unsigned j = 0; j < layout->binding[i].array_size; ++j) {
memcpy(set->header.mapped_ptr + offset, samplers + 4 * j, RADV_SAMPLER_DESC_SIZE);
offset += layout->binding[i].size / 4;
}
}
}
vk_descriptor_set_layout_ref(&layout->vk);
*out_set = set;
return VK_SUCCESS;
}
void
radv_descriptor_set_destroy(struct radv_device *device, struct radv_descriptor_pool *pool,
struct radv_descriptor_set *set)
{
assert(!pool->host_memory_base);
list_del(&set->link);
vk_descriptor_set_layout_unref(&device->vk, &set->header.layout->vk);
if (set->header.size)
util_vma_heap_free(&pool->bo_heap, (uint64_t)set->header.offset + RADV_POOL_HEAP_OFFSET, set->header.size);
pool->entry_count--;
vk_object_base_finish(&set->header.base);
vk_free2(&device->vk.alloc, NULL, set);
}
VKAPI_ATTR VkResult VKAPI_CALL
radv_AllocateDescriptorSets(VkDevice _device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
VkDescriptorSet *pDescriptorSets)
{
VK_FROM_HANDLE(radv_device, device, _device);
VK_FROM_HANDLE(radv_descriptor_pool, pool, pAllocateInfo->descriptorPool);
VkResult result = VK_SUCCESS;
uint32_t i;
struct radv_descriptor_set *set = NULL;
const VkDescriptorSetVariableDescriptorCountAllocateInfo *variable_counts =
vk_find_struct_const(pAllocateInfo->pNext, DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO);
/* allocate a set of buffers for each shader to contain descriptors */
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
VK_FROM_HANDLE(radv_descriptor_set_layout, layout, pAllocateInfo->pSetLayouts[i]);
uint32_t variable_count =
layout->has_variable_descriptors && variable_counts && i < variable_counts->descriptorSetCount
? variable_counts->pDescriptorCounts[i]
: 0;
assert(!(layout->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT));
result = radv_descriptor_set_create(device, pool, layout, variable_count, &set);
if (result != VK_SUCCESS)
break;
pDescriptorSets[i] = radv_descriptor_set_to_handle(set);
}
if (result != VK_SUCCESS) {
radv_FreeDescriptorSets(_device, pAllocateInfo->descriptorPool, i, pDescriptorSets);
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
pDescriptorSets[i] = VK_NULL_HANDLE;
}
}
return result;
}
VKAPI_ATTR VkResult VKAPI_CALL
radv_FreeDescriptorSets(VkDevice _device, VkDescriptorPool descriptorPool, uint32_t count,
const VkDescriptorSet *pDescriptorSets)
{
VK_FROM_HANDLE(radv_device, device, _device);
VK_FROM_HANDLE(radv_descriptor_pool, pool, descriptorPool);
for (uint32_t i = 0; i < count; i++) {
VK_FROM_HANDLE(radv_descriptor_set, set, pDescriptorSets[i]);
if (set && !pool->host_memory_base)
radv_descriptor_set_destroy(device, pool, set);
}
return VK_SUCCESS;
}
static ALWAYS_INLINE void
radv_update_descriptor_sets_impl(struct radv_device *device, struct radv_cmd_buffer *cmd_buffer,
VkDescriptorSet dstSetOverride, uint32_t descriptorWriteCount,
const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
const VkCopyDescriptorSet *pDescriptorCopies)
{
const struct radv_physical_device *pdev = radv_device_physical(device);
uint32_t i, j;
for (i = 0; i < descriptorWriteCount; i++) {
const VkWriteDescriptorSet *writeset = &pDescriptorWrites[i];
VK_FROM_HANDLE(radv_descriptor_set, set, dstSetOverride ? dstSetOverride : writeset->dstSet);
const struct radv_descriptor_set_binding_layout *binding_layout =
set->header.layout->binding + writeset->dstBinding;
uint32_t *ptr = set->header.mapped_ptr;
struct radeon_winsys_bo **buffer_list = set->descriptors;
/* Immutable samplers are not copied into push descriptors when they are
* allocated, so if we are writing push descriptors we have to copy the
* immutable samplers into them now.
*/
const bool copy_immutable_samplers = cmd_buffer && binding_layout->immutable_samplers_offset;
const uint32_t *samplers = radv_immutable_samplers(set->header.layout, binding_layout);
const VkWriteDescriptorSetAccelerationStructureKHR *accel_structs = NULL;
ptr += binding_layout->offset / 4;
if (writeset->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) {
radv_write_block_descriptor(device, cmd_buffer, (uint8_t *)ptr + writeset->dstArrayElement, writeset);
continue;
} else if (writeset->descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) {
accel_structs = vk_find_struct_const(writeset->pNext, WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR);
}
ptr += binding_layout->size * writeset->dstArrayElement / 4;
buffer_list += binding_layout->buffer_offset;
buffer_list += writeset->dstArrayElement * radv_descriptor_type_buffer_count(writeset->descriptorType);
for (j = 0; j < writeset->descriptorCount; ++j) {
switch (writeset->descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
unsigned idx = writeset->dstArrayElement + j;
idx += binding_layout->dynamic_offset_offset;
assert(!(set->header.layout->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT));
radv_write_dynamic_buffer_descriptor(device, set->header.dynamic_descriptors + idx, buffer_list,
writeset->pBufferInfo + j);
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
radv_write_buffer_descriptor_impl(device, cmd_buffer, ptr, buffer_list, writeset->pBufferInfo + j);
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
radv_write_texel_buffer_descriptor(device, cmd_buffer, ptr, buffer_list, writeset->pTexelBufferView[j]);
break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
radv_write_image_descriptor_impl(device, cmd_buffer, RADV_STORAGE_IMAGE_DESC_SIZE, ptr, buffer_list,
writeset->descriptorType, writeset->pImageInfo + j);
break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
radv_write_image_descriptor_impl(device, cmd_buffer, radv_get_sampled_image_desc_size(pdev), ptr,
buffer_list, writeset->descriptorType, writeset->pImageInfo + j);
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
if (binding_layout->has_ycbcr_sampler) {
radv_write_image_descriptor_ycbcr_impl(device, cmd_buffer, ptr, buffer_list, writeset->pImageInfo + j);
} else {
radv_write_combined_image_sampler_descriptor(device, cmd_buffer, ptr, buffer_list,
writeset->descriptorType, writeset->pImageInfo + j,
!binding_layout->immutable_samplers_offset);
}
if (copy_immutable_samplers) {
const uint32_t sampler_offset = radv_get_combined_image_sampler_offset(pdev);
const unsigned idx = writeset->dstArrayElement + j;
memcpy((char *)ptr + sampler_offset, samplers + 4 * idx, RADV_SAMPLER_DESC_SIZE);
}
break;
}
case VK_DESCRIPTOR_TYPE_SAMPLER:
if (!binding_layout->immutable_samplers_offset) {
const VkDescriptorImageInfo *pImageInfo = writeset->pImageInfo + j;
radv_write_sampler_descriptor(ptr, pImageInfo->sampler);
} else if (copy_immutable_samplers) {
unsigned idx = writeset->dstArrayElement + j;
memcpy(ptr, samplers + 4 * idx, RADV_SAMPLER_DESC_SIZE);
}
break;
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
VK_FROM_HANDLE(vk_acceleration_structure, accel_struct, accel_structs->pAccelerationStructures[j]);
radv_write_accel_struct_descriptor(device, ptr,
accel_struct ? vk_acceleration_structure_get_va(accel_struct) : 0);
break;
}
default:
break;
}
ptr += binding_layout->size / 4;
buffer_list += radv_descriptor_type_buffer_count(writeset->descriptorType);
}
}
for (i = 0; i < descriptorCopyCount; i++) {
const VkCopyDescriptorSet *copyset = &pDescriptorCopies[i];
VK_FROM_HANDLE(radv_descriptor_set, src_set, copyset->srcSet);
VK_FROM_HANDLE(radv_descriptor_set, dst_set, copyset->dstSet);
const struct radv_descriptor_set_binding_layout *src_binding_layout =
src_set->header.layout->binding + copyset->srcBinding;
const struct radv_descriptor_set_binding_layout *dst_binding_layout =
dst_set->header.layout->binding + copyset->dstBinding;
uint32_t *src_ptr = src_set->header.mapped_ptr;
uint32_t *dst_ptr = dst_set->header.mapped_ptr;
struct radeon_winsys_bo **src_buffer_list = src_set->descriptors;
struct radeon_winsys_bo **dst_buffer_list = dst_set->descriptors;
src_ptr += src_binding_layout->offset / 4;
dst_ptr += dst_binding_layout->offset / 4;
if (src_binding_layout->type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) {
src_ptr += copyset->srcArrayElement / 4;
dst_ptr += copyset->dstArrayElement / 4;
memcpy(dst_ptr, src_ptr, copyset->descriptorCount);
continue;
}
src_ptr += src_binding_layout->size * copyset->srcArrayElement / 4;
dst_ptr += dst_binding_layout->size * copyset->dstArrayElement / 4;
src_buffer_list += src_binding_layout->buffer_offset;
src_buffer_list += copyset->srcArrayElement;
dst_buffer_list += dst_binding_layout->buffer_offset;
dst_buffer_list += copyset->dstArrayElement;
/* In case of copies between mutable descriptor types
* and non-mutable descriptor types. */
size_t copy_size = MIN2(src_binding_layout->size, dst_binding_layout->size);
for (j = 0; j < copyset->descriptorCount; ++j) {
if (vk_descriptor_type_is_dynamic(src_binding_layout->type)) {
unsigned src_idx = copyset->srcArrayElement + j;
unsigned dst_idx = copyset->dstArrayElement + j;
struct radv_descriptor_range *src_range, *dst_range;
src_idx += src_binding_layout->dynamic_offset_offset;
dst_idx += dst_binding_layout->dynamic_offset_offset;
src_range = src_set->header.dynamic_descriptors + src_idx;
dst_range = dst_set->header.dynamic_descriptors + dst_idx;
*dst_range = *src_range;
} else
memcpy(dst_ptr, src_ptr, copy_size);
src_ptr += src_binding_layout->size / 4;
dst_ptr += dst_binding_layout->size / 4;
unsigned src_buffer_count = radv_descriptor_type_buffer_count(src_binding_layout->type);
unsigned dst_buffer_count = radv_descriptor_type_buffer_count(dst_binding_layout->type);
for (unsigned k = 0; k < dst_buffer_count; k++) {
if (k < src_buffer_count)
dst_buffer_list[k] = src_buffer_list[k];
else
dst_buffer_list[k] = NULL;
}
dst_buffer_list += dst_buffer_count;
src_buffer_list += src_buffer_count;
}
}
}
VKAPI_ATTR void VKAPI_CALL
radv_UpdateDescriptorSets(VkDevice _device, uint32_t descriptorWriteCount,
const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
const VkCopyDescriptorSet *pDescriptorCopies)
{
VK_FROM_HANDLE(radv_device, device, _device);
radv_update_descriptor_sets_impl(device, NULL, VK_NULL_HANDLE, descriptorWriteCount, pDescriptorWrites,
descriptorCopyCount, pDescriptorCopies);
}
void
radv_cmd_update_descriptor_sets(struct radv_device *device, struct radv_cmd_buffer *cmd_buffer,
VkDescriptorSet dstSetOverride, uint32_t descriptorWriteCount,
const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
const VkCopyDescriptorSet *pDescriptorCopies)
{
/* Assume cmd_buffer != NULL to optimize out cmd_buffer checks in generic code above. */
assume(cmd_buffer != NULL);
radv_update_descriptor_sets_impl(device, cmd_buffer, dstSetOverride, descriptorWriteCount, pDescriptorWrites,
descriptorCopyCount, pDescriptorCopies);
}