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