OSDN Git Service

anv: Add a concept of a descriptor buffer
[android-x86/external-mesa.git] / src / intel / vulkan / anv_descriptor_set.c
index 964180c..3f0e323 100644 (file)
@@ -82,6 +82,33 @@ anv_descriptor_data_for_type(const struct anv_physical_device *device,
    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,
@@ -198,6 +225,7 @@ VkResult anv_CreateDescriptorSetLayout(
 
    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];
@@ -267,11 +295,16 @@ VkResult anv_CreateDescriptorSetLayout(
          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);
 
@@ -315,6 +348,7 @@ sha1_update_descriptor_set_binding_layout(struct mesa_sha1 *ctx,
    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++)
@@ -331,6 +365,7 @@ sha1_update_descriptor_set_layout(struct mesa_sha1 *ctx,
    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]);
@@ -420,6 +455,12 @@ void anv_DestroyPipelineLayout(
  * 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(
@@ -433,6 +474,7 @@ 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,
@@ -441,8 +483,22 @@ VkResult anv_CreateDescriptorPool(
       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) +
@@ -459,6 +515,33 @@ VkResult anv_CreateDescriptorPool(
    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;
@@ -479,6 +562,11 @@ void anv_DestroyDescriptorPool(
    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);
 }
@@ -493,6 +581,12 @@ VkResult anv_ResetDescriptorPool(
 
    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);
@@ -606,6 +700,37 @@ anv_descriptor_set_create(struct anv_device *device,
    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);
 
@@ -656,6 +781,13 @@ anv_descriptor_set_destroy(struct anv_device *device,
 {
    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);
 
@@ -925,6 +1057,16 @@ void anv_UpdateDescriptorSets(
 
       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);
+      }
    }
 }