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