Home | History | Annotate | Line # | Download | only in util
      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