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 36 const VkAllocationCallbacks * 37 vk_default_allocator(void); 38 39 static inline void * 40 vk_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 47 static inline void * 48 vk_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 61 static inline void * 62 vk_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 69 static inline void 70 vk_free(const VkAllocationCallbacks *alloc, void *data) 71 { 72 if (data == NULL) 73 return; 74 75 alloc->pfnFree(alloc->pUserData, data); 76 } 77 78 static inline char * 79 vk_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 95 static inline char * 96 vk_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 108 PRINTFLIKE(3, 4) static inline char * 109 vk_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 121 static inline void * 122 vk_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 133 static inline void * 134 vk_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 148 static inline void 149 vk_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 */ 175 struct 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 189 static ALWAYS_INLINE void 190 vk_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 228 static ALWAYS_INLINE void * 229 vk_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 263 static ALWAYS_INLINE void * 264 vk_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 272 static ALWAYS_INLINE void * 273 vk_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 287 static ALWAYS_INLINE void * 288 vk_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