xref: /aosp_15_r20/external/mesa3d/src/gfxstream/guest/vulkan_enc/vk_util.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2017 Intel
3  * SPDX-License-Identifier: MIT
4  */
5 #ifndef VK_UTIL_H
6 #define VK_UTIL_H
7 
8 /* common inlines and macros for vulkan drivers */
9 
10 #include <stdlib.h>
11 #include <vulkan/vulkan.h>
12 
13 #include "vk_struct_id.h"
14 
15 namespace {  // anonymous
16 
17 struct vk_struct_common {
18     VkStructureType sType;
19     struct vk_struct_common* pNext;
20 };
21 
22 struct vk_struct_chain_iterator {
23     vk_struct_common* value;
24 };
25 
26 #define vk_foreach_struct(__iter, __start)                                              \
27     for (struct vk_struct_common* __iter = (struct vk_struct_common*)(__start); __iter; \
28          __iter = __iter->pNext)
29 
30 #define vk_foreach_struct_const(__iter, __start)                                            \
31     for (const struct vk_struct_common* __iter = (const struct vk_struct_common*)(__start); \
32          __iter; __iter = __iter->pNext)
33 
34 /**
35  * A wrapper for a Vulkan output array. A Vulkan output array is one that
36  * follows the convention of the parameters to
37  * vkGetPhysicalDeviceQueueFamilyProperties().
38  *
39  * Example Usage:
40  *
41  *    VkResult
42  *    vkGetPhysicalDeviceQueueFamilyProperties(
43  *       VkPhysicalDevice           physicalDevice,
44  *       uint32_t*                  pQueueFamilyPropertyCount,
45  *       VkQueueFamilyProperties*   pQueueFamilyProperties)
46  *    {
47  *       VK_OUTARRAY_MAKE(props, pQueueFamilyProperties,
48  *                         pQueueFamilyPropertyCount);
49  *
50  *       vk_outarray_append(&props, p) {
51  *          p->queueFlags = ...;
52  *          p->queueCount = ...;
53  *       }
54  *
55  *       vk_outarray_append(&props, p) {
56  *          p->queueFlags = ...;
57  *          p->queueCount = ...;
58  *       }
59  *
60  *       return vk_outarray_status(&props);
61  *    }
62  */
63 struct __vk_outarray {
64     /** May be null. */
65     void* data;
66 
67     /**
68      * Capacity, in number of elements. Capacity is unlimited (UINT32_MAX) if
69      * data is null.
70      */
71     uint32_t cap;
72 
73     /**
74      * Count of elements successfully written to the array. Every write is
75      * considered successful if data is null.
76      */
77     uint32_t* filled_len;
78 
79     /**
80      * Count of elements that would have been written to the array if its
81      * capacity were sufficient. Vulkan functions often return VK_INCOMPLETE
82      * when `*filled_len < wanted_len`.
83      */
84     uint32_t wanted_len;
85 };
86 
__vk_outarray_init(struct __vk_outarray * a,void * data,uint32_t * len)87 static inline void __vk_outarray_init(struct __vk_outarray* a, void* data, uint32_t* len) {
88     a->data = data;
89     a->cap = *len;
90     a->filled_len = len;
91     *a->filled_len = 0;
92     a->wanted_len = 0;
93 
94     if (a->data == NULL) a->cap = UINT32_MAX;
95 }
96 
__vk_outarray_status(const struct __vk_outarray * a)97 static inline VkResult __vk_outarray_status(const struct __vk_outarray* a) {
98     if (*a->filled_len < a->wanted_len)
99         return VK_INCOMPLETE;
100     else
101         return VK_SUCCESS;
102 }
103 
__vk_outarray_next(struct __vk_outarray * a,size_t elem_size)104 static inline void* __vk_outarray_next(struct __vk_outarray* a, size_t elem_size) {
105     void* p = NULL;
106 
107     a->wanted_len += 1;
108 
109     if (*a->filled_len >= a->cap) return NULL;
110 
111     if (a->data != NULL) p = ((uint8_t*)a->data) + (*a->filled_len) * elem_size;
112 
113     *a->filled_len += 1;
114 
115     return p;
116 }
117 
118 #define vk_outarray(elem_t)        \
119     struct {                       \
120         struct __vk_outarray base; \
121         elem_t meta[];             \
122     }
123 
124 #define vk_outarray_typeof_elem(a) __typeof__((a)->meta[0])
125 #define vk_outarray_sizeof_elem(a) sizeof((a)->meta[0])
126 
127 #define vk_outarray_init(a, data, len) __vk_outarray_init(&(a)->base, (data), (len))
128 
129 #define VK_OUTARRAY_MAKE(name, data, len)    \
130     vk_outarray(__typeof__((data)[0])) name; \
131     vk_outarray_init(&name, (data), (len))
132 
133 #define VK_OUTARRAY_MAKE_TYPED(type, name, data, len) \
134     vk_outarray(type) name;                           \
135     vk_outarray_init(&name, (data), (len))
136 
137 #define vk_outarray_status(a) __vk_outarray_status(&(a)->base)
138 
139 #define vk_outarray_next(a) vk_outarray_next_typed(vk_outarray_typeof_elem(a), a)
140 #define vk_outarray_next_typed(type, a) \
141     ((type*)__vk_outarray_next(&(a)->base, vk_outarray_sizeof_elem(a)))
142 
143 /**
144  * Append to a Vulkan output array.
145  *
146  * This is a block-based macro. For example:
147  *
148  *    vk_outarray_append(&a, elem) {
149  *       elem->foo = ...;
150  *       elem->bar = ...;
151  *    }
152  *
153  * The array `a` has type `vk_outarray(elem_t) *`. It is usually declared with
154  * VK_OUTARRAY_MAKE(). The variable `elem` is block-scoped and has type
155  * `elem_t *`.
156  *
157  * The macro unconditionally increments the array's `wanted_len`. If the array
158  * is not full, then the macro also increment its `filled_len` and then
159  * executes the block. When the block is executed, `elem` is non-null and
160  * points to the newly appended element.
161  */
162 #define vk_outarray_append(a, elem) \
163     for (vk_outarray_typeof_elem(a)* elem = vk_outarray_next(a); elem != NULL; elem = NULL)
164 
165 #define vk_outarray_append_typed(type, a, elem) \
166     for (type* elem = vk_outarray_next_typed(type, a); elem != NULL; elem = NULL)
167 
__vk_find_struct(void * start,VkStructureType sType)168 static inline void* __vk_find_struct(void* start, VkStructureType sType) {
169     vk_foreach_struct(s, start) {
170         if (s->sType == sType) return s;
171     }
172 
173     return NULL;
174 }
175 
176 template <class T, class H>
vk_find_struct(H * head)177 T* vk_find_struct(H* head) {
178     (void)vk_get_vk_struct_id<H>::id;
179     return static_cast<T*>(__vk_find_struct(static_cast<void*>(head), vk_get_vk_struct_id<T>::id));
180 }
181 
182 template <class T, class H>
vk_find_struct(const H * head)183 const T* vk_find_struct(const H* head) {
184     (void)vk_get_vk_struct_id<H>::id;
185     return static_cast<const T*>(__vk_find_struct(const_cast<void*>(static_cast<const void*>(head)),
186                                                   vk_get_vk_struct_id<T>::id));
187 }
188 
189 #define VK_EXT_OFFSET (1000000000UL)
190 #define VK_ENUM_EXTENSION(__enum) \
191     ((__enum) >= VK_EXT_OFFSET ? ((((__enum)-VK_EXT_OFFSET) / 1000UL) + 1) : 0)
192 #define VK_ENUM_OFFSET(__enum) ((__enum) >= VK_EXT_OFFSET ? ((__enum) % 1000) : (__enum))
193 
194 template <class T>
vk_make_orphan_copy(const T & vk_struct)195 T vk_make_orphan_copy(const T& vk_struct) {
196     T copy = vk_struct;
197     copy.pNext = NULL;
198     return copy;
199 }
200 
201 template <class T>
vk_make_chain_iterator(T * vk_struct)202 vk_struct_chain_iterator vk_make_chain_iterator(T* vk_struct) {
203     (void)vk_get_vk_struct_id<T>::id;
204     vk_struct_chain_iterator result = {reinterpret_cast<vk_struct_common*>(vk_struct)};
205     return result;
206 }
207 
208 template <class T>
vk_append_struct(vk_struct_chain_iterator * i,T * vk_struct)209 void vk_append_struct(vk_struct_chain_iterator* i, T* vk_struct) {
210     (void)vk_get_vk_struct_id<T>::id;
211 
212     vk_struct_common* p = i->value;
213     if (p->pNext) {
214         ::abort();
215     }
216 
217     p->pNext = reinterpret_cast<vk_struct_common*>(vk_struct);
218     vk_struct->pNext = NULL;
219 
220     *i = vk_make_chain_iterator(vk_struct);
221 }
222 
vk_descriptor_type_has_descriptor_buffer(VkDescriptorType type)223 bool vk_descriptor_type_has_descriptor_buffer(VkDescriptorType type) {
224     switch (type) {
225         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
226         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
227         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
228         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
229             return true;
230         default:
231             return false;
232     }
233 }
234 
235 }  // namespace
236 
237 #endif /* VK_UTIL_H */
238