v3dv/descriptor_set: support for immutable samplers

They are bound at the set layout, and cannot be changed. From
VkDescriptorSetLayoutBinding spec:

   "pImmutableSamplers affects initialization of samplers. 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. Immutable samplers are permanently bound into the set
   layout and must not be changed; updating a
   VK_DESCRIPTOR_TYPE_SAMPLER descriptor with immutable samplers is
   not allowed and updates to a
   VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor with immutable
   samplers does not modify the samplers (the image views are updated,
   but the sampler updates are ignored)"

We stored them as part of the set layout. It also means that when we
need the sampler (like for texture operations) we can't just ask for a
descriptor, as it would not have the sampler. A new method is created.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
This commit is contained in:
Alejandro Piñeiro 2020-04-02 13:24:13 +02:00 committed by Marge Bot
parent 53de8892f4
commit dedff7446a
3 changed files with 112 additions and 18 deletions

View File

@ -325,18 +325,30 @@ v3dv_CreateDescriptorSetLayout(VkDevice _device,
uint32_t immutable_sampler_count = 0;
for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) {
max_binding = MAX2(max_binding, pCreateInfo->pBindings[j].binding);
if ((pCreateInfo->pBindings[j].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
pCreateInfo->pBindings[j].descriptorType == VK_DESCRIPTOR_TYPE_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.
*/
VkDescriptorType desc_type = pCreateInfo->pBindings[j].descriptorType;
if ((desc_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
desc_type == VK_DESCRIPTOR_TYPE_SAMPLER) &&
pCreateInfo->pBindings[j].pImmutableSamplers) {
immutable_sampler_count += pCreateInfo->pBindings[j].descriptorCount;
}
}
/* FIXME: immutable samplers not supported yet */
assert(immutable_sampler_count == 0);
uint32_t size = sizeof(struct v3dv_descriptor_set_layout) +
uint32_t samplers_offset = sizeof(struct v3dv_descriptor_set_layout) +
(max_binding + 1) * sizeof(set_layout->binding[0]);
uint32_t size = samplers_offset +
immutable_sampler_count * sizeof(struct v3dv_sampler);
set_layout = vk_alloc2(&device->alloc, pAllocator, size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
@ -344,6 +356,9 @@ v3dv_CreateDescriptorSetLayout(VkDevice _device,
if (!set_layout)
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
/* We just allocate all the immutable samplers at the end of the struct */
struct v3dv_sampler *samplers = (void*) &set_layout->binding[max_binding + 1];
VkDescriptorSetLayoutBinding *bindings =
create_sorted_bindings(pCreateInfo->pBindings, pCreateInfo->bindingCount,
device, pAllocator);
@ -359,7 +374,6 @@ v3dv_CreateDescriptorSetLayout(VkDevice _device,
set_layout->binding_count = max_binding + 1;
set_layout->flags = pCreateInfo->flags;
set_layout->shader_stages = 0;
set_layout->has_immutable_samplers = false;
uint32_t descriptor_count = 0;
uint32_t dynamic_offset_count = 0;
@ -391,6 +405,19 @@ v3dv_CreateDescriptorSetLayout(VkDevice _device,
set_layout->binding[binding_number].descriptor_index = descriptor_count;
set_layout->binding[binding_number].dynamic_offset_index = dynamic_offset_count;
if ((binding->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
binding->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) &&
binding->pImmutableSamplers) {
set_layout->binding[binding_number].immutable_samplers_offset = samplers_offset;
for (uint32_t i = 0; i < binding->descriptorCount; i++)
samplers[i] = *v3dv_sampler_from_handle(binding->pImmutableSamplers[i]);
samplers += binding->descriptorCount;
samplers_offset += sizeof(struct v3dv_sampler) * binding->descriptorCount;
}
descriptor_count += binding->descriptorCount;
dynamic_offset_count += binding->descriptorCount *
set_layout->binding[binding_number].dynamic_offset_count;
@ -457,9 +484,6 @@ descriptor_set_create(struct v3dv_device *device,
set->layout = layout;
/* FIXME: if we have immutable samplers those are tightly included here */
assert(layout->has_immutable_samplers == false);
if (!pool->host_memory_base && pool->entry_count == pool->max_entry_count) {
vk_free2(&device->alloc, NULL, set);
return vk_error(device->instance, VK_ERROR_OUT_OF_POOL_MEMORY);

View File

@ -951,6 +951,11 @@ struct v3dv_descriptor_set_binding_layout {
uint32_t dynamic_offset_count;
uint32_t dynamic_offset_index;
/* Offset in the v3dv_descriptor_set_layout of the immutable samplers, or 0
* if there are no immutable samplers.
*/
uint32_t immutable_samplers_offset;
};
struct v3dv_descriptor_set_layout {
@ -971,8 +976,6 @@ struct v3dv_descriptor_set_layout {
/* Number of dynamic offsets used by this descriptor set */
uint16_t dynamic_offset_count;
bool has_immutable_samplers;
/* Bindings in this descriptor set */
struct v3dv_descriptor_set_binding_layout binding[0];
};
@ -1218,6 +1221,14 @@ v3dv_descriptor_map_get_descriptor(struct v3dv_descriptor_state *descriptor_stat
uint32_t index,
uint32_t *dynamic_offset);
static inline const struct v3dv_sampler *
v3dv_immutable_samplers(const struct v3dv_descriptor_set_layout *set,
const struct v3dv_descriptor_set_binding_layout *binding)
{
assert(binding->immutable_samplers_offset);
return (const struct v3dv_sampler *) ((const char *) set + binding->immutable_samplers_offset);
}
#define V3DV_DEFINE_HANDLE_CASTS(__v3dv_type, __VkType) \
\
static inline struct __v3dv_type * \

View File

@ -81,6 +81,66 @@ check_push_constants_ubo(struct v3dv_cmd_buffer *cmd_buffer)
cmd_buffer->state.dirty &= ~V3DV_CMD_DIRTY_PUSH_CONSTANTS;
}
/*
* The difference between this method and v3dv_descriptor_map_get_descriptor,
* is that if the sampler are added as immutable when creating the set layout,
* they are bound to the set layout, so not part of the descriptor per
* se. This method return early in that case.
*/
static const struct v3dv_sampler *
descriptor_map_get_sampler(struct v3dv_descriptor_state *descriptor_state,
struct v3dv_descriptor_map *map,
struct v3dv_pipeline_layout *pipeline_layout,
uint32_t index)
{
assert(index >= 0 && index < map->num_desc);
uint32_t set_number = map->set[index];
if (!(descriptor_state->valid & 1 << set_number)) {
return NULL;
}
struct v3dv_descriptor_set *set =
descriptor_state->descriptor_sets[set_number];
if (set == NULL)
return NULL;
uint32_t binding_number = map->binding[index];
assert(binding_number < set->layout->binding_count);
const struct v3dv_descriptor_set_binding_layout *binding_layout =
&set->layout->binding[binding_number];
uint32_t array_index = map->array_index[index];
assert(array_index < binding_layout->array_size);
if (binding_layout->immutable_samplers_offset != 0) {
assert(binding_layout->type == VK_DESCRIPTOR_TYPE_SAMPLER ||
binding_layout->type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
const struct v3dv_sampler *immutable_samplers =
v3dv_immutable_samplers(set->layout, binding_layout);
assert(immutable_samplers);
const struct v3dv_sampler *sampler = &immutable_samplers[array_index];
assert(sampler);
return sampler;
}
struct v3dv_descriptor *descriptor =
&set->descriptors[binding_layout->descriptor_index + array_index];
assert(descriptor->type == VK_DESCRIPTOR_TYPE_SAMPLER ||
descriptor->type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
assert(descriptor->sampler);
return descriptor->sampler;
}
/** V3D 4.x TMU configuration parameter 0 (texture) */
static void
write_tmu_p0(struct v3dv_cmd_buffer *cmd_buffer,
@ -121,15 +181,14 @@ write_tmu_p1(struct v3dv_cmd_buffer *cmd_buffer,
struct v3dv_descriptor_state *descriptor_state =
&cmd_buffer->state.descriptor_state;
struct v3dv_descriptor *descriptor =
v3dv_descriptor_map_get_descriptor(descriptor_state, &pipeline->sampler_map,
pipeline->layout, unit, NULL);
const struct v3dv_sampler *sampler =
descriptor_map_get_sampler(descriptor_state, &pipeline->sampler_map,
pipeline->layout, unit);
assert(descriptor);
assert(descriptor->sampler);
assert(sampler);
cl_aligned_reloc(&job->indirect, uniforms,
descriptor->sampler->state,
sampler->state,
v3d_unit_data_get_offset(data));
}