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