1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2015 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci#ifndef VK_ALLOC_H
24bf215546Sopenharmony_ci#define VK_ALLOC_H
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci/* common allocation inlines for vulkan drivers */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include <stdio.h>
29bf215546Sopenharmony_ci#include <string.h>
30bf215546Sopenharmony_ci#include <vulkan/vulkan.h>
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "util/u_math.h"
33bf215546Sopenharmony_ci#include "util/macros.h"
34bf215546Sopenharmony_ci#include "util/u_printf.h"
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#ifdef __cplusplus
37bf215546Sopenharmony_ciextern "C" {
38bf215546Sopenharmony_ci#endif
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ciconst VkAllocationCallbacks *
41bf215546Sopenharmony_civk_default_allocator(void);
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_cistatic inline void *
44bf215546Sopenharmony_civk_alloc(const VkAllocationCallbacks *alloc,
45bf215546Sopenharmony_ci         size_t size, size_t align,
46bf215546Sopenharmony_ci         VkSystemAllocationScope scope)
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci   return alloc->pfnAllocation(alloc->pUserData, size, align, scope);
49bf215546Sopenharmony_ci}
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_cistatic inline void *
52bf215546Sopenharmony_civk_zalloc(const VkAllocationCallbacks *alloc,
53bf215546Sopenharmony_ci          size_t size, size_t align,
54bf215546Sopenharmony_ci          VkSystemAllocationScope scope)
55bf215546Sopenharmony_ci{
56bf215546Sopenharmony_ci   void *mem = vk_alloc(alloc, size, align, scope);
57bf215546Sopenharmony_ci   if (mem == NULL)
58bf215546Sopenharmony_ci      return NULL;
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci   memset(mem, 0, size);
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   return mem;
63bf215546Sopenharmony_ci}
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_cistatic inline void *
66bf215546Sopenharmony_civk_realloc(const VkAllocationCallbacks *alloc,
67bf215546Sopenharmony_ci           void *ptr, size_t size, size_t align,
68bf215546Sopenharmony_ci           VkSystemAllocationScope scope)
69bf215546Sopenharmony_ci{
70bf215546Sopenharmony_ci   return alloc->pfnReallocation(alloc->pUserData, ptr, size, align, scope);
71bf215546Sopenharmony_ci}
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_cistatic inline void
74bf215546Sopenharmony_civk_free(const VkAllocationCallbacks *alloc, void *data)
75bf215546Sopenharmony_ci{
76bf215546Sopenharmony_ci   if (data == NULL)
77bf215546Sopenharmony_ci      return;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   alloc->pfnFree(alloc->pUserData, data);
80bf215546Sopenharmony_ci}
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_cistatic inline char *
83bf215546Sopenharmony_civk_strdup(const VkAllocationCallbacks *alloc, const char *s,
84bf215546Sopenharmony_ci          VkSystemAllocationScope scope)
85bf215546Sopenharmony_ci{
86bf215546Sopenharmony_ci   if (s == NULL)
87bf215546Sopenharmony_ci      return NULL;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   size_t size = strlen(s) + 1;
90bf215546Sopenharmony_ci   char *copy = (char *)vk_alloc(alloc, size, 1, scope);
91bf215546Sopenharmony_ci   if (copy == NULL)
92bf215546Sopenharmony_ci      return NULL;
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   memcpy(copy, s, size);
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   return copy;
97bf215546Sopenharmony_ci}
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_cistatic inline char *
100bf215546Sopenharmony_civk_vasprintf(const VkAllocationCallbacks *alloc,
101bf215546Sopenharmony_ci             VkSystemAllocationScope scope,
102bf215546Sopenharmony_ci             const char *fmt, va_list args)
103bf215546Sopenharmony_ci{
104bf215546Sopenharmony_ci   size_t size = u_printf_length(fmt, args) + 1;
105bf215546Sopenharmony_ci   char *ptr = (char *)vk_alloc(alloc, size, 1, scope);
106bf215546Sopenharmony_ci   if (ptr != NULL)
107bf215546Sopenharmony_ci      vsnprintf(ptr, size, fmt, args);
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   return ptr;
110bf215546Sopenharmony_ci}
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ciPRINTFLIKE(3, 4) static inline char *
113bf215546Sopenharmony_civk_asprintf(const VkAllocationCallbacks *alloc,
114bf215546Sopenharmony_ci            VkSystemAllocationScope scope,
115bf215546Sopenharmony_ci            const char *fmt, ...)
116bf215546Sopenharmony_ci{
117bf215546Sopenharmony_ci   va_list args;
118bf215546Sopenharmony_ci   va_start(args, fmt);
119bf215546Sopenharmony_ci   char *ptr = vk_vasprintf(alloc, scope, fmt, args);
120bf215546Sopenharmony_ci   va_end(args);
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci   return ptr;
123bf215546Sopenharmony_ci}
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_cistatic inline void *
126bf215546Sopenharmony_civk_alloc2(const VkAllocationCallbacks *parent_alloc,
127bf215546Sopenharmony_ci          const VkAllocationCallbacks *alloc,
128bf215546Sopenharmony_ci          size_t size, size_t align,
129bf215546Sopenharmony_ci          VkSystemAllocationScope scope)
130bf215546Sopenharmony_ci{
131bf215546Sopenharmony_ci   if (alloc)
132bf215546Sopenharmony_ci      return vk_alloc(alloc, size, align, scope);
133bf215546Sopenharmony_ci   else
134bf215546Sopenharmony_ci      return vk_alloc(parent_alloc, size, align, scope);
135bf215546Sopenharmony_ci}
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_cistatic inline void *
138bf215546Sopenharmony_civk_zalloc2(const VkAllocationCallbacks *parent_alloc,
139bf215546Sopenharmony_ci           const VkAllocationCallbacks *alloc,
140bf215546Sopenharmony_ci           size_t size, size_t align,
141bf215546Sopenharmony_ci           VkSystemAllocationScope scope)
142bf215546Sopenharmony_ci{
143bf215546Sopenharmony_ci   void *mem = vk_alloc2(parent_alloc, alloc, size, align, scope);
144bf215546Sopenharmony_ci   if (mem == NULL)
145bf215546Sopenharmony_ci      return NULL;
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   memset(mem, 0, size);
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   return mem;
150bf215546Sopenharmony_ci}
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_cistatic inline void
153bf215546Sopenharmony_civk_free2(const VkAllocationCallbacks *parent_alloc,
154bf215546Sopenharmony_ci         const VkAllocationCallbacks *alloc,
155bf215546Sopenharmony_ci         void *data)
156bf215546Sopenharmony_ci{
157bf215546Sopenharmony_ci   if (alloc)
158bf215546Sopenharmony_ci      vk_free(alloc, data);
159bf215546Sopenharmony_ci   else
160bf215546Sopenharmony_ci      vk_free(parent_alloc, data);
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci/* A multi-pointer allocator
164bf215546Sopenharmony_ci *
165bf215546Sopenharmony_ci * When copying data structures from the user (such as a render pass), it's
166bf215546Sopenharmony_ci * common to need to allocate data for a bunch of different things.  Instead
167bf215546Sopenharmony_ci * of doing several allocations and having to handle all of the error checking
168bf215546Sopenharmony_ci * that entails, it can be easier to do a single allocation.  This struct
169bf215546Sopenharmony_ci * helps facilitate that.  The intended usage looks like this:
170bf215546Sopenharmony_ci *
171bf215546Sopenharmony_ci *    VK_MULTIALLOC(ma)
172bf215546Sopenharmony_ci *    vk_multialloc_add(&ma, &main_ptr, 1);
173bf215546Sopenharmony_ci *    vk_multialloc_add(&ma, &substruct1, substruct1Count);
174bf215546Sopenharmony_ci *    vk_multialloc_add(&ma, &substruct2, substruct2Count);
175bf215546Sopenharmony_ci *
176bf215546Sopenharmony_ci *    if (!vk_multialloc_alloc(&ma, pAllocator, VK_ALLOCATION_SCOPE_FOO))
177bf215546Sopenharmony_ci *       return vk_error(VK_ERROR_OUT_OF_HOST_MEORY);
178bf215546Sopenharmony_ci */
179bf215546Sopenharmony_cistruct vk_multialloc {
180bf215546Sopenharmony_ci    size_t size;
181bf215546Sopenharmony_ci    size_t align;
182bf215546Sopenharmony_ci
183bf215546Sopenharmony_ci    uint32_t ptr_count;
184bf215546Sopenharmony_ci    void **ptrs[12];
185bf215546Sopenharmony_ci};
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci#define VK_MULTIALLOC(_name) \
188bf215546Sopenharmony_ci   struct vk_multialloc _name = { 0, }
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_cistatic ALWAYS_INLINE void
191bf215546Sopenharmony_civk_multialloc_add_size_align(struct vk_multialloc *ma,
192bf215546Sopenharmony_ci                             void **ptr, size_t size, size_t align)
193bf215546Sopenharmony_ci{
194bf215546Sopenharmony_ci   assert(util_is_power_of_two_nonzero(align));
195bf215546Sopenharmony_ci   if (size == 0) {
196bf215546Sopenharmony_ci      *ptr = NULL;
197bf215546Sopenharmony_ci      return;
198bf215546Sopenharmony_ci   }
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   size_t offset = ALIGN_POT(ma->size, align);
201bf215546Sopenharmony_ci   ma->size = offset + size;
202bf215546Sopenharmony_ci   ma->align = MAX2(ma->align, align);
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   /* Store the offset in the pointer. */
205bf215546Sopenharmony_ci   *ptr = (void *)(uintptr_t)offset;
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   assert(ma->ptr_count < ARRAY_SIZE(ma->ptrs));
208bf215546Sopenharmony_ci   ma->ptrs[ma->ptr_count++] = ptr;
209bf215546Sopenharmony_ci}
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci#define vk_multialloc_add_size(_ma, _ptr, _type, _size) \
212bf215546Sopenharmony_ci   do { \
213bf215546Sopenharmony_ci      _type **_tmp = (_ptr); \
214bf215546Sopenharmony_ci      (void)_tmp; \
215bf215546Sopenharmony_ci      vk_multialloc_add_size_align((_ma), (void **)(_ptr), \
216bf215546Sopenharmony_ci                                   (_size), alignof(_type)); \
217bf215546Sopenharmony_ci   } while(0)
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci#define vk_multialloc_add(_ma, _ptr, _type, _count) \
220bf215546Sopenharmony_ci   vk_multialloc_add_size(_ma, _ptr, _type, (_count) * sizeof(**(_ptr)));
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci#define VK_MULTIALLOC_DECL_SIZE(_ma, _type, _name, _size) \
223bf215546Sopenharmony_ci   _type *_name; \
224bf215546Sopenharmony_ci   vk_multialloc_add_size(_ma, &_name, _type, _size);
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci#define VK_MULTIALLOC_DECL(_ma, _type, _name, _count) \
227bf215546Sopenharmony_ci   VK_MULTIALLOC_DECL_SIZE(_ma, _type, _name, (_count) * sizeof(_type));
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_cistatic ALWAYS_INLINE void *
230bf215546Sopenharmony_civk_multialloc_alloc(struct vk_multialloc *ma,
231bf215546Sopenharmony_ci                    const VkAllocationCallbacks *alloc,
232bf215546Sopenharmony_ci                    VkSystemAllocationScope scope)
233bf215546Sopenharmony_ci{
234bf215546Sopenharmony_ci   void *ptr = vk_alloc(alloc, ma->size, ma->align, scope);
235bf215546Sopenharmony_ci   if (!ptr)
236bf215546Sopenharmony_ci      return NULL;
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   /* Fill out each of the pointers with their final value.
239bf215546Sopenharmony_ci    *
240bf215546Sopenharmony_ci    *   for (uint32_t i = 0; i < ma->ptr_count; i++)
241bf215546Sopenharmony_ci    *      *ma->ptrs[i] = ptr + (uintptr_t)*ma->ptrs[i];
242bf215546Sopenharmony_ci    *
243bf215546Sopenharmony_ci    * Unfortunately, even though ma->ptr_count is basically guaranteed to be a
244bf215546Sopenharmony_ci    * constant, GCC is incapable of figuring this out and unrolling the loop
245bf215546Sopenharmony_ci    * so we have to give it a little help.
246bf215546Sopenharmony_ci    */
247bf215546Sopenharmony_ci   STATIC_ASSERT(ARRAY_SIZE(ma->ptrs) == 12);
248bf215546Sopenharmony_ci#define _VK_MULTIALLOC_UPDATE_POINTER(_i) \
249bf215546Sopenharmony_ci   if ((_i) < ma->ptr_count) \
250bf215546Sopenharmony_ci      *ma->ptrs[_i] = (char *)ptr + (uintptr_t)*ma->ptrs[_i]
251bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(0);
252bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(1);
253bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(2);
254bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(3);
255bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(4);
256bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(5);
257bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(6);
258bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(7);
259bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(8);
260bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(9);
261bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(10);
262bf215546Sopenharmony_ci   _VK_MULTIALLOC_UPDATE_POINTER(11);
263bf215546Sopenharmony_ci#undef _VK_MULTIALLOC_UPDATE_POINTER
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   return ptr;
266bf215546Sopenharmony_ci}
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_cistatic ALWAYS_INLINE void *
269bf215546Sopenharmony_civk_multialloc_alloc2(struct vk_multialloc *ma,
270bf215546Sopenharmony_ci                     const VkAllocationCallbacks *parent_alloc,
271bf215546Sopenharmony_ci                     const VkAllocationCallbacks *alloc,
272bf215546Sopenharmony_ci                     VkSystemAllocationScope scope)
273bf215546Sopenharmony_ci{
274bf215546Sopenharmony_ci   return vk_multialloc_alloc(ma, alloc ? alloc : parent_alloc, scope);
275bf215546Sopenharmony_ci}
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_cistatic ALWAYS_INLINE void *
278bf215546Sopenharmony_civk_multialloc_zalloc(struct vk_multialloc *ma,
279bf215546Sopenharmony_ci                     const VkAllocationCallbacks *alloc,
280bf215546Sopenharmony_ci                     VkSystemAllocationScope scope)
281bf215546Sopenharmony_ci{
282bf215546Sopenharmony_ci   void *ptr = vk_multialloc_alloc(ma, alloc, scope);
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   if (ptr == NULL)
285bf215546Sopenharmony_ci      return NULL;
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci   memset(ptr, 0, ma->size);
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   return ptr;
290bf215546Sopenharmony_ci}
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_cistatic ALWAYS_INLINE void *
293bf215546Sopenharmony_civk_multialloc_zalloc2(struct vk_multialloc *ma,
294bf215546Sopenharmony_ci                      const VkAllocationCallbacks *parent_alloc,
295bf215546Sopenharmony_ci                      const VkAllocationCallbacks *alloc,
296bf215546Sopenharmony_ci                      VkSystemAllocationScope scope)
297bf215546Sopenharmony_ci{
298bf215546Sopenharmony_ci   return vk_multialloc_zalloc(ma, alloc ? alloc : parent_alloc, scope);
299bf215546Sopenharmony_ci}
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci#ifdef __cplusplus
302bf215546Sopenharmony_ci}
303bf215546Sopenharmony_ci#endif
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci#endif
306