return data;
}
+static unsigned
+anv_descriptor_data_size(enum anv_descriptor_data data)
+{
+ return 0;
+}
+
+/** Returns the size in bytes of each descriptor with the given layout */
+unsigned
+anv_descriptor_size(const struct anv_descriptor_set_binding_layout *layout)
+{
+ return anv_descriptor_data_size(layout->data);
+}
+
+/** Returns the size in bytes of each descriptor of the given type
+ *
+ * This version of the function does not have access to the entire layout so
+ * it may only work on certain descriptor types where the descriptor size is
+ * entirely determined by the descriptor type. Whenever possible, code should
+ * use anv_descriptor_size() instead.
+ */
+unsigned
+anv_descriptor_type_size(const struct anv_physical_device *pdevice,
+ VkDescriptorType type)
+{
+ return anv_descriptor_data_size(anv_descriptor_data_for_type(pdevice, type));
+}
+
void anv_GetDescriptorSetLayoutSupport(
VkDevice device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
uint32_t buffer_view_count = 0;
uint32_t dynamic_offset_count = 0;
+ uint32_t descriptor_buffer_size = 0;
for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) {
const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[j];
break;
}
+ set_layout->binding[b].descriptor_offset = descriptor_buffer_size;
+ descriptor_buffer_size += anv_descriptor_size(&set_layout->binding[b]) *
+ binding->descriptorCount;
+
set_layout->shader_stages |= binding->stageFlags;
}
set_layout->buffer_view_count = buffer_view_count;
set_layout->dynamic_offset_count = dynamic_offset_count;
+ set_layout->descriptor_buffer_size = descriptor_buffer_size;
*pSetLayout = anv_descriptor_set_layout_to_handle(set_layout);
SHA1_UPDATE_VALUE(ctx, layout->descriptor_index);
SHA1_UPDATE_VALUE(ctx, layout->dynamic_offset_index);
SHA1_UPDATE_VALUE(ctx, layout->buffer_view_index);
+ SHA1_UPDATE_VALUE(ctx, layout->descriptor_offset);
if (layout->immutable_samplers) {
for (uint16_t i = 0; i < layout->array_size; i++)
SHA1_UPDATE_VALUE(ctx, layout->shader_stages);
SHA1_UPDATE_VALUE(ctx, layout->buffer_view_count);
SHA1_UPDATE_VALUE(ctx, layout->dynamic_offset_count);
+ SHA1_UPDATE_VALUE(ctx, layout->descriptor_buffer_size);
for (uint16_t i = 0; i < layout->binding_count; i++)
sha1_update_descriptor_set_binding_layout(ctx, &layout->binding[i]);
* and the free lists lets us recycle blocks for case 2).
*/
+/* The vma heap reserves 0 to mean NULL; we have to offset by some ammount to
+ * ensure we can allocate the entire BO without hitting zero. The actual
+ * amount doesn't matter.
+ */
+#define POOL_HEAP_OFFSET 64
+
#define EMPTY 1
VkResult anv_CreateDescriptorPool(
uint32_t descriptor_count = 0;
uint32_t buffer_view_count = 0;
+ uint32_t descriptor_bo_size = 0;
for (uint32_t i = 0; i < pCreateInfo->poolSizeCount; i++) {
enum anv_descriptor_data desc_data =
anv_descriptor_data_for_type(&device->instance->physicalDevice,
if (desc_data & ANV_DESCRIPTOR_BUFFER_VIEW)
buffer_view_count += pCreateInfo->pPoolSizes[i].descriptorCount;
+ unsigned desc_data_size = anv_descriptor_data_size(desc_data) *
+ pCreateInfo->pPoolSizes[i].descriptorCount;
+ descriptor_bo_size += desc_data_size;
+
descriptor_count += pCreateInfo->pPoolSizes[i].descriptorCount;
}
+ /* We have to align descriptor buffer allocations to 32B so that we can
+ * push descriptor buffers. This means that each descriptor buffer
+ * allocated may burn up to 32B of extra space to get the right alignment.
+ * (Technically, it's at most 28B because we're always going to start at
+ * least 4B aligned but we're being conservative here.) Allocate enough
+ * extra space that we can chop it into maxSets pieces and align each one
+ * of them to 32B.
+ */
+ descriptor_bo_size += 32 * pCreateInfo->maxSets;
+ descriptor_bo_size = ALIGN(descriptor_bo_size, 4096);
const size_t pool_size =
pCreateInfo->maxSets * sizeof(struct anv_descriptor_set) +
pool->next = 0;
pool->free_list = EMPTY;
+ if (descriptor_bo_size > 0) {
+ VkResult result = anv_bo_init_new(&pool->bo, device, descriptor_bo_size);
+ if (result != VK_SUCCESS) {
+ vk_free2(&device->alloc, pAllocator, pool);
+ return result;
+ }
+
+ anv_gem_set_caching(device, pool->bo.gem_handle, I915_CACHING_CACHED);
+
+ pool->bo.map = anv_gem_mmap(device, pool->bo.gem_handle, 0,
+ descriptor_bo_size, 0);
+ if (pool->bo.map == NULL) {
+ anv_gem_close(device, pool->bo.gem_handle);
+ vk_free2(&device->alloc, pAllocator, pool);
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+ }
+
+ if (device->instance->physicalDevice.use_softpin) {
+ pool->bo.flags |= EXEC_OBJECT_PINNED;
+ anv_vma_alloc(device, &pool->bo);
+ }
+
+ util_vma_heap_init(&pool->bo_heap, POOL_HEAP_OFFSET, descriptor_bo_size);
+ } else {
+ pool->bo.size = 0;
+ }
+
anv_state_stream_init(&pool->surface_state_stream,
&device->surface_state_pool, 4096);
pool->surface_state_free_list = NULL;
if (!pool)
return;
+ if (pool->bo.size) {
+ anv_gem_munmap(pool->bo.map, pool->bo.size);
+ anv_vma_free(device, &pool->bo);
+ anv_gem_close(device, pool->bo.gem_handle);
+ }
anv_state_stream_finish(&pool->surface_state_stream);
vk_free2(&device->alloc, pAllocator, pool);
}
pool->next = 0;
pool->free_list = EMPTY;
+
+ if (pool->bo.size) {
+ util_vma_heap_finish(&pool->bo_heap);
+ util_vma_heap_init(&pool->bo_heap, POOL_HEAP_OFFSET, pool->bo.size);
+ }
+
anv_state_stream_finish(&pool->surface_state_stream);
anv_state_stream_init(&pool->surface_state_stream,
&device->surface_state_pool, 4096);
if (result != VK_SUCCESS)
return result;
+ if (layout->descriptor_buffer_size) {
+ /* Align the size to 32 so that alignment gaps don't cause extra holes
+ * in the heap which can lead to bad performance.
+ */
+ uint64_t pool_vma_offset =
+ util_vma_heap_alloc(&pool->bo_heap,
+ ALIGN(layout->descriptor_buffer_size, 32), 32);
+ if (pool_vma_offset == 0) {
+ anv_descriptor_pool_free_set(pool, set);
+ return vk_error(VK_ERROR_FRAGMENTED_POOL);
+ }
+ assert(pool_vma_offset >= POOL_HEAP_OFFSET &&
+ pool_vma_offset - POOL_HEAP_OFFSET <= INT32_MAX);
+ set->desc_mem.offset = pool_vma_offset - POOL_HEAP_OFFSET;
+ set->desc_mem.alloc_size = layout->descriptor_buffer_size;
+ set->desc_mem.map = pool->bo.map + set->desc_mem.offset;
+
+ set->desc_surface_state = anv_descriptor_pool_alloc_state(pool);
+ anv_fill_buffer_surface_state(device, set->desc_surface_state,
+ ISL_FORMAT_R32G32B32A32_FLOAT,
+ (struct anv_address) {
+ .bo = &pool->bo,
+ .offset = set->desc_mem.offset,
+ },
+ layout->descriptor_buffer_size, 1);
+ } else {
+ set->desc_mem = ANV_STATE_NULL;
+ set->desc_surface_state = ANV_STATE_NULL;
+ }
+
+ set->pool = pool;
set->layout = layout;
anv_descriptor_set_layout_ref(layout);
{
anv_descriptor_set_layout_unref(device, set->layout);
+ if (set->desc_mem.alloc_size) {
+ util_vma_heap_free(&pool->bo_heap,
+ (uint64_t)set->desc_mem.offset + POOL_HEAP_OFFSET,
+ set->desc_mem.alloc_size);
+ anv_descriptor_pool_free_state(pool, set->desc_surface_state);
+ }
+
for (uint32_t b = 0; b < set->buffer_view_count; b++)
anv_descriptor_pool_free_state(pool, set->buffer_views[b].surface_state);
for (uint32_t j = 0; j < copy->descriptorCount; j++)
dst_desc[j] = src_desc[j];
+
+ unsigned desc_size = anv_descriptor_size(src_layout);
+ if (desc_size > 0) {
+ assert(desc_size == anv_descriptor_size(dst_layout));
+ memcpy(dst->desc_mem.map + dst_layout->descriptor_offset +
+ copy->dstArrayElement * desc_size,
+ src->desc_mem.map + src_layout->descriptor_offset +
+ copy->srcArrayElement * desc_size,
+ copy->descriptorCount * desc_size);
+ }
}
}
/* Index into the descriptor set buffer views */
int16_t buffer_view_index;
+ /* Offset into the descriptor buffer where this descriptor lives */
+ uint32_t descriptor_offset;
+
/* Immutable samplers (or NULL if no immutable samplers) */
struct anv_sampler **immutable_samplers;
};
+unsigned anv_descriptor_size(const struct anv_descriptor_set_binding_layout *layout);
+
+unsigned anv_descriptor_type_size(const struct anv_physical_device *pdevice,
+ VkDescriptorType type);
+
struct anv_descriptor_set_layout {
/* Descriptor set layouts can be destroyed at almost any time */
uint32_t ref_cnt;
/* Number of dynamic offsets used by this descriptor set */
uint16_t dynamic_offset_count;
+ /* Size of the descriptor buffer for this descriptor set */
+ uint32_t descriptor_buffer_size;
+
/* Bindings in this descriptor set */
struct anv_descriptor_set_binding_layout binding[0];
};
};
struct anv_descriptor_set {
+ struct anv_descriptor_pool *pool;
struct anv_descriptor_set_layout *layout;
uint32_t size;
+
+ /* State relative to anv_descriptor_pool::bo */
+ struct anv_state desc_mem;
+ /* Surface state for the descriptor buffer */
+ struct anv_state desc_surface_state;
+
uint32_t buffer_view_count;
struct anv_buffer_view *buffer_views;
struct anv_descriptor descriptors[0];
/* Put this field right behind anv_descriptor_set so it fills up the
* descriptors[0] field. */
struct anv_descriptor descriptors[MAX_PUSH_DESCRIPTORS];
+
+ /** True if the descriptor set buffer has been referenced by a draw or
+ * dispatch command.
+ */
+ bool set_used_on_gpu;
+
struct anv_buffer_view buffer_views[MAX_PUSH_DESCRIPTORS];
};
uint32_t next;
uint32_t free_list;
+ struct anv_bo bo;
+ struct util_vma_heap bo_heap;
+
struct anv_state_stream surface_state_stream;
void *surface_state_free_list;
struct anv_descriptor_pool *pool,
struct anv_descriptor_set *set);
+#define ANV_DESCRIPTOR_SET_DESCRIPTORS (UINT8_MAX - 3)
#define ANV_DESCRIPTOR_SET_NUM_WORK_GROUPS (UINT8_MAX - 2)
#define ANV_DESCRIPTOR_SET_SHADER_CONSTANTS (UINT8_MAX - 1)
#define ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS UINT8_MAX
return pipe_state->dynamic_offsets[dynamic_offset_idx];
}
+static struct anv_address
+anv_descriptor_set_address(struct anv_cmd_buffer *cmd_buffer,
+ struct anv_descriptor_set *set)
+{
+ if (set->pool) {
+ /* This is a normal descriptor set */
+ return (struct anv_address) {
+ .bo = &set->pool->bo,
+ .offset = set->desc_mem.offset,
+ };
+ } else {
+ /* This is a push descriptor set. We have to flag it as used on the GPU
+ * so that the next time we push descriptors, we grab a new memory.
+ */
+ struct anv_push_descriptor_set *push_set =
+ (struct anv_push_descriptor_set *)set;
+ push_set->set_used_on_gpu = true;
+
+ return (struct anv_address) {
+ .bo = cmd_buffer->dynamic_state_stream.state_pool->block_pool.bo,
+ .offset = set->desc_mem.offset,
+ };
+ }
+}
+
static VkResult
emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
gl_shader_stage stage,
add_surface_reloc(cmd_buffer, surface_state,
cmd_buffer->state.compute.num_workgroups);
continue;
+ } else if (binding->set == ANV_DESCRIPTOR_SET_DESCRIPTORS) {
+ /* This is a descriptor set buffer so the set index is actually
+ * given by binding->binding. (Yes, that's confusing.)
+ */
+ struct anv_descriptor_set *set =
+ pipe_state->descriptors[binding->binding];
+ assert(set->desc_mem.alloc_size);
+ assert(set->desc_surface_state.alloc_size);
+ bt_map[s] = set->desc_surface_state.offset + state_offset;
+ add_surface_reloc(cmd_buffer, set->desc_surface_state,
+ anv_descriptor_set_address(cmd_buffer, set));
+ continue;
}
const struct anv_descriptor *desc =
DIV_ROUND_UP(constant_data_size, 32) - range->start);
read_addr = anv_address_add(constant_data,
range->start * 32);
+ } else if (binding->set == ANV_DESCRIPTOR_SET_DESCRIPTORS) {
+ /* This is a descriptor set buffer so the set index is
+ * actually given by binding->binding. (Yes, that's
+ * confusing.)
+ */
+ struct anv_descriptor_set *set =
+ gfx_state->base.descriptors[binding->binding];
+ struct anv_address desc_buffer_addr =
+ anv_descriptor_set_address(cmd_buffer, set);
+ const unsigned desc_buffer_size = set->desc_mem.alloc_size;
+
+ read_len = MIN2(range->length,
+ DIV_ROUND_UP(desc_buffer_size, 32) - range->start);
+ read_addr = anv_address_add(desc_buffer_addr,
+ range->start * 32);
} else {
const struct anv_descriptor *desc =
anv_descriptor_for_binding(&gfx_state->base, binding);