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 |
45 | enum { |
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 |
55 | enum { |
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 |
66 | enum { |
67 | INVALID_VALUE = 0xFFFFFFFF, |
68 | }; |
69 | // clang-format on |
70 | |
71 | // clang-format off |
72 | enum { |
73 | MAX_NODE_NAME_LENGTH = 1024, |
74 | }; |
75 | // clang-format on |
76 | |
77 | // clang-format off |
78 | enum { |
79 | IMAGE_SAMPLED = 1, |
80 | IMAGE_STORAGE = 2 |
81 | }; |
82 | // clang-format on |
83 | |
84 | // clang-format off |
85 | typedef struct SpvReflectPrvArrayTraits { |
86 | uint32_t element_type_id; |
87 | uint32_t length_id; |
88 | } SpvReflectPrvArrayTraits; |
89 | // clang-format on |
90 | |
91 | // clang-format off |
92 | typedef 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 |
104 | typedef struct SpvReflectPrvNumberDecoration { |
105 | uint32_t word_offset; |
106 | uint32_t value; |
107 | } SpvReflectPrvNumberDecoration; |
108 | // clang-format on |
109 | |
110 | // clang-format off |
111 | typedef struct SpvReflectPrvStringDecoration { |
112 | uint32_t word_offset; |
113 | const char* value; |
114 | } SpvReflectPrvStringDecoration; |
115 | // clang-format on |
116 | |
117 | // clang-format off |
118 | typedef 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 |
146 | typedef 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 |
170 | typedef struct SpvReflectPrvString { |
171 | uint32_t result_id; |
172 | const char* string; |
173 | } SpvReflectPrvString; |
174 | // clang-format on |
175 | |
176 | // clang-format off |
177 | typedef 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 |
188 | typedef 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 |
206 | typedef 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 | |
230 | static uint32_t Max( |
231 | uint32_t a, |
232 | uint32_t b) |
233 | { |
234 | return a > b ? a : b; |
235 | } |
236 | |
237 | static 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 | |
257 | static 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 | // |
274 | static 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 | |
289 | static 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 | |
309 | static 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 | |
365 | static 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 | |
376 | static 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 | |
427 | static 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 | |
474 | static 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 | |
510 | static 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 | |
515 | static 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 | |
520 | static 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 | |
535 | static 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 | |
548 | static 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 | |
574 | static 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 | |
609 | static 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 | |
963 | static 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 | |
1007 | static 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 | |
1047 | static 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 | |
1174 | static 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 | |
1183 | static 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 | |
1262 | static 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 | |
1312 | static 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 | |
1346 | static 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 | |
1556 | static 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 | |
1580 | static 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 | |
1866 | static 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 | |
1906 | static 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 | |
1944 | static 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 | |
1958 | static 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 | |
2098 | static 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 | |
2192 | static 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 | |
2250 | static 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 | |
2327 | static 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 | |
2460 | static 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 | |
2483 | static 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 | |
2613 | static 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 | |
2673 | static 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 | |
2754 | static 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 | |
2815 | static 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 | |
2950 | static 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 | |
2974 | static 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 | |
3003 | static 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 | |
3148 | static 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 | |
3266 | static 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 -- |
3425 | static 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 | |
3487 | static 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 | |
3575 | static 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 | |
3586 | static 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 | |
3656 | static 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 | |
3726 | static 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 | |
3753 | static 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 | |
3769 | static 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 | |
3945 | SpvReflectResult 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 | |
3954 | SpvReflectResult 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 | |
3964 | SpvReflectResult 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 | |
3973 | static 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 | |
3990 | static 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 | |
4007 | static 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 | |
4024 | void 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 | |
4092 | uint32_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 | |
4101 | const 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 | |
4110 | const 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 | |
4126 | SpvReflectResult 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 | |
4156 | SpvReflectResult 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 | |
4203 | SpvReflectResult 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 | |
4233 | SpvReflectResult 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 | |
4270 | SpvReflectResult 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 | |
4300 | SpvReflectResult 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 -- |
4338 | SpvReflectResult 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 | |
4369 | SpvReflectResult 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 | |
4399 | SpvReflectResult 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 | |
4436 | SpvReflectResult 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 | |
4466 | SpvReflectResult 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 | |
4503 | SpvReflectResult 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 | } |
4532 | SpvReflectResult 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 | |
4541 | SpvReflectResult 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 | |
4588 | const 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 | |
4614 | const 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 | |
4653 | const 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 | |
4677 | const 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 | |
4709 | const 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 | } |
4738 | const 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 | |
4747 | const 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 | |
4787 | const 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 | |
4823 | const 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 | |
4867 | const 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 | } |
4896 | const 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 | |
4905 | const 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 | |
4944 | const 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 | |
4980 | const 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 | |
5023 | const 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 | } |
5043 | const 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 | |
5052 | const 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 | |
5087 | SpvReflectResult 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 | } |
5133 | SpvReflectResult 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 | |
5146 | SpvReflectResult 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 | |
5187 | static 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 | |
5202 | SpvReflectResult 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 | |
5222 | SpvReflectResult 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 | |
5242 | const 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 | |
5259 | const 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 | |