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