assert(firstSet + descriptorSetCount < MAX_SETS);
+ uint32_t dynamic_slot = 0;
for (uint32_t i = 0; i < descriptorSetCount; i++) {
ANV_FROM_HANDLE(anv_descriptor_set, set, pDescriptorSets[i]);
set_layout = layout->set[firstSet + i].layout;
- if (cmd_buffer->state.descriptors[firstSet + i] != set) {
- cmd_buffer->state.descriptors[firstSet + i] = set;
- cmd_buffer->state.descriptors_dirty |= set_layout->shader_stages;
- }
+ cmd_buffer->state.descriptors[firstSet + i] = set;
if (set_layout->dynamic_offset_count > 0) {
- anv_foreach_stage(s, set_layout->shader_stages) {
- anv_cmd_buffer_ensure_push_constant_field(cmd_buffer, s, dynamic);
-
- struct anv_push_constants *push =
- cmd_buffer->state.push_constants[s];
-
- unsigned d = layout->set[firstSet + i].dynamic_offset_start;
- const uint32_t *offsets = pDynamicOffsets;
- struct anv_descriptor *desc = set->descriptors;
-
- for (unsigned b = 0; b < set_layout->binding_count; b++) {
- if (set_layout->binding[b].dynamic_offset_index < 0)
- continue;
-
- unsigned array_size = set_layout->binding[b].array_size;
- for (unsigned j = 0; j < array_size; j++) {
- push->dynamic[d].offset = *(offsets++);
- push->dynamic[d].range = (desc->buffer_view) ?
- desc->buffer_view->range : 0;
- desc++;
- d++;
- }
- }
- }
- cmd_buffer->state.push_constants_dirty |= set_layout->shader_stages;
+ uint32_t dynamic_offset_start =
+ layout->set[firstSet + i].dynamic_offset_start;
+
+ /* Assert that everything is in range */
+ assert(dynamic_offset_start + set_layout->dynamic_offset_count <=
+ ARRAY_SIZE(cmd_buffer->state.dynamic_offsets));
+ assert(dynamic_slot + set_layout->dynamic_offset_count <=
+ dynamicOffsetCount);
+
+ typed_memcpy(&cmd_buffer->state.dynamic_offsets[dynamic_offset_start],
+ &pDynamicOffsets[dynamic_slot],
+ set_layout->dynamic_offset_count);
+
+ dynamic_slot += set_layout->dynamic_offset_count;
}
+
+ cmd_buffer->state.descriptors_dirty |= set_layout->shader_stages;
}
}
assert(type == bind_layout->type);
- struct anv_buffer_view *bview =
- &set->buffer_views[bind_layout->buffer_index + element];
-
- bview->format = anv_isl_format_for_descriptor_type(type);
- bview->bo = buffer->bo;
- bview->offset = buffer->offset + offset;
-
- /* For buffers with dynamic offsets, we use the full possible range in the
- * surface state and do the actual range-checking in the shader.
- */
- if (bind_layout->dynamic_offset_index >= 0)
- range = VK_WHOLE_SIZE;
- bview->range = anv_buffer_get_range(buffer, offset, range);
-
- /* If we're writing descriptors through a push command, we need to allocate
- * the surface state from the command buffer. Otherwise it will be
- * allocated by the descriptor pool when calling
- * vkAllocateDescriptorSets. */
- if (alloc_stream)
- bview->surface_state = anv_state_stream_alloc(alloc_stream, 64, 64);
-
- anv_fill_buffer_surface_state(device, bview->surface_state,
- bview->format,
- bview->offset, bview->range, 1);
-
- *desc = (struct anv_descriptor) {
- .type = type,
- .buffer_view = bview,
- };
+ if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
+ type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
+ *desc = (struct anv_descriptor) {
+ .type = type,
+ .buffer = buffer,
+ .offset = offset,
+ .range = range,
+ };
+ } else {
+ struct anv_buffer_view *bview =
+ &set->buffer_views[bind_layout->buffer_index + element];
+
+ bview->format = anv_isl_format_for_descriptor_type(type);
+ bview->bo = buffer->bo;
+ bview->offset = buffer->offset + offset;
+ bview->range = anv_buffer_get_range(buffer, offset, range);
+
+ /* If we're writing descriptors through a push command, we need to
+ * allocate the surface state from the command buffer. Otherwise it will
+ * be allocated by the descriptor pool when calling
+ * vkAllocateDescriptorSets. */
+ if (alloc_stream)
+ bview->surface_state = anv_state_stream_alloc(alloc_stream, 64, 64);
+
+ anv_fill_buffer_surface_state(device, bview->surface_state,
+ bview->format,
+ bview->offset, bview->range, 1);
+
+ *desc = (struct anv_descriptor) {
+ .type = type,
+ .buffer_view = bview,
+ };
+ }
}
void anv_UpdateDescriptorSets(
+++ /dev/null
-/*
- * Copyright © 2015 Intel 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 "anv_nir.h"
-#include "nir/nir_builder.h"
-
-static void
-apply_dynamic_offsets_block(nir_block *block, nir_builder *b,
- const struct anv_pipeline_layout *layout,
- bool add_bounds_checks,
- uint32_t indices_start)
-{
- struct anv_descriptor_set_layout *set_layout;
-
- nir_foreach_instr_safe(instr, block) {
- if (instr->type != nir_instr_type_intrinsic)
- continue;
-
- nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
-
- unsigned block_idx_src;
- switch (intrin->intrinsic) {
- case nir_intrinsic_load_ubo:
- case nir_intrinsic_load_ssbo:
- block_idx_src = 0;
- break;
- case nir_intrinsic_store_ssbo:
- block_idx_src = 1;
- break;
- default:
- continue; /* the loop */
- }
-
- nir_instr *res_instr = intrin->src[block_idx_src].ssa->parent_instr;
- assert(res_instr->type == nir_instr_type_intrinsic);
- nir_intrinsic_instr *res_intrin = nir_instr_as_intrinsic(res_instr);
- assert(res_intrin->intrinsic == nir_intrinsic_vulkan_resource_index);
-
- unsigned set = res_intrin->const_index[0];
- unsigned binding = res_intrin->const_index[1];
-
- set_layout = layout->set[set].layout;
- if (set_layout->binding[binding].dynamic_offset_index < 0)
- continue;
-
- b->cursor = nir_before_instr(&intrin->instr);
-
- /* First, we need to generate the uniform load for the buffer offset */
- uint32_t index = layout->set[set].dynamic_offset_start +
- set_layout->binding[binding].dynamic_offset_index;
- uint32_t array_size = set_layout->binding[binding].array_size;
-
- nir_intrinsic_instr *offset_load =
- nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_uniform);
- offset_load->num_components = 2;
- nir_intrinsic_set_base(offset_load, indices_start + index * 8);
- nir_intrinsic_set_range(offset_load, array_size * 8);
- offset_load->src[0] = nir_src_for_ssa(nir_imul(b, res_intrin->src[0].ssa,
- nir_imm_int(b, 8)));
-
- nir_ssa_dest_init(&offset_load->instr, &offset_load->dest, 2, 32, NULL);
- nir_builder_instr_insert(b, &offset_load->instr);
-
- nir_src *offset_src = nir_get_io_offset_src(intrin);
- nir_ssa_def *old_offset = nir_ssa_for_src(b, *offset_src, 1);
- nir_ssa_def *new_offset = nir_iadd(b, old_offset, &offset_load->dest.ssa);
- nir_instr_rewrite_src(&intrin->instr, offset_src,
- nir_src_for_ssa(new_offset));
-
- if (!add_bounds_checks)
- continue;
-
- /* In order to avoid out-of-bounds access, we predicate */
- nir_ssa_def *pred = nir_uge(b, nir_channel(b, &offset_load->dest.ssa, 1),
- old_offset);
- nir_if *if_stmt = nir_if_create(b->shader);
- if_stmt->condition = nir_src_for_ssa(pred);
- nir_cf_node_insert(b->cursor, &if_stmt->cf_node);
-
- nir_instr_remove(&intrin->instr);
- nir_instr_insert_after_cf_list(&if_stmt->then_list, &intrin->instr);
-
- if (intrin->intrinsic != nir_intrinsic_store_ssbo) {
- /* It's a load, we need a phi node */
- nir_phi_instr *phi = nir_phi_instr_create(b->shader);
- nir_ssa_dest_init(&phi->instr, &phi->dest,
- intrin->num_components,
- intrin->dest.ssa.bit_size, NULL);
-
- nir_phi_src *src1 = ralloc(phi, nir_phi_src);
- struct exec_node *tnode = exec_list_get_tail(&if_stmt->then_list);
- src1->pred = exec_node_data(nir_block, tnode, cf_node.node);
- src1->src = nir_src_for_ssa(&intrin->dest.ssa);
- exec_list_push_tail(&phi->srcs, &src1->node);
-
- b->cursor = nir_after_cf_list(&if_stmt->else_list);
- nir_const_value zero_val = { .u32 = { 0, 0, 0, 0 } };
- nir_ssa_def *zero = nir_build_imm(b, intrin->num_components,
- intrin->dest.ssa.bit_size, zero_val);
-
- nir_phi_src *src2 = ralloc(phi, nir_phi_src);
- struct exec_node *enode = exec_list_get_tail(&if_stmt->else_list);
- src2->pred = exec_node_data(nir_block, enode, cf_node.node);
- src2->src = nir_src_for_ssa(zero);
- exec_list_push_tail(&phi->srcs, &src2->node);
-
- assert(intrin->dest.is_ssa);
- nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
- nir_src_for_ssa(&phi->dest.ssa));
-
- nir_instr_insert_after_cf(&if_stmt->cf_node, &phi->instr);
- }
- }
-}
-
-void
-anv_nir_apply_dynamic_offsets(struct anv_pipeline *pipeline,
- nir_shader *shader,
- struct brw_stage_prog_data *prog_data)
-{
- const struct anv_pipeline_layout *layout = pipeline->layout;
- if (!layout || !layout->stage[shader->stage].has_dynamic_offsets)
- return;
-
- const bool add_bounds_checks = pipeline->device->robust_buffer_access;
-
- nir_foreach_function(function, shader) {
- if (!function->impl)
- continue;
-
- nir_builder builder;
- nir_builder_init(&builder, function->impl);
-
- nir_foreach_block(block, function->impl) {
- apply_dynamic_offsets_block(block, &builder, pipeline->layout,
- add_bounds_checks, shader->num_uniforms);
- }
-
- nir_metadata_preserve(function->impl, nir_metadata_block_index |
- nir_metadata_dominance);
- }
-
- struct anv_push_constants *null_data = NULL;
- for (unsigned i = 0; i < MAX_DYNAMIC_BUFFERS; i++) {
- prog_data->param[i * 2 + shader->num_uniforms / 4] =
- (const union gl_constant_value *)&null_data->dynamic[i].offset;
- prog_data->param[i * 2 + 1 + shader->num_uniforms / 4] =
- (const union gl_constant_value *)&null_data->dynamic[i].range;
- }
-
- shader->num_uniforms += MAX_DYNAMIC_BUFFERS * 8;
-}
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:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
surface_state = desc->buffer_view->surface_state;
assert(surface_state.alloc_size);
desc->buffer_view->offset);
break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
+ uint32_t dynamic_offset_idx =
+ pipeline->layout->set[binding->set].dynamic_offset_start +
+ set->layout->binding[binding->binding].dynamic_offset_index +
+ binding->index;
+
+ /* Compute the offset within the buffer */
+ uint64_t offset = desc->offset +
+ cmd_buffer->state.dynamic_offsets[dynamic_offset_idx];
+ /* Clamp to the buffer size */
+ offset = MIN2(offset, desc->buffer->size);
+ /* Clamp the range to the buffer size */
+ uint32_t range = MIN2(desc->range, desc->buffer->size - offset);
+
+ surface_state =
+ anv_state_stream_alloc(&cmd_buffer->surface_state_stream, 64, 64);
+ enum isl_format format =
+ anv_isl_format_for_descriptor_type(desc->type);
+
+ anv_fill_buffer_surface_state(cmd_buffer->device, surface_state,
+ format, offset, range, 1);
+ add_surface_state_reloc(cmd_buffer, surface_state,
+ desc->buffer->bo,
+ desc->buffer->offset + offset);
+ break;
+ }
+
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
surface_state = (binding->write_only)
? desc->buffer_view->writeonly_storage_surface_state