1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2017 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_UTIL_H
24bf215546Sopenharmony_ci#define VK_UTIL_H
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "util/bitscan.h"
27bf215546Sopenharmony_ci#include "util/macros.h"
28bf215546Sopenharmony_ci#include "compiler/shader_enums.h"
29bf215546Sopenharmony_ci#include <stdlib.h>
30bf215546Sopenharmony_ci#include <string.h>
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#ifdef __cplusplus
33bf215546Sopenharmony_ciextern "C" {
34bf215546Sopenharmony_ci#endif
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci/* common inlines and macros for vulkan drivers */
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci#include <vulkan/vulkan.h>
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_cistruct vk_pnext_iterator {
41bf215546Sopenharmony_ci   VkBaseOutStructure *pos;
42bf215546Sopenharmony_ci#ifndef NDEBUG
43bf215546Sopenharmony_ci   VkBaseOutStructure *half_pos;
44bf215546Sopenharmony_ci   unsigned idx;
45bf215546Sopenharmony_ci#endif
46bf215546Sopenharmony_ci   bool done;
47bf215546Sopenharmony_ci};
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_cistatic inline struct vk_pnext_iterator
50bf215546Sopenharmony_civk_pnext_iterator_init(void *start)
51bf215546Sopenharmony_ci{
52bf215546Sopenharmony_ci   struct vk_pnext_iterator iter;
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci   iter.pos = (VkBaseOutStructure *)start;
55bf215546Sopenharmony_ci#ifndef NDEBUG
56bf215546Sopenharmony_ci   iter.half_pos = (VkBaseOutStructure *)start;
57bf215546Sopenharmony_ci   iter.idx = 0;
58bf215546Sopenharmony_ci#endif
59bf215546Sopenharmony_ci   iter.done = false;
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   return iter;
62bf215546Sopenharmony_ci}
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_cistatic inline struct vk_pnext_iterator
65bf215546Sopenharmony_civk_pnext_iterator_init_const(const void *start)
66bf215546Sopenharmony_ci{
67bf215546Sopenharmony_ci   return vk_pnext_iterator_init((void *)start);
68bf215546Sopenharmony_ci}
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_cistatic inline VkBaseOutStructure *
71bf215546Sopenharmony_civk_pnext_iterator_next(struct vk_pnext_iterator *iter)
72bf215546Sopenharmony_ci{
73bf215546Sopenharmony_ci   iter->pos = iter->pos->pNext;
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci#ifndef NDEBUG
76bf215546Sopenharmony_ci   if (iter->idx++ & 1) {
77bf215546Sopenharmony_ci      /** This the "tortoise and the hare" algorithm.  We increment
78bf215546Sopenharmony_ci       * chaser->pNext every other time *iter gets incremented.  Because *iter
79bf215546Sopenharmony_ci       * is incrementing twice as fast as chaser->pNext, the distance between
80bf215546Sopenharmony_ci       * them in the list increases by one for each time we get here.  If we
81bf215546Sopenharmony_ci       * have a loop, eventually, both iterators will be inside the loop and
82bf215546Sopenharmony_ci       * this distance will be an integer multiple of the loop length, at
83bf215546Sopenharmony_ci       * which point the two pointers will be equal.
84bf215546Sopenharmony_ci       */
85bf215546Sopenharmony_ci      iter->half_pos = iter->half_pos->pNext;
86bf215546Sopenharmony_ci      if (iter->half_pos == iter->pos)
87bf215546Sopenharmony_ci         assert(!"Vulkan input pNext chain has a loop!");
88bf215546Sopenharmony_ci   }
89bf215546Sopenharmony_ci#endif
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   return iter->pos;
92bf215546Sopenharmony_ci}
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci/* Because the outer loop only executes once, independently of what happens in
95bf215546Sopenharmony_ci * the inner loop, breaks and continues should work exactly the same as if
96bf215546Sopenharmony_ci * there were only one for loop.
97bf215546Sopenharmony_ci */
98bf215546Sopenharmony_ci#define vk_foreach_struct(__e, __start) \
99bf215546Sopenharmony_ci   for (struct vk_pnext_iterator __iter = vk_pnext_iterator_init(__start); \
100bf215546Sopenharmony_ci        !__iter.done; __iter.done = true) \
101bf215546Sopenharmony_ci      for (VkBaseOutStructure *__e = __iter.pos; \
102bf215546Sopenharmony_ci           __e; __e = vk_pnext_iterator_next(&__iter))
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci#define vk_foreach_struct_const(__e, __start) \
105bf215546Sopenharmony_ci   for (struct vk_pnext_iterator __iter = \
106bf215546Sopenharmony_ci            vk_pnext_iterator_init_const(__start); \
107bf215546Sopenharmony_ci        !__iter.done; __iter.done = true) \
108bf215546Sopenharmony_ci      for (const VkBaseInStructure *__e = (VkBaseInStructure *)__iter.pos; \
109bf215546Sopenharmony_ci           __e; __e = (VkBaseInStructure *)vk_pnext_iterator_next(&__iter))
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci/**
113bf215546Sopenharmony_ci * A wrapper for a Vulkan output array. A Vulkan output array is one that
114bf215546Sopenharmony_ci * follows the convention of the parameters to
115bf215546Sopenharmony_ci * vkGetPhysicalDeviceQueueFamilyProperties().
116bf215546Sopenharmony_ci *
117bf215546Sopenharmony_ci * Example Usage:
118bf215546Sopenharmony_ci *
119bf215546Sopenharmony_ci *    VkResult
120bf215546Sopenharmony_ci *    vkGetPhysicalDeviceQueueFamilyProperties(
121bf215546Sopenharmony_ci *       VkPhysicalDevice           physicalDevice,
122bf215546Sopenharmony_ci *       uint32_t*                  pQueueFamilyPropertyCount,
123bf215546Sopenharmony_ci *       VkQueueFamilyProperties*   pQueueFamilyProperties)
124bf215546Sopenharmony_ci *    {
125bf215546Sopenharmony_ci *       VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties, props,
126bf215546Sopenharmony_ci *                              pQueueFamilyProperties,
127bf215546Sopenharmony_ci *                              pQueueFamilyPropertyCount);
128bf215546Sopenharmony_ci *
129bf215546Sopenharmony_ci *       vk_outarray_append_typed(VkQueueFamilyProperties, &props, p) {
130bf215546Sopenharmony_ci *          p->queueFlags = ...;
131bf215546Sopenharmony_ci *          p->queueCount = ...;
132bf215546Sopenharmony_ci *       }
133bf215546Sopenharmony_ci *
134bf215546Sopenharmony_ci *       vk_outarray_append_typed(VkQueueFamilyProperties, &props, p) {
135bf215546Sopenharmony_ci *          p->queueFlags = ...;
136bf215546Sopenharmony_ci *          p->queueCount = ...;
137bf215546Sopenharmony_ci *       }
138bf215546Sopenharmony_ci *
139bf215546Sopenharmony_ci *       return vk_outarray_status(&props);
140bf215546Sopenharmony_ci *    }
141bf215546Sopenharmony_ci */
142bf215546Sopenharmony_cistruct __vk_outarray {
143bf215546Sopenharmony_ci   /** May be null. */
144bf215546Sopenharmony_ci   void *data;
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci   /**
147bf215546Sopenharmony_ci    * Capacity, in number of elements. Capacity is unlimited (UINT32_MAX) if
148bf215546Sopenharmony_ci    * data is null.
149bf215546Sopenharmony_ci    */
150bf215546Sopenharmony_ci   uint32_t cap;
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   /**
153bf215546Sopenharmony_ci    * Count of elements successfully written to the array. Every write is
154bf215546Sopenharmony_ci    * considered successful if data is null.
155bf215546Sopenharmony_ci    */
156bf215546Sopenharmony_ci   uint32_t *filled_len;
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   /**
159bf215546Sopenharmony_ci    * Count of elements that would have been written to the array if its
160bf215546Sopenharmony_ci    * capacity were sufficient. Vulkan functions often return VK_INCOMPLETE
161bf215546Sopenharmony_ci    * when `*filled_len < wanted_len`.
162bf215546Sopenharmony_ci    */
163bf215546Sopenharmony_ci   uint32_t wanted_len;
164bf215546Sopenharmony_ci};
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_cistatic inline void
167bf215546Sopenharmony_ci__vk_outarray_init(struct __vk_outarray *a,
168bf215546Sopenharmony_ci                   void *data, uint32_t *restrict len)
169bf215546Sopenharmony_ci{
170bf215546Sopenharmony_ci   a->data = data;
171bf215546Sopenharmony_ci   a->cap = *len;
172bf215546Sopenharmony_ci   a->filled_len = len;
173bf215546Sopenharmony_ci   *a->filled_len = 0;
174bf215546Sopenharmony_ci   a->wanted_len = 0;
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci   if (a->data == NULL)
177bf215546Sopenharmony_ci      a->cap = UINT32_MAX;
178bf215546Sopenharmony_ci}
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_cistatic inline VkResult
181bf215546Sopenharmony_ci__vk_outarray_status(const struct __vk_outarray *a)
182bf215546Sopenharmony_ci{
183bf215546Sopenharmony_ci   if (*a->filled_len < a->wanted_len)
184bf215546Sopenharmony_ci      return VK_INCOMPLETE;
185bf215546Sopenharmony_ci   else
186bf215546Sopenharmony_ci      return VK_SUCCESS;
187bf215546Sopenharmony_ci}
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_cistatic inline void *
190bf215546Sopenharmony_ci__vk_outarray_next(struct __vk_outarray *a, size_t elem_size)
191bf215546Sopenharmony_ci{
192bf215546Sopenharmony_ci   void *p = NULL;
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   a->wanted_len += 1;
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   if (*a->filled_len >= a->cap)
197bf215546Sopenharmony_ci      return NULL;
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   if (a->data != NULL)
200bf215546Sopenharmony_ci      p = (uint8_t *)a->data + (*a->filled_len) * elem_size;
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   *a->filled_len += 1;
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   return p;
205bf215546Sopenharmony_ci}
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci#define vk_outarray(elem_t) \
208bf215546Sopenharmony_ci   struct { \
209bf215546Sopenharmony_ci      struct __vk_outarray base; \
210bf215546Sopenharmony_ci      elem_t meta[]; \
211bf215546Sopenharmony_ci   }
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci#define vk_outarray_typeof_elem(a) __typeof__((a)->meta[0])
214bf215546Sopenharmony_ci#define vk_outarray_sizeof_elem(a) sizeof((a)->meta[0])
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci#define vk_outarray_init(a, data, len) \
217bf215546Sopenharmony_ci   __vk_outarray_init(&(a)->base, (data), (len))
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci#define VK_OUTARRAY_MAKE_TYPED(type, name, data, len) \
220bf215546Sopenharmony_ci   vk_outarray(type) name; \
221bf215546Sopenharmony_ci   vk_outarray_init(&name, (data), (len))
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci#define vk_outarray_status(a) \
224bf215546Sopenharmony_ci   __vk_outarray_status(&(a)->base)
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci#define vk_outarray_next(a) \
227bf215546Sopenharmony_ci   vk_outarray_next_typed(vk_outarray_typeof_elem(a), a)
228bf215546Sopenharmony_ci#define vk_outarray_next_typed(type, a) \
229bf215546Sopenharmony_ci   ((type *) \
230bf215546Sopenharmony_ci      __vk_outarray_next(&(a)->base, vk_outarray_sizeof_elem(a)))
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci/**
233bf215546Sopenharmony_ci * Append to a Vulkan output array.
234bf215546Sopenharmony_ci *
235bf215546Sopenharmony_ci * This is a block-based macro. For example:
236bf215546Sopenharmony_ci *
237bf215546Sopenharmony_ci *    vk_outarray_append_typed(T, &a, elem) {
238bf215546Sopenharmony_ci *       elem->foo = ...;
239bf215546Sopenharmony_ci *       elem->bar = ...;
240bf215546Sopenharmony_ci *    }
241bf215546Sopenharmony_ci *
242bf215546Sopenharmony_ci * The array `a` has type `vk_outarray(elem_t) *`. It is usually declared with
243bf215546Sopenharmony_ci * VK_OUTARRAY_MAKE_TYPED(). The variable `elem` is block-scoped and has type
244bf215546Sopenharmony_ci * `elem_t *`.
245bf215546Sopenharmony_ci *
246bf215546Sopenharmony_ci * The macro unconditionally increments the array's `wanted_len`. If the array
247bf215546Sopenharmony_ci * is not full, then the macro also increment its `filled_len` and then
248bf215546Sopenharmony_ci * executes the block. When the block is executed, `elem` is non-null and
249bf215546Sopenharmony_ci * points to the newly appended element.
250bf215546Sopenharmony_ci */
251bf215546Sopenharmony_ci#define vk_outarray_append_typed(type, a, elem) \
252bf215546Sopenharmony_ci   for (type *elem = vk_outarray_next_typed(type, a); \
253bf215546Sopenharmony_ci        elem != NULL; elem = NULL)
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_cistatic inline void *
256bf215546Sopenharmony_ci__vk_find_struct(void *start, VkStructureType sType)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci   vk_foreach_struct(s, start) {
259bf215546Sopenharmony_ci      if (s->sType == sType)
260bf215546Sopenharmony_ci         return s;
261bf215546Sopenharmony_ci   }
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   return NULL;
264bf215546Sopenharmony_ci}
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci#define vk_find_struct(__start, __sType) \
267bf215546Sopenharmony_ci   __vk_find_struct((__start), VK_STRUCTURE_TYPE_##__sType)
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci#define vk_find_struct_const(__start, __sType) \
270bf215546Sopenharmony_ci   (const void *)__vk_find_struct((void *)(__start), VK_STRUCTURE_TYPE_##__sType)
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_cistatic inline void
273bf215546Sopenharmony_ci__vk_append_struct(void *start, void *element)
274bf215546Sopenharmony_ci{
275bf215546Sopenharmony_ci   vk_foreach_struct(s, start) {
276bf215546Sopenharmony_ci      if (s->pNext)
277bf215546Sopenharmony_ci         continue;
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci      s->pNext = (struct VkBaseOutStructure *) element;
280bf215546Sopenharmony_ci      break;
281bf215546Sopenharmony_ci   }
282bf215546Sopenharmony_ci}
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ciuint32_t vk_get_driver_version(void);
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ciuint32_t vk_get_version_override(void);
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_civoid vk_warn_non_conformant_implementation(const char *driver_name);
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_cistruct vk_pipeline_cache_header {
291bf215546Sopenharmony_ci   uint32_t header_size;
292bf215546Sopenharmony_ci   uint32_t header_version;
293bf215546Sopenharmony_ci   uint32_t vendor_id;
294bf215546Sopenharmony_ci   uint32_t device_id;
295bf215546Sopenharmony_ci   uint8_t  uuid[VK_UUID_SIZE];
296bf215546Sopenharmony_ci};
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci#define VK_EXT_OFFSET (1000000000UL)
299bf215546Sopenharmony_ci#define VK_ENUM_EXTENSION(__enum) \
300bf215546Sopenharmony_ci   ((__enum) >= VK_EXT_OFFSET ? ((((__enum) - VK_EXT_OFFSET) / 1000UL) + 1) : 0)
301bf215546Sopenharmony_ci#define VK_ENUM_OFFSET(__enum) \
302bf215546Sopenharmony_ci   ((__enum) >= VK_EXT_OFFSET ? ((__enum) % 1000) : (__enum))
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci#define typed_memcpy(dest, src, count) do { \
305bf215546Sopenharmony_ci   STATIC_ASSERT(sizeof(*(src)) == sizeof(*(dest))); \
306bf215546Sopenharmony_ci   memcpy((dest), (src), (count) * sizeof(*(src))); \
307bf215546Sopenharmony_ci} while (0)
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_cistatic inline gl_shader_stage
310bf215546Sopenharmony_civk_to_mesa_shader_stage(VkShaderStageFlagBits vk_stage)
311bf215546Sopenharmony_ci{
312bf215546Sopenharmony_ci   assert(util_bitcount((uint32_t) vk_stage) == 1);
313bf215546Sopenharmony_ci   return (gl_shader_stage) (ffs((uint32_t) vk_stage) - 1);
314bf215546Sopenharmony_ci}
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_cistatic inline VkShaderStageFlagBits
317bf215546Sopenharmony_cimesa_to_vk_shader_stage(gl_shader_stage mesa_stage)
318bf215546Sopenharmony_ci{
319bf215546Sopenharmony_ci   return (VkShaderStageFlagBits) (1 << ((uint32_t) mesa_stage));
320bf215546Sopenharmony_ci}
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci/* iterate over a sequence of indexed multidraws for VK_EXT_multi_draw extension */
323bf215546Sopenharmony_ci/* 'i' must be explicitly declared */
324bf215546Sopenharmony_ci#define vk_foreach_multi_draw_indexed(_draw, _i, _pDrawInfo, _num_draws, _stride) \
325bf215546Sopenharmony_ci   for (const VkMultiDrawIndexedInfoEXT *_draw = (const void*)(_pDrawInfo); \
326bf215546Sopenharmony_ci        (_i) < (_num_draws); \
327bf215546Sopenharmony_ci        (_i)++, (_draw) = (const VkMultiDrawIndexedInfoEXT*)((const uint8_t*)(_draw) + (_stride)))
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci/* iterate over a sequence of multidraws for VK_EXT_multi_draw extension */
330bf215546Sopenharmony_ci/* 'i' must be explicitly declared */
331bf215546Sopenharmony_ci#define vk_foreach_multi_draw(_draw, _i, _pDrawInfo, _num_draws, _stride) \
332bf215546Sopenharmony_ci   for (const VkMultiDrawInfoEXT *_draw = (const void*)(_pDrawInfo); \
333bf215546Sopenharmony_ci        (_i) < (_num_draws); \
334bf215546Sopenharmony_ci        (_i)++, (_draw) = (const VkMultiDrawInfoEXT*)((const uint8_t*)(_draw) + (_stride)))
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_cistruct nir_spirv_specialization;
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_cistruct nir_spirv_specialization*
340bf215546Sopenharmony_civk_spec_info_to_nir_spirv(const VkSpecializationInfo *spec_info,
341bf215546Sopenharmony_ci                          uint32_t *out_num_spec_entries);
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci#define STACK_ARRAY_SIZE 8
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci#ifdef __cplusplus
346bf215546Sopenharmony_ci#define STACK_ARRAY_ZERO_INIT {}
347bf215546Sopenharmony_ci#else
348bf215546Sopenharmony_ci#define STACK_ARRAY_ZERO_INIT {0}
349bf215546Sopenharmony_ci#endif
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci#define STACK_ARRAY(type, name, size) \
352bf215546Sopenharmony_ci   type _stack_##name[STACK_ARRAY_SIZE] = STACK_ARRAY_ZERO_INIT; \
353bf215546Sopenharmony_ci   type *const name = \
354bf215546Sopenharmony_ci     ((size) <= STACK_ARRAY_SIZE ? _stack_##name : (type *)malloc((size) * sizeof(type)))
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci#define STACK_ARRAY_FINISH(name) \
357bf215546Sopenharmony_ci   if (name != _stack_##name) free(name)
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci#ifdef __cplusplus
360bf215546Sopenharmony_ci}
361bf215546Sopenharmony_ci#endif
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci#endif /* VK_UTIL_H */
364