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#ifdef __cplusplus 37extern "C" { 38#endif 39 40const VkAllocationCallbacks * 41vk_default_allocator(void); 42 43static inline void * 44vk_alloc(const VkAllocationCallbacks *alloc, 45 size_t size, size_t align, 46 VkSystemAllocationScope scope) 47{ 48 return alloc->pfnAllocation(alloc->pUserData, size, align, scope); 49} 50 51static inline void * 52vk_zalloc(const VkAllocationCallbacks *alloc, 53 size_t size, size_t align, 54 VkSystemAllocationScope scope) 55{ 56 void *mem = vk_alloc(alloc, size, align, scope); 57 if (mem == NULL) 58 return NULL; 59 60 memset(mem, 0, size); 61 62 return mem; 63} 64 65static inline void * 66vk_realloc(const VkAllocationCallbacks *alloc, 67 void *ptr, size_t size, size_t align, 68 VkSystemAllocationScope scope) 69{ 70 return alloc->pfnReallocation(alloc->pUserData, ptr, size, align, scope); 71} 72 73static inline void 74vk_free(const VkAllocationCallbacks *alloc, void *data) 75{ 76 if (data == NULL) 77 return; 78 79 alloc->pfnFree(alloc->pUserData, data); 80} 81 82static inline char * 83vk_strdup(const VkAllocationCallbacks *alloc, const char *s, 84 VkSystemAllocationScope scope) 85{ 86 if (s == NULL) 87 return NULL; 88 89 size_t size = strlen(s) + 1; 90 char *copy = (char *)vk_alloc(alloc, size, 1, scope); 91 if (copy == NULL) 92 return NULL; 93 94 memcpy(copy, s, size); 95 96 return copy; 97} 98 99static inline char * 100vk_vasprintf(const VkAllocationCallbacks *alloc, 101 VkSystemAllocationScope scope, 102 const char *fmt, va_list args) 103{ 104 size_t size = u_printf_length(fmt, args) + 1; 105 char *ptr = (char *)vk_alloc(alloc, size, 1, scope); 106 if (ptr != NULL) 107 vsnprintf(ptr, size, fmt, args); 108 109 return ptr; 110} 111 112PRINTFLIKE(3, 4) static inline char * 113vk_asprintf(const VkAllocationCallbacks *alloc, 114 VkSystemAllocationScope scope, 115 const char *fmt, ...) 116{ 117 va_list args; 118 va_start(args, fmt); 119 char *ptr = vk_vasprintf(alloc, scope, fmt, args); 120 va_end(args); 121 122 return ptr; 123} 124 125static inline void * 126vk_alloc2(const VkAllocationCallbacks *parent_alloc, 127 const VkAllocationCallbacks *alloc, 128 size_t size, size_t align, 129 VkSystemAllocationScope scope) 130{ 131 if (alloc) 132 return vk_alloc(alloc, size, align, scope); 133 else 134 return vk_alloc(parent_alloc, size, align, scope); 135} 136 137static inline void * 138vk_zalloc2(const VkAllocationCallbacks *parent_alloc, 139 const VkAllocationCallbacks *alloc, 140 size_t size, size_t align, 141 VkSystemAllocationScope scope) 142{ 143 void *mem = vk_alloc2(parent_alloc, alloc, size, align, scope); 144 if (mem == NULL) 145 return NULL; 146 147 memset(mem, 0, size); 148 149 return mem; 150} 151 152static inline void 153vk_free2(const VkAllocationCallbacks *parent_alloc, 154 const VkAllocationCallbacks *alloc, 155 void *data) 156{ 157 if (alloc) 158 vk_free(alloc, data); 159 else 160 vk_free(parent_alloc, data); 161} 162 163/* A multi-pointer allocator 164 * 165 * When copying data structures from the user (such as a render pass), it's 166 * common to need to allocate data for a bunch of different things. Instead 167 * of doing several allocations and having to handle all of the error checking 168 * that entails, it can be easier to do a single allocation. This struct 169 * helps facilitate that. The intended usage looks like this: 170 * 171 * VK_MULTIALLOC(ma) 172 * vk_multialloc_add(&ma, &main_ptr, 1); 173 * vk_multialloc_add(&ma, &substruct1, substruct1Count); 174 * vk_multialloc_add(&ma, &substruct2, substruct2Count); 175 * 176 * if (!vk_multialloc_alloc(&ma, pAllocator, VK_ALLOCATION_SCOPE_FOO)) 177 * return vk_error(VK_ERROR_OUT_OF_HOST_MEORY); 178 */ 179struct vk_multialloc { 180 size_t size; 181 size_t align; 182 183 uint32_t ptr_count; 184 void **ptrs[12]; 185}; 186 187#define VK_MULTIALLOC(_name) \ 188 struct vk_multialloc _name = { 0, } 189 190static ALWAYS_INLINE void 191vk_multialloc_add_size_align(struct vk_multialloc *ma, 192 void **ptr, size_t size, size_t align) 193{ 194 assert(util_is_power_of_two_nonzero(align)); 195 if (size == 0) { 196 *ptr = NULL; 197 return; 198 } 199 200 size_t offset = ALIGN_POT(ma->size, align); 201 ma->size = offset + size; 202 ma->align = MAX2(ma->align, align); 203 204 /* Store the offset in the pointer. */ 205 *ptr = (void *)(uintptr_t)offset; 206 207 assert(ma->ptr_count < ARRAY_SIZE(ma->ptrs)); 208 ma->ptrs[ma->ptr_count++] = ptr; 209} 210 211#define vk_multialloc_add_size(_ma, _ptr, _type, _size) \ 212 do { \ 213 _type **_tmp = (_ptr); \ 214 (void)_tmp; \ 215 vk_multialloc_add_size_align((_ma), (void **)(_ptr), \ 216 (_size), alignof(_type)); \ 217 } while(0) 218 219#define vk_multialloc_add(_ma, _ptr, _type, _count) \ 220 vk_multialloc_add_size(_ma, _ptr, _type, (_count) * sizeof(**(_ptr))); 221 222#define VK_MULTIALLOC_DECL_SIZE(_ma, _type, _name, _size) \ 223 _type *_name; \ 224 vk_multialloc_add_size(_ma, &_name, _type, _size); 225 226#define VK_MULTIALLOC_DECL(_ma, _type, _name, _count) \ 227 VK_MULTIALLOC_DECL_SIZE(_ma, _type, _name, (_count) * sizeof(_type)); 228 229static ALWAYS_INLINE void * 230vk_multialloc_alloc(struct vk_multialloc *ma, 231 const VkAllocationCallbacks *alloc, 232 VkSystemAllocationScope scope) 233{ 234 void *ptr = vk_alloc(alloc, ma->size, ma->align, scope); 235 if (!ptr) 236 return NULL; 237 238 /* Fill out each of the pointers with their final value. 239 * 240 * for (uint32_t i = 0; i < ma->ptr_count; i++) 241 * *ma->ptrs[i] = ptr + (uintptr_t)*ma->ptrs[i]; 242 * 243 * Unfortunately, even though ma->ptr_count is basically guaranteed to be a 244 * constant, GCC is incapable of figuring this out and unrolling the loop 245 * so we have to give it a little help. 246 */ 247 STATIC_ASSERT(ARRAY_SIZE(ma->ptrs) == 12); 248#define _VK_MULTIALLOC_UPDATE_POINTER(_i) \ 249 if ((_i) < ma->ptr_count) \ 250 *ma->ptrs[_i] = (char *)ptr + (uintptr_t)*ma->ptrs[_i] 251 _VK_MULTIALLOC_UPDATE_POINTER(0); 252 _VK_MULTIALLOC_UPDATE_POINTER(1); 253 _VK_MULTIALLOC_UPDATE_POINTER(2); 254 _VK_MULTIALLOC_UPDATE_POINTER(3); 255 _VK_MULTIALLOC_UPDATE_POINTER(4); 256 _VK_MULTIALLOC_UPDATE_POINTER(5); 257 _VK_MULTIALLOC_UPDATE_POINTER(6); 258 _VK_MULTIALLOC_UPDATE_POINTER(7); 259 _VK_MULTIALLOC_UPDATE_POINTER(8); 260 _VK_MULTIALLOC_UPDATE_POINTER(9); 261 _VK_MULTIALLOC_UPDATE_POINTER(10); 262 _VK_MULTIALLOC_UPDATE_POINTER(11); 263#undef _VK_MULTIALLOC_UPDATE_POINTER 264 265 return ptr; 266} 267 268static ALWAYS_INLINE void * 269vk_multialloc_alloc2(struct vk_multialloc *ma, 270 const VkAllocationCallbacks *parent_alloc, 271 const VkAllocationCallbacks *alloc, 272 VkSystemAllocationScope scope) 273{ 274 return vk_multialloc_alloc(ma, alloc ? alloc : parent_alloc, scope); 275} 276 277static ALWAYS_INLINE void * 278vk_multialloc_zalloc(struct vk_multialloc *ma, 279 const VkAllocationCallbacks *alloc, 280 VkSystemAllocationScope scope) 281{ 282 void *ptr = vk_multialloc_alloc(ma, alloc, scope); 283 284 if (ptr == NULL) 285 return NULL; 286 287 memset(ptr, 0, ma->size); 288 289 return ptr; 290} 291 292static ALWAYS_INLINE void * 293vk_multialloc_zalloc2(struct vk_multialloc *ma, 294 const VkAllocationCallbacks *parent_alloc, 295 const VkAllocationCallbacks *alloc, 296 VkSystemAllocationScope scope) 297{ 298 return vk_multialloc_zalloc(ma, alloc ? alloc : parent_alloc, scope); 299} 300 301#ifdef __cplusplus 302} 303#endif 304 305#endif 306