diff --git a/src/broadcom/vulkan/v3dv_descriptor_set.c b/src/broadcom/vulkan/v3dv_descriptor_set.c index 0fd6bcd4435..34d3ca2726b 100644 --- a/src/broadcom/vulkan/v3dv_descriptor_set.c +++ b/src/broadcom/vulkan/v3dv_descriptor_set.c @@ -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); diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h index 747b62461d4..25f81c9b9b1 100644 --- a/src/broadcom/vulkan/v3dv_private.h +++ b/src/broadcom/vulkan/v3dv_private.h @@ -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 * \ diff --git a/src/broadcom/vulkan/v3dv_uniforms.c b/src/broadcom/vulkan/v3dv_uniforms.c index 7493afea306..456c16c7305 100644 --- a/src/broadcom/vulkan/v3dv_uniforms.c +++ b/src/broadcom/vulkan/v3dv_uniforms.c @@ -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)); }