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 *
vk_alloc(const VkAllocationCallbacks * alloc,size_t size,size_t align,VkSystemAllocationScope scope)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 *
vk_zalloc(const VkAllocationCallbacks * alloc,size_t size,size_t align,VkSystemAllocationScope scope)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 *
vk_realloc(const VkAllocationCallbacks * alloc,void * ptr,size_t size,size_t align,VkSystemAllocationScope scope)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
vk_free(const VkAllocationCallbacks * alloc,void * data)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 *
vk_strdup(const VkAllocationCallbacks * alloc,const char * s,VkSystemAllocationScope scope)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 *
vk_vasprintf(const VkAllocationCallbacks * alloc,VkSystemAllocationScope scope,const char * fmt,va_list args)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 *
vk_asprintf(const VkAllocationCallbacks * alloc,VkSystemAllocationScope scope,const char * fmt,...)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 *
vk_alloc2(const VkAllocationCallbacks * parent_alloc,const VkAllocationCallbacks * alloc,size_t size,size_t align,VkSystemAllocationScope scope)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 *
vk_zalloc2(const VkAllocationCallbacks * parent_alloc,const VkAllocationCallbacks * alloc,size_t size,size_t align,VkSystemAllocationScope scope)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
vk_free2(const VkAllocationCallbacks * parent_alloc,const VkAllocationCallbacks * alloc,void * data)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
vk_multialloc_add_size_align(struct vk_multialloc * ma,void ** ptr,size_t size,size_t align)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 *
vk_multialloc_alloc(struct vk_multialloc * ma,const VkAllocationCallbacks * alloc,VkSystemAllocationScope scope)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 *
vk_multialloc_alloc2(struct vk_multialloc * ma,const VkAllocationCallbacks * parent_alloc,const VkAllocationCallbacks * alloc,VkSystemAllocationScope scope)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 *
vk_multialloc_zalloc(struct vk_multialloc * ma,const VkAllocationCallbacks * alloc,VkSystemAllocationScope scope)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 *
vk_multialloc_zalloc2(struct vk_multialloc * ma,const VkAllocationCallbacks * parent_alloc,const VkAllocationCallbacks * alloc,VkSystemAllocationScope scope)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