1/*
2 Copyright 2017-2022 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17#include "spirv_reflect.h"
18#include <assert.h>
19#include <stdbool.h>
20#include <string.h>
21
22#if defined(WIN32)
23 #define _CRTDBG_MAP_ALLOC
24 #include <stdlib.h>
25 #include <crtdbg.h>
26#else
27 #include <stdlib.h>
28#endif
29
30#if defined(SPIRV_REFLECT_ENABLE_ASSERTS)
31 #define SPV_REFLECT_ASSERT(COND) \
32 assert(COND);
33#else
34#define SPV_REFLECT_ASSERT(COND)
35#endif
36
37// Temporary enums until these make it into SPIR-V/Vulkan
38// clang-format off
39enum {
40 SpvReflectOpDecorateId = 332,
41 SpvReflectOpDecorateStringGOOGLE = 5632,
42 SpvReflectOpMemberDecorateStringGOOGLE = 5633,
43 SpvReflectDecorationHlslCounterBufferGOOGLE = 5634,
44 SpvReflectDecorationHlslSemanticGOOGLE = 5635
45};
46// clang-format on
47
48// clang-format off
49enum {
50 SPIRV_STARTING_WORD_INDEX = 5,
51 SPIRV_WORD_SIZE = sizeof(uint32_t),
52 SPIRV_BYTE_WIDTH = 8,
53 SPIRV_MINIMUM_FILE_SIZE = SPIRV_STARTING_WORD_INDEX * SPIRV_WORD_SIZE,
54 SPIRV_DATA_ALIGNMENT = 4 * SPIRV_WORD_SIZE, // 16
55 SPIRV_ACCESS_CHAIN_INDEX_OFFSET = 4,
56};
57// clang-format on
58
59// clang-format off
60enum {
61 INVALID_VALUE = 0xFFFFFFFF,
62};
63// clang-format on
64
65// clang-format off
66enum {
67 MAX_NODE_NAME_LENGTH = 1024,
68};
69// clang-format on
70
71// clang-format off
72enum {
73 IMAGE_SAMPLED = 1,
74 IMAGE_STORAGE = 2
75};
76// clang-format on
77
78// clang-format off
79typedef struct SpvReflectPrvArrayTraits {
80 uint32_t element_type_id;
81 uint32_t length_id;
82} SpvReflectPrvArrayTraits;
83// clang-format on
84
85// clang-format off
86typedef struct SpvReflectPrvImageTraits {
87 uint32_t sampled_type_id;
88 SpvDim dim;
89 uint32_t depth;
90 uint32_t arrayed;
91 uint32_t ms;
92 uint32_t sampled;
93 SpvImageFormat image_format;
94} SpvReflectPrvImageTraits;
95// clang-format on
96
97// clang-format off
98typedef struct SpvReflectPrvNumberDecoration {
99 uint32_t word_offset;
100 uint32_t value;
101} SpvReflectPrvNumberDecoration;
102// clang-format on
103
104// clang-format off
105typedef struct SpvReflectPrvStringDecoration {
106 uint32_t word_offset;
107 const char* value;
108} SpvReflectPrvStringDecoration;
109// clang-format on
110
111// clang-format off
112typedef struct SpvReflectPrvDecorations {
113 bool is_relaxed_precision;
114 bool is_block;
115 bool is_buffer_block;
116 bool is_row_major;
117 bool is_column_major;
118 bool is_built_in;
119 bool is_noperspective;
120 bool is_flat;
121 bool is_non_writable;
122 SpvReflectPrvNumberDecoration set;
123 SpvReflectPrvNumberDecoration binding;
124 SpvReflectPrvNumberDecoration input_attachment_index;
125 SpvReflectPrvNumberDecoration location;
126 SpvReflectPrvNumberDecoration offset;
127 SpvReflectPrvNumberDecoration uav_counter_buffer;
128 SpvReflectPrvStringDecoration semantic;
129 uint32_t array_stride;
130 uint32_t matrix_stride;
131 SpvBuiltIn built_in;
132} SpvReflectPrvDecorations;
133// clang-format on
134
135// clang-format off
136typedef struct SpvReflectPrvNode {
137 uint32_t result_id;
138 SpvOp op;
139 uint32_t result_type_id;
140 uint32_t type_id;
141 SpvStorageClass storage_class;
142 uint32_t word_offset;
143 uint32_t word_count;
144 bool is_type;
145
146 SpvReflectPrvArrayTraits array_traits;
147 SpvReflectPrvImageTraits image_traits;
148 uint32_t image_type_id;
149
150 const char* name;
151 SpvReflectPrvDecorations decorations;
152 uint32_t member_count;
153 const char** member_names;
154 SpvReflectPrvDecorations* member_decorations;
155} SpvReflectPrvNode;
156// clang-format on
157
158// clang-format off
159typedef struct SpvReflectPrvString {
160 uint32_t result_id;
161 const char* string;
162} SpvReflectPrvString;
163// clang-format on
164
165// clang-format off
166typedef struct SpvReflectPrvFunction {
167 uint32_t id;
168 uint32_t callee_count;
169 uint32_t* callees;
170 struct SpvReflectPrvFunction** callee_ptrs;
171 uint32_t accessed_ptr_count;
172 uint32_t* accessed_ptrs;
173} SpvReflectPrvFunction;
174// clang-format on
175
176// clang-format off
177typedef struct SpvReflectPrvAccessChain {
178 uint32_t result_id;
179 uint32_t result_type_id;
180 //
181 // Pointing to the base of a composite object.
182 // Generally the id of descriptor block variable
183 uint32_t base_id;
184 //
185 // From spec:
186 // The first index in Indexes will select the
187 // top-level member/element/component/element
188 // of the base composite
189 uint32_t index_count;
190 uint32_t* indexes;
191} SpvReflectPrvAccessChain;
192// clang-format on
193
194// clang-format off
195typedef struct SpvReflectPrvParser {
196 size_t spirv_word_count;
197 uint32_t* spirv_code;
198 uint32_t string_count;
199 SpvReflectPrvString* strings;
200 SpvSourceLanguage source_language;
201 uint32_t source_language_version;
202 uint32_t source_file_id;
203 const char* source_embedded;
204 size_t node_count;
205 SpvReflectPrvNode* nodes;
206 uint32_t entry_point_count;
207 uint32_t function_count;
208 SpvReflectPrvFunction* functions;
209 uint32_t access_chain_count;
210 SpvReflectPrvAccessChain* access_chains;
211
212 uint32_t type_count;
213 uint32_t descriptor_count;
214 uint32_t push_constant_count;
215} SpvReflectPrvParser;
216// clang-format on
217
218static uint32_t Max(
219 uint32_t a,
220 uint32_t b)
221{
222 return a > b ? a : b;
223}
224
225static uint32_t RoundUp(
226 uint32_t value,
227 uint32_t multiple)
228{
229 assert(multiple && ((multiple & (multiple - 1)) == 0));
230 return (value + multiple - 1) & ~(multiple - 1);
231}
232
233#define IsNull(ptr) \
234 (ptr == NULL)
235
236#define IsNotNull(ptr) \
237 (ptr != NULL)
238
239#define SafeFree(ptr) \
240 { \
241 free((void*)ptr); \
242 ptr = NULL; \
243 }
244
245static int SortCompareUint32(
246 const void* a,
247 const void* b)
248{
249 const uint32_t* p_a = (const uint32_t*)a;
250 const uint32_t* p_b = (const uint32_t*)b;
251
252 return (int)*p_a - (int)*p_b;
253}
254
255//
256// De-duplicates a sorted array and returns the new size.
257//
258// Note: The array doesn't actually need to be sorted, just
259// arranged into "runs" so that all the entries with one
260// value are adjacent.
261//
262static size_t DedupSortedUint32(uint32_t* arr, size_t size)
263{
264 if (size == 0) {
265 return 0;
266 }
267 size_t dedup_idx = 0;
268 for (size_t i = 0; i < size; ++i) {
269 if (arr[dedup_idx] != arr[i]) {
270 ++dedup_idx;
271 arr[dedup_idx] = arr[i];
272 }
273 }
274 return dedup_idx+1;
275}
276
277static bool SearchSortedUint32(
278 const uint32_t* arr,
279 size_t size,
280 uint32_t target)
281{
282 size_t lo = 0;
283 size_t hi = size;
284 while (lo < hi) {
285 size_t mid = (hi - lo) / 2 + lo;
286 if (arr[mid] == target) {
287 return true;
288 } else if (arr[mid] < target) {
289 lo = mid+1;
290 } else {
291 hi = mid;
292 }
293 }
294 return false;
295}
296
297static SpvReflectResult IntersectSortedUint32(
298 const uint32_t* p_arr0,
299 size_t arr0_size,
300 const uint32_t* p_arr1,
301 size_t arr1_size,
302 uint32_t** pp_res,
303 size_t* res_size
304)
305{
306 *res_size = 0;
307 const uint32_t* arr0_end = p_arr0 + arr0_size;
308 const uint32_t* arr1_end = p_arr1 + arr1_size;
309
310 const uint32_t* idx0 = p_arr0;
311 const uint32_t* idx1 = p_arr1;
312 while (idx0 != arr0_end && idx1 != arr1_end) {
313 if (*idx0 < *idx1) {
314 ++idx0;
315 } else if (*idx0 > *idx1) {
316 ++idx1;
317 } else {
318 ++*res_size;
319 ++idx0;
320 ++idx1;
321 }
322 }
323
324 *pp_res = NULL;
325 if (*res_size > 0) {
326 *pp_res = (uint32_t*)calloc(*res_size, sizeof(**pp_res));
327 if (IsNull(*pp_res)) {
328 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
329 }
330 uint32_t* idxr = *pp_res;
331 idx0 = p_arr0;
332 idx1 = p_arr1;
333 while (idx0 != arr0_end && idx1 != arr1_end) {
334 if (*idx0 < *idx1) {
335 ++idx0;
336 } else if (*idx0 > *idx1) {
337 ++idx1;
338 } else {
339 *(idxr++) = *idx0;
340 ++idx0;
341 ++idx1;
342 }
343 }
344 }
345 return SPV_REFLECT_RESULT_SUCCESS;
346}
347
348
349static bool InRange(
350 const SpvReflectPrvParser* p_parser,
351 uint32_t index)
352{
353 bool in_range = false;
354 if (IsNotNull(p_parser)) {
355 in_range = (index < p_parser->spirv_word_count);
356 }
357 return in_range;
358}
359
360static SpvReflectResult ReadU32(
361 SpvReflectPrvParser* p_parser,
362 uint32_t word_offset,
363 uint32_t* p_value)
364{
365 assert(IsNotNull(p_parser));
366 assert(IsNotNull(p_parser->spirv_code));
367 assert(InRange(p_parser, word_offset));
368 SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF;
369 if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && InRange(p_parser, word_offset)) {
370 *p_value = *(p_parser->spirv_code + word_offset);
371 result = SPV_REFLECT_RESULT_SUCCESS;
372 }
373 return result;
374}
375
376#define CHECKED_READU32(parser, word_offset, value) \
377 { \
378 SpvReflectResult checked_readu32_result = ReadU32(parser, \
379 word_offset, (uint32_t*)&(value)); \
380 if (checked_readu32_result != SPV_REFLECT_RESULT_SUCCESS) { \
381 return checked_readu32_result; \
382 } \
383 }
384
385#define CHECKED_READU32_CAST(parser, word_offset, cast_to_type, value) \
386 { \
387 uint32_t checked_readu32_cast_u32 = UINT32_MAX; \
388 SpvReflectResult checked_readu32_cast_result = ReadU32(parser, \
389 word_offset, \
390 (uint32_t*)&(checked_readu32_cast_u32)); \
391 if (checked_readu32_cast_result != SPV_REFLECT_RESULT_SUCCESS) { \
392 return checked_readu32_cast_result; \
393 } \
394 value = (cast_to_type)checked_readu32_cast_u32; \
395 }
396
397#define IF_READU32(result, parser, word_offset, value) \
398 if ((result) == SPV_REFLECT_RESULT_SUCCESS) { \
399 result = ReadU32(parser, word_offset, (uint32_t*)&(value)); \
400 }
401
402#define IF_READU32_CAST(result, parser, word_offset, cast_to_type, value) \
403 if ((result) == SPV_REFLECT_RESULT_SUCCESS) { \
404 uint32_t if_readu32_cast_u32 = UINT32_MAX; \
405 result = ReadU32(parser, word_offset, &if_readu32_cast_u32); \
406 if ((result) == SPV_REFLECT_RESULT_SUCCESS) { \
407 value = (cast_to_type)if_readu32_cast_u32; \
408 } \
409 }
410
411static SpvReflectResult ReadStr(
412 SpvReflectPrvParser* p_parser,
413 uint32_t word_offset,
414 uint32_t word_index,
415 uint32_t word_count,
416 uint32_t* p_buf_size,
417 char* p_buf
418)
419{
420 uint32_t limit = (word_offset + word_count);
421 assert(IsNotNull(p_parser));
422 assert(IsNotNull(p_parser->spirv_code));
423 assert(InRange(p_parser, limit));
424 SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF;
425 if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && InRange(p_parser, limit)) {
426 const char* c_str = (const char*)(p_parser->spirv_code + word_offset + word_index);
427 uint32_t n = word_count * SPIRV_WORD_SIZE;
428 uint32_t length_with_terminator = 0;
429 for (uint32_t i = 0; i < n; ++i) {
430 char c = *(c_str + i);
431 if (c == 0) {
432 length_with_terminator = i + 1;
433 break;
434 }
435 }
436
437 if (length_with_terminator > 0) {
438 result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
439 if (IsNotNull(p_buf_size) && IsNotNull(p_buf)) {
440 result = SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
441 if (length_with_terminator <= *p_buf_size) {
442 memset(p_buf, 0, *p_buf_size);
443 memcpy(p_buf, c_str, length_with_terminator);
444 result = SPV_REFLECT_RESULT_SUCCESS;
445 }
446 }
447 else {
448 if (IsNotNull(p_buf_size)) {
449 *p_buf_size = length_with_terminator;
450 result = SPV_REFLECT_RESULT_SUCCESS;
451 }
452 }
453 }
454 }
455 return result;
456}
457
458static SpvReflectDecorationFlags ApplyDecorations(const SpvReflectPrvDecorations* p_decoration_fields)
459{
460 SpvReflectDecorationFlags decorations = SPV_REFLECT_DECORATION_NONE;
461 if (p_decoration_fields->is_relaxed_precision) {
462 decorations |= SPV_REFLECT_DECORATION_RELAXED_PRECISION;
463 }
464 if (p_decoration_fields->is_block) {
465 decorations |= SPV_REFLECT_DECORATION_BLOCK;
466 }
467 if (p_decoration_fields->is_buffer_block) {
468 decorations |= SPV_REFLECT_DECORATION_BUFFER_BLOCK;
469 }
470 if (p_decoration_fields->is_row_major) {
471 decorations |= SPV_REFLECT_DECORATION_ROW_MAJOR;
472 }
473 if (p_decoration_fields->is_column_major) {
474 decorations |= SPV_REFLECT_DECORATION_COLUMN_MAJOR;
475 }
476 if (p_decoration_fields->is_built_in) {
477 decorations |= SPV_REFLECT_DECORATION_BUILT_IN;
478 }
479 if (p_decoration_fields->is_noperspective) {
480 decorations |= SPV_REFLECT_DECORATION_NOPERSPECTIVE;
481 }
482 if (p_decoration_fields->is_flat) {
483 decorations |= SPV_REFLECT_DECORATION_FLAT;
484 }
485 if (p_decoration_fields->is_non_writable) {
486 decorations |= SPV_REFLECT_DECORATION_NON_WRITABLE;
487 }
488 return decorations;
489}
490
491static void ApplyNumericTraits(const SpvReflectTypeDescription* p_type, SpvReflectNumericTraits* p_numeric_traits)
492{
493 memcpy(p_numeric_traits, &p_type->traits.numeric, sizeof(p_type->traits.numeric));
494}
495
496static void ApplyArrayTraits(const SpvReflectTypeDescription* p_type, SpvReflectArrayTraits* p_array_traits)
497{
498 memcpy(p_array_traits, &p_type->traits.array, sizeof(p_type->traits.array));
499}
500
501static SpvReflectPrvNode* FindNode(
502 SpvReflectPrvParser* p_parser,
503 uint32_t result_id)
504{
505 SpvReflectPrvNode* p_node = NULL;
506 for (size_t i = 0; i < p_parser->node_count; ++i) {
507 SpvReflectPrvNode* p_elem = &(p_parser->nodes[i]);
508 if (p_elem->result_id == result_id) {
509 p_node = p_elem;
510 break;
511 }
512 }
513 return p_node;
514}
515
516static SpvReflectTypeDescription* FindType(SpvReflectShaderModule* p_module, uint32_t type_id)
517{
518 SpvReflectTypeDescription* p_type = NULL;
519 for (size_t i = 0; i < p_module->_internal->type_description_count; ++i) {
520 SpvReflectTypeDescription* p_elem = &(p_module->_internal->type_descriptions[i]);
521 if (p_elem->id == type_id) {
522 p_type = p_elem;
523 break;
524 }
525 }
526 return p_type;
527}
528
529static SpvReflectResult CreateParser(
530 size_t size,
531 void* p_code,
532 SpvReflectPrvParser* p_parser)
533{
534 if (p_code == NULL) {
535 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
536 }
537
538 if (size < SPIRV_MINIMUM_FILE_SIZE) {
539 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_CODE_SIZE;
540 }
541 if ((size % 4) != 0) {
542 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_CODE_SIZE;
543 }
544
545 p_parser->spirv_word_count = size / SPIRV_WORD_SIZE;
546 p_parser->spirv_code = (uint32_t*)p_code;
547
548 if (p_parser->spirv_code[0] != SpvMagicNumber) {
549 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_MAGIC_NUMBER;
550 }
551
552 return SPV_REFLECT_RESULT_SUCCESS;
553}
554
555static void DestroyParser(SpvReflectPrvParser* p_parser)
556{
557 if (!IsNull(p_parser->nodes)) {
558 // Free nodes
559 for (size_t i = 0; i < p_parser->node_count; ++i) {
560 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
561 if (IsNotNull(p_node->member_names)) {
562 SafeFree(p_node->member_names);
563 }
564 if (IsNotNull(p_node->member_decorations)) {
565 SafeFree(p_node->member_decorations);
566 }
567 }
568
569 // Free functions
570 for (size_t i = 0; i < p_parser->function_count; ++i) {
571 SafeFree(p_parser->functions[i].callees);
572 SafeFree(p_parser->functions[i].callee_ptrs);
573 SafeFree(p_parser->functions[i].accessed_ptrs);
574 }
575
576 // Free access chains
577 for (uint32_t i = 0; i < p_parser->access_chain_count; ++i) {
578 SafeFree(p_parser->access_chains[i].indexes);
579 }
580
581 SafeFree(p_parser->nodes);
582 SafeFree(p_parser->strings);
583 SafeFree(p_parser->source_embedded);
584 SafeFree(p_parser->functions);
585 SafeFree(p_parser->access_chains);
586 p_parser->node_count = 0;
587 }
588}
589
590static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser)
591{
592 assert(IsNotNull(p_parser));
593 assert(IsNotNull(p_parser->spirv_code));
594
595 uint32_t* p_spirv = p_parser->spirv_code;
596 uint32_t spirv_word_index = SPIRV_STARTING_WORD_INDEX;
597
598 // Count nodes
599 uint32_t node_count = 0;
600 while (spirv_word_index < p_parser->spirv_word_count) {
601 uint32_t word = p_spirv[spirv_word_index];
602 SpvOp op = (SpvOp)(word & 0xFFFF);
603 uint32_t node_word_count = (word >> 16) & 0xFFFF;
604 if (node_word_count == 0) {
605 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_INSTRUCTION;
606 }
607 if (op == SpvOpAccessChain) {
608 ++(p_parser->access_chain_count);
609 }
610 spirv_word_index += node_word_count;
611 ++node_count;
612 }
613
614 if (node_count == 0) {
615 return SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_EOF;
616 }
617
618 // Allocate nodes
619 p_parser->node_count = node_count;
620 p_parser->nodes = (SpvReflectPrvNode*)calloc(p_parser->node_count, sizeof(*(p_parser->nodes)));
621 if (IsNull(p_parser->nodes)) {
622 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
623 }
624 // Mark all nodes with an invalid state
625 for (uint32_t i = 0; i < node_count; ++i) {
626 p_parser->nodes[i].op = (SpvOp)INVALID_VALUE;
627 p_parser->nodes[i].storage_class = (SpvStorageClass)INVALID_VALUE;
628 p_parser->nodes[i].decorations.set.value = (uint32_t)INVALID_VALUE;
629 p_parser->nodes[i].decorations.binding.value = (uint32_t)INVALID_VALUE;
630 p_parser->nodes[i].decorations.location.value = (uint32_t)INVALID_VALUE;
631 p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE;
632 p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE;
633 p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE;
634 }
635 // Mark source file id node
636 p_parser->source_file_id = (uint32_t)INVALID_VALUE;
637 p_parser->source_embedded = NULL;
638
639 // Function node
640 uint32_t function_node = (uint32_t)INVALID_VALUE;
641
642 // Allocate access chain
643 if (p_parser->access_chain_count > 0) {
644 p_parser->access_chains = (SpvReflectPrvAccessChain*)calloc(p_parser->access_chain_count, sizeof(*(p_parser->access_chains)));
645 if (IsNull(p_parser->access_chains)) {
646 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
647 }
648 }
649
650 // Parse nodes
651 uint32_t node_index = 0;
652 uint32_t access_chain_index = 0;
653 spirv_word_index = SPIRV_STARTING_WORD_INDEX;
654 while (spirv_word_index < p_parser->spirv_word_count) {
655 uint32_t word = p_spirv[spirv_word_index];
656 SpvOp op = (SpvOp)(word & 0xFFFF);
657 uint32_t node_word_count = (word >> 16) & 0xFFFF;
658
659 SpvReflectPrvNode* p_node = &(p_parser->nodes[node_index]);
660 p_node->op = op;
661 p_node->word_offset = spirv_word_index;
662 p_node->word_count = node_word_count;
663
664 switch (p_node->op) {
665 default: break;
666
667 case SpvOpString: {
668 ++(p_parser->string_count);
669 }
670 break;
671
672 case SpvOpSource: {
673 CHECKED_READU32_CAST(p_parser, p_node->word_offset + 1, SpvSourceLanguage, p_parser->source_language);
674 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_parser->source_language_version);
675 if (p_node->word_count >= 4) {
676 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_parser->source_file_id);
677 }
678 if (p_node->word_count >= 5) {
679 const char* p_source = (const char*)(p_parser->spirv_code + p_node->word_offset + 4);
680
681 const size_t source_len = strlen(p_source);
682 char* p_source_temp = (char*)calloc(source_len + 1, sizeof(char*));
683
684 if (IsNull(p_source_temp)) {
685 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
686 }
687
688 #ifdef _WIN32
689 strcpy_s(p_source_temp, source_len + 1, p_source);
690 #else
691 strcpy(p_source_temp, p_source);
692 #endif
693
694 p_parser->source_embedded = p_source_temp;
695 }
696 }
697 break;
698
699 case SpvOpSourceContinued: {
700 const char* p_source = (const char*)(p_parser->spirv_code + p_node->word_offset + 1);
701
702 const size_t source_len = strlen(p_source);
703 const size_t embedded_source_len = strlen(p_parser->source_embedded);
704 char* p_continued_source = (char*)calloc(source_len + embedded_source_len + 1, sizeof(char*));
705
706 if (IsNull(p_continued_source)) {
707 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
708 }
709
710 #ifdef _WIN32
711 strcpy_s(p_continued_source, embedded_source_len + 1, p_parser->source_embedded);
712 strcat_s(p_continued_source, source_len + 1, p_source);
713 #else
714 strcpy(p_continued_source, p_parser->source_embedded);
715 strcat(p_continued_source, p_source);
716 #endif
717
718 SafeFree(p_parser->source_embedded);
719 p_parser->source_embedded = p_continued_source;
720 }
721 break;
722
723 case SpvOpEntryPoint: {
724 ++(p_parser->entry_point_count);
725 }
726 break;
727
728 case SpvOpName:
729 case SpvOpMemberName:
730 {
731 uint32_t member_offset = (p_node->op == SpvOpMemberName) ? 1 : 0;
732 uint32_t name_start = p_node->word_offset + member_offset + 2;
733 p_node->name = (const char*)(p_parser->spirv_code + name_start);
734 }
735 break;
736
737 case SpvOpTypeStruct:
738 {
739 p_node->member_count = p_node->word_count - 2;
740 } // Fall through
741 case SpvOpTypeVoid:
742 case SpvOpTypeBool:
743 case SpvOpTypeInt:
744 case SpvOpTypeFloat:
745 case SpvOpTypeVector:
746 case SpvOpTypeMatrix:
747 case SpvOpTypeSampler:
748 case SpvOpTypeOpaque:
749 case SpvOpTypeFunction:
750 case SpvOpTypeEvent:
751 case SpvOpTypeDeviceEvent:
752 case SpvOpTypeReserveId:
753 case SpvOpTypeQueue:
754 case SpvOpTypePipe:
755 case SpvOpTypeAccelerationStructureKHR:
756 case SpvOpTypeRayQueryKHR:
757 {
758 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
759 p_node->is_type = true;
760 }
761 break;
762
763 case SpvOpTypeImage: {
764 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
765 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->image_traits.sampled_type_id);
766 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_node->image_traits.dim);
767 CHECKED_READU32(p_parser, p_node->word_offset + 4, p_node->image_traits.depth);
768 CHECKED_READU32(p_parser, p_node->word_offset + 5, p_node->image_traits.arrayed);
769 CHECKED_READU32(p_parser, p_node->word_offset + 6, p_node->image_traits.ms);
770 CHECKED_READU32(p_parser, p_node->word_offset + 7, p_node->image_traits.sampled);
771 CHECKED_READU32(p_parser, p_node->word_offset + 8, p_node->image_traits.image_format);
772 p_node->is_type = true;
773 }
774 break;
775
776 case SpvOpTypeSampledImage: {
777 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
778 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->image_type_id);
779 p_node->is_type = true;
780 }
781 break;
782
783 case SpvOpTypeArray: {
784 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
785 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->array_traits.element_type_id);
786 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_node->array_traits.length_id);
787 p_node->is_type = true;
788 }
789 break;
790
791 case SpvOpTypeRuntimeArray: {
792 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
793 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->array_traits.element_type_id);
794 p_node->is_type = true;
795 }
796 break;
797
798 case SpvOpTypePointer: {
799 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
800 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->storage_class);
801 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_node->type_id);
802 p_node->is_type = true;
803 }
804 break;
805
806 case SpvOpTypeForwardPointer:
807 {
808 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_id);
809 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->storage_class);
810 p_node->is_type = true;
811 }
812 break;
813
814 case SpvOpConstantTrue:
815 case SpvOpConstantFalse:
816 case SpvOpConstant:
817 case SpvOpConstantComposite:
818 case SpvOpConstantSampler:
819 case SpvOpConstantNull: {
820 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
821 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
822 }
823 break;
824
825 case SpvOpSpecConstantTrue:
826 case SpvOpSpecConstantFalse:
827 case SpvOpSpecConstant:
828 case SpvOpSpecConstantComposite:
829 case SpvOpSpecConstantOp: {
830 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
831 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
832 }
833 break;
834
835 case SpvOpVariable:
836 {
837 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->type_id);
838 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
839 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_node->storage_class);
840 }
841 break;
842
843 case SpvOpLoad:
844 {
845 // Only load enough so OpDecorate can reference the node, skip the remaining operands.
846 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
847 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
848 }
849 break;
850
851 case SpvOpAccessChain:
852 {
853 SpvReflectPrvAccessChain* p_access_chain = &(p_parser->access_chains[access_chain_index]);
854 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_access_chain->result_type_id);
855 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_access_chain->result_id);
856 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_access_chain->base_id);
857 //
858 // SPIRV_ACCESS_CHAIN_INDEX_OFFSET (4) is the number of words up until the first index:
859 // [Node, Result Type Id, Result Id, Base Id, <Indexes>]
860 //
861 p_access_chain->index_count = (node_word_count - SPIRV_ACCESS_CHAIN_INDEX_OFFSET);
862 if (p_access_chain->index_count > 0) {
863 p_access_chain->indexes = (uint32_t*)calloc(p_access_chain->index_count, sizeof(*(p_access_chain->indexes)));
864 if (IsNull( p_access_chain->indexes)) {
865 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
866 }
867 // Parse any index values for access chain
868 for (uint32_t index_index = 0; index_index < p_access_chain->index_count; ++index_index) {
869 // Read index id
870 uint32_t index_id = 0;
871 CHECKED_READU32(p_parser, p_node->word_offset + SPIRV_ACCESS_CHAIN_INDEX_OFFSET + index_index, index_id);
872 // Find OpConstant node that contains index value
873 SpvReflectPrvNode* p_index_value_node = FindNode(p_parser, index_id);
874 if ((p_index_value_node != NULL) && (p_index_value_node->op == SpvOpConstant)) {
875 // Read index value
876 uint32_t index_value = UINT32_MAX;
877 CHECKED_READU32(p_parser, p_index_value_node->word_offset + 3, index_value);
878 assert(index_value != UINT32_MAX);
879 // Write index value to array
880 p_access_chain->indexes[index_index] = index_value;
881 }
882 }
883 }
884 ++access_chain_index;
885 }
886 break;
887
888 case SpvOpFunction:
889 {
890 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
891 // Count function definitions, not function declarations. To determine
892 // the difference, set an in-function variable, and then if an OpLabel
893 // is reached before the end of the function increment the function
894 // count.
895 function_node = node_index;
896 }
897 break;
898
899 case SpvOpLabel:
900 {
901 if (function_node != (uint32_t)INVALID_VALUE) {
902 SpvReflectPrvNode* p_func_node = &(p_parser->nodes[function_node]);
903 CHECKED_READU32(p_parser, p_func_node->word_offset + 2, p_func_node->result_id);
904 ++(p_parser->function_count);
905 }
906 } // Fall through
907
908 case SpvOpFunctionEnd:
909 {
910 function_node = (uint32_t)INVALID_VALUE;
911 }
912 break;
913 }
914
915 if (p_node->is_type) {
916 ++(p_parser->type_count);
917 }
918
919 spirv_word_index += node_word_count;
920 ++node_index;
921 }
922
923 return SPV_REFLECT_RESULT_SUCCESS;
924}
925
926static SpvReflectResult ParseStrings(SpvReflectPrvParser* p_parser)
927{
928 assert(IsNotNull(p_parser));
929 assert(IsNotNull(p_parser->spirv_code));
930 assert(IsNotNull(p_parser->nodes));
931
932 // Early out
933 if (p_parser->string_count == 0) {
934 return SPV_REFLECT_RESULT_SUCCESS;
935 }
936
937 if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
938 // Allocate string storage
939 p_parser->strings = (SpvReflectPrvString*)calloc(p_parser->string_count, sizeof(*(p_parser->strings)));
940
941 uint32_t string_index = 0;
942 for (size_t i = 0; i < p_parser->node_count; ++i) {
943 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
944 if (p_node->op != SpvOpString) {
945 continue;
946 }
947
948 // Paranoid check against string count
949 assert(string_index < p_parser->string_count);
950 if (string_index >= p_parser->string_count) {
951 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
952 }
953
954 // Result id
955 SpvReflectPrvString* p_string = &(p_parser->strings[string_index]);
956 CHECKED_READU32(p_parser, p_node->word_offset + 1, p_string->result_id);
957
958 // String
959 uint32_t string_start = p_node->word_offset + 2;
960 p_string->string = (const char*)(p_parser->spirv_code + string_start);
961
962 // Increment string index
963 ++string_index;
964 }
965 }
966
967 return SPV_REFLECT_RESULT_SUCCESS;
968}
969
970static SpvReflectResult ParseSource(SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module)
971{
972 assert(IsNotNull(p_parser));
973 assert(IsNotNull(p_parser->spirv_code));
974
975 if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code)) {
976 // Source file
977 if (IsNotNull(p_parser->strings)) {
978 for (uint32_t i = 0; i < p_parser->string_count; ++i) {
979 SpvReflectPrvString* p_string = &(p_parser->strings[i]);
980 if (p_string->result_id == p_parser->source_file_id) {
981 p_module->source_file = p_string->string;
982 break;
983 }
984 }
985 }
986
987 //Source code
988 if (IsNotNull(p_parser->source_embedded))
989 {
990 const size_t source_len = strlen(p_parser->source_embedded);
991 char* p_source = (char*)calloc(source_len + 1, sizeof(char*));
992
993 if (IsNull(p_source)) {
994 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
995 }
996
997 #ifdef _WIN32
998 strcpy_s(p_source, source_len + 1, p_parser->source_embedded);
999 #else
1000 strcpy(p_source, p_parser->source_embedded);
1001 #endif
1002
1003 p_module->source_source = p_source;
1004 }
1005 }
1006
1007 return SPV_REFLECT_RESULT_SUCCESS;
1008}
1009
1010static SpvReflectResult ParseFunction(
1011 SpvReflectPrvParser* p_parser,
1012 SpvReflectPrvNode* p_func_node,
1013 SpvReflectPrvFunction* p_func,
1014 size_t first_label_index)
1015{
1016 p_func->id = p_func_node->result_id;
1017
1018 p_func->callee_count = 0;
1019 p_func->accessed_ptr_count = 0;
1020
1021 for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
1022 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1023 if (p_node->op == SpvOpFunctionEnd) {
1024 break;
1025 }
1026 switch (p_node->op) {
1027 case SpvOpFunctionCall: {
1028 ++(p_func->callee_count);
1029 }
1030 break;
1031 case SpvOpLoad:
1032 case SpvOpAccessChain:
1033 case SpvOpInBoundsAccessChain:
1034 case SpvOpPtrAccessChain:
1035 case SpvOpArrayLength:
1036 case SpvOpGenericPtrMemSemantics:
1037 case SpvOpInBoundsPtrAccessChain:
1038 case SpvOpStore:
1039 case SpvOpImageTexelPointer:
1040 {
1041 ++(p_func->accessed_ptr_count);
1042 }
1043 break;
1044 case SpvOpCopyMemory:
1045 case SpvOpCopyMemorySized:
1046 {
1047 p_func->accessed_ptr_count += 2;
1048 }
1049 break;
1050 default: break;
1051 }
1052 }
1053
1054 if (p_func->callee_count > 0) {
1055 p_func->callees = (uint32_t*)calloc(p_func->callee_count,
1056 sizeof(*(p_func->callees)));
1057 if (IsNull(p_func->callees)) {
1058 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1059 }
1060 }
1061
1062 if (p_func->accessed_ptr_count > 0) {
1063 p_func->accessed_ptrs = (uint32_t*)calloc(p_func->accessed_ptr_count,
1064 sizeof(*(p_func->accessed_ptrs)));
1065 if (IsNull(p_func->accessed_ptrs)) {
1066 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1067 }
1068 }
1069
1070 p_func->callee_count = 0;
1071 p_func->accessed_ptr_count = 0;
1072 for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
1073 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1074 if (p_node->op == SpvOpFunctionEnd) {
1075 break;
1076 }
1077 switch (p_node->op) {
1078 case SpvOpFunctionCall: {
1079 CHECKED_READU32(p_parser, p_node->word_offset + 3,
1080 p_func->callees[p_func->callee_count]);
1081 (++p_func->callee_count);
1082 }
1083 break;
1084 case SpvOpLoad:
1085 case SpvOpAccessChain:
1086 case SpvOpInBoundsAccessChain:
1087 case SpvOpPtrAccessChain:
1088 case SpvOpArrayLength:
1089 case SpvOpGenericPtrMemSemantics:
1090 case SpvOpInBoundsPtrAccessChain:
1091 case SpvOpImageTexelPointer:
1092 {
1093 CHECKED_READU32(p_parser, p_node->word_offset + 3,
1094 p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1095 (++p_func->accessed_ptr_count);
1096 }
1097 break;
1098 case SpvOpStore:
1099 {
1100 CHECKED_READU32(p_parser, p_node->word_offset + 2,
1101 p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1102 (++p_func->accessed_ptr_count);
1103 }
1104 break;
1105 case SpvOpCopyMemory:
1106 case SpvOpCopyMemorySized:
1107 {
1108 CHECKED_READU32(p_parser, p_node->word_offset + 2,
1109 p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1110 (++p_func->accessed_ptr_count);
1111 CHECKED_READU32(p_parser, p_node->word_offset + 3,
1112 p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1113 (++p_func->accessed_ptr_count);
1114 }
1115 break;
1116 default: break;
1117 }
1118 }
1119
1120 if (p_func->callee_count > 0) {
1121 qsort(p_func->callees, p_func->callee_count,
1122 sizeof(*(p_func->callees)), SortCompareUint32);
1123 }
1124 p_func->callee_count = (uint32_t)DedupSortedUint32(p_func->callees,
1125 p_func->callee_count);
1126
1127 if (p_func->accessed_ptr_count > 0) {
1128 qsort(p_func->accessed_ptrs, p_func->accessed_ptr_count,
1129 sizeof(*(p_func->accessed_ptrs)), SortCompareUint32);
1130 }
1131 p_func->accessed_ptr_count = (uint32_t)DedupSortedUint32(p_func->accessed_ptrs,
1132 p_func->accessed_ptr_count);
1133
1134 return SPV_REFLECT_RESULT_SUCCESS;
1135}
1136
1137static int SortCompareFunctions(
1138 const void* a,
1139 const void* b)
1140{
1141 const SpvReflectPrvFunction* af = (const SpvReflectPrvFunction*)a;
1142 const SpvReflectPrvFunction* bf = (const SpvReflectPrvFunction*)b;
1143 return (int)af->id - (int)bf->id;
1144}
1145
1146static SpvReflectResult ParseFunctions(SpvReflectPrvParser* p_parser)
1147{
1148 assert(IsNotNull(p_parser));
1149 assert(IsNotNull(p_parser->spirv_code));
1150 assert(IsNotNull(p_parser->nodes));
1151
1152 if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
1153 if (p_parser->function_count == 0) {
1154 return SPV_REFLECT_RESULT_SUCCESS;
1155 }
1156
1157 p_parser->functions = (SpvReflectPrvFunction*)calloc(p_parser->function_count,
1158 sizeof(*(p_parser->functions)));
1159 if (IsNull(p_parser->functions)) {
1160 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1161 }
1162
1163 size_t function_index = 0;
1164 for (size_t i = 0; i < p_parser->node_count; ++i) {
1165 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1166 if (p_node->op != SpvOpFunction) {
1167 continue;
1168 }
1169
1170 // Skip over function declarations that aren't definitions
1171 bool func_definition = false;
1172 // Intentionally reuse i to avoid iterating over these nodes more than
1173 // once
1174 for (; i < p_parser->node_count; ++i) {
1175 if (p_parser->nodes[i].op == SpvOpLabel) {
1176 func_definition = true;
1177 break;
1178 }
1179 if (p_parser->nodes[i].op == SpvOpFunctionEnd) {
1180 break;
1181 }
1182 }
1183 if (!func_definition) {
1184 continue;
1185 }
1186
1187 SpvReflectPrvFunction* p_function = &(p_parser->functions[function_index]);
1188
1189 SpvReflectResult result = ParseFunction(p_parser, p_node, p_function, i);
1190 if (result != SPV_REFLECT_RESULT_SUCCESS) {
1191 return result;
1192 }
1193
1194 ++function_index;
1195 }
1196
1197 qsort(p_parser->functions, p_parser->function_count,
1198 sizeof(*(p_parser->functions)), SortCompareFunctions);
1199
1200 // Once they're sorted, link the functions with pointers to improve graph
1201 // traversal efficiency
1202 for (size_t i = 0; i < p_parser->function_count; ++i) {
1203 SpvReflectPrvFunction* p_func = &(p_parser->functions[i]);
1204 if (p_func->callee_count == 0) {
1205 continue;
1206 }
1207 p_func->callee_ptrs = (SpvReflectPrvFunction**)calloc(p_func->callee_count,
1208 sizeof(*(p_func->callee_ptrs)));
1209 for (size_t j = 0, k = 0; j < p_func->callee_count; ++j) {
1210 while (p_parser->functions[k].id != p_func->callees[j]) {
1211 ++k;
1212 if (k >= p_parser->function_count) {
1213 // Invalid called function ID somewhere
1214 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1215 }
1216 }
1217 p_func->callee_ptrs[j] = &(p_parser->functions[k]);
1218 }
1219 }
1220 }
1221
1222 return SPV_REFLECT_RESULT_SUCCESS;
1223}
1224
1225static SpvReflectResult ParseMemberCounts(SpvReflectPrvParser* p_parser)
1226{
1227 assert(IsNotNull(p_parser));
1228 assert(IsNotNull(p_parser->spirv_code));
1229 assert(IsNotNull(p_parser->nodes));
1230
1231 if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
1232 for (size_t i = 0; i < p_parser->node_count; ++i) {
1233 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1234 if ((p_node->op != SpvOpMemberName) && (p_node->op != SpvOpMemberDecorate)) {
1235 continue;
1236 }
1237
1238 uint32_t target_id = 0;
1239 uint32_t member_index = (uint32_t)INVALID_VALUE;
1240 CHECKED_READU32(p_parser, p_node->word_offset + 1, target_id);
1241 CHECKED_READU32(p_parser, p_node->word_offset + 2, member_index);
1242 SpvReflectPrvNode* p_target_node = FindNode(p_parser, target_id);
1243 // Not all nodes get parsed, so FindNode returning NULL is expected.
1244 if (IsNull(p_target_node)) {
1245 continue;
1246 }
1247
1248 if (member_index == INVALID_VALUE) {
1249 return SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
1250 }
1251
1252 p_target_node->member_count = Max(p_target_node->member_count, member_index + 1);
1253 }
1254
1255 for (uint32_t i = 0; i < p_parser->node_count; ++i) {
1256 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1257 if (p_node->member_count == 0) {
1258 continue;
1259 }
1260
1261 p_node->member_names = (const char **)calloc(p_node->member_count, sizeof(*(p_node->member_names)));
1262 if (IsNull(p_node->member_names)) {
1263 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1264 }
1265
1266 p_node->member_decorations = (SpvReflectPrvDecorations*)calloc(p_node->member_count, sizeof(*(p_node->member_decorations)));
1267 if (IsNull(p_node->member_decorations)) {
1268 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1269 }
1270 }
1271 }
1272 return SPV_REFLECT_RESULT_SUCCESS;
1273}
1274
1275static SpvReflectResult ParseNames(SpvReflectPrvParser* p_parser)
1276{
1277 assert(IsNotNull(p_parser));
1278 assert(IsNotNull(p_parser->spirv_code));
1279 assert(IsNotNull(p_parser->nodes));
1280
1281 if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
1282 for (size_t i = 0; i < p_parser->node_count; ++i) {
1283 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1284 if ((p_node->op != SpvOpName) && (p_node->op != SpvOpMemberName)) {
1285 continue;
1286 }
1287
1288 uint32_t target_id = 0;
1289 CHECKED_READU32(p_parser, p_node->word_offset + 1, target_id);
1290 SpvReflectPrvNode* p_target_node = FindNode(p_parser, target_id);
1291 // Not all nodes get parsed, so FindNode returning NULL is expected.
1292 if (IsNull(p_target_node)) {
1293 continue;
1294 }
1295
1296 const char** pp_target_name = &(p_target_node->name);
1297 if (p_node->op == SpvOpMemberName) {
1298 uint32_t member_index = UINT32_MAX;
1299 CHECKED_READU32(p_parser, p_node->word_offset + 2, member_index);
1300 pp_target_name = &(p_target_node->member_names[member_index]);
1301 }
1302
1303 *pp_target_name = p_node->name;
1304 }
1305 }
1306 return SPV_REFLECT_RESULT_SUCCESS;
1307}
1308
1309static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser)
1310{
1311 for (uint32_t i = 0; i < p_parser->node_count; ++i) {
1312 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1313
1314 if (((uint32_t)p_node->op != (uint32_t)SpvOpDecorate) &&
1315 ((uint32_t)p_node->op != (uint32_t)SpvOpMemberDecorate) &&
1316 ((uint32_t)p_node->op != (uint32_t)SpvReflectOpDecorateId) &&
1317 ((uint32_t)p_node->op != (uint32_t)SpvReflectOpDecorateStringGOOGLE) &&
1318 ((uint32_t)p_node->op != (uint32_t)SpvReflectOpMemberDecorateStringGOOGLE))
1319 {
1320 continue;
1321 }
1322
1323 // Need to adjust the read offset if this is a member decoration
1324 uint32_t member_offset = 0;
1325 if (p_node->op == SpvOpMemberDecorate) {
1326 member_offset = 1;
1327 }
1328
1329 // Get decoration
1330 uint32_t decoration = (uint32_t)INVALID_VALUE;
1331 CHECKED_READU32(p_parser, p_node->word_offset + member_offset + 2, decoration);
1332
1333 // Filter out the decoration that do not affect reflection, otherwise
1334 // there will be random crashes because the nodes aren't found.
1335 bool skip = false;
1336 switch (decoration) {
1337 default: {
1338 skip = true;
1339 }
1340 break;
1341 case SpvDecorationRelaxedPrecision:
1342 case SpvDecorationBlock:
1343 case SpvDecorationBufferBlock:
1344 case SpvDecorationColMajor:
1345 case SpvDecorationRowMajor:
1346 case SpvDecorationArrayStride:
1347 case SpvDecorationMatrixStride:
1348 case SpvDecorationBuiltIn:
1349 case SpvDecorationNoPerspective:
1350 case SpvDecorationFlat:
1351 case SpvDecorationNonWritable:
1352 case SpvDecorationLocation:
1353 case SpvDecorationBinding:
1354 case SpvDecorationDescriptorSet:
1355 case SpvDecorationOffset:
1356 case SpvDecorationInputAttachmentIndex:
1357 case SpvReflectDecorationHlslCounterBufferGOOGLE:
1358 case SpvReflectDecorationHlslSemanticGOOGLE: {
1359 skip = false;
1360 }
1361 break;
1362 }
1363 if (skip) {
1364 continue;
1365 }
1366
1367 // Find target target node
1368 uint32_t target_id = 0;
1369 CHECKED_READU32(p_parser, p_node->word_offset + 1, target_id);
1370 SpvReflectPrvNode* p_target_node = FindNode(p_parser, target_id);
1371 if (IsNull(p_target_node)) {
1372 if ((p_node->op == (uint32_t)SpvOpDecorate) && (decoration == SpvDecorationRelaxedPrecision)) {
1373 // Many OPs can be decorated that we don't care about. Ignore those.
1374 // See https://github.com/KhronosGroup/SPIRV-Reflect/issues/134
1375 continue;
1376 }
1377 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1378 }
1379 // Get decorations
1380 SpvReflectPrvDecorations* p_target_decorations = &(p_target_node->decorations);
1381 // Update pointer if this is a member member decoration
1382 if (p_node->op == SpvOpMemberDecorate) {
1383 uint32_t member_index = (uint32_t)INVALID_VALUE;
1384 CHECKED_READU32(p_parser, p_node->word_offset + 2, member_index);
1385 p_target_decorations = &(p_target_node->member_decorations[member_index]);
1386 }
1387
1388 switch (decoration) {
1389 default: break;
1390
1391 case SpvDecorationRelaxedPrecision: {
1392 p_target_decorations->is_relaxed_precision = true;
1393 }
1394 break;
1395
1396 case SpvDecorationBlock: {
1397 p_target_decorations->is_block = true;
1398 }
1399 break;
1400
1401 case SpvDecorationBufferBlock: {
1402 p_target_decorations->is_buffer_block = true;
1403 }
1404 break;
1405
1406 case SpvDecorationColMajor: {
1407 p_target_decorations->is_column_major = true;
1408 }
1409 break;
1410
1411 case SpvDecorationRowMajor: {
1412 p_target_decorations->is_row_major = true;
1413 }
1414 break;
1415
1416 case SpvDecorationArrayStride: {
1417 uint32_t word_offset = p_node->word_offset + member_offset + 3;
1418 CHECKED_READU32(p_parser, word_offset, p_target_decorations->array_stride);
1419 }
1420 break;
1421
1422 case SpvDecorationMatrixStride: {
1423 uint32_t word_offset = p_node->word_offset + member_offset + 3;
1424 CHECKED_READU32(p_parser, word_offset, p_target_decorations->matrix_stride);
1425 }
1426 break;
1427
1428 case SpvDecorationBuiltIn: {
1429 p_target_decorations->is_built_in = true;
1430 uint32_t word_offset = p_node->word_offset + member_offset + 3;
1431 CHECKED_READU32_CAST(p_parser, word_offset, SpvBuiltIn, p_target_decorations->built_in);
1432 }
1433 break;
1434
1435 case SpvDecorationNoPerspective: {
1436 p_target_decorations->is_noperspective = true;
1437 }
1438 break;
1439
1440 case SpvDecorationFlat: {
1441 p_target_decorations->is_flat = true;
1442 }
1443 break;
1444
1445 case SpvDecorationNonWritable: {
1446 p_target_decorations->is_non_writable = true;
1447 }
1448 break;
1449
1450 case SpvDecorationLocation: {
1451 uint32_t word_offset = p_node->word_offset + member_offset + 3;
1452 CHECKED_READU32(p_parser, word_offset, p_target_decorations->location.value);
1453 p_target_decorations->location.word_offset = word_offset;
1454 }
1455 break;
1456
1457 case SpvDecorationBinding: {
1458 uint32_t word_offset = p_node->word_offset + member_offset+ 3;
1459 CHECKED_READU32(p_parser, word_offset, p_target_decorations->binding.value);
1460 p_target_decorations->binding.word_offset = word_offset;
1461 }
1462 break;
1463
1464 case SpvDecorationDescriptorSet: {
1465 uint32_t word_offset = p_node->word_offset + member_offset+ 3;
1466 CHECKED_READU32(p_parser, word_offset, p_target_decorations->set.value);
1467 p_target_decorations->set.word_offset = word_offset;
1468 }
1469 break;
1470
1471 case SpvDecorationOffset: {
1472 uint32_t word_offset = p_node->word_offset + member_offset+ 3;
1473 CHECKED_READU32(p_parser, word_offset, p_target_decorations->offset.value);
1474 p_target_decorations->offset.word_offset = word_offset;
1475 }
1476 break;
1477
1478 case SpvDecorationInputAttachmentIndex: {
1479 uint32_t word_offset = p_node->word_offset + member_offset+ 3;
1480 CHECKED_READU32(p_parser, word_offset, p_target_decorations->input_attachment_index.value);
1481 p_target_decorations->input_attachment_index.word_offset = word_offset;
1482 }
1483 break;
1484
1485 case SpvReflectDecorationHlslCounterBufferGOOGLE: {
1486 uint32_t word_offset = p_node->word_offset + member_offset+ 3;
1487 CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value);
1488 p_target_decorations->uav_counter_buffer.word_offset = word_offset;
1489 }
1490 break;
1491
1492 case SpvReflectDecorationHlslSemanticGOOGLE: {
1493 uint32_t word_offset = p_node->word_offset + member_offset + 3;
1494 p_target_decorations->semantic.value = (const char*)(p_parser->spirv_code + word_offset);
1495 p_target_decorations->semantic.word_offset = word_offset;
1496 }
1497 break;
1498 }
1499 }
1500 return SPV_REFLECT_RESULT_SUCCESS;
1501}
1502
1503static SpvReflectResult EnumerateAllUniforms(
1504 SpvReflectShaderModule* p_module,
1505 size_t* p_uniform_count,
1506 uint32_t** pp_uniforms
1507)
1508{
1509 *p_uniform_count = p_module->descriptor_binding_count;
1510 if (*p_uniform_count == 0) {
1511 return SPV_REFLECT_RESULT_SUCCESS;
1512 }
1513 *pp_uniforms = (uint32_t*)calloc(*p_uniform_count, sizeof(**pp_uniforms));
1514
1515 if (IsNull(*pp_uniforms)) {
1516 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1517 }
1518
1519 for (size_t i = 0; i < *p_uniform_count; ++i) {
1520 (*pp_uniforms)[i] = p_module->descriptor_bindings[i].spirv_id;
1521 }
1522 qsort(*pp_uniforms, *p_uniform_count, sizeof(**pp_uniforms),
1523 SortCompareUint32);
1524 return SPV_REFLECT_RESULT_SUCCESS;
1525}
1526
1527static SpvReflectResult ParseType(
1528 SpvReflectPrvParser* p_parser,
1529 SpvReflectPrvNode* p_node,
1530 SpvReflectPrvDecorations* p_struct_member_decorations,
1531 SpvReflectShaderModule* p_module,
1532 SpvReflectTypeDescription* p_type
1533)
1534{
1535 SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
1536
1537 if (p_node->member_count > 0) {
1538 p_type->member_count = p_node->member_count;
1539 p_type->members = (SpvReflectTypeDescription*)calloc(p_type->member_count, sizeof(*(p_type->members)));
1540 if (IsNotNull(p_type->members)) {
1541 // Mark all members types with an invalid state
1542 for (size_t i = 0; i < p_type->members->member_count; ++i) {
1543 SpvReflectTypeDescription* p_member_type = &(p_type->members[i]);
1544 p_member_type->id = (uint32_t)INVALID_VALUE;
1545 p_member_type->op = (SpvOp)INVALID_VALUE;
1546 p_member_type->storage_class = (SpvStorageClass)INVALID_VALUE;
1547 }
1548 }
1549 else {
1550 result = SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1551 }
1552 }
1553
1554 if (result == SPV_REFLECT_RESULT_SUCCESS) {
1555 // Since the parse descends on type information, these will get overwritten
1556 // if not guarded against assignment. Only assign if the id is invalid.
1557 if (p_type->id == INVALID_VALUE) {
1558 p_type->id = p_node->result_id;
1559 p_type->op = p_node->op;
1560 p_type->decoration_flags = 0;
1561 }
1562 // Top level types need to pick up decorations from all types below it.
1563 // Issue and fix here: https://github.com/chaoticbob/SPIRV-Reflect/issues/64
1564 p_type->decoration_flags = ApplyDecorations(&p_node->decorations);
1565
1566 switch (p_node->op) {
1567 default: break;
1568 case SpvOpTypeVoid:
1569 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_VOID;
1570 break;
1571
1572 case SpvOpTypeBool:
1573 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_BOOL;
1574 break;
1575
1576 case SpvOpTypeInt: {
1577 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_INT;
1578 IF_READU32(result, p_parser, p_node->word_offset + 2, p_type->traits.numeric.scalar.width);
1579 IF_READU32(result, p_parser, p_node->word_offset + 3, p_type->traits.numeric.scalar.signedness);
1580 }
1581 break;
1582
1583 case SpvOpTypeFloat: {
1584 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_FLOAT;
1585 IF_READU32(result, p_parser, p_node->word_offset + 2, p_type->traits.numeric.scalar.width);
1586 }
1587 break;
1588
1589 case SpvOpTypeVector: {
1590 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_VECTOR;
1591 uint32_t component_type_id = (uint32_t)INVALID_VALUE;
1592 IF_READU32(result, p_parser, p_node->word_offset + 2, component_type_id);
1593 IF_READU32(result, p_parser, p_node->word_offset + 3, p_type->traits.numeric.vector.component_count);
1594 // Parse component type
1595 SpvReflectPrvNode* p_next_node = FindNode(p_parser, component_type_id);
1596 if (IsNotNull(p_next_node)) {
1597 result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
1598 }
1599 else {
1600 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1601 SPV_REFLECT_ASSERT(false);
1602 }
1603 }
1604 break;
1605
1606 case SpvOpTypeMatrix: {
1607 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_MATRIX;
1608 uint32_t column_type_id = (uint32_t)INVALID_VALUE;
1609 IF_READU32(result, p_parser, p_node->word_offset + 2, column_type_id);
1610 IF_READU32(result, p_parser, p_node->word_offset + 3, p_type->traits.numeric.matrix.column_count);
1611 SpvReflectPrvNode* p_next_node = FindNode(p_parser, column_type_id);
1612 if (IsNotNull(p_next_node)) {
1613 result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
1614 }
1615 else {
1616 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1617 SPV_REFLECT_ASSERT(false);
1618 }
1619 p_type->traits.numeric.matrix.row_count = p_type->traits.numeric.vector.component_count;
1620 p_type->traits.numeric.matrix.stride = p_node->decorations.matrix_stride;
1621 // NOTE: Matrix stride is decorated using OpMemberDecoreate - not OpDecoreate.
1622 if (IsNotNull(p_struct_member_decorations)) {
1623 p_type->traits.numeric.matrix.stride = p_struct_member_decorations->matrix_stride;
1624 }
1625 }
1626 break;
1627
1628 case SpvOpTypeImage: {
1629 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE;
1630 uint32_t sampled_type_id = (uint32_t)INVALID_VALUE;
1631 IF_READU32(result, p_parser, p_node->word_offset + 2, sampled_type_id);
1632 SpvReflectPrvNode* p_next_node = FindNode(p_parser, sampled_type_id);
1633 if (IsNotNull(p_next_node)) {
1634 result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
1635 }
1636 else {
1637 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1638 }
1639 IF_READU32_CAST(result, p_parser, p_node->word_offset + 3, SpvDim, p_type->traits.image.dim);
1640 IF_READU32(result, p_parser, p_node->word_offset + 4, p_type->traits.image.depth);
1641 IF_READU32(result, p_parser, p_node->word_offset + 5, p_type->traits.image.arrayed);
1642 IF_READU32(result, p_parser, p_node->word_offset + 6, p_type->traits.image.ms);
1643 IF_READU32(result, p_parser, p_node->word_offset + 7, p_type->traits.image.sampled);
1644 IF_READU32_CAST(result, p_parser, p_node->word_offset + 8, SpvImageFormat, p_type->traits.image.image_format);
1645 }
1646 break;
1647
1648 case SpvOpTypeSampler: {
1649 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLER;
1650 }
1651 break;
1652
1653 case SpvOpTypeSampledImage: {
1654 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLED_IMAGE;
1655 uint32_t image_type_id = (uint32_t)INVALID_VALUE;
1656 IF_READU32(result, p_parser, p_node->word_offset + 2, image_type_id);
1657 SpvReflectPrvNode* p_next_node = FindNode(p_parser, image_type_id);
1658 if (IsNotNull(p_next_node)) {
1659 result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
1660 }
1661 else {
1662 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1663 SPV_REFLECT_ASSERT(false);
1664 }
1665 }
1666 break;
1667
1668 case SpvOpTypeArray: {
1669 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_ARRAY;
1670 if (result == SPV_REFLECT_RESULT_SUCCESS) {
1671 uint32_t element_type_id = (uint32_t)INVALID_VALUE;
1672 uint32_t length_id = (uint32_t)INVALID_VALUE;
1673 IF_READU32(result, p_parser, p_node->word_offset + 2, element_type_id);
1674 IF_READU32(result, p_parser, p_node->word_offset + 3, length_id);
1675 // NOTE: Array stride is decorated using OpDecorate instead of
1676 // OpMemberDecorate, even if the array is apart of a struct.
1677 p_type->traits.array.stride = p_node->decorations.array_stride;
1678 // Get length for current dimension
1679 SpvReflectPrvNode* p_length_node = FindNode(p_parser, length_id);
1680 if (IsNotNull(p_length_node)) {
1681 uint32_t dim_index = p_type->traits.array.dims_count;
1682 if (p_length_node->op == SpvOpSpecConstant ||
1683 p_length_node->op == SpvOpSpecConstantOp) {
1684 p_type->traits.array.dims[dim_index] = 0xFFFFFFFF;
1685 p_type->traits.array.spec_constant_op_ids[dim_index] = length_id;
1686 p_type->traits.array.dims_count += 1;
1687 } else {
1688 uint32_t length = 0;
1689 IF_READU32(result, p_parser, p_length_node->word_offset + 3, length);
1690 if (result == SPV_REFLECT_RESULT_SUCCESS) {
1691 // Write the array dim and increment the count and offset
1692 p_type->traits.array.dims[dim_index] = length;
1693 p_type->traits.array.spec_constant_op_ids[dim_index] = 0xFFFFFFFF;
1694 p_type->traits.array.dims_count += 1;
1695 } else {
1696 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1697 SPV_REFLECT_ASSERT(false);
1698 }
1699 }
1700 // Parse next dimension or element type
1701 SpvReflectPrvNode* p_next_node = FindNode(p_parser, element_type_id);
1702 if (IsNotNull(p_next_node)) {
1703 result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
1704 }
1705 }
1706 else {
1707 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1708 SPV_REFLECT_ASSERT(false);
1709 }
1710 }
1711 }
1712 break;
1713
1714 case SpvOpTypeRuntimeArray: {
1715 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_ARRAY;
1716 uint32_t element_type_id = (uint32_t)INVALID_VALUE;
1717 IF_READU32(result, p_parser, p_node->word_offset + 2, element_type_id);
1718 p_type->traits.array.stride = p_node->decorations.array_stride;
1719 uint32_t dim_index = p_type->traits.array.dims_count;
1720 p_type->traits.array.dims[dim_index] = 0;
1721 p_type->traits.array.spec_constant_op_ids[dim_index] = 0;
1722 p_type->traits.array.dims_count += 1;
1723 // Parse next dimension or element type
1724 SpvReflectPrvNode* p_next_node = FindNode(p_parser, element_type_id);
1725 if (IsNotNull(p_next_node)) {
1726 result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
1727 }
1728 else {
1729 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1730 SPV_REFLECT_ASSERT(false);
1731 }
1732 }
1733 break;
1734
1735 case SpvOpTypeStruct: {
1736 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_STRUCT;
1737 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_BLOCK;
1738 uint32_t word_index = 2;
1739 uint32_t member_index = 0;
1740 for (; word_index < p_node->word_count; ++word_index, ++member_index) {
1741 uint32_t member_id = (uint32_t)INVALID_VALUE;
1742 IF_READU32(result, p_parser, p_node->word_offset + word_index, member_id);
1743 // Find member node
1744 SpvReflectPrvNode* p_member_node = FindNode(p_parser, member_id);
1745 if (IsNull(p_member_node)) {
1746 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1747 SPV_REFLECT_ASSERT(false);
1748 break;
1749 }
1750
1751 // Member decorations
1752 SpvReflectPrvDecorations* p_member_decorations = &p_node->member_decorations[member_index];
1753
1754 assert(member_index < p_type->member_count);
1755 // Parse member type
1756 SpvReflectTypeDescription* p_member_type = &(p_type->members[member_index]);
1757 p_member_type->id = member_id;
1758 p_member_type->op = p_member_node->op;
1759 result = ParseType(p_parser, p_member_node, p_member_decorations, p_module, p_member_type);
1760 if (result != SPV_REFLECT_RESULT_SUCCESS) {
1761 break;
1762 }
1763 // This looks wrong
1764 //p_member_type->type_name = p_member_node->name;
1765 p_member_type->struct_member_name = p_node->member_names[member_index];
1766 }
1767 }
1768 break;
1769
1770 case SpvOpTypeOpaque: break;
1771
1772 case SpvOpTypePointer: {
1773 IF_READU32_CAST(result, p_parser, p_node->word_offset + 2, SpvStorageClass, p_type->storage_class);
1774 uint32_t type_id = (uint32_t)INVALID_VALUE;
1775 IF_READU32(result, p_parser, p_node->word_offset + 3, type_id);
1776 // Parse type
1777 SpvReflectPrvNode* p_next_node = FindNode(p_parser, type_id);
1778 if (IsNotNull(p_next_node)) {
1779 result = ParseType(p_parser, p_next_node, NULL, p_module, p_type);
1780 }
1781 else {
1782 result = SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1783 SPV_REFLECT_ASSERT(false);
1784 }
1785 }
1786 break;
1787
1788 case SpvOpTypeAccelerationStructureKHR: {
1789 p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE;
1790 }
1791 break;
1792 }
1793
1794 if (result == SPV_REFLECT_RESULT_SUCCESS) {
1795 // Names get assigned on the way down. Guard against names
1796 // get overwritten on the way up.
1797 if (IsNull(p_type->type_name)) {
1798 p_type->type_name = p_node->name;
1799 }
1800 }
1801 }
1802
1803 return result;
1804}
1805
1806static SpvReflectResult ParseTypes(
1807 SpvReflectPrvParser* p_parser,
1808 SpvReflectShaderModule* p_module)
1809{
1810 if (p_parser->type_count == 0) {
1811 return SPV_REFLECT_RESULT_SUCCESS;
1812 }
1813
1814 p_module->_internal->type_description_count = p_parser->type_count;
1815 p_module->_internal->type_descriptions = (SpvReflectTypeDescription*)calloc(p_module->_internal->type_description_count,
1816 sizeof(*(p_module->_internal->type_descriptions)));
1817 if (IsNull(p_module->_internal->type_descriptions)) {
1818 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1819 }
1820
1821 // Mark all types with an invalid state
1822 for (size_t i = 0; i < p_module->_internal->type_description_count; ++i) {
1823 SpvReflectTypeDescription* p_type = &(p_module->_internal->type_descriptions[i]);
1824 p_type->id = (uint32_t)INVALID_VALUE;
1825 p_type->op = (SpvOp)INVALID_VALUE;
1826 p_type->storage_class = (SpvStorageClass)INVALID_VALUE;
1827 }
1828
1829 size_t type_index = 0;
1830 for (size_t i = 0; i < p_parser->node_count; ++i) {
1831 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1832 if (! p_node->is_type) {
1833 continue;
1834 }
1835
1836 SpvReflectTypeDescription* p_type = &(p_module->_internal->type_descriptions[type_index]);
1837 SpvReflectResult result = ParseType(p_parser, p_node, NULL, p_module, p_type);
1838 if (result != SPV_REFLECT_RESULT_SUCCESS) {
1839 return result;
1840 }
1841 ++type_index;
1842 }
1843 return SPV_REFLECT_RESULT_SUCCESS;
1844}
1845
1846static int SortCompareDescriptorBinding(const void* a, const void* b)
1847{
1848 const SpvReflectDescriptorBinding* p_elem_a = (const SpvReflectDescriptorBinding*)a;
1849 const SpvReflectDescriptorBinding* p_elem_b = (const SpvReflectDescriptorBinding*)b;
1850 int value = (int)(p_elem_a->binding) - (int)(p_elem_b->binding);
1851 if (value == 0) {
1852 // use spirv-id as a tiebreaker to ensure a stable ordering, as they're guaranteed
1853 // unique.
1854 assert(p_elem_a->spirv_id != p_elem_b->spirv_id);
1855 value = (int)(p_elem_a->spirv_id) - (int)(p_elem_b->spirv_id);
1856 }
1857 return value;
1858}
1859
1860static SpvReflectResult ParseDescriptorBindings(
1861 SpvReflectPrvParser* p_parser,
1862 SpvReflectShaderModule* p_module)
1863{
1864 p_module->descriptor_binding_count = 0;
1865 for (size_t i = 0; i < p_parser->node_count; ++i) {
1866 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1867 if ((p_node->op != SpvOpVariable) ||
1868 ((p_node->storage_class != SpvStorageClassUniform) &&
1869 (p_node->storage_class != SpvStorageClassStorageBuffer) &&
1870 (p_node->storage_class != SpvStorageClassUniformConstant)))
1871 {
1872 continue;
1873 }
1874 if ((p_node->decorations.set.value == INVALID_VALUE) || (p_node->decorations.binding.value == INVALID_VALUE)) {
1875 continue;
1876 }
1877
1878 p_module->descriptor_binding_count += 1;
1879 }
1880
1881 if (p_module->descriptor_binding_count == 0) {
1882 return SPV_REFLECT_RESULT_SUCCESS;
1883 }
1884
1885 p_module->descriptor_bindings = (SpvReflectDescriptorBinding*)calloc(p_module->descriptor_binding_count, sizeof(*(p_module->descriptor_bindings)));
1886 if (IsNull(p_module->descriptor_bindings)) {
1887 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1888 }
1889
1890 // Mark all types with an invalid state
1891 for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
1892 SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
1893 p_descriptor->binding = (uint32_t)INVALID_VALUE;
1894 p_descriptor->input_attachment_index = (uint32_t)INVALID_VALUE;
1895 p_descriptor->set = (uint32_t)INVALID_VALUE;
1896 p_descriptor->descriptor_type = (SpvReflectDescriptorType)INVALID_VALUE;
1897 p_descriptor->uav_counter_id = (uint32_t)INVALID_VALUE;
1898 }
1899
1900 size_t descriptor_index = 0;
1901 for (size_t i = 0; i < p_parser->node_count; ++i) {
1902 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1903 if ((p_node->op != SpvOpVariable) ||
1904 ((p_node->storage_class != SpvStorageClassUniform) &&
1905 (p_node->storage_class != SpvStorageClassStorageBuffer) &&
1906 (p_node->storage_class != SpvStorageClassUniformConstant)))
1907 {
1908 continue;
1909 }
1910 if ((p_node->decorations.set.value == INVALID_VALUE) || (p_node->decorations.binding.value == INVALID_VALUE)) {
1911 continue;
1912 }
1913
1914 SpvReflectTypeDescription* p_type = FindType(p_module, p_node->type_id);
1915 if (IsNull(p_type)) {
1916 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1917 }
1918 // If the type is a pointer, resolve it. We need to retain the storage class
1919 // from the pointer so that we can use it to deduce deescriptor types.
1920 SpvStorageClass pointer_storage_class = SpvStorageClassMax;
1921 if (p_type->op == SpvOpTypePointer) {
1922 pointer_storage_class = p_type->storage_class;
1923 // Find the type's node
1924 SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
1925 if (IsNull(p_type_node)) {
1926 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1927 }
1928 // Should be the resolved type
1929 p_type = FindType(p_module, p_type_node->type_id);
1930 if (IsNull(p_type)) {
1931 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
1932 }
1933 }
1934
1935 SpvReflectDescriptorBinding* p_descriptor = &p_module->descriptor_bindings[descriptor_index];
1936 p_descriptor->spirv_id = p_node->result_id;
1937 p_descriptor->name = p_node->name;
1938 p_descriptor->binding = p_node->decorations.binding.value;
1939 p_descriptor->input_attachment_index = p_node->decorations.input_attachment_index.value;
1940 p_descriptor->set = p_node->decorations.set.value;
1941 p_descriptor->count = 1;
1942 p_descriptor->uav_counter_id = p_node->decorations.uav_counter_buffer.value;
1943 p_descriptor->type_description = p_type;
1944
1945 // If this is in the StorageBuffer storage class, it's for sure a storage
1946 // buffer descriptor. We need to handle this case earlier because in SPIR-V
1947 // there are two ways to indicate a storage buffer:
1948 // 1) Uniform storage class + BufferBlock decoration, or
1949 // 2) StorageBuffer storage class + Buffer decoration.
1950 // The 1) way is deprecated since SPIR-V v1.3. But the Buffer decoration is
1951 // also used together with Uniform storage class to mean uniform buffer..
1952 // We'll handle the pre-v1.3 cases in ParseDescriptorType().
1953 if (pointer_storage_class == SpvStorageClassStorageBuffer) {
1954 p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1955 }
1956
1957 // Copy image traits
1958 if ((p_type->type_flags & SPV_REFLECT_TYPE_FLAG_EXTERNAL_MASK) == SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE) {
1959 memcpy(&p_descriptor->image, &p_type->traits.image, sizeof(p_descriptor->image));
1960 }
1961
1962 // This is a workaround for: https://github.com/KhronosGroup/glslang/issues/1096
1963 {
1964 const uint32_t resource_mask = SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLED_IMAGE | SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE;
1965 if ((p_type->type_flags & resource_mask) == resource_mask) {
1966 memcpy(&p_descriptor->image, &p_type->traits.image, sizeof(p_descriptor->image));
1967 }
1968 }
1969
1970 // Copy array traits
1971 if (p_type->traits.array.dims_count > 0) {
1972 p_descriptor->array.dims_count = p_type->traits.array.dims_count;
1973 for (uint32_t dim_index = 0; dim_index < p_type->traits.array.dims_count; ++dim_index) {
1974 uint32_t dim_value = p_type->traits.array.dims[dim_index];
1975 p_descriptor->array.dims[dim_index] = dim_value;
1976 p_descriptor->count *= dim_value;
1977 }
1978 }
1979
1980 // Count
1981
1982
1983 p_descriptor->word_offset.binding = p_node->decorations.binding.word_offset;
1984 p_descriptor->word_offset.set = p_node->decorations.set.word_offset;
1985
1986 ++descriptor_index;
1987 }
1988
1989 if (p_module->descriptor_binding_count > 0) {
1990 qsort(p_module->descriptor_bindings,
1991 p_module->descriptor_binding_count,
1992 sizeof(*(p_module->descriptor_bindings)),
1993 SortCompareDescriptorBinding);
1994 }
1995
1996 return SPV_REFLECT_RESULT_SUCCESS;
1997}
1998
1999static SpvReflectResult ParseDescriptorType(SpvReflectShaderModule* p_module)
2000{
2001 if (p_module->descriptor_binding_count == 0) {
2002 return SPV_REFLECT_RESULT_SUCCESS;
2003 }
2004
2005 for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
2006 SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
2007 SpvReflectTypeDescription* p_type = p_descriptor->type_description;
2008
2009 if ((int)p_descriptor->descriptor_type == (int)INVALID_VALUE) {
2010 switch (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_EXTERNAL_MASK) {
2011 default: assert(false && "unknown type flag"); break;
2012
2013 case SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE: {
2014 if (p_descriptor->image.dim == SpvDimBuffer) {
2015 switch (p_descriptor->image.sampled) {
2016 default: assert(false && "unknown texel buffer sampled value"); break;
2017 case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; break;
2018 case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; break;
2019 }
2020 }
2021 else if(p_descriptor->image.dim == SpvDimSubpassData) {
2022 p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2023 }
2024 else {
2025 switch (p_descriptor->image.sampled) {
2026 default: assert(false && "unknown image sampled value"); break;
2027 case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE; break;
2028 case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE; break;
2029 }
2030 }
2031 }
2032 break;
2033
2034 case SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLER: {
2035 p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER;
2036 }
2037 break;
2038
2039 case (SPV_REFLECT_TYPE_FLAG_EXTERNAL_SAMPLED_IMAGE | SPV_REFLECT_TYPE_FLAG_EXTERNAL_IMAGE): {
2040 // This is a workaround for: https://github.com/KhronosGroup/glslang/issues/1096
2041 if (p_descriptor->image.dim == SpvDimBuffer) {
2042 switch (p_descriptor->image.sampled) {
2043 default: assert(false && "unknown texel buffer sampled value"); break;
2044 case IMAGE_SAMPLED: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; break;
2045 case IMAGE_STORAGE: p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; break;
2046 }
2047 }
2048 else {
2049 p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
2050 }
2051 }
2052 break;
2053
2054 case SPV_REFLECT_TYPE_FLAG_EXTERNAL_BLOCK: {
2055 if (p_type->decoration_flags & SPV_REFLECT_DECORATION_BLOCK) {
2056 p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
2057 }
2058 else if (p_type->decoration_flags & SPV_REFLECT_DECORATION_BUFFER_BLOCK) {
2059 p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER;
2060 }
2061 else {
2062 assert(false && "unknown struct");
2063 }
2064 }
2065 break;
2066
2067 case SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE: {
2068 p_descriptor->descriptor_type = SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
2069 }
2070 break;
2071 }
2072 }
2073
2074 switch (p_descriptor->descriptor_type) {
2075 case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SAMPLER; break;
2076 case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : p_descriptor->resource_type = (SpvReflectResourceType)(SPV_REFLECT_RESOURCE_FLAG_SAMPLER | SPV_REFLECT_RESOURCE_FLAG_SRV); break;
2077 case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SRV; break;
2078 case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_UAV; break;
2079 case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SRV; break;
2080 case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_UAV; break;
2081 case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_CBV; break;
2082 case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_CBV; break;
2083 case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_UAV; break;
2084 case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_UAV; break;
2085 case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT : break;
2086 case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR : p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SRV; break;
2087 }
2088 }
2089
2090 return SPV_REFLECT_RESULT_SUCCESS;
2091}
2092
2093static SpvReflectResult ParseUAVCounterBindings(SpvReflectShaderModule* p_module)
2094{
2095 char name[MAX_NODE_NAME_LENGTH];
2096 const char* k_count_tag = "@count";
2097
2098 for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
2099 SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
2100
2101 if (p_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
2102 continue;
2103 }
2104
2105 SpvReflectDescriptorBinding* p_counter_descriptor = NULL;
2106 // Use UAV counter buffer id if present...
2107 if (p_descriptor->uav_counter_id != UINT32_MAX) {
2108 for (uint32_t counter_descriptor_index = 0; counter_descriptor_index < p_module->descriptor_binding_count; ++counter_descriptor_index) {
2109 SpvReflectDescriptorBinding* p_test_counter_descriptor = &(p_module->descriptor_bindings[counter_descriptor_index]);
2110 if (p_test_counter_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
2111 continue;
2112 }
2113 if (p_descriptor->uav_counter_id == p_test_counter_descriptor->spirv_id) {
2114 p_counter_descriptor = p_test_counter_descriptor;
2115 break;
2116 }
2117 }
2118 }
2119 // ...otherwise use old @count convention.
2120 else {
2121 const size_t descriptor_name_length = p_descriptor->name? strlen(p_descriptor->name): 0;
2122
2123 memset(name, 0, MAX_NODE_NAME_LENGTH);
2124 memcpy(name, p_descriptor->name, descriptor_name_length);
2125#if defined(_WIN32)
2126 strcat_s(name, MAX_NODE_NAME_LENGTH, k_count_tag);
2127#else
2128 strcat(name, k_count_tag);
2129#endif
2130
2131 for (uint32_t counter_descriptor_index = 0; counter_descriptor_index < p_module->descriptor_binding_count; ++counter_descriptor_index) {
2132 SpvReflectDescriptorBinding* p_test_counter_descriptor = &(p_module->descriptor_bindings[counter_descriptor_index]);
2133 if (p_test_counter_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
2134 continue;
2135 }
2136 if (p_test_counter_descriptor->name && strcmp(name, p_test_counter_descriptor->name) == 0) {
2137 p_counter_descriptor = p_test_counter_descriptor;
2138 break;
2139 }
2140 }
2141 }
2142
2143 if (p_counter_descriptor != NULL) {
2144 p_descriptor->uav_counter_binding = p_counter_descriptor;
2145 }
2146 }
2147
2148 return SPV_REFLECT_RESULT_SUCCESS;
2149}
2150
2151static SpvReflectResult ParseDescriptorBlockVariable(
2152 SpvReflectPrvParser* p_parser,
2153 SpvReflectShaderModule* p_module,
2154 SpvReflectTypeDescription* p_type,
2155 SpvReflectBlockVariable* p_var
2156)
2157{
2158 bool has_non_writable = false;
2159
2160 if (IsNotNull(p_type->members) && (p_type->member_count > 0)) {
2161 p_var->member_count = p_type->member_count;
2162 p_var->members = (SpvReflectBlockVariable*)calloc(p_var->member_count, sizeof(*p_var->members));
2163 if (IsNull(p_var->members)) {
2164 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
2165 }
2166
2167 SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
2168 if (IsNull(p_type_node)) {
2169 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2170 }
2171 // Resolve to element type if current type is array or run time array
2172 while (p_type_node->op == SpvOpTypeArray || p_type_node->op == SpvOpTypeRuntimeArray) {
2173 if (p_type_node->op == SpvOpTypeArray) {
2174 p_type_node = FindNode(p_parser, p_type_node->array_traits.element_type_id);
2175 }
2176 else {
2177 // Element type description
2178 SpvReflectTypeDescription* p_type_temp = FindType(p_module, p_type_node->array_traits.element_type_id);
2179 if (IsNull(p_type_temp)) {
2180 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2181 }
2182 // Element type node
2183 p_type_node = FindNode(p_parser, p_type_temp->id);
2184 }
2185 if (IsNull(p_type_node)) {
2186 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2187 }
2188 }
2189
2190 // Parse members
2191 for (uint32_t member_index = 0; member_index < p_type->member_count; ++member_index) {
2192 SpvReflectTypeDescription* p_member_type = &p_type->members[member_index];
2193 SpvReflectBlockVariable* p_member_var = &p_var->members[member_index];
2194 bool is_struct = (p_member_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) == SPV_REFLECT_TYPE_FLAG_STRUCT;
2195 if (is_struct) {
2196 SpvReflectResult result = ParseDescriptorBlockVariable(p_parser, p_module, p_member_type, p_member_var);
2197 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2198 return result;
2199 }
2200 }
2201
2202 p_member_var->name = p_type_node->member_names[member_index];
2203 p_member_var->offset = p_type_node->member_decorations[member_index].offset.value;
2204 p_member_var->decoration_flags = ApplyDecorations(&p_type_node->member_decorations[member_index]);
2205 p_member_var->flags |= SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
2206 if (!has_non_writable && (p_member_var->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE)) {
2207 has_non_writable = true;
2208 }
2209 ApplyNumericTraits(p_member_type, &p_member_var->numeric);
2210 if (p_member_type->op == SpvOpTypeArray) {
2211 ApplyArrayTraits(p_member_type, &p_member_var->array);
2212 }
2213
2214 p_member_var->type_description = p_member_type;
2215 }
2216 }
2217
2218 p_var->name = p_type->type_name;
2219 p_var->type_description = p_type;
2220 if (has_non_writable) {
2221 p_var->decoration_flags |= SPV_REFLECT_DECORATION_NON_WRITABLE;
2222 }
2223
2224 return SPV_REFLECT_RESULT_SUCCESS;
2225}
2226
2227static SpvReflectResult ParseDescriptorBlockVariableSizes(
2228 SpvReflectPrvParser* p_parser,
2229 SpvReflectShaderModule* p_module,
2230 bool is_parent_root,
2231 bool is_parent_aos,
2232 bool is_parent_rta,
2233 SpvReflectBlockVariable* p_var
2234)
2235{
2236 if (p_var->member_count == 0) {
2237 return SPV_REFLECT_RESULT_SUCCESS;
2238 }
2239
2240 // Absolute offsets
2241 for (uint32_t member_index = 0; member_index < p_var->member_count; ++member_index) {
2242 SpvReflectBlockVariable* p_member_var = &p_var->members[member_index];
2243 if (is_parent_root) {
2244 p_member_var->absolute_offset = p_member_var->offset;
2245 }
2246 else {
2247 p_member_var->absolute_offset = is_parent_aos ? 0 : p_member_var->offset + p_var->absolute_offset;
2248 }
2249 }
2250
2251 // Size
2252 for (uint32_t member_index = 0; member_index < p_var->member_count; ++member_index) {
2253 SpvReflectBlockVariable* p_member_var = &p_var->members[member_index];
2254 SpvReflectTypeDescription* p_member_type = p_member_var->type_description;
2255
2256 switch (p_member_type->op) {
2257 case SpvOpTypeBool: {
2258 p_member_var->size = SPIRV_WORD_SIZE;
2259 }
2260 break;
2261
2262 case SpvOpTypeInt:
2263 case SpvOpTypeFloat: {
2264 p_member_var->size = p_member_type->traits.numeric.scalar.width / SPIRV_BYTE_WIDTH;
2265 }
2266 break;
2267
2268 case SpvOpTypeVector: {
2269 uint32_t size = p_member_type->traits.numeric.vector.component_count *
2270 (p_member_type->traits.numeric.scalar.width / SPIRV_BYTE_WIDTH);
2271 p_member_var->size = size;
2272 }
2273 break;
2274
2275 case SpvOpTypeMatrix: {
2276 if (p_member_var->decoration_flags & SPV_REFLECT_DECORATION_COLUMN_MAJOR) {
2277 p_member_var->size = p_member_var->numeric.matrix.column_count * p_member_var->numeric.matrix.stride;
2278 }
2279 else if (p_member_var->decoration_flags & SPV_REFLECT_DECORATION_ROW_MAJOR) {
2280 p_member_var->size = p_member_var->numeric.matrix.row_count * p_member_var->numeric.matrix.stride;
2281 }
2282 }
2283 break;
2284
2285 case SpvOpTypeArray: {
2286 // If array of structs, parse members first...
2287 bool is_struct = (p_member_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) == SPV_REFLECT_TYPE_FLAG_STRUCT;
2288 if (is_struct) {
2289 SpvReflectResult result = ParseDescriptorBlockVariableSizes(p_parser, p_module, false, true, is_parent_rta, p_member_var);
2290 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2291 return result;
2292 }
2293 }
2294 // ...then array
2295 uint32_t element_count = (p_member_var->array.dims_count > 0 ? 1 : 0);
2296 for (uint32_t i = 0; i < p_member_var->array.dims_count; ++i) {
2297 element_count *= p_member_var->array.dims[i];
2298 }
2299 p_member_var->size = element_count * p_member_var->array.stride;
2300 }
2301 break;
2302
2303 case SpvOpTypeRuntimeArray: {
2304 bool is_struct = (p_member_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) == SPV_REFLECT_TYPE_FLAG_STRUCT;
2305 if (is_struct) {
2306 SpvReflectResult result = ParseDescriptorBlockVariableSizes(p_parser, p_module, false, true, true, p_member_var);
2307 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2308 return result;
2309 }
2310 }
2311 }
2312 break;
2313
2314 case SpvOpTypeStruct: {
2315 SpvReflectResult result = ParseDescriptorBlockVariableSizes(p_parser, p_module, false, is_parent_aos, is_parent_rta, p_member_var);
2316 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2317 return result;
2318 }
2319 }
2320 break;
2321
2322 default:
2323 break;
2324 }
2325 }
2326
2327 // Parse padded size using offset difference for all member except for the last entry...
2328 for (uint32_t member_index = 0; member_index < (p_var->member_count - 1); ++member_index) {
2329 SpvReflectBlockVariable* p_member_var = &p_var->members[member_index];
2330 SpvReflectBlockVariable* p_next_member_var = &p_var->members[member_index + 1];
2331 p_member_var->padded_size = p_next_member_var->offset - p_member_var->offset;
2332 if (p_member_var->size > p_member_var->padded_size) {
2333 p_member_var->size = p_member_var->padded_size;
2334 }
2335 if (is_parent_rta) {
2336 p_member_var->padded_size = p_member_var->size;
2337 }
2338 }
2339 // ...last entry just gets rounded up to near multiple of SPIRV_DATA_ALIGNMENT, which is 16 and
2340 // subtract the offset.
2341 if (p_var->member_count > 0) {
2342 SpvReflectBlockVariable* p_member_var = &p_var->members[p_var->member_count - 1];
2343 p_member_var->padded_size = RoundUp(p_member_var->offset + p_member_var->size, SPIRV_DATA_ALIGNMENT) - p_member_var->offset;
2344 if (p_member_var->size > p_member_var->padded_size) {
2345 p_member_var->size = p_member_var->padded_size;
2346 }
2347 if (is_parent_rta) {
2348 p_member_var->padded_size = p_member_var->size;
2349 }
2350 }
2351
2352 // @TODO validate this with assertion
2353 p_var->size = p_var->members[p_var->member_count - 1].offset +
2354 p_var->members[p_var->member_count - 1].padded_size;
2355 p_var->padded_size = p_var->size;
2356
2357 return SPV_REFLECT_RESULT_SUCCESS;
2358}
2359
2360static void MarkSelfAndAllMemberVarsAsUsed(SpvReflectBlockVariable* p_var)
2361{
2362 // Clear the current variable's USED flag
2363 p_var->flags &= ~SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
2364
2365 SpvOp op_type = p_var->type_description->op;
2366 switch (op_type) {
2367 default: break;
2368
2369 case SpvOpTypeArray: {
2370 }
2371 break;
2372
2373 case SpvOpTypeStruct: {
2374 for (uint32_t i = 0; i < p_var->member_count; ++i) {
2375 SpvReflectBlockVariable* p_member_var = &p_var->members[i];
2376 MarkSelfAndAllMemberVarsAsUsed(p_member_var);
2377 }
2378 }
2379 break;
2380 }
2381}
2382
2383static SpvReflectResult ParseDescriptorBlockVariableUsage(
2384 SpvReflectPrvParser* p_parser,
2385 SpvReflectShaderModule* p_module,
2386 SpvReflectPrvAccessChain* p_access_chain,
2387 uint32_t index_index,
2388 SpvOp override_op_type,
2389 SpvReflectBlockVariable* p_var
2390)
2391{
2392 (void)p_parser;
2393 (void)p_access_chain;
2394 (void)p_var;
2395
2396 // Clear the current variable's UNUSED flag
2397 p_var->flags &= ~SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
2398
2399 // Parsing arrays requires overriding the op type for
2400 // for the lowest dim's element type.
2401 SpvOp op_type = p_var->type_description->op;
2402 if (override_op_type != (SpvOp)INVALID_VALUE) {
2403 op_type = override_op_type;
2404 }
2405
2406 switch (op_type) {
2407 default: break;
2408
2409 case SpvOpTypeArray: {
2410 // Parse through array's type hierarchy to find the actual/non-array element type
2411 SpvReflectTypeDescription* p_type = p_var->type_description;
2412 while ((p_type->op == SpvOpTypeArray) && (index_index < p_access_chain->index_count)) {
2413 // Find the array element type id
2414 SpvReflectPrvNode* p_node = FindNode(p_parser, p_type->id);
2415 if (p_node == NULL) {
2416 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2417 }
2418 uint32_t element_type_id = p_node->array_traits.element_type_id;
2419 // Get the array element type
2420 p_type = FindType(p_module, element_type_id);
2421 if (p_type == NULL) {
2422 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2423 }
2424 // Next access chain index
2425 index_index += 1;
2426 }
2427
2428 // Only continue parsing if there's remaining indices in the access
2429 // chain. If the end of the access chain has been reach then all
2430 // remaining variables (including those in struct hierarchies)
2431 // are considered USED.
2432 //
2433 // See: https://github.com/KhronosGroup/SPIRV-Reflect/issues/78
2434 //
2435 if (index_index < p_access_chain->index_count) {
2436 // Parse current var again with a type override and advanced index index
2437 SpvReflectResult result = ParseDescriptorBlockVariableUsage(
2438 p_parser,
2439 p_module,
2440 p_access_chain,
2441 index_index,
2442 p_type->op,
2443 p_var);
2444 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2445 return result;
2446 }
2447 }
2448 else {
2449 // Clear UNUSED flag for remaining variables
2450 MarkSelfAndAllMemberVarsAsUsed(p_var);
2451 }
2452 }
2453 break;
2454
2455 case SpvOpTypeStruct: {
2456 assert(p_var->member_count > 0);
2457 if (p_var->member_count == 0) {
2458 return SPV_REFLECT_RESULT_ERROR_SPIRV_UNEXPECTED_BLOCK_DATA;
2459 }
2460 // Get member variable at the access's chain current index
2461 uint32_t index = p_access_chain->indexes[index_index];
2462 if (index >= p_var->member_count) {
2463 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_BLOCK_MEMBER_REFERENCE;
2464 }
2465 SpvReflectBlockVariable* p_member_var = &p_var->members[index];
2466
2467 // Next access chain index
2468 index_index += 1;
2469
2470 // Only continue parsing if there's remaining indices in the access
2471 // chain. If the end of the access chain has been reach then all
2472 // remaining variables (including those in struct hierarchies)
2473 // are considered USED.
2474 //
2475 // See: https://github.com/KhronosGroup/SPIRV-Reflect/issues/78
2476 //
2477 if (index_index < p_access_chain->index_count) {
2478 SpvReflectResult result = ParseDescriptorBlockVariableUsage(
2479 p_parser,
2480 p_module,
2481 p_access_chain,
2482 index_index,
2483 (SpvOp)INVALID_VALUE,
2484 p_member_var);
2485 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2486 return result;
2487 }
2488 }
2489 else {
2490 // Clear UNUSED flag for remaining variables
2491 MarkSelfAndAllMemberVarsAsUsed(p_member_var);
2492 }
2493 //SpvReflectBlockVariable* p_member_var = &p_var->members[index];
2494 //if (index_index < p_access_chain->index_count) {
2495 // SpvReflectResult result = ParseDescriptorBlockVariableUsage(
2496 // p_parser,
2497 // p_module,
2498 // p_access_chain,
2499 // index_index + 1,
2500 // (SpvOp)INVALID_VALUE,
2501 // p_member_var);
2502 // if (result != SPV_REFLECT_RESULT_SUCCESS) {
2503 // return result;
2504 // }
2505 //}
2506 }
2507 break;
2508 }
2509
2510 return SPV_REFLECT_RESULT_SUCCESS;
2511}
2512
2513static SpvReflectResult ParseDescriptorBlocks(
2514 SpvReflectPrvParser* p_parser,
2515 SpvReflectShaderModule* p_module)
2516{
2517 if (p_module->descriptor_binding_count == 0) {
2518 return SPV_REFLECT_RESULT_SUCCESS;
2519 }
2520
2521 for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
2522 SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
2523 SpvReflectTypeDescription* p_type = p_descriptor->type_description;
2524 if ((p_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER) &&
2525 (p_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) )
2526 {
2527 continue;
2528 }
2529
2530 // Mark UNUSED
2531 p_descriptor->block.flags |= SPV_REFLECT_VARIABLE_FLAGS_UNUSED;
2532 // Parse descriptor block
2533 SpvReflectResult result = ParseDescriptorBlockVariable(p_parser, p_module, p_type, &p_descriptor->block);
2534 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2535 return result;
2536 }
2537
2538 for (uint32_t access_chain_index = 0; access_chain_index < p_parser->access_chain_count; ++access_chain_index) {
2539 SpvReflectPrvAccessChain* p_access_chain = &(p_parser->access_chains[access_chain_index]);
2540 // Skip any access chains that aren't touching this descriptor block
2541 if (p_descriptor->spirv_id != p_access_chain->base_id) {
2542 continue;
2543 }
2544 result = ParseDescriptorBlockVariableUsage(
2545 p_parser,
2546 p_module,
2547 p_access_chain,
2548 0,
2549 (SpvOp)INVALID_VALUE,
2550 &p_descriptor->block);
2551 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2552 return result;
2553 }
2554 }
2555
2556 p_descriptor->block.name = p_descriptor->name;
2557
2558 bool is_parent_rta = (p_descriptor->descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER);
2559 result = ParseDescriptorBlockVariableSizes(p_parser, p_module, true, false, is_parent_rta, &p_descriptor->block);
2560 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2561 return result;
2562 }
2563
2564 if (is_parent_rta) {
2565 p_descriptor->block.size = 0;
2566 p_descriptor->block.padded_size = 0;
2567 }
2568 }
2569
2570 return SPV_REFLECT_RESULT_SUCCESS;
2571}
2572
2573static SpvReflectResult ParseFormat(
2574 const SpvReflectTypeDescription* p_type,
2575 SpvReflectFormat* p_format
2576)
2577{
2578 SpvReflectResult result = SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;
2579 bool signedness = (p_type->traits.numeric.scalar.signedness != 0);
2580 uint32_t bit_width = p_type->traits.numeric.scalar.width;
2581 if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_VECTOR) {
2582 uint32_t component_count = p_type->traits.numeric.vector.component_count;
2583 if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_FLOAT) {
2584 switch (bit_width) {
2585 case 32: {
2586 switch (component_count) {
2587 case 2: *p_format = SPV_REFLECT_FORMAT_R32G32_SFLOAT; break;
2588 case 3: *p_format = SPV_REFLECT_FORMAT_R32G32B32_SFLOAT; break;
2589 case 4: *p_format = SPV_REFLECT_FORMAT_R32G32B32A32_SFLOAT; break;
2590 }
2591 }
2592 break;
2593
2594 case 64: {
2595 switch (component_count) {
2596 case 2: *p_format = SPV_REFLECT_FORMAT_R64G64_SFLOAT; break;
2597 case 3: *p_format = SPV_REFLECT_FORMAT_R64G64B64_SFLOAT; break;
2598 case 4: *p_format = SPV_REFLECT_FORMAT_R64G64B64A64_SFLOAT; break;
2599 }
2600 }
2601 }
2602 result = SPV_REFLECT_RESULT_SUCCESS;
2603 }
2604 else if (p_type->type_flags & (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_BOOL)) {
2605 switch (bit_width) {
2606 case 32: {
2607 switch (component_count) {
2608 case 2: *p_format = signedness ? SPV_REFLECT_FORMAT_R32G32_SINT : SPV_REFLECT_FORMAT_R32G32_UINT; break;
2609 case 3: *p_format = signedness ? SPV_REFLECT_FORMAT_R32G32B32_SINT : SPV_REFLECT_FORMAT_R32G32B32_UINT; break;
2610 case 4: *p_format = signedness ? SPV_REFLECT_FORMAT_R32G32B32A32_SINT : SPV_REFLECT_FORMAT_R32G32B32A32_UINT; break;
2611 }
2612 }
2613 break;
2614
2615 case 64: {
2616 switch (component_count) {
2617 case 2: *p_format = signedness ? SPV_REFLECT_FORMAT_R64G64_SINT : SPV_REFLECT_FORMAT_R64G64_UINT; break;
2618 case 3: *p_format = signedness ? SPV_REFLECT_FORMAT_R64G64B64_SINT : SPV_REFLECT_FORMAT_R64G64B64_UINT; break;
2619 case 4: *p_format = signedness ? SPV_REFLECT_FORMAT_R64G64B64A64_SINT : SPV_REFLECT_FORMAT_R64G64B64A64_UINT; break;
2620 }
2621 }
2622 }
2623 result = SPV_REFLECT_RESULT_SUCCESS;
2624 }
2625 }
2626 else if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_FLOAT) {
2627 switch(bit_width) {
2628 case 32:
2629 *p_format = SPV_REFLECT_FORMAT_R32_SFLOAT;
2630 break;
2631 case 64:
2632 *p_format = SPV_REFLECT_FORMAT_R64_SFLOAT;
2633 break;
2634 }
2635 result = SPV_REFLECT_RESULT_SUCCESS;
2636 }
2637 else if (p_type->type_flags & (SPV_REFLECT_TYPE_FLAG_INT | SPV_REFLECT_TYPE_FLAG_BOOL)) {
2638 switch(bit_width) {
2639 case 32:
2640 *p_format = signedness ? SPV_REFLECT_FORMAT_R32_SINT : SPV_REFLECT_FORMAT_R32_UINT; break;
2641 break;
2642 case 64:
2643 *p_format = signedness ? SPV_REFLECT_FORMAT_R64_SINT : SPV_REFLECT_FORMAT_R64_UINT; break;
2644 }
2645 result = SPV_REFLECT_RESULT_SUCCESS;
2646 }
2647 else if (p_type->type_flags & SPV_REFLECT_TYPE_FLAG_STRUCT) {
2648 *p_format = SPV_REFLECT_FORMAT_UNDEFINED;
2649 result = SPV_REFLECT_RESULT_SUCCESS;
2650 }
2651 return result;
2652}
2653
2654static SpvReflectResult ParseInterfaceVariable(
2655 SpvReflectPrvParser* p_parser,
2656 const SpvReflectPrvDecorations* p_var_node_decorations,
2657 const SpvReflectPrvDecorations* p_type_node_decorations,
2658 SpvReflectShaderModule* p_module,
2659 SpvReflectTypeDescription* p_type,
2660 SpvReflectInterfaceVariable* p_var,
2661 bool* p_has_built_in
2662)
2663{
2664 SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
2665 if (IsNull(p_type_node)) {
2666 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2667 }
2668
2669 if (p_type->member_count > 0) {
2670 p_var->member_count = p_type->member_count;
2671 p_var->members = (SpvReflectInterfaceVariable*)calloc(p_var->member_count, sizeof(*p_var->members));
2672 if (IsNull(p_var->members)) {
2673 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
2674 }
2675
2676 for (uint32_t member_index = 0; member_index < p_type_node->member_count; ++member_index) {
2677 SpvReflectPrvDecorations* p_member_decorations = &p_type_node->member_decorations[member_index];
2678 SpvReflectTypeDescription* p_member_type = &p_type->members[member_index];
2679 SpvReflectInterfaceVariable* p_member_var = &p_var->members[member_index];
2680 SpvReflectResult result = ParseInterfaceVariable(p_parser, NULL, p_member_decorations, p_module, p_member_type, p_member_var, p_has_built_in);
2681 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2682 SPV_REFLECT_ASSERT(false);
2683 return result;
2684 }
2685 }
2686 }
2687
2688 p_var->name = p_type_node->name;
2689 p_var->decoration_flags = ApplyDecorations(p_type_node_decorations);
2690 if (p_var_node_decorations != NULL) {
2691 p_var->decoration_flags |= ApplyDecorations(p_var_node_decorations);
2692 }
2693 p_var->built_in = p_type_node_decorations->built_in;
2694 ApplyNumericTraits(p_type, &p_var->numeric);
2695 if (p_type->op == SpvOpTypeArray) {
2696 ApplyArrayTraits(p_type, &p_var->array);
2697 }
2698
2699 p_var->type_description = p_type;
2700
2701 *p_has_built_in |= p_type_node_decorations->is_built_in;
2702
2703 // Only parse format for interface variables that are input or output
2704 if ((p_var->storage_class == SpvStorageClassInput) || (p_var->storage_class == SpvStorageClassOutput)) {
2705 SpvReflectResult result = ParseFormat(p_var->type_description, &p_var->format);
2706 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2707 SPV_REFLECT_ASSERT(false);
2708 return result;
2709 }
2710 }
2711
2712 return SPV_REFLECT_RESULT_SUCCESS;
2713}
2714
2715static SpvReflectResult ParseInterfaceVariables(
2716 SpvReflectPrvParser* p_parser,
2717 SpvReflectShaderModule* p_module,
2718 SpvReflectEntryPoint* p_entry,
2719 uint32_t interface_variable_count,
2720 uint32_t* p_interface_variable_ids
2721)
2722{
2723 if (interface_variable_count == 0) {
2724 return SPV_REFLECT_RESULT_SUCCESS;
2725 }
2726
2727 p_entry->interface_variable_count = interface_variable_count;
2728 p_entry->input_variable_count = 0;
2729 p_entry->output_variable_count = 0;
2730 for (size_t i = 0; i < interface_variable_count; ++i) {
2731 uint32_t var_result_id = *(p_interface_variable_ids + i);
2732 SpvReflectPrvNode* p_node = FindNode(p_parser, var_result_id);
2733 if (IsNull(p_node)) {
2734 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2735 }
2736
2737 if (p_node->storage_class == SpvStorageClassInput) {
2738 p_entry->input_variable_count += 1;
2739 }
2740 else if (p_node->storage_class == SpvStorageClassOutput) {
2741 p_entry->output_variable_count += 1;
2742 }
2743 }
2744
2745 if (p_entry->input_variable_count > 0) {
2746 p_entry->input_variables = (SpvReflectInterfaceVariable**)calloc(p_entry->input_variable_count, sizeof(*(p_entry->input_variables)));
2747 if (IsNull(p_entry->input_variables)) {
2748 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
2749 }
2750 }
2751
2752 if (p_entry->output_variable_count > 0) {
2753 p_entry->output_variables = (SpvReflectInterfaceVariable**)calloc(p_entry->output_variable_count, sizeof(*(p_entry->output_variables)));
2754 if (IsNull(p_entry->output_variables)) {
2755 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
2756 }
2757 }
2758
2759 if (p_entry->interface_variable_count > 0) {
2760 p_entry->interface_variables = (SpvReflectInterfaceVariable*)calloc(p_entry->interface_variable_count, sizeof(*(p_entry->interface_variables)));
2761 if (IsNull(p_entry->interface_variables)) {
2762 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
2763 }
2764 }
2765
2766 size_t input_index = 0;
2767 size_t output_index = 0;
2768 for (size_t i = 0; i < interface_variable_count; ++i) {
2769 uint32_t var_result_id = *(p_interface_variable_ids + i);
2770 SpvReflectPrvNode* p_node = FindNode(p_parser, var_result_id);
2771 if (IsNull(p_node)) {
2772 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2773 }
2774
2775 SpvReflectTypeDescription* p_type = FindType(p_module, p_node->type_id);
2776 if (IsNull(p_node)) {
2777 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2778 }
2779 // If the type is a pointer, resolve it
2780 if (p_type->op == SpvOpTypePointer) {
2781 // Find the type's node
2782 SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
2783 if (IsNull(p_type_node)) {
2784 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2785 }
2786 // Should be the resolved type
2787 p_type = FindType(p_module, p_type_node->type_id);
2788 if (IsNull(p_type)) {
2789 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2790 }
2791 }
2792
2793 SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
2794 if (IsNull(p_type_node)) {
2795 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2796 }
2797
2798 SpvReflectInterfaceVariable* p_var = &(p_entry->interface_variables[i]);
2799 p_var->storage_class = p_node->storage_class;
2800
2801 bool has_built_in = p_node->decorations.is_built_in;
2802 SpvReflectResult result = ParseInterfaceVariable(
2803 p_parser,
2804 &p_node->decorations,
2805 &p_type_node->decorations,
2806 p_module,
2807 p_type,
2808 p_var,
2809 &has_built_in);
2810 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2811 SPV_REFLECT_ASSERT(false);
2812 return result;
2813 }
2814
2815 // Input and output variables
2816 if (p_var->storage_class == SpvStorageClassInput) {
2817 p_entry->input_variables[input_index] = p_var;
2818 ++input_index;
2819 }
2820 else if (p_node->storage_class == SpvStorageClassOutput) {
2821 p_entry->output_variables[output_index] = p_var;
2822 ++output_index;
2823 }
2824
2825 // SPIR-V result id
2826 p_var->spirv_id = p_node->result_id;
2827 // Name
2828 p_var->name = p_node->name;
2829 // Semantic
2830 p_var->semantic = p_node->decorations.semantic.value;
2831
2832 // Decorate with built-in if any member is built-in
2833 if (has_built_in) {
2834 p_var->decoration_flags |= SPV_REFLECT_DECORATION_BUILT_IN;
2835 }
2836
2837 // Location is decorated on OpVariable node, not the type node.
2838 p_var->location = p_node->decorations.location.value;
2839 p_var->word_offset.location = p_node->decorations.location.word_offset;
2840
2841 // Built in
2842 if (p_node->decorations.is_built_in) {
2843 p_var->built_in = p_node->decorations.built_in;
2844 }
2845 }
2846
2847 return SPV_REFLECT_RESULT_SUCCESS;
2848}
2849
2850static SpvReflectResult EnumerateAllPushConstants(
2851 SpvReflectShaderModule* p_module,
2852 size_t* p_push_constant_count,
2853 uint32_t** p_push_constants
2854)
2855{
2856 *p_push_constant_count = p_module->push_constant_block_count;
2857 if (*p_push_constant_count == 0) {
2858 return SPV_REFLECT_RESULT_SUCCESS;
2859 }
2860 *p_push_constants = (uint32_t*)calloc(*p_push_constant_count, sizeof(**p_push_constants));
2861
2862 if (IsNull(*p_push_constants)) {
2863 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
2864 }
2865
2866 for (size_t i = 0; i < *p_push_constant_count; ++i) {
2867 (*p_push_constants)[i] = p_module->push_constant_blocks[i].spirv_id;
2868 }
2869 qsort(*p_push_constants, *p_push_constant_count, sizeof(**p_push_constants),
2870 SortCompareUint32);
2871 return SPV_REFLECT_RESULT_SUCCESS;
2872}
2873
2874static SpvReflectResult TraverseCallGraph(
2875 SpvReflectPrvParser* p_parser,
2876 SpvReflectPrvFunction* p_func,
2877 size_t* p_func_count,
2878 uint32_t* p_func_ids,
2879 uint32_t depth
2880)
2881{
2882 if (depth > p_parser->function_count) {
2883 // Vulkan does not permit recursion (Vulkan spec Appendix A):
2884 // "Recursion: The static function-call graph for an entry point must not
2885 // contain cycles."
2886 return SPV_REFLECT_RESULT_ERROR_SPIRV_RECURSION;
2887 }
2888 if (IsNotNull(p_func_ids)) {
2889 p_func_ids[(*p_func_count)++] = p_func->id;
2890 } else {
2891 ++*p_func_count;
2892 }
2893 for (size_t i = 0; i < p_func->callee_count; ++i) {
2894 SpvReflectResult result = TraverseCallGraph(
2895 p_parser, p_func->callee_ptrs[i], p_func_count, p_func_ids, depth + 1);
2896 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2897 return result;
2898 }
2899 }
2900 return SPV_REFLECT_RESULT_SUCCESS;
2901}
2902
2903static SpvReflectResult ParseStaticallyUsedResources(
2904 SpvReflectPrvParser* p_parser,
2905 SpvReflectShaderModule* p_module,
2906 SpvReflectEntryPoint* p_entry,
2907 size_t uniform_count,
2908 uint32_t* uniforms,
2909 size_t push_constant_count,
2910 uint32_t* push_constants
2911)
2912{
2913 // Find function with the right id
2914 SpvReflectPrvFunction* p_func = NULL;
2915 for (size_t i = 0; i < p_parser->function_count; ++i) {
2916 if (p_parser->functions[i].id == p_entry->id) {
2917 p_func = &(p_parser->functions[i]);
2918 break;
2919 }
2920 }
2921 if (p_func == NULL) {
2922 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
2923 }
2924
2925 size_t called_function_count = 0;
2926 SpvReflectResult result = TraverseCallGraph(
2927 p_parser,
2928 p_func,
2929 &called_function_count,
2930 NULL,
2931 0);
2932 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2933 return result;
2934 }
2935
2936 uint32_t* p_called_functions = NULL;
2937 if (called_function_count > 0) {
2938 p_called_functions = (uint32_t*)calloc(called_function_count, sizeof(*p_called_functions));
2939 if (IsNull(p_called_functions)) {
2940 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
2941 }
2942 }
2943
2944 called_function_count = 0;
2945 result = TraverseCallGraph(
2946 p_parser,
2947 p_func,
2948 &called_function_count,
2949 p_called_functions,
2950 0);
2951 if (result != SPV_REFLECT_RESULT_SUCCESS) {
2952 return result;
2953 }
2954
2955 if (called_function_count > 0) {
2956 qsort(
2957 p_called_functions,
2958 called_function_count,
2959 sizeof(*p_called_functions),
2960 SortCompareUint32);
2961 }
2962 called_function_count = DedupSortedUint32(p_called_functions, called_function_count);
2963
2964 uint32_t used_variable_count = 0;
2965 for (size_t i = 0, j = 0; i < called_function_count; ++i) {
2966 // No need to bounds check j because a missing ID issue would have been
2967 // found during TraverseCallGraph
2968 while (p_parser->functions[j].id != p_called_functions[i]) {
2969 ++j;
2970 }
2971 used_variable_count += p_parser->functions[j].accessed_ptr_count;
2972 }
2973 uint32_t* used_variables = NULL;
2974 if (used_variable_count > 0) {
2975 used_variables = (uint32_t*)calloc(used_variable_count,
2976 sizeof(*used_variables));
2977 if (IsNull(used_variables)) {
2978 SafeFree(p_called_functions);
2979 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
2980 }
2981 }
2982 used_variable_count = 0;
2983 for (size_t i = 0, j = 0; i < called_function_count; ++i) {
2984 while (p_parser->functions[j].id != p_called_functions[i]) {
2985 ++j;
2986 }
2987
2988 memcpy(&used_variables[used_variable_count],
2989 p_parser->functions[j].accessed_ptrs,
2990 p_parser->functions[j].accessed_ptr_count * sizeof(*used_variables));
2991 used_variable_count += p_parser->functions[j].accessed_ptr_count;
2992 }
2993 SafeFree(p_called_functions);
2994
2995 if (used_variable_count > 0) {
2996 qsort(used_variables, used_variable_count, sizeof(*used_variables),
2997 SortCompareUint32);
2998 }
2999 used_variable_count = (uint32_t)DedupSortedUint32(used_variables,
3000 used_variable_count);
3001
3002 // Do set intersection to find the used uniform and push constants
3003 size_t used_uniform_count = 0;
3004 //
3005 SpvReflectResult result0 = IntersectSortedUint32(
3006 used_variables,
3007 used_variable_count,
3008 uniforms,
3009 uniform_count,
3010 &p_entry->used_uniforms,
3011 &used_uniform_count);
3012
3013 size_t used_push_constant_count = 0;
3014 //
3015 SpvReflectResult result1 = IntersectSortedUint32(
3016 used_variables,
3017 used_variable_count,
3018 push_constants,
3019 push_constant_count,
3020 &p_entry->used_push_constants,
3021 &used_push_constant_count);
3022
3023 for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) {
3024 SpvReflectDescriptorBinding* p_binding = &p_module->descriptor_bindings[j];
3025 bool found = SearchSortedUint32(
3026 used_variables,
3027 used_variable_count,
3028 p_binding->spirv_id);
3029 if (found) {
3030 p_binding->accessed = 1;
3031 }
3032 }
3033
3034 SafeFree(used_variables);
3035 if (result0 != SPV_REFLECT_RESULT_SUCCESS) {
3036 return result0;
3037 }
3038 if (result1 != SPV_REFLECT_RESULT_SUCCESS) {
3039 return result1;
3040 }
3041
3042 p_entry->used_uniform_count = (uint32_t)used_uniform_count;
3043 p_entry->used_push_constant_count = (uint32_t)used_push_constant_count;
3044
3045 return SPV_REFLECT_RESULT_SUCCESS;
3046}
3047
3048static SpvReflectResult ParseEntryPoints(
3049 SpvReflectPrvParser* p_parser,
3050 SpvReflectShaderModule* p_module)
3051{
3052 if (p_parser->entry_point_count == 0) {
3053 return SPV_REFLECT_RESULT_SUCCESS;
3054 }
3055
3056 p_module->entry_point_count = p_parser->entry_point_count;
3057 p_module->entry_points = (SpvReflectEntryPoint*)calloc(p_module->entry_point_count,
3058 sizeof(*(p_module->entry_points)));
3059 if (IsNull(p_module->entry_points)) {
3060 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3061 }
3062
3063 SpvReflectResult result;
3064 size_t uniform_count = 0;
3065 uint32_t* uniforms = NULL;
3066 if ((result = EnumerateAllUniforms(p_module, &uniform_count, &uniforms)) !=
3067 SPV_REFLECT_RESULT_SUCCESS) {
3068 return result;
3069 }
3070 size_t push_constant_count = 0;
3071 uint32_t* push_constants = NULL;
3072 if ((result = EnumerateAllPushConstants(p_module, &push_constant_count, &push_constants)) !=
3073 SPV_REFLECT_RESULT_SUCCESS) {
3074 return result;
3075 }
3076
3077 size_t entry_point_index = 0;
3078 for (size_t i = 0; entry_point_index < p_parser->entry_point_count && i < p_parser->node_count; ++i) {
3079 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
3080 if (p_node->op != SpvOpEntryPoint) {
3081 continue;
3082 }
3083
3084 SpvReflectEntryPoint* p_entry_point = &(p_module->entry_points[entry_point_index]);
3085 CHECKED_READU32_CAST(p_parser, p_node->word_offset + 1, SpvExecutionModel, p_entry_point->spirv_execution_model);
3086 CHECKED_READU32(p_parser, p_node->word_offset + 2, p_entry_point->id);
3087
3088 switch (p_entry_point->spirv_execution_model) {
3089 default: break;
3090 case SpvExecutionModelVertex : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_VERTEX_BIT; break;
3091 case SpvExecutionModelTessellationControl : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_TESSELLATION_CONTROL_BIT; break;
3092 case SpvExecutionModelTessellationEvaluation : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; break;
3093 case SpvExecutionModelGeometry : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_GEOMETRY_BIT; break;
3094 case SpvExecutionModelFragment : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_FRAGMENT_BIT; break;
3095 case SpvExecutionModelGLCompute : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT; break;
3096 case SpvExecutionModelTaskNV : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_TASK_BIT_NV; break;
3097 case SpvExecutionModelMeshNV : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_MESH_BIT_NV; break;
3098 case SpvExecutionModelRayGenerationKHR : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_RAYGEN_BIT_KHR; break;
3099 case SpvExecutionModelIntersectionKHR : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_INTERSECTION_BIT_KHR; break;
3100 case SpvExecutionModelAnyHitKHR : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_ANY_HIT_BIT_KHR; break;
3101 case SpvExecutionModelClosestHitKHR : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; break;
3102 case SpvExecutionModelMissKHR : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_MISS_BIT_KHR; break;
3103 case SpvExecutionModelCallableKHR : p_entry_point->shader_stage = SPV_REFLECT_SHADER_STAGE_CALLABLE_BIT_KHR; break;
3104 }
3105
3106 ++entry_point_index;
3107
3108 // Name length is required to calculate next operand
3109 uint32_t name_start_word_offset = 3;
3110 uint32_t name_length_with_terminator = 0;
3111 result = ReadStr(p_parser, p_node->word_offset + name_start_word_offset, 0, p_node->word_count, &name_length_with_terminator, NULL);
3112 if (result != SPV_REFLECT_RESULT_SUCCESS) {
3113 return result;
3114 }
3115 p_entry_point->name = (const char*)(p_parser->spirv_code + p_node->word_offset + name_start_word_offset);
3116
3117 uint32_t name_word_count = RoundUp(name_length_with_terminator, SPIRV_WORD_SIZE) / SPIRV_WORD_SIZE;
3118 uint32_t interface_variable_count = (p_node->word_count - (name_start_word_offset + name_word_count));
3119 uint32_t* p_interface_variables = NULL;
3120 if (interface_variable_count > 0) {
3121 p_interface_variables = (uint32_t*)calloc(interface_variable_count, sizeof(*(p_interface_variables)));
3122 if (IsNull(p_interface_variables)) {
3123 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3124 }
3125 }
3126
3127 for (uint32_t var_index = 0; var_index < interface_variable_count; ++var_index) {
3128 uint32_t var_result_id = (uint32_t)INVALID_VALUE;
3129 uint32_t offset = name_start_word_offset + name_word_count + var_index;
3130 CHECKED_READU32(p_parser, p_node->word_offset + offset, var_result_id);
3131 p_interface_variables[var_index] = var_result_id;
3132 }
3133
3134 result = ParseInterfaceVariables(
3135 p_parser,
3136 p_module,
3137 p_entry_point,
3138 interface_variable_count,
3139 p_interface_variables);
3140 if (result != SPV_REFLECT_RESULT_SUCCESS) {
3141 return result;
3142 }
3143 SafeFree(p_interface_variables);
3144
3145 result = ParseStaticallyUsedResources(
3146 p_parser,
3147 p_module,
3148 p_entry_point,
3149 uniform_count,
3150 uniforms,
3151 push_constant_count,
3152 push_constants);
3153 if (result != SPV_REFLECT_RESULT_SUCCESS) {
3154 return result;
3155 }
3156 }
3157
3158 SafeFree(uniforms);
3159 SafeFree(push_constants);
3160
3161 return SPV_REFLECT_RESULT_SUCCESS;
3162}
3163
3164static SpvReflectResult ParseExecutionModes(
3165 SpvReflectPrvParser* p_parser,
3166 SpvReflectShaderModule* p_module)
3167{
3168 assert(IsNotNull(p_parser));
3169 assert(IsNotNull(p_parser->nodes));
3170 assert(IsNotNull(p_module));
3171
3172 if (IsNotNull(p_parser) && IsNotNull(p_parser->spirv_code) && IsNotNull(p_parser->nodes)) {
3173 for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) {
3174 SpvReflectPrvNode* p_node = &(p_parser->nodes[node_idx]);
3175 if (p_node->op != SpvOpExecutionMode) {
3176 continue;
3177 }
3178
3179 // Read entry point id
3180 uint32_t entry_point_id = 0;
3181 CHECKED_READU32(p_parser, p_node->word_offset + 1, entry_point_id);
3182
3183 // Find entry point
3184 SpvReflectEntryPoint* p_entry_point = NULL;
3185 for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) {
3186 if (p_module->entry_points[entry_point_idx].id == entry_point_id) {
3187 p_entry_point = &p_module->entry_points[entry_point_idx];
3188 break;
3189 }
3190 }
3191 // Bail if entry point is null
3192 if (IsNull(p_entry_point)) {
3193 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT;
3194 }
3195
3196 // Read execution mode
3197 uint32_t execution_mode = (uint32_t)INVALID_VALUE;
3198 CHECKED_READU32(p_parser, p_node->word_offset + 2, execution_mode);
3199
3200 // Parse execution mode
3201 switch (execution_mode) {
3202 default: {
3203 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_EXECUTION_MODE;
3204 }
3205 break;
3206
3207 case SpvExecutionModeInvocations: {
3208 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->invocations);
3209 }
3210 break;
3211
3212 case SpvExecutionModeSpacingEqual:
3213 case SpvExecutionModeSpacingFractionalEven:
3214 case SpvExecutionModeSpacingFractionalOdd:
3215 case SpvExecutionModeVertexOrderCw:
3216 case SpvExecutionModeVertexOrderCcw:
3217 case SpvExecutionModePixelCenterInteger:
3218 case SpvExecutionModeOriginUpperLeft:
3219 case SpvExecutionModeOriginLowerLeft:
3220 case SpvExecutionModeEarlyFragmentTests:
3221 case SpvExecutionModePointMode:
3222 case SpvExecutionModeXfb:
3223 case SpvExecutionModeDepthReplacing:
3224 case SpvExecutionModeDepthGreater:
3225 case SpvExecutionModeDepthLess:
3226 case SpvExecutionModeDepthUnchanged:
3227 break;
3228
3229 case SpvExecutionModeLocalSize: {
3230 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->local_size.x);
3231 CHECKED_READU32(p_parser, p_node->word_offset + 4, p_entry_point->local_size.y);
3232 CHECKED_READU32(p_parser, p_node->word_offset + 5, p_entry_point->local_size.z);
3233 }
3234 break;
3235
3236 case SpvExecutionModeLocalSizeHint:
3237 case SpvExecutionModeInputPoints:
3238 case SpvExecutionModeInputLines:
3239 case SpvExecutionModeInputLinesAdjacency:
3240 case SpvExecutionModeTriangles:
3241 case SpvExecutionModeInputTrianglesAdjacency:
3242 case SpvExecutionModeQuads:
3243 case SpvExecutionModeIsolines:
3244 case SpvExecutionModeOutputVertices: {
3245 CHECKED_READU32(p_parser, p_node->word_offset + 3, p_entry_point->output_vertices);
3246 }
3247 break;
3248
3249 case SpvExecutionModeOutputPoints:
3250 case SpvExecutionModeOutputLineStrip:
3251 case SpvExecutionModeOutputTriangleStrip:
3252 case SpvExecutionModeVecTypeHint:
3253 case SpvExecutionModeContractionOff:
3254 case SpvExecutionModeInitializer:
3255 case SpvExecutionModeFinalizer:
3256 case SpvExecutionModeSubgroupSize:
3257 case SpvExecutionModeSubgroupsPerWorkgroup:
3258 case SpvExecutionModeSubgroupsPerWorkgroupId:
3259 case SpvExecutionModeLocalSizeId:
3260 case SpvExecutionModeLocalSizeHintId:
3261 case SpvExecutionModePostDepthCoverage:
3262 case SpvExecutionModeStencilRefReplacingEXT:
3263 case SpvExecutionModeOutputPrimitivesNV:
3264 case SpvExecutionModeOutputTrianglesNV:
3265 break;
3266 }
3267 }
3268 }
3269 return SPV_REFLECT_RESULT_SUCCESS;
3270}
3271
3272static SpvReflectResult ParsePushConstantBlocks(
3273 SpvReflectPrvParser* p_parser,
3274 SpvReflectShaderModule* p_module)
3275{
3276 for (size_t i = 0; i < p_parser->node_count; ++i) {
3277 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
3278 if ((p_node->op != SpvOpVariable) || (p_node->storage_class != SpvStorageClassPushConstant)) {
3279 continue;
3280 }
3281
3282 p_module->push_constant_block_count += 1;
3283 }
3284
3285 if (p_module->push_constant_block_count == 0) {
3286 return SPV_REFLECT_RESULT_SUCCESS;
3287 }
3288
3289 p_module->push_constant_blocks = (SpvReflectBlockVariable*)calloc(p_module->push_constant_block_count, sizeof(*p_module->push_constant_blocks));
3290 if (IsNull(p_module->push_constant_blocks)) {
3291 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3292 }
3293
3294 uint32_t push_constant_index = 0;
3295 for (size_t i = 0; i < p_parser->node_count; ++i) {
3296 SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
3297 if ((p_node->op != SpvOpVariable) || (p_node->storage_class != SpvStorageClassPushConstant)) {
3298 continue;
3299 }
3300
3301 SpvReflectTypeDescription* p_type = FindType(p_module, p_node->type_id);
3302 if (IsNull(p_node)) {
3303 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
3304 }
3305 // If the type is a pointer, resolve it
3306 if (p_type->op == SpvOpTypePointer) {
3307 // Find the type's node
3308 SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
3309 if (IsNull(p_type_node)) {
3310 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
3311 }
3312 // Should be the resolved type
3313 p_type = FindType(p_module, p_type_node->type_id);
3314 if (IsNull(p_type)) {
3315 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
3316 }
3317 }
3318
3319 SpvReflectPrvNode* p_type_node = FindNode(p_parser, p_type->id);
3320 if (IsNull(p_type_node)) {
3321 return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
3322 }
3323
3324 SpvReflectBlockVariable* p_push_constant = &p_module->push_constant_blocks[push_constant_index];
3325 p_push_constant->spirv_id = p_node->result_id;
3326 SpvReflectResult result = ParseDescriptorBlockVariable(p_parser, p_module, p_type, p_push_constant);
3327 if (result != SPV_REFLECT_RESULT_SUCCESS) {
3328 return result;
3329 }
3330 result = ParseDescriptorBlockVariableSizes(p_parser, p_module, true, false, false, p_push_constant);
3331 if (result != SPV_REFLECT_RESULT_SUCCESS) {
3332 return result;
3333 }
3334
3335 ++push_constant_index;
3336 }
3337
3338 return SPV_REFLECT_RESULT_SUCCESS;
3339}
3340
3341static int SortCompareDescriptorSet(const void* a, const void* b)
3342{
3343 const SpvReflectDescriptorSet* p_elem_a = (const SpvReflectDescriptorSet*)a;
3344 const SpvReflectDescriptorSet* p_elem_b = (const SpvReflectDescriptorSet*)b;
3345 int value = (int)(p_elem_a->set) - (int)(p_elem_b->set);
3346 // We should never see duplicate descriptor set numbers in a shader; if so, a tiebreaker
3347 // would be needed here.
3348 assert(value != 0);
3349 return value;
3350}
3351
3352static SpvReflectResult ParseEntrypointDescriptorSets(SpvReflectShaderModule* p_module) {
3353 // Update the entry point's sets
3354 for (uint32_t i = 0; i < p_module->entry_point_count; ++i) {
3355 SpvReflectEntryPoint* p_entry = &p_module->entry_points[i];
3356 for (uint32_t j = 0; j < p_entry->descriptor_set_count; ++j) {
3357 SafeFree(p_entry->descriptor_sets[j].bindings);
3358 }
3359 SafeFree(p_entry->descriptor_sets);
3360 p_entry->descriptor_set_count = 0;
3361 for (uint32_t j = 0; j < p_module->descriptor_set_count; ++j) {
3362 const SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[j];
3363 for (uint32_t k = 0; k < p_set->binding_count; ++k) {
3364 bool found = SearchSortedUint32(
3365 p_entry->used_uniforms,
3366 p_entry->used_uniform_count,
3367 p_set->bindings[k]->spirv_id);
3368 if (found) {
3369 ++p_entry->descriptor_set_count;
3370 break;
3371 }
3372 }
3373 }
3374
3375 p_entry->descriptor_sets = NULL;
3376 if (p_entry->descriptor_set_count > 0) {
3377 p_entry->descriptor_sets = (SpvReflectDescriptorSet*)calloc(p_entry->descriptor_set_count,
3378 sizeof(*p_entry->descriptor_sets));
3379 if (IsNull(p_entry->descriptor_sets)) {
3380 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3381 }
3382 }
3383 p_entry->descriptor_set_count = 0;
3384 for (uint32_t j = 0; j < p_module->descriptor_set_count; ++j) {
3385 const SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[j];
3386 uint32_t count = 0;
3387 for (uint32_t k = 0; k < p_set->binding_count; ++k) {
3388 bool found = SearchSortedUint32(
3389 p_entry->used_uniforms,
3390 p_entry->used_uniform_count,
3391 p_set->bindings[k]->spirv_id);
3392 if (found) {
3393 ++count;
3394 }
3395 }
3396 if (count == 0) {
3397 continue;
3398 }
3399 SpvReflectDescriptorSet* p_entry_set = &p_entry->descriptor_sets[
3400 p_entry->descriptor_set_count++];
3401 p_entry_set->set = p_set->set;
3402 p_entry_set->bindings = (SpvReflectDescriptorBinding**)calloc(count,
3403 sizeof(*p_entry_set->bindings));
3404 if (IsNull(p_entry_set->bindings)) {
3405 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3406 }
3407 for (uint32_t k = 0; k < p_set->binding_count; ++k) {
3408 bool found = SearchSortedUint32(
3409 p_entry->used_uniforms,
3410 p_entry->used_uniform_count,
3411 p_set->bindings[k]->spirv_id);
3412 if (found) {
3413 p_entry_set->bindings[p_entry_set->binding_count++] = p_set->bindings[k];
3414 }
3415 }
3416 }
3417 }
3418
3419 return SPV_REFLECT_RESULT_SUCCESS;
3420}
3421
3422static SpvReflectResult ParseDescriptorSets(SpvReflectShaderModule* p_module)
3423{
3424 // Count the descriptors in each set
3425 for (uint32_t i = 0; i < p_module->descriptor_binding_count; ++i) {
3426 SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[i]);
3427
3428 // Look for a target set using the descriptor's set number
3429 SpvReflectDescriptorSet* p_target_set = NULL;
3430 for (uint32_t j = 0; j < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++j) {
3431 SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[j];
3432 if (p_set->set == p_descriptor->set) {
3433 p_target_set = p_set;
3434 break;
3435 }
3436 }
3437
3438 // If a target set isn't found, find the first available one.
3439 if (IsNull(p_target_set)) {
3440 for (uint32_t j = 0; j < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++j) {
3441 SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[j];
3442 if (p_set->set == (uint32_t)INVALID_VALUE) {
3443 p_target_set = p_set;
3444 p_target_set->set = p_descriptor->set;
3445 break;
3446 }
3447 }
3448 }
3449
3450 if (IsNull(p_target_set)) {
3451 return SPV_REFLECT_RESULT_ERROR_INTERNAL_ERROR;
3452 }
3453
3454 p_target_set->binding_count += 1;
3455 }
3456
3457 // Count the descriptor sets
3458 for (uint32_t i = 0; i < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++i) {
3459 const SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[i];
3460 if (p_set->set != (uint32_t)INVALID_VALUE) {
3461 p_module->descriptor_set_count += 1;
3462 }
3463 }
3464
3465 // Sort the descriptor sets based on numbers
3466 if (p_module->descriptor_set_count > 0) {
3467 qsort(p_module->descriptor_sets,
3468 p_module->descriptor_set_count,
3469 sizeof(*(p_module->descriptor_sets)),
3470 SortCompareDescriptorSet);
3471 }
3472
3473 // Build descriptor pointer array
3474 for (uint32_t i = 0; i <p_module->descriptor_set_count; ++i) {
3475 SpvReflectDescriptorSet* p_set = &(p_module->descriptor_sets[i]);
3476 p_set->bindings = (SpvReflectDescriptorBinding **)calloc(p_set->binding_count, sizeof(*(p_set->bindings)));
3477
3478 uint32_t descriptor_index = 0;
3479 for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) {
3480 SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[j]);
3481 if (p_descriptor->set == p_set->set) {
3482 assert(descriptor_index < p_set->binding_count);
3483 p_set->bindings[descriptor_index] = p_descriptor;
3484 ++descriptor_index;
3485 }
3486 }
3487 }
3488
3489 return ParseEntrypointDescriptorSets(p_module);
3490}
3491
3492static SpvReflectResult DisambiguateStorageBufferSrvUav(SpvReflectShaderModule* p_module)
3493{
3494 if (p_module->descriptor_binding_count == 0) {
3495 return SPV_REFLECT_RESULT_SUCCESS;
3496 }
3497
3498 for (uint32_t descriptor_index = 0; descriptor_index < p_module->descriptor_binding_count; ++descriptor_index) {
3499 SpvReflectDescriptorBinding* p_descriptor = &(p_module->descriptor_bindings[descriptor_index]);
3500 // Skip everything that isn't a STORAGE_BUFFER descriptor
3501 if (p_descriptor->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
3502 continue;
3503 }
3504
3505 //
3506 // Vulkan doesn't disambiguate between SRVs and UAVs so they
3507 // come back as STORAGE_BUFFER. The block parsing process will
3508 // mark a block as non-writable should any member of the block
3509 // or its descendants are non-writable.
3510 //
3511 if (p_descriptor->block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) {
3512 p_descriptor->resource_type = SPV_REFLECT_RESOURCE_FLAG_SRV;
3513 }
3514 }
3515
3516 return SPV_REFLECT_RESULT_SUCCESS;
3517}
3518
3519static SpvReflectResult SynchronizeDescriptorSets(SpvReflectShaderModule* p_module)
3520{
3521 // Free and reset all descriptor set numbers
3522 for (uint32_t i = 0; i < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++i) {
3523 SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[i];
3524 SafeFree(p_set->bindings);
3525 p_set->binding_count = 0;
3526 p_set->set = (uint32_t)INVALID_VALUE;
3527 }
3528 // Set descriptor set count to zero
3529 p_module->descriptor_set_count = 0;
3530
3531 SpvReflectResult result = ParseDescriptorSets(p_module);
3532 return result;
3533}
3534
3535static SpvReflectResult CreateShaderModule(
3536 uint32_t flags,
3537 size_t size,
3538 const void* p_code,
3539 SpvReflectShaderModule* p_module
3540)
3541{
3542 // Initialize all module fields to zero
3543 memset(p_module, 0, sizeof(*p_module));
3544
3545 // Allocate module internals
3546#ifdef __cplusplus
3547 p_module->_internal = (SpvReflectShaderModule::Internal*)calloc(1, sizeof(*(p_module->_internal)));
3548#else
3549 p_module->_internal = calloc(1, sizeof(*(p_module->_internal)));
3550#endif
3551 if (IsNull(p_module->_internal)) {
3552 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3553 }
3554 // Copy flags
3555 p_module->_internal->module_flags = flags;
3556 // Figure out if we need to copy the SPIR-V code or not
3557 if (flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) {
3558 // Set internal size and pointer to args passed in
3559 p_module->_internal->spirv_size = size;
3560 p_module->_internal->spirv_code = (void*)p_code; // cast that const away
3561 p_module->_internal->spirv_word_count = (uint32_t)(size / SPIRV_WORD_SIZE);
3562 }
3563 else {
3564 // Allocate SPIR-V code storage
3565 p_module->_internal->spirv_size = size;
3566 p_module->_internal->spirv_code = (uint32_t*)calloc(1, p_module->_internal->spirv_size);
3567 p_module->_internal->spirv_word_count = (uint32_t)(size / SPIRV_WORD_SIZE);
3568 if (IsNull(p_module->_internal->spirv_code)) {
3569 SafeFree(p_module->_internal);
3570 return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3571 }
3572 // Copy SPIR-V to code storage
3573 memcpy(p_module->_internal->spirv_code, p_code, size);
3574 }
3575
3576 SpvReflectPrvParser parser = { 0 };
3577 SpvReflectResult result = CreateParser(p_module->_internal->spirv_size,
3578 p_module->_internal->spirv_code,
3579 &parser);
3580
3581 // Generator
3582 {
3583 const uint32_t* p_ptr = (const uint32_t*)p_module->_internal->spirv_code;
3584 p_module->generator = (SpvReflectGenerator)((*(p_ptr + 2) & 0xFFFF0000) >> 16);
3585 }
3586
3587 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3588 result = ParseNodes(&parser);
3589 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3590 }
3591 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3592 result = ParseStrings(&parser);
3593 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3594 }
3595 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3596 result = ParseSource(&parser, p_module);
3597 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3598 }
3599 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3600 result = ParseFunctions(&parser);
3601 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3602 }
3603 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3604 result = ParseMemberCounts(&parser);
3605 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3606 }
3607 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3608 result = ParseNames(&parser);
3609 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3610 }
3611 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3612 result = ParseDecorations(&parser);
3613 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3614 }
3615
3616 // Start of reflection data parsing
3617 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3618 p_module->source_language = parser.source_language;
3619 p_module->source_language_version = parser.source_language_version;
3620
3621 // Zero out descriptor set data
3622 p_module->descriptor_set_count = 0;
3623 memset(p_module->descriptor_sets, 0, SPV_REFLECT_MAX_DESCRIPTOR_SETS * sizeof(*p_module->descriptor_sets));
3624 // Initialize descriptor set numbers
3625 for (uint32_t set_number = 0; set_number < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++set_number) {
3626 p_module->descriptor_sets[set_number].set = (uint32_t)INVALID_VALUE;
3627 }
3628 }
3629 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3630 result = ParseTypes(&parser, p_module);
3631 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3632 }
3633 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3634 result = ParseDescriptorBindings(&parser, p_module);
3635 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3636 }
3637 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3638 result = ParseDescriptorType(p_module);
3639 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3640 }
3641 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3642 result = ParseUAVCounterBindings(p_module);
3643 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3644 }
3645 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3646 result = ParseDescriptorBlocks(&parser, p_module);
3647 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3648 }
3649 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3650 result = ParsePushConstantBlocks(&parser, p_module);
3651 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3652 }
3653 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3654 result = ParseEntryPoints(&parser, p_module);
3655 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3656 }
3657 if (result == SPV_REFLECT_RESULT_SUCCESS && p_module->entry_point_count > 0) {
3658 SpvReflectEntryPoint* p_entry = &(p_module->entry_points[0]);
3659 p_module->entry_point_name = p_entry->name;
3660 p_module->entry_point_id = p_entry->id;
3661 p_module->spirv_execution_model = p_entry->spirv_execution_model;
3662 p_module->shader_stage = p_entry->shader_stage;
3663 p_module->input_variable_count = p_entry->input_variable_count;
3664 p_module->input_variables = p_entry->input_variables;
3665 p_module->output_variable_count = p_entry->output_variable_count;
3666 p_module->output_variables = p_entry->output_variables;
3667 p_module->interface_variable_count = p_entry->interface_variable_count;
3668 p_module->interface_variables = p_entry->interface_variables;
3669 }
3670 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3671 result = DisambiguateStorageBufferSrvUav(p_module);
3672 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3673 }
3674 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3675 result = SynchronizeDescriptorSets(p_module);
3676 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3677 }
3678 if (result == SPV_REFLECT_RESULT_SUCCESS) {
3679 result = ParseExecutionModes(&parser, p_module);
3680 SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
3681 }
3682
3683 // Destroy module if parse was not successful
3684 if (result != SPV_REFLECT_RESULT_SUCCESS) {
3685 spvReflectDestroyShaderModule(p_module);
3686 }
3687
3688 DestroyParser(&parser);
3689
3690 return result;
3691}
3692
3693SpvReflectResult spvReflectCreateShaderModule(
3694 size_t size,
3695 const void* p_code,
3696 SpvReflectShaderModule* p_module
3697)
3698{
3699 return CreateShaderModule(0, size, p_code, p_module);
3700}
3701
3702SpvReflectResult spvReflectCreateShaderModule2(
3703 uint32_t flags,
3704 size_t size,
3705 const void* p_code,
3706 SpvReflectShaderModule* p_module
3707)
3708{
3709 return CreateShaderModule(flags, size, p_code, p_module);
3710}
3711
3712SpvReflectResult spvReflectGetShaderModule(
3713 size_t size,
3714 const void* p_code,
3715 SpvReflectShaderModule* p_module
3716)
3717{
3718 return spvReflectCreateShaderModule(size, p_code, p_module);
3719}
3720
3721static void SafeFreeTypes(SpvReflectTypeDescription* p_type)
3722{
3723 if (IsNull(p_type)) {
3724 return;
3725 }
3726
3727 if (IsNotNull(p_type->members)) {
3728 for (size_t i = 0; i < p_type->member_count; ++i) {
3729 SpvReflectTypeDescription* p_member = &p_type->members[i];
3730 SafeFreeTypes(p_member);
3731 }
3732
3733 SafeFree(p_type->members);
3734 p_type->members = NULL;
3735 }
3736}
3737
3738static void SafeFreeBlockVariables(SpvReflectBlockVariable* p_block)
3739{
3740 if (IsNull(p_block)) {
3741 return;
3742 }
3743
3744 if (IsNotNull(p_block->members)) {
3745 for (size_t i = 0; i < p_block->member_count; ++i) {
3746 SpvReflectBlockVariable* p_member = &p_block->members[i];
3747 SafeFreeBlockVariables(p_member);
3748 }
3749
3750 SafeFree(p_block->members);
3751 p_block->members = NULL;
3752 }
3753}
3754
3755static void SafeFreeInterfaceVariable(SpvReflectInterfaceVariable* p_interface)
3756{
3757 if (IsNull(p_interface)) {
3758 return;
3759 }
3760
3761 if (IsNotNull(p_interface->members)) {
3762 for (size_t i = 0; i < p_interface->member_count; ++i) {
3763 SpvReflectInterfaceVariable* p_member = &p_interface->members[i];
3764 SafeFreeInterfaceVariable(p_member);
3765 }
3766
3767 SafeFree(p_interface->members);
3768 p_interface->members = NULL;
3769 }
3770}
3771
3772void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module)
3773{
3774 if (IsNull(p_module->_internal)) {
3775 return;
3776 }
3777
3778 SafeFree(p_module->source_source);
3779
3780 // Descriptor set bindings
3781 for (size_t i = 0; i < p_module->descriptor_set_count; ++i) {
3782 SpvReflectDescriptorSet* p_set = &p_module->descriptor_sets[i];
3783 free(p_set->bindings);
3784 }
3785
3786 // Descriptor binding blocks
3787 for (size_t i = 0; i < p_module->descriptor_binding_count; ++i) {
3788 SpvReflectDescriptorBinding* p_descriptor = &p_module->descriptor_bindings[i];
3789 SafeFreeBlockVariables(&p_descriptor->block);
3790 }
3791 SafeFree(p_module->descriptor_bindings);
3792
3793 // Entry points
3794 for (size_t i = 0; i < p_module->entry_point_count; ++i) {
3795 SpvReflectEntryPoint* p_entry = &p_module->entry_points[i];
3796 for (size_t j = 0; j < p_entry->interface_variable_count; j++) {
3797 SafeFreeInterfaceVariable(&p_entry->interface_variables[j]);
3798 }
3799 for (uint32_t j = 0; j < p_entry->descriptor_set_count; ++j) {
3800 SafeFree(p_entry->descriptor_sets[j].bindings);
3801 }
3802 SafeFree(p_entry->descriptor_sets);
3803 SafeFree(p_entry->input_variables);
3804 SafeFree(p_entry->output_variables);
3805 SafeFree(p_entry->interface_variables);
3806 SafeFree(p_entry->used_uniforms);
3807 SafeFree(p_entry->used_push_constants);
3808 }
3809 SafeFree(p_module->entry_points);
3810
3811 // Push constants
3812 for (size_t i = 0; i < p_module->push_constant_block_count; ++i) {
3813 SafeFreeBlockVariables(&p_module->push_constant_blocks[i]);
3814 }
3815 SafeFree(p_module->push_constant_blocks);
3816
3817 // Type infos
3818 for (size_t i = 0; i < p_module->_internal->type_description_count; ++i) {
3819 SpvReflectTypeDescription* p_type = &p_module->_internal->type_descriptions[i];
3820 if (IsNotNull(p_type->members)) {
3821 SafeFreeTypes(p_type);
3822 }
3823 SafeFree(p_type->members);
3824 }
3825 SafeFree(p_module->_internal->type_descriptions);
3826
3827 // Free SPIR-V code if there was a copy
3828 if ((p_module->_internal->module_flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) == 0) {
3829 SafeFree(p_module->_internal->spirv_code);
3830 }
3831 // Free internal
3832 SafeFree(p_module->_internal);
3833}
3834
3835uint32_t spvReflectGetCodeSize(const SpvReflectShaderModule* p_module)
3836{
3837 if (IsNull(p_module)) {
3838 return 0;
3839 }
3840
3841 return (uint32_t)(p_module->_internal->spirv_size);
3842}
3843
3844const uint32_t* spvReflectGetCode(const SpvReflectShaderModule* p_module)
3845{
3846 if (IsNull(p_module)) {
3847 return NULL;
3848 }
3849
3850 return p_module->_internal->spirv_code;
3851}
3852
3853const SpvReflectEntryPoint* spvReflectGetEntryPoint(
3854 const SpvReflectShaderModule* p_module,
3855 const char* entry_point
3856) {
3857 if (IsNull(p_module) || IsNull(entry_point)) {
3858 return NULL;
3859 }
3860
3861 for (uint32_t i = 0; i < p_module->entry_point_count; ++i) {
3862 if (strcmp(p_module->entry_points[i].name, entry_point) == 0) {
3863 return &p_module->entry_points[i];
3864 }
3865 }
3866 return NULL;
3867}
3868
3869SpvReflectResult spvReflectEnumerateDescriptorBindings(
3870 const SpvReflectShaderModule* p_module,
3871 uint32_t* p_count,
3872 SpvReflectDescriptorBinding** pp_bindings
3873)
3874{
3875 if (IsNull(p_module)) {
3876 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
3877 }
3878 if (IsNull(p_count)) {
3879 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
3880 }
3881
3882 if (IsNotNull(pp_bindings)) {
3883 if (*p_count != p_module->descriptor_binding_count) {
3884 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
3885 }
3886
3887 for (uint32_t index = 0; index < *p_count; ++index) {
3888 SpvReflectDescriptorBinding* p_bindings = (SpvReflectDescriptorBinding*)&p_module->descriptor_bindings[index];
3889 pp_bindings[index] = p_bindings;
3890 }
3891 }
3892 else {
3893 *p_count = p_module->descriptor_binding_count;
3894 }
3895
3896 return SPV_REFLECT_RESULT_SUCCESS;
3897}
3898
3899SpvReflectResult spvReflectEnumerateEntryPointDescriptorBindings(
3900 const SpvReflectShaderModule* p_module,
3901 const char* entry_point,
3902 uint32_t* p_count,
3903 SpvReflectDescriptorBinding** pp_bindings
3904)
3905{
3906 if (IsNull(p_module)) {
3907 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
3908 }
3909 if (IsNull(p_count)) {
3910 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
3911 }
3912
3913 const SpvReflectEntryPoint* p_entry =
3914 spvReflectGetEntryPoint(p_module, entry_point);
3915 if (IsNull(p_entry)) {
3916 return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
3917 }
3918
3919 uint32_t count = 0;
3920 for (uint32_t i = 0; i < p_module->descriptor_binding_count; ++i) {
3921 bool found = SearchSortedUint32(
3922 p_entry->used_uniforms,
3923 p_entry->used_uniform_count,
3924 p_module->descriptor_bindings[i].spirv_id);
3925 if (found) {
3926 if (IsNotNull(pp_bindings)) {
3927 if (count >= *p_count) {
3928 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
3929 }
3930 pp_bindings[count++] = (SpvReflectDescriptorBinding*)&p_module->descriptor_bindings[i];
3931 } else {
3932 ++count;
3933 }
3934 }
3935 }
3936 if (IsNotNull(pp_bindings)) {
3937 if (count != *p_count) {
3938 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
3939 }
3940 } else {
3941 *p_count = count;
3942 }
3943 return SPV_REFLECT_RESULT_SUCCESS;
3944}
3945
3946SpvReflectResult spvReflectEnumerateDescriptorSets(
3947 const SpvReflectShaderModule* p_module,
3948 uint32_t* p_count,
3949 SpvReflectDescriptorSet** pp_sets
3950)
3951{
3952 if (IsNull(p_module)) {
3953 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
3954 }
3955 if (IsNull(p_count)) {
3956 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
3957 }
3958
3959 if (IsNotNull(pp_sets)) {
3960 if (*p_count != p_module->descriptor_set_count) {
3961 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
3962 }
3963
3964 for (uint32_t index = 0; index < *p_count; ++index) {
3965 SpvReflectDescriptorSet* p_set = (SpvReflectDescriptorSet*)&p_module->descriptor_sets[index];
3966 pp_sets[index] = p_set;
3967 }
3968 }
3969 else {
3970 *p_count = p_module->descriptor_set_count;
3971 }
3972
3973 return SPV_REFLECT_RESULT_SUCCESS;
3974}
3975
3976SpvReflectResult spvReflectEnumerateEntryPointDescriptorSets(
3977 const SpvReflectShaderModule* p_module,
3978 const char* entry_point,
3979 uint32_t* p_count,
3980 SpvReflectDescriptorSet** pp_sets
3981)
3982{
3983 if (IsNull(p_module)) {
3984 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
3985 }
3986 if (IsNull(p_count)) {
3987 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
3988 }
3989
3990 const SpvReflectEntryPoint* p_entry =
3991 spvReflectGetEntryPoint(p_module, entry_point);
3992 if (IsNull(p_entry)) {
3993 return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
3994 }
3995
3996 if (IsNotNull(pp_sets)) {
3997 if (*p_count != p_entry->descriptor_set_count) {
3998 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
3999 }
4000
4001 for (uint32_t index = 0; index < *p_count; ++index) {
4002 SpvReflectDescriptorSet* p_set = (SpvReflectDescriptorSet*)&p_entry->descriptor_sets[index];
4003 pp_sets[index] = p_set;
4004 }
4005 }
4006 else {
4007 *p_count = p_entry->descriptor_set_count;
4008 }
4009
4010 return SPV_REFLECT_RESULT_SUCCESS;
4011}
4012
4013SpvReflectResult spvReflectEnumerateInterfaceVariables(
4014 const SpvReflectShaderModule* p_module,
4015 uint32_t* p_count,
4016 SpvReflectInterfaceVariable** pp_variables
4017)
4018{
4019 if (IsNull(p_module)) {
4020 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4021 }
4022 if (IsNull(p_count)) {
4023 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4024 }
4025
4026 if (IsNotNull(pp_variables)) {
4027 if (*p_count != p_module->interface_variable_count) {
4028 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4029 }
4030
4031 for (uint32_t index = 0; index < *p_count; ++index) {
4032 SpvReflectInterfaceVariable* p_var = &p_module->interface_variables[index];
4033 pp_variables[index] = p_var;
4034 }
4035 }
4036 else {
4037 *p_count = p_module->interface_variable_count;
4038 }
4039
4040 return SPV_REFLECT_RESULT_SUCCESS;
4041}
4042
4043SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables(
4044 const SpvReflectShaderModule* p_module,
4045 const char* entry_point,
4046 uint32_t* p_count,
4047 SpvReflectInterfaceVariable** pp_variables
4048)
4049{
4050 if (IsNull(p_module)) {
4051 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4052 }
4053 if (IsNull(p_count)) {
4054 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4055 }
4056
4057 const SpvReflectEntryPoint* p_entry =
4058 spvReflectGetEntryPoint(p_module, entry_point);
4059 if (IsNull(p_entry)) {
4060 return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4061 }
4062
4063 if (IsNotNull(pp_variables)) {
4064 if (*p_count != p_entry->interface_variable_count) {
4065 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4066 }
4067
4068 for (uint32_t index = 0; index < *p_count; ++index) {
4069 SpvReflectInterfaceVariable* p_var = &p_entry->interface_variables[index];
4070 pp_variables[index] = p_var;
4071 }
4072 }
4073 else {
4074 *p_count = p_entry->interface_variable_count;
4075 }
4076
4077 return SPV_REFLECT_RESULT_SUCCESS;
4078}
4079
4080SpvReflectResult spvReflectEnumerateInputVariables(
4081 const SpvReflectShaderModule* p_module,
4082 uint32_t* p_count,
4083 SpvReflectInterfaceVariable** pp_variables
4084)
4085{
4086 if (IsNull(p_module)) {
4087 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4088 }
4089 if (IsNull(p_count)) {
4090 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4091 }
4092
4093 if (IsNotNull(pp_variables)) {
4094 if (*p_count != p_module->input_variable_count) {
4095 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4096 }
4097
4098 for (uint32_t index = 0; index < *p_count; ++index) {
4099 SpvReflectInterfaceVariable* p_var = p_module->input_variables[index];
4100 pp_variables[index] = p_var;
4101 }
4102 }
4103 else {
4104 *p_count = p_module->input_variable_count;
4105 }
4106
4107 return SPV_REFLECT_RESULT_SUCCESS;
4108}
4109
4110SpvReflectResult spvReflectEnumerateEntryPointInputVariables(
4111 const SpvReflectShaderModule* p_module,
4112 const char* entry_point,
4113 uint32_t* p_count,
4114 SpvReflectInterfaceVariable** pp_variables
4115)
4116{
4117 if (IsNull(p_module)) {
4118 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4119 }
4120 if (IsNull(p_count)) {
4121 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4122 }
4123
4124 const SpvReflectEntryPoint* p_entry =
4125 spvReflectGetEntryPoint(p_module, entry_point);
4126 if (IsNull(p_entry)) {
4127 return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4128 }
4129
4130 if (IsNotNull(pp_variables)) {
4131 if (*p_count != p_entry->input_variable_count) {
4132 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4133 }
4134
4135 for (uint32_t index = 0; index < *p_count; ++index) {
4136 SpvReflectInterfaceVariable* p_var = p_entry->input_variables[index];
4137 pp_variables[index] = p_var;
4138 }
4139 }
4140 else {
4141 *p_count = p_entry->input_variable_count;
4142 }
4143
4144 return SPV_REFLECT_RESULT_SUCCESS;
4145}
4146
4147SpvReflectResult spvReflectEnumerateOutputVariables(
4148 const SpvReflectShaderModule* p_module,
4149 uint32_t* p_count,
4150 SpvReflectInterfaceVariable** pp_variables
4151)
4152{
4153 if (IsNull(p_module)) {
4154 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4155 }
4156 if (IsNull(p_count)) {
4157 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4158 }
4159
4160 if (IsNotNull(pp_variables)) {
4161 if (*p_count != p_module->output_variable_count) {
4162 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4163 }
4164
4165 for (uint32_t index = 0; index < *p_count; ++index) {
4166 SpvReflectInterfaceVariable* p_var = p_module->output_variables[index];
4167 pp_variables[index] = p_var;
4168 }
4169 }
4170 else {
4171 *p_count = p_module->output_variable_count;
4172 }
4173
4174 return SPV_REFLECT_RESULT_SUCCESS;
4175}
4176
4177SpvReflectResult spvReflectEnumerateEntryPointOutputVariables(
4178 const SpvReflectShaderModule* p_module,
4179 const char* entry_point,
4180 uint32_t* p_count,
4181 SpvReflectInterfaceVariable** pp_variables
4182)
4183{
4184 if (IsNull(p_module)) {
4185 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4186 }
4187 if (IsNull(p_count)) {
4188 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4189 }
4190
4191 const SpvReflectEntryPoint* p_entry =
4192 spvReflectGetEntryPoint(p_module, entry_point);
4193 if (IsNull(p_entry)) {
4194 return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4195 }
4196
4197 if (IsNotNull(pp_variables)) {
4198 if (*p_count != p_entry->output_variable_count) {
4199 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4200 }
4201
4202 for (uint32_t index = 0; index < *p_count; ++index) {
4203 SpvReflectInterfaceVariable* p_var = p_entry->output_variables[index];
4204 pp_variables[index] = p_var;
4205 }
4206 }
4207 else {
4208 *p_count = p_entry->output_variable_count;
4209 }
4210
4211 return SPV_REFLECT_RESULT_SUCCESS;
4212}
4213
4214SpvReflectResult spvReflectEnumeratePushConstantBlocks(
4215 const SpvReflectShaderModule* p_module,
4216 uint32_t* p_count,
4217 SpvReflectBlockVariable** pp_blocks
4218)
4219{
4220 if (IsNull(p_module)) {
4221 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4222 }
4223 if (IsNull(p_count)) {
4224 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4225 }
4226
4227 if (pp_blocks != NULL) {
4228 if (*p_count != p_module->push_constant_block_count) {
4229 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4230 }
4231
4232 for (uint32_t index = 0; index < *p_count; ++index) {
4233 SpvReflectBlockVariable* p_push_constant_blocks = (SpvReflectBlockVariable*)&p_module->push_constant_blocks[index];
4234 pp_blocks[index] = p_push_constant_blocks;
4235 }
4236 }
4237 else {
4238 *p_count = p_module->push_constant_block_count;
4239 }
4240
4241 return SPV_REFLECT_RESULT_SUCCESS;
4242}
4243SpvReflectResult spvReflectEnumeratePushConstants(
4244 const SpvReflectShaderModule* p_module,
4245 uint32_t* p_count,
4246 SpvReflectBlockVariable** pp_blocks
4247)
4248{
4249 return spvReflectEnumeratePushConstantBlocks(p_module, p_count, pp_blocks);
4250}
4251
4252SpvReflectResult spvReflectEnumerateEntryPointPushConstantBlocks(
4253 const SpvReflectShaderModule* p_module,
4254 const char* entry_point,
4255 uint32_t* p_count,
4256 SpvReflectBlockVariable** pp_blocks
4257)
4258{
4259 if (IsNull(p_module)) {
4260 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4261 }
4262 if (IsNull(p_count)) {
4263 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4264 }
4265
4266
4267 const SpvReflectEntryPoint* p_entry =
4268 spvReflectGetEntryPoint(p_module, entry_point);
4269 if (IsNull(p_entry)) {
4270 return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4271 }
4272
4273 uint32_t count = 0;
4274 for (uint32_t i = 0; i < p_module->push_constant_block_count; ++i) {
4275 bool found = SearchSortedUint32(p_entry->used_push_constants,
4276 p_entry->used_push_constant_count,
4277 p_module->push_constant_blocks[i].spirv_id);
4278 if (found) {
4279 if (IsNotNull(pp_blocks)) {
4280 if (count >= *p_count) {
4281 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4282 }
4283 pp_blocks[count++] = (SpvReflectBlockVariable*)&p_module->push_constant_blocks[i];
4284 } else {
4285 ++count;
4286 }
4287 }
4288 }
4289 if (IsNotNull(pp_blocks)) {
4290 if (count != *p_count) {
4291 return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
4292 }
4293 } else {
4294 *p_count = count;
4295 }
4296 return SPV_REFLECT_RESULT_SUCCESS;
4297}
4298
4299const SpvReflectDescriptorBinding* spvReflectGetDescriptorBinding(
4300 const SpvReflectShaderModule* p_module,
4301 uint32_t binding_number,
4302 uint32_t set_number,
4303 SpvReflectResult* p_result
4304)
4305{
4306 const SpvReflectDescriptorBinding* p_descriptor = NULL;
4307 if (IsNotNull(p_module)) {
4308 for (uint32_t index = 0; index < p_module->descriptor_binding_count; ++index) {
4309 const SpvReflectDescriptorBinding* p_potential = &p_module->descriptor_bindings[index];
4310 if ((p_potential->binding == binding_number) && (p_potential->set == set_number)) {
4311 p_descriptor = p_potential;
4312 break;
4313 }
4314 }
4315 }
4316 if (IsNotNull(p_result)) {
4317 *p_result = IsNotNull(p_descriptor)
4318 ? SPV_REFLECT_RESULT_SUCCESS
4319 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4320 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4321 }
4322 return p_descriptor;
4323}
4324
4325const SpvReflectDescriptorBinding* spvReflectGetEntryPointDescriptorBinding(
4326 const SpvReflectShaderModule* p_module,
4327 const char* entry_point,
4328 uint32_t binding_number,
4329 uint32_t set_number,
4330 SpvReflectResult* p_result
4331)
4332{
4333 const SpvReflectEntryPoint* p_entry =
4334 spvReflectGetEntryPoint(p_module, entry_point);
4335 if (IsNull(p_entry)) {
4336 if (IsNotNull(p_result)) {
4337 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4338 }
4339 return NULL;
4340 }
4341 const SpvReflectDescriptorBinding* p_descriptor = NULL;
4342 if (IsNotNull(p_module)) {
4343 for (uint32_t index = 0; index < p_module->descriptor_binding_count; ++index) {
4344 const SpvReflectDescriptorBinding* p_potential = &p_module->descriptor_bindings[index];
4345 bool found = SearchSortedUint32(
4346 p_entry->used_uniforms,
4347 p_entry->used_uniform_count,
4348 p_potential->spirv_id);
4349 if ((p_potential->binding == binding_number) && (p_potential->set == set_number) && found) {
4350 p_descriptor = p_potential;
4351 break;
4352 }
4353 }
4354 }
4355 if (IsNotNull(p_result)) {
4356 *p_result = IsNotNull(p_descriptor)
4357 ? SPV_REFLECT_RESULT_SUCCESS
4358 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4359 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4360 }
4361 return p_descriptor;
4362}
4363
4364const SpvReflectDescriptorSet* spvReflectGetDescriptorSet(
4365 const SpvReflectShaderModule* p_module,
4366 uint32_t set_number,
4367 SpvReflectResult* p_result
4368)
4369{
4370 const SpvReflectDescriptorSet* p_set = NULL;
4371 if (IsNotNull(p_module)) {
4372 for (uint32_t index = 0; index < p_module->descriptor_set_count; ++index) {
4373 const SpvReflectDescriptorSet* p_potential = &p_module->descriptor_sets[index];
4374 if (p_potential->set == set_number) {
4375 p_set = p_potential;
4376 }
4377 }
4378 }
4379 if (IsNotNull(p_result)) {
4380 *p_result = IsNotNull(p_set)
4381 ? SPV_REFLECT_RESULT_SUCCESS
4382 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4383 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4384 }
4385 return p_set;
4386}
4387
4388const SpvReflectDescriptorSet* spvReflectGetEntryPointDescriptorSet(
4389 const SpvReflectShaderModule* p_module,
4390 const char* entry_point,
4391 uint32_t set_number,
4392 SpvReflectResult* p_result)
4393{
4394 const SpvReflectDescriptorSet* p_set = NULL;
4395 if (IsNotNull(p_module)) {
4396 const SpvReflectEntryPoint* p_entry = spvReflectGetEntryPoint(p_module, entry_point);
4397 if (IsNull(p_entry)) {
4398 if (IsNotNull(p_result)) {
4399 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4400 }
4401 return NULL;
4402 }
4403 for (uint32_t index = 0; index < p_entry->descriptor_set_count; ++index) {
4404 const SpvReflectDescriptorSet* p_potential = &p_entry->descriptor_sets[index];
4405 if (p_potential->set == set_number) {
4406 p_set = p_potential;
4407 }
4408 }
4409 }
4410 if (IsNotNull(p_result)) {
4411 *p_result = IsNotNull(p_set)
4412 ? SPV_REFLECT_RESULT_SUCCESS
4413 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4414 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4415 }
4416 return p_set;
4417}
4418
4419
4420const SpvReflectInterfaceVariable* spvReflectGetInputVariableByLocation(
4421 const SpvReflectShaderModule* p_module,
4422 uint32_t location,
4423 SpvReflectResult* p_result
4424)
4425{
4426 if (location == INVALID_VALUE) {
4427 if (IsNotNull(p_result)) {
4428 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4429 }
4430 return NULL;
4431 }
4432 const SpvReflectInterfaceVariable* p_var = NULL;
4433 if (IsNotNull(p_module)) {
4434 for (uint32_t index = 0; index < p_module->input_variable_count; ++index) {
4435 const SpvReflectInterfaceVariable* p_potential = p_module->input_variables[index];
4436 if (p_potential->location == location) {
4437 p_var = p_potential;
4438 }
4439 }
4440 }
4441 if (IsNotNull(p_result)) {
4442 *p_result = IsNotNull(p_var)
4443 ? SPV_REFLECT_RESULT_SUCCESS
4444 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4445 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4446 }
4447 return p_var;
4448}
4449const SpvReflectInterfaceVariable* spvReflectGetInputVariable(
4450 const SpvReflectShaderModule* p_module,
4451 uint32_t location,
4452 SpvReflectResult* p_result
4453)
4454{
4455 return spvReflectGetInputVariableByLocation(p_module, location, p_result);
4456}
4457
4458const SpvReflectInterfaceVariable* spvReflectGetEntryPointInputVariableByLocation(
4459 const SpvReflectShaderModule* p_module,
4460 const char* entry_point,
4461 uint32_t location,
4462 SpvReflectResult* p_result
4463)
4464{
4465 if (location == INVALID_VALUE) {
4466 if (IsNotNull(p_result)) {
4467 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4468 }
4469 return NULL;
4470 }
4471
4472 const SpvReflectInterfaceVariable* p_var = NULL;
4473 if (IsNotNull(p_module)) {
4474 const SpvReflectEntryPoint* p_entry =
4475 spvReflectGetEntryPoint(p_module, entry_point);
4476 if (IsNull(p_entry)) {
4477 if (IsNotNull(p_result)) {
4478 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4479 }
4480 return NULL;
4481 }
4482 for (uint32_t index = 0; index < p_entry->input_variable_count; ++index) {
4483 const SpvReflectInterfaceVariable* p_potential = p_entry->input_variables[index];
4484 if (p_potential->location == location) {
4485 p_var = p_potential;
4486 }
4487 }
4488 }
4489 if (IsNotNull(p_result)) {
4490 *p_result = IsNotNull(p_var)
4491 ? SPV_REFLECT_RESULT_SUCCESS
4492 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4493 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4494 }
4495 return p_var;
4496}
4497
4498const SpvReflectInterfaceVariable* spvReflectGetInputVariableBySemantic(
4499 const SpvReflectShaderModule* p_module,
4500 const char* semantic,
4501 SpvReflectResult* p_result
4502)
4503{
4504 if (IsNull(semantic)) {
4505 if (IsNotNull(p_result)) {
4506 *p_result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4507 }
4508 return NULL;
4509 }
4510 if (semantic[0] == '\0') {
4511 if (IsNotNull(p_result)) {
4512 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4513 }
4514 return NULL;
4515 }
4516 const SpvReflectInterfaceVariable* p_var = NULL;
4517 if (IsNotNull(p_module)) {
4518 for (uint32_t index = 0; index < p_module->input_variable_count; ++index) {
4519 const SpvReflectInterfaceVariable* p_potential = p_module->input_variables[index];
4520 if (p_potential->semantic != NULL && strcmp(p_potential->semantic, semantic) == 0) {
4521 p_var = p_potential;
4522 }
4523 }
4524 }
4525 if (IsNotNull(p_result)) {
4526 *p_result = IsNotNull(p_var)
4527 ? SPV_REFLECT_RESULT_SUCCESS
4528 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4529 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4530 }
4531 return p_var;
4532}
4533
4534const SpvReflectInterfaceVariable* spvReflectGetEntryPointInputVariableBySemantic(
4535 const SpvReflectShaderModule* p_module,
4536 const char* entry_point,
4537 const char* semantic,
4538 SpvReflectResult* p_result
4539)
4540{
4541 if (IsNull(semantic)) {
4542 if (IsNotNull(p_result)) {
4543 *p_result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4544 }
4545 return NULL;
4546 }
4547 if (semantic[0] == '\0') {
4548 if (IsNotNull(p_result)) {
4549 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4550 }
4551 return NULL;
4552 }
4553 const SpvReflectInterfaceVariable* p_var = NULL;
4554 if (IsNotNull(p_module)) {
4555 const SpvReflectEntryPoint* p_entry = spvReflectGetEntryPoint(p_module, entry_point);
4556 if (IsNull(p_entry)) {
4557 if (IsNotNull(p_result)) {
4558 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4559 }
4560 return NULL;
4561 }
4562 for (uint32_t index = 0; index < p_entry->input_variable_count; ++index) {
4563 const SpvReflectInterfaceVariable* p_potential = p_entry->input_variables[index];
4564 if (p_potential->semantic != NULL && strcmp(p_potential->semantic, semantic) == 0) {
4565 p_var = p_potential;
4566 }
4567 }
4568 }
4569 if (IsNotNull(p_result)) {
4570 *p_result = IsNotNull(p_var)
4571 ? SPV_REFLECT_RESULT_SUCCESS
4572 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4573 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4574 }
4575 return p_var;
4576}
4577
4578const SpvReflectInterfaceVariable* spvReflectGetOutputVariableByLocation(
4579 const SpvReflectShaderModule* p_module,
4580 uint32_t location,
4581 SpvReflectResult* p_result
4582)
4583{
4584 if (location == INVALID_VALUE) {
4585 if (IsNotNull(p_result)) {
4586 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4587 }
4588 return NULL;
4589 }
4590 const SpvReflectInterfaceVariable* p_var = NULL;
4591 if (IsNotNull(p_module)) {
4592 for (uint32_t index = 0; index < p_module->output_variable_count; ++index) {
4593 const SpvReflectInterfaceVariable* p_potential = p_module->output_variables[index];
4594 if (p_potential->location == location) {
4595 p_var = p_potential;
4596 }
4597 }
4598 }
4599 if (IsNotNull(p_result)) {
4600 *p_result = IsNotNull(p_var)
4601 ? SPV_REFLECT_RESULT_SUCCESS
4602 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4603 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4604 }
4605 return p_var;
4606}
4607const SpvReflectInterfaceVariable* spvReflectGetOutputVariable(
4608 const SpvReflectShaderModule* p_module,
4609 uint32_t location,
4610 SpvReflectResult* p_result
4611)
4612{
4613 return spvReflectGetOutputVariableByLocation(p_module, location, p_result);
4614}
4615
4616const SpvReflectInterfaceVariable* spvReflectGetEntryPointOutputVariableByLocation(
4617 const SpvReflectShaderModule* p_module,
4618 const char* entry_point,
4619 uint32_t location,
4620 SpvReflectResult* p_result
4621)
4622{
4623 if (location == INVALID_VALUE) {
4624 if (IsNotNull(p_result)) {
4625 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4626 }
4627 return NULL;
4628 }
4629
4630 const SpvReflectInterfaceVariable* p_var = NULL;
4631 if (IsNotNull(p_module)) {
4632 const SpvReflectEntryPoint* p_entry = spvReflectGetEntryPoint(p_module, entry_point);
4633 if (IsNull(p_entry)) {
4634 if (IsNotNull(p_result)) {
4635 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4636 }
4637 return NULL;
4638 }
4639 for (uint32_t index = 0; index < p_entry->output_variable_count; ++index) {
4640 const SpvReflectInterfaceVariable* p_potential = p_entry->output_variables[index];
4641 if (p_potential->location == location) {
4642 p_var = p_potential;
4643 }
4644 }
4645 }
4646 if (IsNotNull(p_result)) {
4647 *p_result = IsNotNull(p_var)
4648 ? SPV_REFLECT_RESULT_SUCCESS
4649 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4650 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4651 }
4652 return p_var;
4653}
4654
4655const SpvReflectInterfaceVariable* spvReflectGetOutputVariableBySemantic(
4656 const SpvReflectShaderModule* p_module,
4657 const char* semantic,
4658 SpvReflectResult* p_result
4659)
4660{
4661 if (IsNull(semantic)) {
4662 if (IsNotNull(p_result)) {
4663 *p_result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4664 }
4665 return NULL;
4666 }
4667 if (semantic[0] == '\0') {
4668 if (IsNotNull(p_result)) {
4669 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4670 }
4671 return NULL;
4672 }
4673 const SpvReflectInterfaceVariable* p_var = NULL;
4674 if (IsNotNull(p_module)) {
4675 for (uint32_t index = 0; index < p_module->output_variable_count; ++index) {
4676 const SpvReflectInterfaceVariable* p_potential = p_module->output_variables[index];
4677 if (p_potential->semantic != NULL && strcmp(p_potential->semantic, semantic) == 0) {
4678 p_var = p_potential;
4679 }
4680 }
4681 }
4682 if (IsNotNull(p_result)) {
4683 *p_result = IsNotNull(p_var)
4684 ? SPV_REFLECT_RESULT_SUCCESS
4685 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4686 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4687 }
4688 return p_var;
4689}
4690
4691const SpvReflectInterfaceVariable* spvReflectGetEntryPointOutputVariableBySemantic(
4692 const SpvReflectShaderModule* p_module,
4693 const char* entry_point,
4694 const char* semantic,
4695 SpvReflectResult* p_result)
4696{
4697 if (IsNull(semantic)) {
4698 if (IsNotNull(p_result)) {
4699 *p_result = SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4700 }
4701 return NULL;
4702 }
4703 if (semantic[0] == '\0') {
4704 if (IsNotNull(p_result)) {
4705 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4706 }
4707 return NULL;
4708 }
4709 const SpvReflectInterfaceVariable* p_var = NULL;
4710 if (IsNotNull(p_module)) {
4711 const SpvReflectEntryPoint* p_entry = spvReflectGetEntryPoint(p_module, entry_point);
4712 if (IsNull(p_entry)) {
4713 if (IsNotNull(p_result)) {
4714 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4715 }
4716 return NULL;
4717 }
4718 for (uint32_t index = 0; index < p_entry->output_variable_count; ++index) {
4719 const SpvReflectInterfaceVariable* p_potential = p_entry->output_variables[index];
4720 if (p_potential->semantic != NULL && strcmp(p_potential->semantic, semantic) == 0) {
4721 p_var = p_potential;
4722 }
4723 }
4724 }
4725 if (IsNotNull(p_result)) {
4726 *p_result = IsNotNull(p_var)
4727 ? SPV_REFLECT_RESULT_SUCCESS
4728 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4729 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4730 }
4731 return p_var;
4732}
4733
4734const SpvReflectBlockVariable* spvReflectGetPushConstantBlock(
4735 const SpvReflectShaderModule* p_module,
4736 uint32_t index,
4737 SpvReflectResult* p_result
4738)
4739{
4740 const SpvReflectBlockVariable* p_push_constant = NULL;
4741 if (IsNotNull(p_module)) {
4742 if (index < p_module->push_constant_block_count) {
4743 p_push_constant = &p_module->push_constant_blocks[index];
4744 }
4745 }
4746 if (IsNotNull(p_result)) {
4747 *p_result = IsNotNull(p_push_constant)
4748 ? SPV_REFLECT_RESULT_SUCCESS
4749 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4750 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4751 }
4752 return p_push_constant;
4753}
4754const SpvReflectBlockVariable* spvReflectGetPushConstant(
4755 const SpvReflectShaderModule* p_module,
4756 uint32_t index,
4757 SpvReflectResult* p_result
4758)
4759{
4760 return spvReflectGetPushConstantBlock(p_module, index, p_result);
4761}
4762
4763const SpvReflectBlockVariable* spvReflectGetEntryPointPushConstantBlock(
4764 const SpvReflectShaderModule* p_module,
4765 const char* entry_point,
4766 SpvReflectResult* p_result)
4767{
4768 const SpvReflectBlockVariable* p_push_constant = NULL;
4769 if (IsNotNull(p_module)) {
4770 const SpvReflectEntryPoint* p_entry =
4771 spvReflectGetEntryPoint(p_module, entry_point);
4772 if (IsNull(p_entry)) {
4773 if (IsNotNull(p_result)) {
4774 *p_result = SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4775 }
4776 return NULL;
4777 }
4778 for (uint32_t i = 0; i < p_module->push_constant_block_count; ++i) {
4779 bool found = SearchSortedUint32(
4780 p_entry->used_push_constants,
4781 p_entry->used_push_constant_count,
4782 p_module->push_constant_blocks[i].spirv_id);
4783 if (found) {
4784 p_push_constant = &p_module->push_constant_blocks[i];
4785 break;
4786 }
4787 }
4788 }
4789 if (IsNotNull(p_result)) {
4790 *p_result = IsNotNull(p_push_constant)
4791 ? SPV_REFLECT_RESULT_SUCCESS
4792 : (IsNull(p_module) ? SPV_REFLECT_RESULT_ERROR_NULL_POINTER
4793 : SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
4794 }
4795 return p_push_constant;
4796}
4797
4798SpvReflectResult spvReflectChangeDescriptorBindingNumbers(
4799 SpvReflectShaderModule* p_module,
4800 const SpvReflectDescriptorBinding* p_binding,
4801 uint32_t new_binding_number,
4802 uint32_t new_set_binding
4803)
4804{
4805 if (IsNull(p_module)) {
4806 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4807 }
4808 if (IsNull(p_binding)) {
4809 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4810 }
4811
4812 SpvReflectDescriptorBinding* p_target_descriptor = NULL;
4813 for (uint32_t index = 0; index < p_module->descriptor_binding_count; ++index) {
4814 if(&p_module->descriptor_bindings[index] == p_binding) {
4815 p_target_descriptor = &p_module->descriptor_bindings[index];
4816 break;
4817 }
4818 }
4819
4820 if (IsNotNull(p_target_descriptor)) {
4821 if (p_target_descriptor->word_offset.binding > (p_module->_internal->spirv_word_count - 1)) {
4822 return SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
4823 }
4824 // Binding number
4825 if (new_binding_number != (uint32_t)SPV_REFLECT_BINDING_NUMBER_DONT_CHANGE) {
4826 uint32_t* p_code = p_module->_internal->spirv_code + p_target_descriptor->word_offset.binding;
4827 *p_code = new_binding_number;
4828 p_target_descriptor->binding = new_binding_number;
4829 }
4830 // Set number
4831 if (new_set_binding != (uint32_t)SPV_REFLECT_SET_NUMBER_DONT_CHANGE) {
4832 uint32_t* p_code = p_module->_internal->spirv_code + p_target_descriptor->word_offset.set;
4833 *p_code = new_set_binding;
4834 p_target_descriptor->set = new_set_binding;
4835 }
4836 }
4837
4838 SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
4839 if (new_set_binding != (uint32_t)SPV_REFLECT_SET_NUMBER_DONT_CHANGE) {
4840 result = SynchronizeDescriptorSets(p_module);
4841 }
4842 return result;
4843}
4844SpvReflectResult spvReflectChangeDescriptorBindingNumber(
4845 SpvReflectShaderModule* p_module,
4846 const SpvReflectDescriptorBinding* p_descriptor_binding,
4847 uint32_t new_binding_number,
4848 uint32_t optional_new_set_number
4849)
4850{
4851 return spvReflectChangeDescriptorBindingNumbers(
4852 p_module,p_descriptor_binding,
4853 new_binding_number,
4854 optional_new_set_number);
4855}
4856
4857SpvReflectResult spvReflectChangeDescriptorSetNumber(
4858 SpvReflectShaderModule* p_module,
4859 const SpvReflectDescriptorSet* p_set,
4860 uint32_t new_set_number
4861)
4862{
4863 if (IsNull(p_module)) {
4864 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4865 }
4866 if (IsNull(p_set)) {
4867 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4868 }
4869 SpvReflectDescriptorSet* p_target_set = NULL;
4870 for (uint32_t index = 0; index < SPV_REFLECT_MAX_DESCRIPTOR_SETS; ++index) {
4871 // The descriptor sets for specific entry points might not be in this set,
4872 // so just match on set index.
4873 if (p_module->descriptor_sets[index].set == p_set->set) {
4874 p_target_set = (SpvReflectDescriptorSet*)p_set;
4875 break;
4876 }
4877 }
4878
4879 SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
4880 if (IsNotNull(p_target_set) && new_set_number != (uint32_t)SPV_REFLECT_SET_NUMBER_DONT_CHANGE) {
4881 for (uint32_t index = 0; index < p_target_set->binding_count; ++index) {
4882 SpvReflectDescriptorBinding* p_descriptor = p_target_set->bindings[index];
4883 if (p_descriptor->word_offset.set > (p_module->_internal->spirv_word_count - 1)) {
4884 return SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
4885 }
4886
4887 uint32_t* p_code = p_module->_internal->spirv_code + p_descriptor->word_offset.set;
4888 *p_code = new_set_number;
4889 p_descriptor->set = new_set_number;
4890 }
4891
4892 result = SynchronizeDescriptorSets(p_module);
4893 }
4894
4895 return result;
4896}
4897
4898static SpvReflectResult ChangeVariableLocation(
4899 SpvReflectShaderModule* p_module,
4900 SpvReflectInterfaceVariable* p_variable,
4901 uint32_t new_location
4902)
4903{
4904 if (p_variable->word_offset.location > (p_module->_internal->spirv_word_count - 1)) {
4905 return SPV_REFLECT_RESULT_ERROR_RANGE_EXCEEDED;
4906 }
4907 uint32_t* p_code = p_module->_internal->spirv_code + p_variable->word_offset.location;
4908 *p_code = new_location;
4909 p_variable->location = new_location;
4910 return SPV_REFLECT_RESULT_SUCCESS;
4911}
4912
4913SpvReflectResult spvReflectChangeInputVariableLocation(
4914 SpvReflectShaderModule* p_module,
4915 const SpvReflectInterfaceVariable* p_input_variable,
4916 uint32_t new_location
4917)
4918{
4919 if (IsNull(p_module)) {
4920 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4921 }
4922 if (IsNull(p_input_variable)) {
4923 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4924 }
4925 for (uint32_t index = 0; index < p_module->input_variable_count; ++index) {
4926 if(p_module->input_variables[index] == p_input_variable) {
4927 return ChangeVariableLocation(p_module, p_module->input_variables[index], new_location);
4928 }
4929 }
4930 return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4931}
4932
4933SpvReflectResult spvReflectChangeOutputVariableLocation(
4934 SpvReflectShaderModule* p_module,
4935 const SpvReflectInterfaceVariable* p_output_variable,
4936 uint32_t new_location
4937)
4938{
4939 if (IsNull(p_module)) {
4940 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4941 }
4942 if (IsNull(p_output_variable)) {
4943 return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
4944 }
4945 for (uint32_t index = 0; index < p_module->output_variable_count; ++index) {
4946 if(p_module->output_variables[index] == p_output_variable) {
4947 return ChangeVariableLocation(p_module, p_module->output_variables[index], new_location);
4948 }
4949 }
4950 return SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND;
4951}
4952
4953const char* spvReflectSourceLanguage(SpvSourceLanguage source_lang)
4954{
4955 switch (source_lang) {
4956 case SpvSourceLanguageUnknown : return "Unknown";
4957 case SpvSourceLanguageESSL : return "ESSL";
4958 case SpvSourceLanguageGLSL : return "GLSL";
4959 case SpvSourceLanguageOpenCL_C : return "OpenCL_C";
4960 case SpvSourceLanguageOpenCL_CPP : return "OpenCL_CPP";
4961 case SpvSourceLanguageHLSL : return "HLSL";
4962 case SpvSourceLanguageCPP_for_OpenCL : return "CPP_for_OpenCL";
4963 case SpvSourceLanguageMax:
4964 break;
4965 }
4966 return "";
4967}
4968
4969const char* spvReflectBlockVariableTypeName(
4970 const SpvReflectBlockVariable* p_var
4971)
4972{
4973 if (p_var == NULL) {
4974 return NULL;
4975 }
4976 return p_var->type_description->type_name;
4977}
4978