summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKristian Høgsberg Kristensen <kristian.h.kristensen@intel.com>2016-02-11 22:46:28 -0800
committerKristian Høgsberg Kristensen <kristian.h.kristensen@intel.com>2016-02-22 17:13:51 -0800
commit2570a58bcdf30d699b89323fef60692093dee7ea (patch)
treed27100ecad296a746182c96e6cc5aa3e5998b491 /src
parent353d5bf286e1509af9ec2f1b8152d1f64790b52c (diff)
downloadexternal_mesa3d-2570a58bcdf30d699b89323fef60692093dee7ea.zip
external_mesa3d-2570a58bcdf30d699b89323fef60692093dee7ea.tar.gz
external_mesa3d-2570a58bcdf30d699b89323fef60692093dee7ea.tar.bz2
anv: Implement descriptor pools
Descriptor pools are an optimization that lets applications allocate descriptor sets through an externally synchronized object (that is, unlocked). In our case it's also plugging a memory leak, since we didn't track all allocated sets and failed to free them in vkResetDescriptorPool() and vkDestroyDescriptorPool().
Diffstat (limited to 'src')
-rw-r--r--src/intel/vulkan/anv_descriptor_set.c189
-rw-r--r--src/intel/vulkan/anv_meta.c25
-rw-r--r--src/intel/vulkan/anv_meta_blit.c6
-rw-r--r--src/intel/vulkan/anv_meta_resolve.c8
-rw-r--r--src/intel/vulkan/anv_private.h17
5 files changed, 200 insertions, 45 deletions
diff --git a/src/intel/vulkan/anv_descriptor_set.c b/src/intel/vulkan/anv_descriptor_set.c
index 7a77336..718bc21 100644
--- a/src/intel/vulkan/anv_descriptor_set.c
+++ b/src/intel/vulkan/anv_descriptor_set.c
@@ -244,17 +244,67 @@ void anv_DestroyPipelineLayout(
}
/*
- * Descriptor pools. These are a no-op for now.
+ * Descriptor pools.
+ *
+ * These are implemented using a big pool of memory and a free-list for the
+ * host memory allocations and a state_stream and a free list for the buffer
+ * view surface state. The spec allows us to fail to allocate due to
+ * fragmentation in all cases but two: 1) after pool reset, allocating up
+ * until the pool size with no freeing must succeed and 2) allocating and
+ * freeing only descriptor sets with the same layout. Case 1) is easy enogh,
+ * and the free lists lets us recycle blocks for case 2).
*/
+#define EMPTY 1
+
VkResult anv_CreateDescriptorPool(
- VkDevice device,
+ VkDevice _device,
const VkDescriptorPoolCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorPool* pDescriptorPool)
{
- anv_finishme("VkDescriptorPool is a stub");
- *pDescriptorPool = (VkDescriptorPool)1;
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ struct anv_descriptor_pool *pool;
+
+ uint32_t descriptor_count = 0;
+ uint32_t buffer_count = 0;
+ for (uint32_t i = 0; i < pCreateInfo->poolSizeCount; i++) {
+ switch (pCreateInfo->pPoolSizes[i].type) {
+ 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:
+ buffer_count += pCreateInfo->pPoolSizes[i].descriptorCount;
+ default:
+ descriptor_count += pCreateInfo->pPoolSizes[i].descriptorCount;
+ break;
+ }
+ }
+
+ const size_t set_size =
+ sizeof(struct anv_descriptor_set) +
+ descriptor_count * sizeof(struct anv_descriptor) +
+ buffer_count * sizeof(struct anv_buffer_view);
+
+ const size_t size =
+ sizeof(*pool) +
+ pCreateInfo->maxSets * set_size;
+
+ pool = anv_alloc2(&device->alloc, pAllocator, size, 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ if (!pool)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ pool->size = size;
+ pool->next = 0;
+ pool->free_list = EMPTY;
+
+ anv_state_stream_init(&pool->surface_state_stream,
+ &device->surface_state_block_pool);
+ pool->surface_state_free_list = NULL;
+
+ *pDescriptorPool = anv_descriptor_pool_to_handle(pool);
+
return VK_SUCCESS;
}
@@ -263,37 +313,85 @@ void anv_DestroyDescriptorPool(
VkDescriptorPool _pool,
const VkAllocationCallbacks* pAllocator)
{
- anv_finishme("VkDescriptorPool is a stub: free the pool's descriptor sets");
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_descriptor_pool, pool, _pool);
+
+ anv_state_stream_finish(&pool->surface_state_stream);
+ anv_free2(&device->alloc, pAllocator, pool);
}
VkResult anv_ResetDescriptorPool(
- VkDevice device,
+ VkDevice _device,
VkDescriptorPool descriptorPool,
VkDescriptorPoolResetFlags flags)
{
- anv_finishme("VkDescriptorPool is a stub: free the pool's descriptor sets");
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_descriptor_pool, pool, descriptorPool);
+
+ pool->next = 0;
+ pool->free_list = EMPTY;
+ anv_state_stream_finish(&pool->surface_state_stream);
+ anv_state_stream_init(&pool->surface_state_stream,
+ &device->surface_state_block_pool);
+ pool->surface_state_free_list = NULL;
+
return VK_SUCCESS;
}
+struct pool_free_list_entry {
+ uint32_t next;
+ uint32_t size;
+};
+
+static size_t
+layout_size(const struct anv_descriptor_set_layout *layout)
+{
+ return
+ sizeof(struct anv_descriptor_set) +
+ layout->size * sizeof(struct anv_descriptor) +
+ layout->buffer_count * sizeof(struct anv_buffer_view);
+}
+
+struct surface_state_free_list_entry {
+ void *next;
+ uint32_t offset;
+};
+
VkResult
anv_descriptor_set_create(struct anv_device *device,
+ struct anv_descriptor_pool *pool,
const struct anv_descriptor_set_layout *layout,
struct anv_descriptor_set **out_set)
{
struct anv_descriptor_set *set;
- size_t size = sizeof(*set) + layout->size * sizeof(set->descriptors[0]);
+ const size_t size = layout_size(layout);
+
+ set = NULL;
+ if (size <= pool->size - pool->next) {
+ set = (struct anv_descriptor_set *) (pool->data + pool->next);
+ pool->next += size;
+ } else {
+ struct pool_free_list_entry *entry;
+ uint32_t *link = &pool->free_list;
+ for (uint32_t f = pool->free_list; f != EMPTY; f = entry->next) {
+ entry = (struct pool_free_list_entry *) (pool->data + f);
+ if (size <= entry->size) {
+ *link = entry->next;
+ set = (struct anv_descriptor_set *) entry;
+ break;
+ }
+ link = &entry->next;
+ }
+ }
- set = anv_alloc(&device->alloc /* XXX: Use the pool */, size, 8,
- VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
- if (!set)
+ if (set == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
- /* A descriptor set may not be 100% filled. Clear the set so we can can
- * later detect holes in it.
- */
- memset(set, 0, size);
-
+ set->size = size;
set->layout = layout;
+ set->buffer_views =
+ (struct anv_buffer_view *) &set->descriptors[layout->size];
+ set->buffer_count = layout->buffer_count;
/* Go through and fill out immutable samplers if we have any */
struct anv_descriptor *desc = set->descriptors;
@@ -305,21 +403,24 @@ anv_descriptor_set_create(struct anv_device *device,
desc += layout->binding[b].array_size;
}
- /* XXX: Use the pool */
- set->buffer_views =
- anv_alloc(&device->alloc,
- sizeof(set->buffer_views[0]) * layout->buffer_count, 8,
- VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
- if (!set->buffer_views) {
- anv_free(&device->alloc, set);
- return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
- }
-
+ /* Allocate surface state for the buffer views. */
for (uint32_t b = 0; b < layout->buffer_count; b++) {
- set->buffer_views[b].surface_state =
- anv_state_pool_alloc(&device->surface_state_pool, 64, 64);
+ struct surface_state_free_list_entry *entry =
+ pool->surface_state_free_list;
+ struct anv_state state;
+
+ if (entry) {
+ state.map = entry;
+ state.offset = entry->offset;
+ state.alloc_size = 64;
+ pool->surface_state_free_list = entry->next;
+ } else {
+ state = anv_state_stream_alloc(&pool->surface_state_stream, 64, 64);
+ }
+
+ set->buffer_views[b].surface_state = state;
}
- set->buffer_count = layout->buffer_count;
+
*out_set = set;
return VK_SUCCESS;
@@ -327,15 +428,27 @@ anv_descriptor_set_create(struct anv_device *device,
void
anv_descriptor_set_destroy(struct anv_device *device,
+ struct anv_descriptor_pool *pool,
struct anv_descriptor_set *set)
{
- /* XXX: Use the pool */
- for (uint32_t b = 0; b < set->buffer_count; b++)
- anv_state_pool_free(&device->surface_state_pool,
- set->buffer_views[b].surface_state);
+ /* Put the buffer view surface state back on the free list. */
+ for (uint32_t b = 0; b < set->buffer_count; b++) {
+ struct surface_state_free_list_entry *entry =
+ set->buffer_views[b].surface_state.map;
+ entry->next = pool->surface_state_free_list;
+ pool->surface_state_free_list = entry;
+ }
- anv_free(&device->alloc, set->buffer_views);
- anv_free(&device->alloc, set);
+ /* Put the descriptor set allocation back on the free list. */
+ const uint32_t index = (char *) set - pool->data;
+ if (index + set->size == pool->next) {
+ pool->next = index;
+ } else {
+ struct pool_free_list_entry *entry = (struct pool_free_list_entry *) set;
+ entry->next = pool->free_list;
+ entry->size = set->size;
+ pool->free_list = (char *) entry - pool->data;
+ }
}
VkResult anv_AllocateDescriptorSets(
@@ -344,6 +457,7 @@ VkResult anv_AllocateDescriptorSets(
VkDescriptorSet* pDescriptorSets)
{
ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_descriptor_pool, pool, pAllocateInfo->descriptorPool);
VkResult result = VK_SUCCESS;
struct anv_descriptor_set *set;
@@ -353,7 +467,7 @@ VkResult anv_AllocateDescriptorSets(
ANV_FROM_HANDLE(anv_descriptor_set_layout, layout,
pAllocateInfo->pSetLayouts[i]);
- result = anv_descriptor_set_create(device, layout, &set);
+ result = anv_descriptor_set_create(device, pool, layout, &set);
if (result != VK_SUCCESS)
break;
@@ -374,11 +488,12 @@ VkResult anv_FreeDescriptorSets(
const VkDescriptorSet* pDescriptorSets)
{
ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_descriptor_pool, pool, descriptorPool);
for (uint32_t i = 0; i < count; i++) {
ANV_FROM_HANDLE(anv_descriptor_set, set, pDescriptorSets[i]);
- anv_descriptor_set_destroy(device, set);
+ anv_descriptor_set_destroy(device, pool, set);
}
return VK_SUCCESS;
diff --git a/src/intel/vulkan/anv_meta.c b/src/intel/vulkan/anv_meta.c
index 82944ea..683a162 100644
--- a/src/intel/vulkan/anv_meta.c
+++ b/src/intel/vulkan/anv_meta.c
@@ -138,6 +138,27 @@ anv_device_init_meta(struct anv_device *device)
.pfnFree = meta_free,
};
+ const VkDescriptorPoolCreateInfo create_info = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+ .pNext = NULL,
+ .flags = 0,
+ .maxSets = 1,
+ .poolSizeCount = 1,
+ .pPoolSizes = (VkDescriptorPoolSize[]) {
+ {
+ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .descriptorCount = 1
+ },
+ }
+ };
+
+ result = anv_CreateDescriptorPool(anv_device_to_handle(device),
+ &create_info,
+ &device->meta_state.alloc,
+ &device->meta_state.desc_pool);
+ if (result != VK_SUCCESS)
+ goto fail_desc_pool;
+
result = anv_device_init_meta_clear_state(device);
if (result != VK_SUCCESS)
goto fail_clear;
@@ -157,6 +178,10 @@ fail_blit:
fail_resolve:
anv_device_finish_meta_clear_state(device);
fail_clear:
+ anv_DestroyDescriptorPool(anv_device_to_handle(device),
+ device->meta_state.desc_pool,
+ &device->meta_state.alloc);
+fail_desc_pool:
return result;
}
diff --git a/src/intel/vulkan/anv_meta_blit.c b/src/intel/vulkan/anv_meta_blit.c
index 06f13ec..9c6cd8c 100644
--- a/src/intel/vulkan/anv_meta_blit.c
+++ b/src/intel/vulkan/anv_meta_blit.c
@@ -165,7 +165,6 @@ meta_emit_blit(struct anv_cmd_buffer *cmd_buffer,
VkFilter blit_filter)
{
struct anv_device *device = cmd_buffer->device;
- VkDescriptorPool dummy_desc_pool = (VkDescriptorPool)1;
struct blit_vb_data {
float pos[2];
@@ -248,7 +247,7 @@ meta_emit_blit(struct anv_cmd_buffer *cmd_buffer,
anv_AllocateDescriptorSets(anv_device_to_handle(device),
&(VkDescriptorSetAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
- .descriptorPool = dummy_desc_pool,
+ .descriptorPool = device->meta_state.desc_pool,
.descriptorSetCount = 1,
.pSetLayouts = &device->meta_state.blit.ds_layout
}, &set);
@@ -341,7 +340,8 @@ meta_emit_blit(struct anv_cmd_buffer *cmd_buffer,
/* At the point where we emit the draw call, all data from the
* descriptor sets, etc. has been used. We are free to delete it.
*/
- anv_descriptor_set_destroy(device, anv_descriptor_set_from_handle(set));
+ anv_ResetDescriptorPool(anv_device_to_handle(device),
+ device->meta_state.desc_pool, 0);
anv_DestroySampler(anv_device_to_handle(device), sampler,
&cmd_buffer->pool->alloc);
anv_DestroyFramebuffer(anv_device_to_handle(device), fb,
diff --git a/src/intel/vulkan/anv_meta_resolve.c b/src/intel/vulkan/anv_meta_resolve.c
index ea5020c..9a77d21 100644
--- a/src/intel/vulkan/anv_meta_resolve.c
+++ b/src/intel/vulkan/anv_meta_resolve.c
@@ -483,7 +483,6 @@ emit_resolve(struct anv_cmd_buffer *cmd_buffer,
VkCommandBuffer cmd_buffer_h = anv_cmd_buffer_to_handle(cmd_buffer);
const struct anv_framebuffer *fb = cmd_buffer->state.framebuffer;
const struct anv_image *src_image = src_iview->image;
- VkDescriptorPool dummy_desc_pool_h = (VkDescriptorPool) 1;
const struct vertex_attrs vertex_data[3] = {
{
@@ -564,7 +563,7 @@ emit_resolve(struct anv_cmd_buffer *cmd_buffer,
anv_AllocateDescriptorSets(device_h,
&(VkDescriptorSetAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
- .descriptorPool = dummy_desc_pool_h,
+ .descriptorPool = device->meta_state.desc_pool,
.descriptorSetCount = 1,
.pSetLayouts = (VkDescriptorSetLayout[]) {
device->meta_state.resolve.ds_layout,
@@ -572,8 +571,6 @@ emit_resolve(struct anv_cmd_buffer *cmd_buffer,
},
&desc_set_h);
- ANV_FROM_HANDLE(anv_descriptor_set, desc_set, desc_set_h);
-
anv_UpdateDescriptorSets(device_h,
/*writeCount*/ 1,
(VkWriteDescriptorSet[]) {
@@ -644,7 +641,8 @@ emit_resolve(struct anv_cmd_buffer *cmd_buffer,
/* All objects below are consumed by the draw call. We may safely destroy
* them.
*/
- anv_descriptor_set_destroy(device, desc_set);
+ anv_ResetDescriptorPool(anv_device_to_handle(device),
+ device->meta_state.desc_pool, 0);
anv_DestroySampler(device_h, sampler_h,
&cmd_buffer->pool->alloc);
}
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index 479f382..6ce3f02 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -571,6 +571,8 @@ void anv_finish_wsi(struct anv_instance *instance);
struct anv_meta_state {
VkAllocationCallbacks alloc;
+ VkDescriptorPool desc_pool;
+
/**
* Use array element `i` for images with `2^i` samples.
*/
@@ -959,18 +961,32 @@ struct anv_descriptor {
struct anv_descriptor_set {
const struct anv_descriptor_set_layout *layout;
+ uint32_t size;
uint32_t buffer_count;
struct anv_buffer_view *buffer_views;
struct anv_descriptor descriptors[0];
};
+struct anv_descriptor_pool {
+ uint32_t size;
+ uint32_t next;
+ uint32_t free_list;
+
+ struct anv_state_stream surface_state_stream;
+ void *surface_state_free_list;
+
+ char data[0];
+};
+
VkResult
anv_descriptor_set_create(struct anv_device *device,
+ struct anv_descriptor_pool *pool,
const struct anv_descriptor_set_layout *layout,
struct anv_descriptor_set **out_set);
void
anv_descriptor_set_destroy(struct anv_device *device,
+ struct anv_descriptor_pool *pool,
struct anv_descriptor_set *set);
struct anv_pipeline_binding {
@@ -1839,6 +1855,7 @@ ANV_DEFINE_HANDLE_CASTS(anv_queue, VkQueue)
ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_cmd_pool, VkCommandPool)
ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_buffer, VkBuffer)
ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_buffer_view, VkBufferView)
+ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_descriptor_pool, VkDescriptorPool)
ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_descriptor_set, VkDescriptorSet)
ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_descriptor_set_layout, VkDescriptorSetLayout)
ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_device_memory, VkDeviceMemory)