101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2015 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg#ifndef VK_ALLOC_H 2401e04c3fSmrg#define VK_ALLOC_H 2501e04c3fSmrg 2601e04c3fSmrg/* common allocation inlines for vulkan drivers */ 2701e04c3fSmrg 287ec681f3Smrg#include <stdio.h> 2901e04c3fSmrg#include <string.h> 3001e04c3fSmrg#include <vulkan/vulkan.h> 3101e04c3fSmrg 327ec681f3Smrg#include "util/u_math.h" 337ec681f3Smrg#include "util/macros.h" 347ec681f3Smrg#include "util/u_printf.h" 357ec681f3Smrg 367ec681f3Smrgconst VkAllocationCallbacks * 377ec681f3Smrgvk_default_allocator(void); 387ec681f3Smrg 3901e04c3fSmrgstatic inline void * 4001e04c3fSmrgvk_alloc(const VkAllocationCallbacks *alloc, 4101e04c3fSmrg size_t size, size_t align, 4201e04c3fSmrg VkSystemAllocationScope scope) 4301e04c3fSmrg{ 4401e04c3fSmrg return alloc->pfnAllocation(alloc->pUserData, size, align, scope); 4501e04c3fSmrg} 4601e04c3fSmrg 4701e04c3fSmrgstatic inline void * 4801e04c3fSmrgvk_zalloc(const VkAllocationCallbacks *alloc, 4901e04c3fSmrg size_t size, size_t align, 5001e04c3fSmrg VkSystemAllocationScope scope) 5101e04c3fSmrg{ 5201e04c3fSmrg void *mem = vk_alloc(alloc, size, align, scope); 5301e04c3fSmrg if (mem == NULL) 5401e04c3fSmrg return NULL; 5501e04c3fSmrg 5601e04c3fSmrg memset(mem, 0, size); 5701e04c3fSmrg 5801e04c3fSmrg return mem; 5901e04c3fSmrg} 6001e04c3fSmrg 6101e04c3fSmrgstatic inline void * 6201e04c3fSmrgvk_realloc(const VkAllocationCallbacks *alloc, 6301e04c3fSmrg void *ptr, size_t size, size_t align, 6401e04c3fSmrg VkSystemAllocationScope scope) 6501e04c3fSmrg{ 6601e04c3fSmrg return alloc->pfnReallocation(alloc->pUserData, ptr, size, align, scope); 6701e04c3fSmrg} 6801e04c3fSmrg 6901e04c3fSmrgstatic inline void 7001e04c3fSmrgvk_free(const VkAllocationCallbacks *alloc, void *data) 7101e04c3fSmrg{ 7201e04c3fSmrg if (data == NULL) 7301e04c3fSmrg return; 7401e04c3fSmrg 7501e04c3fSmrg alloc->pfnFree(alloc->pUserData, data); 7601e04c3fSmrg} 7701e04c3fSmrg 7801e04c3fSmrgstatic inline char * 7901e04c3fSmrgvk_strdup(const VkAllocationCallbacks *alloc, const char *s, 8001e04c3fSmrg VkSystemAllocationScope scope) 8101e04c3fSmrg{ 8201e04c3fSmrg if (s == NULL) 8301e04c3fSmrg return NULL; 8401e04c3fSmrg 8501e04c3fSmrg size_t size = strlen(s) + 1; 867ec681f3Smrg char *copy = (char *)vk_alloc(alloc, size, 1, scope); 8701e04c3fSmrg if (copy == NULL) 8801e04c3fSmrg return NULL; 8901e04c3fSmrg 9001e04c3fSmrg memcpy(copy, s, size); 9101e04c3fSmrg 9201e04c3fSmrg return copy; 9301e04c3fSmrg} 9401e04c3fSmrg 957ec681f3Smrgstatic inline char * 967ec681f3Smrgvk_vasprintf(const VkAllocationCallbacks *alloc, 977ec681f3Smrg VkSystemAllocationScope scope, 987ec681f3Smrg const char *fmt, va_list args) 997ec681f3Smrg{ 1007ec681f3Smrg size_t size = u_printf_length(fmt, args) + 1; 1017ec681f3Smrg char *ptr = (char *)vk_alloc(alloc, size, 1, scope); 1027ec681f3Smrg if (ptr != NULL) 1037ec681f3Smrg vsnprintf(ptr, size, fmt, args); 1047ec681f3Smrg 1057ec681f3Smrg return ptr; 1067ec681f3Smrg} 1077ec681f3Smrg 1087ec681f3SmrgPRINTFLIKE(3, 4) static inline char * 1097ec681f3Smrgvk_asprintf(const VkAllocationCallbacks *alloc, 1107ec681f3Smrg VkSystemAllocationScope scope, 1117ec681f3Smrg const char *fmt, ...) 1127ec681f3Smrg{ 1137ec681f3Smrg va_list args; 1147ec681f3Smrg va_start(args, fmt); 1157ec681f3Smrg char *ptr = vk_vasprintf(alloc, scope, fmt, args); 1167ec681f3Smrg va_end(args); 1177ec681f3Smrg 1187ec681f3Smrg return ptr; 1197ec681f3Smrg} 1207ec681f3Smrg 12101e04c3fSmrgstatic inline void * 12201e04c3fSmrgvk_alloc2(const VkAllocationCallbacks *parent_alloc, 12301e04c3fSmrg const VkAllocationCallbacks *alloc, 12401e04c3fSmrg size_t size, size_t align, 12501e04c3fSmrg VkSystemAllocationScope scope) 12601e04c3fSmrg{ 12701e04c3fSmrg if (alloc) 12801e04c3fSmrg return vk_alloc(alloc, size, align, scope); 12901e04c3fSmrg else 13001e04c3fSmrg return vk_alloc(parent_alloc, size, align, scope); 13101e04c3fSmrg} 13201e04c3fSmrg 13301e04c3fSmrgstatic inline void * 13401e04c3fSmrgvk_zalloc2(const VkAllocationCallbacks *parent_alloc, 13501e04c3fSmrg const VkAllocationCallbacks *alloc, 13601e04c3fSmrg size_t size, size_t align, 13701e04c3fSmrg VkSystemAllocationScope scope) 13801e04c3fSmrg{ 13901e04c3fSmrg void *mem = vk_alloc2(parent_alloc, alloc, size, align, scope); 14001e04c3fSmrg if (mem == NULL) 14101e04c3fSmrg return NULL; 14201e04c3fSmrg 14301e04c3fSmrg memset(mem, 0, size); 14401e04c3fSmrg 14501e04c3fSmrg return mem; 14601e04c3fSmrg} 14701e04c3fSmrg 14801e04c3fSmrgstatic inline void 14901e04c3fSmrgvk_free2(const VkAllocationCallbacks *parent_alloc, 15001e04c3fSmrg const VkAllocationCallbacks *alloc, 15101e04c3fSmrg void *data) 15201e04c3fSmrg{ 15301e04c3fSmrg if (alloc) 15401e04c3fSmrg vk_free(alloc, data); 15501e04c3fSmrg else 15601e04c3fSmrg vk_free(parent_alloc, data); 15701e04c3fSmrg} 15801e04c3fSmrg 1597ec681f3Smrg/* A multi-pointer allocator 1607ec681f3Smrg * 1617ec681f3Smrg * When copying data structures from the user (such as a render pass), it's 1627ec681f3Smrg * common to need to allocate data for a bunch of different things. Instead 1637ec681f3Smrg * of doing several allocations and having to handle all of the error checking 1647ec681f3Smrg * that entails, it can be easier to do a single allocation. This struct 1657ec681f3Smrg * helps facilitate that. The intended usage looks like this: 1667ec681f3Smrg * 1677ec681f3Smrg * VK_MULTIALLOC(ma) 1687ec681f3Smrg * vk_multialloc_add(&ma, &main_ptr, 1); 1697ec681f3Smrg * vk_multialloc_add(&ma, &substruct1, substruct1Count); 1707ec681f3Smrg * vk_multialloc_add(&ma, &substruct2, substruct2Count); 1717ec681f3Smrg * 1727ec681f3Smrg * if (!vk_multialloc_alloc(&ma, pAllocator, VK_ALLOCATION_SCOPE_FOO)) 1737ec681f3Smrg * return vk_error(VK_ERROR_OUT_OF_HOST_MEORY); 1747ec681f3Smrg */ 1757ec681f3Smrgstruct vk_multialloc { 1767ec681f3Smrg size_t size; 1777ec681f3Smrg size_t align; 1787ec681f3Smrg 1797ec681f3Smrg uint32_t ptr_count; 1807ec681f3Smrg void **ptrs[8]; 1817ec681f3Smrg}; 1827ec681f3Smrg 1837ec681f3Smrg#define VK_MULTIALLOC_INIT \ 1847ec681f3Smrg ((struct vk_multialloc) { 0, }) 1857ec681f3Smrg 1867ec681f3Smrg#define VK_MULTIALLOC(_name) \ 1877ec681f3Smrg struct vk_multialloc _name = VK_MULTIALLOC_INIT 1887ec681f3Smrg 1897ec681f3Smrgstatic ALWAYS_INLINE void 1907ec681f3Smrgvk_multialloc_add_size_align(struct vk_multialloc *ma, 1917ec681f3Smrg void **ptr, size_t size, size_t align) 1927ec681f3Smrg{ 1937ec681f3Smrg assert(util_is_power_of_two_nonzero(align)); 1947ec681f3Smrg if (size == 0) { 1957ec681f3Smrg *ptr = NULL; 1967ec681f3Smrg return; 1977ec681f3Smrg } 1987ec681f3Smrg 1997ec681f3Smrg size_t offset = ALIGN_POT(ma->size, align); 2007ec681f3Smrg ma->size = offset + size; 2017ec681f3Smrg ma->align = MAX2(ma->align, align); 2027ec681f3Smrg 2037ec681f3Smrg /* Store the offset in the pointer. */ 2047ec681f3Smrg *ptr = (void *)(uintptr_t)offset; 2057ec681f3Smrg 2067ec681f3Smrg assert(ma->ptr_count < ARRAY_SIZE(ma->ptrs)); 2077ec681f3Smrg ma->ptrs[ma->ptr_count++] = ptr; 2087ec681f3Smrg} 2097ec681f3Smrg 2107ec681f3Smrg#define vk_multialloc_add_size(_ma, _ptr, _type, _size) \ 2117ec681f3Smrg do { \ 2127ec681f3Smrg _type **_tmp = (_ptr); \ 2137ec681f3Smrg (void)_tmp; \ 2147ec681f3Smrg vk_multialloc_add_size_align((_ma), (void **)(_ptr), \ 2157ec681f3Smrg (_size), alignof(_type)); \ 2167ec681f3Smrg } while(0) 2177ec681f3Smrg 2187ec681f3Smrg#define vk_multialloc_add(_ma, _ptr, _type, _count) \ 2197ec681f3Smrg vk_multialloc_add_size(_ma, _ptr, _type, (_count) * sizeof(**(_ptr))); 2207ec681f3Smrg 2217ec681f3Smrg#define VK_MULTIALLOC_DECL_SIZE(_ma, _type, _name, _size) \ 2227ec681f3Smrg _type *_name; \ 2237ec681f3Smrg vk_multialloc_add_size(_ma, &_name, _type, _size); 2247ec681f3Smrg 2257ec681f3Smrg#define VK_MULTIALLOC_DECL(_ma, _type, _name, _count) \ 2267ec681f3Smrg VK_MULTIALLOC_DECL_SIZE(_ma, _type, _name, (_count) * sizeof(_type)); 2277ec681f3Smrg 2287ec681f3Smrgstatic ALWAYS_INLINE void * 2297ec681f3Smrgvk_multialloc_alloc(struct vk_multialloc *ma, 2307ec681f3Smrg const VkAllocationCallbacks *alloc, 2317ec681f3Smrg VkSystemAllocationScope scope) 2327ec681f3Smrg{ 2337ec681f3Smrg char *ptr = (char *)vk_alloc(alloc, ma->size, ma->align, scope); 2347ec681f3Smrg if (!ptr) 2357ec681f3Smrg return NULL; 2367ec681f3Smrg 2377ec681f3Smrg /* Fill out each of the pointers with their final value. 2387ec681f3Smrg * 2397ec681f3Smrg * for (uint32_t i = 0; i < ma->ptr_count; i++) 2407ec681f3Smrg * *ma->ptrs[i] = ptr + (uintptr_t)*ma->ptrs[i]; 2417ec681f3Smrg * 2427ec681f3Smrg * Unfortunately, even though ma->ptr_count is basically guaranteed to be a 2437ec681f3Smrg * constant, GCC is incapable of figuring this out and unrolling the loop 2447ec681f3Smrg * so we have to give it a little help. 2457ec681f3Smrg */ 2467ec681f3Smrg STATIC_ASSERT(ARRAY_SIZE(ma->ptrs) == 8); 2477ec681f3Smrg#define _VK_MULTIALLOC_UPDATE_POINTER(_i) \ 2487ec681f3Smrg if ((_i) < ma->ptr_count) \ 2497ec681f3Smrg *ma->ptrs[_i] = ptr + (uintptr_t)*ma->ptrs[_i] 2507ec681f3Smrg _VK_MULTIALLOC_UPDATE_POINTER(0); 2517ec681f3Smrg _VK_MULTIALLOC_UPDATE_POINTER(1); 2527ec681f3Smrg _VK_MULTIALLOC_UPDATE_POINTER(2); 2537ec681f3Smrg _VK_MULTIALLOC_UPDATE_POINTER(3); 2547ec681f3Smrg _VK_MULTIALLOC_UPDATE_POINTER(4); 2557ec681f3Smrg _VK_MULTIALLOC_UPDATE_POINTER(5); 2567ec681f3Smrg _VK_MULTIALLOC_UPDATE_POINTER(6); 2577ec681f3Smrg _VK_MULTIALLOC_UPDATE_POINTER(7); 2587ec681f3Smrg#undef _VK_MULTIALLOC_UPDATE_POINTER 2597ec681f3Smrg 2607ec681f3Smrg return ptr; 2617ec681f3Smrg} 2627ec681f3Smrg 2637ec681f3Smrgstatic ALWAYS_INLINE void * 2647ec681f3Smrgvk_multialloc_alloc2(struct vk_multialloc *ma, 2657ec681f3Smrg const VkAllocationCallbacks *parent_alloc, 2667ec681f3Smrg const VkAllocationCallbacks *alloc, 2677ec681f3Smrg VkSystemAllocationScope scope) 2687ec681f3Smrg{ 2697ec681f3Smrg return vk_multialloc_alloc(ma, alloc ? alloc : parent_alloc, scope); 2707ec681f3Smrg} 2717ec681f3Smrg 2727ec681f3Smrgstatic ALWAYS_INLINE void * 2737ec681f3Smrgvk_multialloc_zalloc(struct vk_multialloc *ma, 2747ec681f3Smrg const VkAllocationCallbacks *alloc, 2757ec681f3Smrg VkSystemAllocationScope scope) 2767ec681f3Smrg{ 2777ec681f3Smrg void *ptr = vk_multialloc_alloc(ma, alloc, scope); 2787ec681f3Smrg 2797ec681f3Smrg if (ptr == NULL) 2807ec681f3Smrg return NULL; 2817ec681f3Smrg 2827ec681f3Smrg memset(ptr, 0, ma->size); 2837ec681f3Smrg 2847ec681f3Smrg return ptr; 2857ec681f3Smrg} 2867ec681f3Smrg 2877ec681f3Smrgstatic ALWAYS_INLINE void * 2887ec681f3Smrgvk_multialloc_zalloc2(struct vk_multialloc *ma, 2897ec681f3Smrg const VkAllocationCallbacks *parent_alloc, 2907ec681f3Smrg const VkAllocationCallbacks *alloc, 2917ec681f3Smrg VkSystemAllocationScope scope) 2927ec681f3Smrg{ 2937ec681f3Smrg return vk_multialloc_zalloc(ma, alloc ? alloc : parent_alloc, scope); 2947ec681f3Smrg} 2957ec681f3Smrg 29601e04c3fSmrg#endif 297