1/* 2 * Copyright © 2015 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23#ifndef VK_ALLOC_H 24#define VK_ALLOC_H 25 26/* common allocation inlines for vulkan drivers */ 27 28#include <stdio.h> 29#include <string.h> 30#include <vulkan/vulkan.h> 31 32#include "util/u_math.h" 33#include "util/macros.h" 34#include "util/u_printf.h" 35 36const VkAllocationCallbacks * 37vk_default_allocator(void); 38 39static inline void * 40vk_alloc(const VkAllocationCallbacks *alloc, 41 size_t size, size_t align, 42 VkSystemAllocationScope scope) 43{ 44 return alloc->pfnAllocation(alloc->pUserData, size, align, scope); 45} 46 47static inline void * 48vk_zalloc(const VkAllocationCallbacks *alloc, 49 size_t size, size_t align, 50 VkSystemAllocationScope scope) 51{ 52 void *mem = vk_alloc(alloc, size, align, scope); 53 if (mem == NULL) 54 return NULL; 55 56 memset(mem, 0, size); 57 58 return mem; 59} 60 61static inline void * 62vk_realloc(const VkAllocationCallbacks *alloc, 63 void *ptr, size_t size, size_t align, 64 VkSystemAllocationScope scope) 65{ 66 return alloc->pfnReallocation(alloc->pUserData, ptr, size, align, scope); 67} 68 69static inline void 70vk_free(const VkAllocationCallbacks *alloc, void *data) 71{ 72 if (data == NULL) 73 return; 74 75 alloc->pfnFree(alloc->pUserData, data); 76} 77 78static inline char * 79vk_strdup(const VkAllocationCallbacks *alloc, const char *s, 80 VkSystemAllocationScope scope) 81{ 82 if (s == NULL) 83 return NULL; 84 85 size_t size = strlen(s) + 1; 86 char *copy = (char *)vk_alloc(alloc, size, 1, scope); 87 if (copy == NULL) 88 return NULL; 89 90 memcpy(copy, s, size); 91 92 return copy; 93} 94 95static inline char * 96vk_vasprintf(const VkAllocationCallbacks *alloc, 97 VkSystemAllocationScope scope, 98 const char *fmt, va_list args) 99{ 100 size_t size = u_printf_length(fmt, args) + 1; 101 char *ptr = (char *)vk_alloc(alloc, size, 1, scope); 102 if (ptr != NULL) 103 vsnprintf(ptr, size, fmt, args); 104 105 return ptr; 106} 107 108PRINTFLIKE(3, 4) static inline char * 109vk_asprintf(const VkAllocationCallbacks *alloc, 110 VkSystemAllocationScope scope, 111 const char *fmt, ...) 112{ 113 va_list args; 114 va_start(args, fmt); 115 char *ptr = vk_vasprintf(alloc, scope, fmt, args); 116 va_end(args); 117 118 return ptr; 119} 120 121static inline void * 122vk_alloc2(const VkAllocationCallbacks *parent_alloc, 123 const VkAllocationCallbacks *alloc, 124 size_t size, size_t align, 125 VkSystemAllocationScope scope) 126{ 127 if (alloc) 128 return vk_alloc(alloc, size, align, scope); 129 else 130 return vk_alloc(parent_alloc, size, align, scope); 131} 132 133static inline void * 134vk_zalloc2(const VkAllocationCallbacks *parent_alloc, 135 const VkAllocationCallbacks *alloc, 136 size_t size, size_t align, 137 VkSystemAllocationScope scope) 138{ 139 void *mem = vk_alloc2(parent_alloc, alloc, size, align, scope); 140 if (mem == NULL) 141 return NULL; 142 143 memset(mem, 0, size); 144 145 return mem; 146} 147 148static inline void 149vk_free2(const VkAllocationCallbacks *parent_alloc, 150 const VkAllocationCallbacks *alloc, 151 void *data) 152{ 153 if (alloc) 154 vk_free(alloc, data); 155 else 156 vk_free(parent_alloc, data); 157} 158 159/* A multi-pointer allocator 160 * 161 * When copying data structures from the user (such as a render pass), it's 162 * common to need to allocate data for a bunch of different things. Instead 163 * of doing several allocations and having to handle all of the error checking 164 * that entails, it can be easier to do a single allocation. This struct 165 * helps facilitate that. The intended usage looks like this: 166 * 167 * VK_MULTIALLOC(ma) 168 * vk_multialloc_add(&ma, &main_ptr, 1); 169 * vk_multialloc_add(&ma, &substruct1, substruct1Count); 170 * vk_multialloc_add(&ma, &substruct2, substruct2Count); 171 * 172 * if (!vk_multialloc_alloc(&ma, pAllocator, VK_ALLOCATION_SCOPE_FOO)) 173 * return vk_error(VK_ERROR_OUT_OF_HOST_MEORY); 174 */ 175struct vk_multialloc { 176 size_t size; 177 size_t align; 178 179 uint32_t ptr_count; 180 void **ptrs[8]; 181}; 182 183#define VK_MULTIALLOC_INIT \ 184 ((struct vk_multialloc) { 0, }) 185 186#define VK_MULTIALLOC(_name) \ 187 struct vk_multialloc _name = VK_MULTIALLOC_INIT 188 189static ALWAYS_INLINE void 190vk_multialloc_add_size_align(struct vk_multialloc *ma, 191 void **ptr, size_t size, size_t align) 192{ 193 assert(util_is_power_of_two_nonzero(align)); 194 if (size == 0) { 195 *ptr = NULL; 196 return; 197 } 198 199 size_t offset = ALIGN_POT(ma->size, align); 200 ma->size = offset + size; 201 ma->align = MAX2(ma->align, align); 202 203 /* Store the offset in the pointer. */ 204 *ptr = (void *)(uintptr_t)offset; 205 206 assert(ma->ptr_count < ARRAY_SIZE(ma->ptrs)); 207 ma->ptrs[ma->ptr_count++] = ptr; 208} 209 210#define vk_multialloc_add_size(_ma, _ptr, _type, _size) \ 211 do { \ 212 _type **_tmp = (_ptr); \ 213 (void)_tmp; \ 214 vk_multialloc_add_size_align((_ma), (void **)(_ptr), \ 215 (_size), alignof(_type)); \ 216 } while(0) 217 218#define vk_multialloc_add(_ma, _ptr, _type, _count) \ 219 vk_multialloc_add_size(_ma, _ptr, _type, (_count) * sizeof(**(_ptr))); 220 221#define VK_MULTIALLOC_DECL_SIZE(_ma, _type, _name, _size) \ 222 _type *_name; \ 223 vk_multialloc_add_size(_ma, &_name, _type, _size); 224 225#define VK_MULTIALLOC_DECL(_ma, _type, _name, _count) \ 226 VK_MULTIALLOC_DECL_SIZE(_ma, _type, _name, (_count) * sizeof(_type)); 227 228static ALWAYS_INLINE void * 229vk_multialloc_alloc(struct vk_multialloc *ma, 230 const VkAllocationCallbacks *alloc, 231 VkSystemAllocationScope scope) 232{ 233 char *ptr = (char *)vk_alloc(alloc, ma->size, ma->align, scope); 234 if (!ptr) 235 return NULL; 236 237 /* Fill out each of the pointers with their final value. 238 * 239 * for (uint32_t i = 0; i < ma->ptr_count; i++) 240 * *ma->ptrs[i] = ptr + (uintptr_t)*ma->ptrs[i]; 241 * 242 * Unfortunately, even though ma->ptr_count is basically guaranteed to be a 243 * constant, GCC is incapable of figuring this out and unrolling the loop 244 * so we have to give it a little help. 245 */ 246 STATIC_ASSERT(ARRAY_SIZE(ma->ptrs) == 8); 247#define _VK_MULTIALLOC_UPDATE_POINTER(_i) \ 248 if ((_i) < ma->ptr_count) \ 249 *ma->ptrs[_i] = ptr + (uintptr_t)*ma->ptrs[_i] 250 _VK_MULTIALLOC_UPDATE_POINTER(0); 251 _VK_MULTIALLOC_UPDATE_POINTER(1); 252 _VK_MULTIALLOC_UPDATE_POINTER(2); 253 _VK_MULTIALLOC_UPDATE_POINTER(3); 254 _VK_MULTIALLOC_UPDATE_POINTER(4); 255 _VK_MULTIALLOC_UPDATE_POINTER(5); 256 _VK_MULTIALLOC_UPDATE_POINTER(6); 257 _VK_MULTIALLOC_UPDATE_POINTER(7); 258#undef _VK_MULTIALLOC_UPDATE_POINTER 259 260 return ptr; 261} 262 263static ALWAYS_INLINE void * 264vk_multialloc_alloc2(struct vk_multialloc *ma, 265 const VkAllocationCallbacks *parent_alloc, 266 const VkAllocationCallbacks *alloc, 267 VkSystemAllocationScope scope) 268{ 269 return vk_multialloc_alloc(ma, alloc ? alloc : parent_alloc, scope); 270} 271 272static ALWAYS_INLINE void * 273vk_multialloc_zalloc(struct vk_multialloc *ma, 274 const VkAllocationCallbacks *alloc, 275 VkSystemAllocationScope scope) 276{ 277 void *ptr = vk_multialloc_alloc(ma, alloc, scope); 278 279 if (ptr == NULL) 280 return NULL; 281 282 memset(ptr, 0, ma->size); 283 284 return ptr; 285} 286 287static ALWAYS_INLINE void * 288vk_multialloc_zalloc2(struct vk_multialloc *ma, 289 const VkAllocationCallbacks *parent_alloc, 290 const VkAllocationCallbacks *alloc, 291 VkSystemAllocationScope scope) 292{ 293 return vk_multialloc_zalloc(ma, alloc ? alloc : parent_alloc, scope); 294} 295 296#endif 297