diff options
author | Jason Ekstrand <[email protected]> | 2017-04-06 22:15:16 -0700 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2017-04-07 19:24:14 -0700 |
commit | e5c29b8c2713f622a66cae9ad35f85469cda2a46 (patch) | |
tree | 12b5ff89785659ac6314c87c8739dd0a093067b0 /src/intel/vulkan | |
parent | 82695c32b6f5afe742de17a2d617dc200f7f0676 (diff) |
anv: Add a helper for doing mass allocations
We tend to try to reduce the number of allocation calls the Vulkan
driver uses by doing a single allocation whenever possible for a data
structure. While this has certain downsides (usually code complexity),
it does mean error handling and cleanup is much easier. This commit
adds a nice little helper struct for getting rid of some of that
complexity.
Reviewed-by: Nanley Chery <[email protected]>
Diffstat (limited to 'src/intel/vulkan')
-rw-r--r-- | src/intel/vulkan/anv_private.h | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 90974d9dd23..1d740bc9744 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -269,6 +269,102 @@ void anv_loge_v(const char *format, va_list va); #define anv_assert(x) #endif +/* A multi-pointer allocator + * + * When copying data structures from the user (such as a render pass), it's + * common to need to allocate data for a bunch of different things. Instead + * of doing several allocations and having to handle all of the error checking + * that entails, it can be easier to do a single allocation. This struct + * helps facilitate that. The intended usage looks like this: + * + * ANV_MULTIALLOC(ma) + * anv_multialloc_add(&ma, &main_ptr, 1); + * anv_multialloc_add(&ma, &substruct1, substruct1Count); + * anv_multialloc_add(&ma, &substruct2, substruct2Count); + * + * if (!anv_multialloc_alloc(&ma, pAllocator, VK_ALLOCATION_SCOPE_FOO)) + * return vk_error(VK_ERROR_OUT_OF_HOST_MEORY); + */ +struct anv_multialloc { + size_t size; + size_t align; + + uint32_t ptr_count; + void **ptrs[8]; +}; + +#define ANV_MULTIALLOC_INIT \ + ((struct anv_multialloc) { 0, }) + +#define ANV_MULTIALLOC(_name) \ + struct anv_multialloc _name = ANV_MULTIALLOC_INIT + +__attribute__((always_inline)) +static inline void +_anv_multialloc_add(struct anv_multialloc *ma, + void **ptr, size_t size, size_t align) +{ + size_t offset = align_u64(ma->size, align); + ma->size = offset + size; + ma->align = MAX2(ma->align, align); + + /* Store the offset in the pointer. */ + *ptr = (void *)(uintptr_t)offset; + + assert(ma->ptr_count < ARRAY_SIZE(ma->ptrs)); + ma->ptrs[ma->ptr_count++] = ptr; +} + +#define anv_multialloc_add(_ma, _ptr, _count) \ + _anv_multialloc_add((_ma), (void **)(_ptr), \ + (_count) * sizeof(**(_ptr)), __alignof__(**(_ptr))) + +__attribute__((always_inline)) +static inline void * +anv_multialloc_alloc(struct anv_multialloc *ma, + const VkAllocationCallbacks *alloc, + VkSystemAllocationScope scope) +{ + void *ptr = vk_alloc(alloc, ma->size, ma->align, scope); + if (!ptr) + return NULL; + + /* Fill out each of the pointers with their final value. + * + * for (uint32_t i = 0; i < ma->ptr_count; i++) + * *ma->ptrs[i] = ptr + (uintptr_t)*ma->ptrs[i]; + * + * Unfortunately, even though ma->ptr_count is basically guaranteed to be a + * constant, GCC is incapable of figuring this out and unrolling the loop + * so we have to give it a little help. + */ + STATIC_ASSERT(ARRAY_SIZE(ma->ptrs) == 8); +#define _ANV_MULTIALLOC_UPDATE_POINTER(_i) \ + if ((_i) < ma->ptr_count) \ + *ma->ptrs[_i] = ptr + (uintptr_t)*ma->ptrs[_i] + _ANV_MULTIALLOC_UPDATE_POINTER(0); + _ANV_MULTIALLOC_UPDATE_POINTER(1); + _ANV_MULTIALLOC_UPDATE_POINTER(2); + _ANV_MULTIALLOC_UPDATE_POINTER(3); + _ANV_MULTIALLOC_UPDATE_POINTER(4); + _ANV_MULTIALLOC_UPDATE_POINTER(5); + _ANV_MULTIALLOC_UPDATE_POINTER(6); + _ANV_MULTIALLOC_UPDATE_POINTER(7); +#undef _ANV_MULTIALLOC_UPDATE_POINTER + + return ptr; +} + +__attribute__((always_inline)) +static inline void * +anv_multialloc_alloc2(struct anv_multialloc *ma, + const VkAllocationCallbacks *parent_alloc, + const VkAllocationCallbacks *alloc, + VkSystemAllocationScope scope) +{ + return anv_multialloc_alloc(ma, alloc ? alloc : parent_alloc, scope); +} + /** * A dynamically growable, circular buffer. Elements are added at head and * removed from tail. head and tail are free-running uint32_t indices and we |