1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2010-2017 - Hans-Kristian Arntzen
3 *
4 * RetroArch is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with RetroArch.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "spirv_cross.hpp"
17 #include "slang_reflection.h"
18 #include "slang_reflection.hpp"
19 #include <vector>
20 #include <algorithm>
21 #include <stdio.h>
22 #include <compat/strl.h>
23 #include "glslang_util.h"
24 #include "../../verbosity.h"
25
26 using namespace std;
27 using namespace spirv_cross;
28
29 static const char *texture_semantic_names[] = {
30 "Original",
31 "Source",
32 "OriginalHistory",
33 "PassOutput",
34 "PassFeedback",
35 "User",
36 nullptr
37 };
38
39 static const char *texture_semantic_uniform_names[] = {
40 "OriginalSize",
41 "SourceSize",
42 "OriginalHistorySize",
43 "PassOutputSize",
44 "PassFeedbackSize",
45 "UserSize",
46 nullptr
47 };
48
49 static const char *semantic_uniform_names[] = {
50 "MVP",
51 "OutputSize",
52 "FinalViewportSize",
53 "FrameCount",
54 "FrameDirection",
55 };
56
slang_name_to_texture_semantic(const std::unordered_map<std::string,slang_texture_semantic_map> & semantic_map,const std::string & name,unsigned * index)57 static slang_texture_semantic slang_name_to_texture_semantic(
58 const std::unordered_map<std::string, slang_texture_semantic_map> &semantic_map,
59 const std::string &name, unsigned *index)
60 {
61 auto itr = semantic_map.find(name);
62 if (itr != end(semantic_map))
63 {
64 *index = itr->second.index;
65 return itr->second.semantic;
66 }
67
68 return slang_name_to_texture_semantic_array(
69 name.c_str(), texture_semantic_names, index);
70 }
71
slang_uniform_name_to_texture_semantic(const std::unordered_map<std::string,slang_texture_semantic_map> & semantic_map,const std::string & name,unsigned * index)72 static slang_texture_semantic slang_uniform_name_to_texture_semantic(
73 const std::unordered_map<std::string, slang_texture_semantic_map> &semantic_map,
74 const std::string &name, unsigned *index)
75 {
76 auto itr = semantic_map.find(name);
77 if (itr != end(semantic_map))
78 {
79 *index = itr->second.index;
80 return itr->second.semantic;
81 }
82
83 return slang_name_to_texture_semantic_array(name.c_str(),
84 texture_semantic_uniform_names, index);
85 }
86
slang_uniform_name_to_semantic(const std::unordered_map<std::string,slang_semantic_map> & semantic_map,const std::string & name,unsigned * index)87 static slang_semantic slang_uniform_name_to_semantic(
88 const std::unordered_map<std::string, slang_semantic_map> &semantic_map,
89 const std::string &name, unsigned *index)
90 {
91 unsigned i = 0;
92 auto itr = semantic_map.find(name);
93
94 if (itr != end(semantic_map))
95 {
96 *index = itr->second.index;
97 return itr->second.semantic;
98 }
99
100 /* No builtin semantics are arrayed. */
101 *index = 0;
102 for (auto n : semantic_uniform_names)
103 {
104 if (name == n)
105 return static_cast<slang_semantic>(i);
106 i++;
107 }
108
109 return SLANG_INVALID_SEMANTIC;
110 }
111
112 template <typename T>
resize_minimum(T & vec,unsigned minimum)113 static void resize_minimum(T &vec, unsigned minimum)
114 {
115 if (vec.size() < minimum)
116 vec.resize(minimum);
117 }
118
set_ubo_texture_offset(slang_reflection * reflection,slang_texture_semantic semantic,unsigned index,size_t offset,bool push_constant)119 static bool set_ubo_texture_offset(
120 slang_reflection *reflection,
121 slang_texture_semantic semantic,
122 unsigned index,
123 size_t offset, bool push_constant)
124 {
125 resize_minimum(reflection->semantic_textures[semantic], index + 1);
126 slang_texture_semantic_meta &sem = reflection->semantic_textures[semantic][index];
127 bool &active = push_constant ? sem.push_constant : sem.uniform;
128 size_t &active_offset = push_constant ? sem.push_constant_offset : sem.ubo_offset;
129
130 if (active)
131 {
132 if (active_offset != offset)
133 {
134 RARCH_ERR("[slang]: Vertex and fragment have"
135 " different offsets for same semantic %s #%u (%u vs. %u).\n",
136 texture_semantic_uniform_names[semantic],
137 index,
138 unsigned(active_offset),
139 unsigned(offset));
140 return false;
141 }
142 }
143
144 active = true;
145 active_offset = offset;
146 return true;
147 }
148
set_ubo_float_parameter_offset(slang_reflection * reflection,unsigned index,size_t offset,unsigned num_components,bool push_constant)149 static bool set_ubo_float_parameter_offset(
150 slang_reflection *reflection,
151 unsigned index, size_t offset,
152 unsigned num_components,
153 bool push_constant)
154 {
155 resize_minimum(reflection->semantic_float_parameters, index + 1);
156 slang_semantic_meta &sem = reflection->semantic_float_parameters[index];
157 bool &active = push_constant ? sem.push_constant : sem.uniform;
158 size_t &active_offset = push_constant ? sem.push_constant_offset : sem.ubo_offset;
159
160 if (active)
161 {
162 if (active_offset != offset)
163 {
164 RARCH_ERR("[slang]: Vertex and fragment have different"
165 " offsets for same parameter #%u (%u vs. %u).\n",
166 index,
167 unsigned(active_offset),
168 unsigned(offset));
169 return false;
170 }
171 }
172
173 if ( (sem.num_components != num_components) &&
174 (sem.uniform || sem.push_constant))
175 {
176 RARCH_ERR("[slang]: Vertex and fragment have different "
177 "components for same parameter #%u (%u vs. %u).\n",
178 index,
179 unsigned(sem.num_components),
180 unsigned(num_components));
181 return false;
182 }
183
184 active = true;
185 active_offset = offset;
186 sem.num_components = num_components;
187 return true;
188 }
189
set_ubo_offset(slang_reflection * reflection,slang_semantic semantic,size_t offset,unsigned num_components,bool push_constant)190 static bool set_ubo_offset(
191 slang_reflection *reflection,
192 slang_semantic semantic,
193 size_t offset, unsigned num_components, bool push_constant)
194 {
195 slang_semantic_meta &sem = reflection->semantics[semantic];
196 bool &active = push_constant ? sem.push_constant : sem.uniform;
197 size_t &active_offset = push_constant ? sem.push_constant_offset : sem.ubo_offset;
198
199 if (active)
200 {
201 if (active_offset != offset)
202 {
203 RARCH_ERR("[slang]: Vertex and fragment have "
204 "different offsets for same semantic %s (%u vs. %u).\n",
205 semantic_uniform_names[semantic],
206 unsigned(active_offset),
207 unsigned(offset));
208 return false;
209 }
210
211 }
212
213 if ( (sem.num_components != num_components) &&
214 (sem.uniform || sem.push_constant))
215 {
216 RARCH_ERR("[slang]: Vertex and fragment have different"
217 " components for same semantic %s (%u vs. %u).\n",
218 semantic_uniform_names[semantic],
219 unsigned(sem.num_components),
220 unsigned(num_components));
221 return false;
222 }
223
224 active = true;
225 active_offset = offset;
226 sem.num_components = num_components;
227 return true;
228 }
229
validate_type_for_semantic(const SPIRType & type,slang_semantic sem)230 static bool validate_type_for_semantic(const SPIRType &type, slang_semantic sem)
231 {
232 if (!type.array.empty())
233 return false;
234 if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt)
235 return false;
236
237 switch (sem)
238 {
239 /* mat4 */
240 case SLANG_SEMANTIC_MVP:
241 return type.basetype == SPIRType::Float && type.vecsize == 4 && type.columns == 4;
242 /* uint */
243 case SLANG_SEMANTIC_FRAME_COUNT:
244 return type.basetype == SPIRType::UInt && type.vecsize == 1 && type.columns == 1;
245 /* int */
246 case SLANG_SEMANTIC_FRAME_DIRECTION:
247 return type.basetype == SPIRType::Int && type.vecsize == 1 && type.columns == 1;
248 /* float */
249 case SLANG_SEMANTIC_FLOAT_PARAMETER:
250 return type.basetype == SPIRType::Float && type.vecsize == 1 && type.columns == 1;
251 /* vec4 */
252 default:
253 return type.basetype == SPIRType::Float && type.vecsize == 4 && type.columns == 1;
254 }
255 }
256
validate_type_for_texture_semantic(const SPIRType & type)257 static bool validate_type_for_texture_semantic(const SPIRType &type)
258 {
259 if (!type.array.empty())
260 return false;
261 return (type.basetype == SPIRType::Float) &&
262 (type.vecsize == 4) &&
263 (type.columns == 1);
264 }
265
add_active_buffer_ranges(const Compiler & compiler,const Resource & resource,slang_reflection * reflection,bool push_constant)266 static bool add_active_buffer_ranges(
267 const Compiler &compiler,
268 const Resource &resource,
269 slang_reflection *reflection,
270 bool push_constant)
271 {
272 unsigned i;
273 /* Get which uniforms are actually in use by this shader. */
274 auto ranges = compiler.get_active_buffer_ranges(resource.id);
275
276 for (i = 0; i < ranges.size(); i++)
277 {
278 unsigned sem_index = 0;
279 unsigned tex_sem_index = 0;
280 const std::string &name = compiler.get_member_name(
281 resource.base_type_id, ranges[i].index);
282 const SPIRType &type = compiler.get_type(
283 compiler.get_type(resource.base_type_id).member_types[
284 ranges[i].index]);
285 slang_semantic sem = slang_uniform_name_to_semantic(
286 *reflection->semantic_map, name, &sem_index);
287 slang_texture_semantic tex_sem = slang_uniform_name_to_texture_semantic(
288 *reflection->texture_semantic_uniform_map,
289 name, &tex_sem_index);
290
291 if (tex_sem == SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT && tex_sem_index >= reflection->pass_number)
292 {
293 RARCH_ERR("[slang]: Non causal filter chain detected. "
294 "Shader is trying to use output from pass #%u,"
295 " but this shader is pass #%u.\n",
296 tex_sem_index, reflection->pass_number);
297 return false;
298 }
299
300 if (sem != SLANG_INVALID_SEMANTIC)
301 {
302 if (!validate_type_for_semantic(type, sem))
303 {
304 RARCH_ERR("[slang]: Underlying type of semantic is invalid.\n");
305 return false;
306 }
307
308 switch (sem)
309 {
310 case SLANG_SEMANTIC_FLOAT_PARAMETER:
311 if (!set_ubo_float_parameter_offset(reflection, sem_index,
312 ranges[i].offset, type.vecsize, push_constant))
313 return false;
314 break;
315
316 default:
317 if (!set_ubo_offset(reflection, sem,
318 ranges[i].offset,
319 type.vecsize * type.columns, push_constant))
320 return false;
321 break;
322 }
323 }
324 else if (tex_sem != SLANG_INVALID_TEXTURE_SEMANTIC)
325 {
326 if (!validate_type_for_texture_semantic(type))
327 {
328 RARCH_ERR("[slang]: Underlying type of texture"
329 " semantic is invalid.\n");
330 return false;
331 }
332
333 if (!set_ubo_texture_offset(reflection, tex_sem, tex_sem_index,
334 ranges[i].offset, push_constant))
335 return false;
336 }
337 else
338 {
339 RARCH_ERR("[slang]: Unknown semantic found.\n");
340 return false;
341 }
342 }
343 return true;
344 }
345
346
slang_reflection()347 slang_reflection::slang_reflection()
348 {
349 unsigned i;
350
351 for (i = 0; i < SLANG_NUM_TEXTURE_SEMANTICS; i++)
352 semantic_textures[i].resize(
353 slang_texture_semantic_is_array(
354 static_cast<slang_texture_semantic>(i))
355 ? 0 : 1);
356 }
357
slang_reflect(const Compiler & vertex_compiler,const Compiler & fragment_compiler,const ShaderResources & vertex,const ShaderResources & fragment,slang_reflection * reflection)358 bool slang_reflect(
359 const Compiler &vertex_compiler,
360 const Compiler &fragment_compiler,
361 const ShaderResources &vertex,
362 const ShaderResources &fragment,
363 slang_reflection *reflection)
364 {
365 uint32_t location_mask = 0;
366 uint32_t binding_mask = 0;
367 unsigned i = 0;
368
369 /* Validate use of unexpected types. */
370 if (
371 !vertex.sampled_images.empty() ||
372 !vertex.storage_buffers.empty() ||
373 !vertex.subpass_inputs.empty() ||
374 !vertex.storage_images.empty() ||
375 !vertex.atomic_counters.empty() ||
376 !fragment.storage_buffers.empty() ||
377 !fragment.subpass_inputs.empty() ||
378 !fragment.storage_images.empty() ||
379 !fragment.atomic_counters.empty())
380 {
381 RARCH_ERR("[slang]: Invalid resource type detected.\n");
382 return false;
383 }
384
385 /* Validate vertex input. */
386 if (vertex.stage_inputs.size() != 2)
387 {
388 RARCH_ERR("[slang]: Vertex must have two attributes.\n");
389 return false;
390 }
391
392 if (fragment.stage_outputs.size() != 1)
393 {
394 RARCH_ERR("[slang]: Multiple render targets not supported.\n");
395 return false;
396 }
397
398 if (fragment_compiler.get_decoration(
399 fragment.stage_outputs[0].id, spv::DecorationLocation) != 0)
400 {
401 RARCH_ERR("[slang]: Render target must use location = 0.\n");
402 return false;
403 }
404
405 for (i = 0; i < vertex.stage_inputs.size(); i++)
406 location_mask |= 1 << vertex_compiler.get_decoration(
407 vertex.stage_inputs[i].id, spv::DecorationLocation);
408
409 if (location_mask != 0x3)
410 {
411 RARCH_ERR("[slang]: The two vertex attributes do not"
412 " use location = 0 and location = 1.\n");
413 return false;
414 }
415
416 /* Validate the single uniform buffer. */
417 if (vertex.uniform_buffers.size() > 1)
418 {
419 RARCH_ERR("[slang]: Vertex must use zero or one uniform buffer.\n");
420 return false;
421 }
422
423 if (fragment.uniform_buffers.size() > 1)
424 {
425 RARCH_ERR("[slang]: Fragment must use zero or one uniform buffer.\n");
426 return false;
427 }
428
429 /* Validate the single push constant buffer. */
430 if (vertex.push_constant_buffers.size() > 1)
431 {
432 RARCH_ERR("[slang]: Vertex must use zero or one push constant buffers.\n");
433 return false;
434 }
435
436 if (fragment.push_constant_buffers.size() > 1)
437 {
438 RARCH_ERR("[slang]: Fragment must use zero or one push cosntant buffer.\n");
439 return false;
440 }
441
442 uint32_t vertex_ubo = vertex.uniform_buffers.empty() ? 0 : vertex.uniform_buffers[0].id;
443 uint32_t fragment_ubo = fragment.uniform_buffers.empty() ? 0 : fragment.uniform_buffers[0].id;
444 uint32_t vertex_push = vertex.push_constant_buffers.empty() ? 0 : vertex.push_constant_buffers[0].id;
445 uint32_t fragment_push = fragment.push_constant_buffers.empty() ? 0 : fragment.push_constant_buffers[0].id;
446
447 if (vertex_ubo &&
448 vertex_compiler.get_decoration(
449 vertex_ubo, spv::DecorationDescriptorSet) != 0)
450 {
451 RARCH_ERR("[slang]: Resources must use descriptor set #0.\n");
452 return false;
453 }
454
455 if (fragment_ubo &&
456 fragment_compiler.get_decoration(
457 fragment_ubo, spv::DecorationDescriptorSet) != 0)
458 {
459 RARCH_ERR("[slang]: Resources must use descriptor set #0.\n");
460 return false;
461 }
462
463 unsigned vertex_ubo_binding = vertex_ubo
464 ? vertex_compiler.get_decoration(vertex_ubo, spv::DecorationBinding)
465 : -1u;
466 unsigned fragment_ubo_binding = fragment_ubo
467 ? fragment_compiler.get_decoration(fragment_ubo, spv::DecorationBinding)
468 : -1u;
469 bool has_ubo = vertex_ubo || fragment_ubo;
470
471 if ( (vertex_ubo_binding != -1u) &&
472 (fragment_ubo_binding != -1u) &&
473 (vertex_ubo_binding != fragment_ubo_binding))
474 {
475 RARCH_ERR("[slang]: Vertex and fragment uniform buffer must have same binding.\n");
476 return false;
477 }
478
479 unsigned ubo_binding = (vertex_ubo_binding != -1u)
480 ? vertex_ubo_binding
481 : fragment_ubo_binding;
482
483 if (has_ubo && ubo_binding >= SLANG_NUM_BINDINGS)
484 {
485 RARCH_ERR("[slang]: Binding %u is out of range.\n", ubo_binding);
486 return false;
487 }
488
489 reflection->ubo_binding = has_ubo ? ubo_binding : 0;
490 reflection->ubo_stage_mask = 0;
491 reflection->ubo_size = 0;
492 reflection->push_constant_size = 0;
493 reflection->push_constant_stage_mask = 0;
494
495 if (vertex_ubo)
496 {
497 reflection->ubo_stage_mask |= SLANG_STAGE_VERTEX_MASK;
498 reflection->ubo_size = max(reflection->ubo_size,
499 vertex_compiler.get_declared_struct_size(
500 vertex_compiler.get_type(
501 vertex.uniform_buffers[0].base_type_id)));
502 }
503
504 if (fragment_ubo)
505 {
506 reflection->ubo_stage_mask |= SLANG_STAGE_FRAGMENT_MASK;
507 reflection->ubo_size = max(reflection->ubo_size,
508 fragment_compiler.get_declared_struct_size(
509 fragment_compiler.get_type(
510 fragment.uniform_buffers[0].base_type_id)));
511 }
512
513 if (vertex_push)
514 {
515 reflection->push_constant_stage_mask |= SLANG_STAGE_VERTEX_MASK;
516 reflection->push_constant_size = max(
517 reflection->push_constant_size,
518 vertex_compiler.get_declared_struct_size(
519 vertex_compiler.get_type(
520 vertex.push_constant_buffers[0].base_type_id)));
521 }
522
523 if (fragment_push)
524 {
525 reflection->push_constant_stage_mask |= SLANG_STAGE_FRAGMENT_MASK;
526 reflection->push_constant_size = max(
527 reflection->push_constant_size,
528 fragment_compiler.get_declared_struct_size(
529 fragment_compiler.get_type(
530 fragment.push_constant_buffers[0].base_type_id)));
531 }
532
533 /* Validate push constant size against Vulkan's
534 * minimum spec to avoid cross-vendor issues. */
535 if (reflection->push_constant_size > 128)
536 {
537 RARCH_ERR("[slang]: Exceeded maximum size of 128 bytes"
538 " for push constant buffer.\n");
539 return false;
540 }
541
542 /* Find all relevant uniforms and push constants. */
543 if (vertex_ubo && !add_active_buffer_ranges(vertex_compiler,
544 vertex.uniform_buffers[0], reflection, false))
545 return false;
546 if (fragment_ubo && !add_active_buffer_ranges(fragment_compiler,
547 fragment.uniform_buffers[0], reflection, false))
548 return false;
549 if (vertex_push && !add_active_buffer_ranges(vertex_compiler,
550 vertex.push_constant_buffers[0], reflection, true))
551 return false;
552 if (fragment_push && !add_active_buffer_ranges(fragment_compiler,
553 fragment.push_constant_buffers[0], reflection, true))
554 return false;
555
556 if (has_ubo)
557 binding_mask = 1 << ubo_binding;
558
559 /* On to textures. */
560 for (i = 0; i < fragment.sampled_images.size(); i++)
561 {
562 unsigned array_index = 0;
563 unsigned set = fragment_compiler.get_decoration(
564 fragment.sampled_images[i].id,
565 spv::DecorationDescriptorSet);
566 unsigned binding = fragment_compiler.get_decoration(
567 fragment.sampled_images[i].id,
568 spv::DecorationBinding);
569
570 if (set != 0)
571 {
572 RARCH_ERR("[slang]: Resources must use descriptor set #0.\n");
573 return false;
574 }
575
576 if (binding >= SLANG_NUM_BINDINGS)
577 {
578 RARCH_ERR("[slang]: Binding %u is out of range.\n", ubo_binding);
579 return false;
580 }
581
582 if (binding_mask & (1 << binding))
583 {
584 RARCH_ERR("[slang]: Binding %u is already in use.\n", binding);
585 return false;
586 }
587 binding_mask |= 1 << binding;
588
589 slang_texture_semantic index = slang_name_to_texture_semantic(
590 *reflection->texture_semantic_map,
591 fragment.sampled_images[i].name, &array_index);
592
593 if (index == SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT && array_index >= reflection->pass_number)
594 {
595 RARCH_ERR("[slang]: Non causal filter chain detected. "
596 "Shader is trying to use output from pass #%u,"
597 " but this shader is pass #%u.\n",
598 array_index, reflection->pass_number);
599 return false;
600 }
601 else if (index == SLANG_INVALID_TEXTURE_SEMANTIC)
602 {
603 RARCH_ERR("[slang]: Texture name '%s' not found in semantic map, "
604 "Probably the texture name or pass alias is not defined "
605 "in the preset (Non-semantic textures not supported yet)\n",
606 fragment.sampled_images[i].name.c_str());
607 return false;
608 }
609
610 resize_minimum(reflection->semantic_textures[index], array_index + 1);
611 slang_texture_semantic_meta &semantic =
612 reflection->semantic_textures[index][array_index];
613 semantic.binding = binding;
614 semantic.stage_mask = SLANG_STAGE_FRAGMENT_MASK;
615 semantic.texture = true;
616 }
617
618 #ifdef DEBUG
619 RARCH_LOG("[slang]: Reflection\n");
620 RARCH_LOG("[slang]: Textures:\n");
621
622 for (i = 0; i < SLANG_NUM_TEXTURE_SEMANTICS; i++)
623 {
624 unsigned index = 0;
625 for (auto &sem : reflection->semantic_textures[i])
626 {
627 if (sem.texture)
628 RARCH_LOG("[slang]: %s (#%u)\n",
629 texture_semantic_names[i], index);
630 index++;
631 }
632 }
633
634 RARCH_LOG("[slang]:\n");
635 RARCH_LOG("[slang]: Uniforms (Vertex: %s, Fragment: %s):\n",
636 reflection->ubo_stage_mask & SLANG_STAGE_VERTEX_MASK ? "yes": "no",
637 reflection->ubo_stage_mask & SLANG_STAGE_FRAGMENT_MASK ? "yes": "no");
638 RARCH_LOG("[slang]: Push Constants (Vertex: %s, Fragment: %s):\n",
639 reflection->push_constant_stage_mask & SLANG_STAGE_VERTEX_MASK ? "yes": "no",
640 reflection->push_constant_stage_mask & SLANG_STAGE_FRAGMENT_MASK ? "yes": "no");
641
642 for (i = 0; i < SLANG_NUM_SEMANTICS; i++)
643 {
644 if (reflection->semantics[i].uniform)
645 {
646 RARCH_LOG("[slang]: %s (Offset: %u)\n",
647 semantic_uniform_names[i],
648 unsigned(reflection->semantics[i].ubo_offset));
649 }
650
651 if (reflection->semantics[i].push_constant)
652 {
653 RARCH_LOG("[slang]: %s (PushOffset: %u)\n",
654 semantic_uniform_names[i],
655 unsigned(reflection->semantics[i].push_constant_offset));
656 }
657 }
658
659 for (i = 0; i < SLANG_NUM_TEXTURE_SEMANTICS; i++)
660 {
661 unsigned index = 0;
662 for (auto &sem : reflection->semantic_textures[i])
663 {
664 if (sem.uniform)
665 {
666 RARCH_LOG("[slang]: %s (#%u) (Offset: %u)\n",
667 texture_semantic_uniform_names[i],
668 index,
669 unsigned(sem.ubo_offset));
670 }
671
672 if (sem.push_constant)
673 {
674 RARCH_LOG("[slang]: %s (#%u) (PushOffset: %u)\n",
675 texture_semantic_uniform_names[i],
676 index,
677 unsigned(sem.push_constant_offset));
678 }
679 index++;
680 }
681 }
682
683 {
684 char buf[64];
685 buf[0] = '\0';
686 snprintf(buf, sizeof(buf),
687 "[slang]:\n%s [slang]: Parameters:\n", FILE_PATH_LOG_INFO);
688 RARCH_LOG(buf);
689 }
690
691 for (i = 0; i < reflection->semantic_float_parameters.size(); i++)
692 {
693 slang_semantic_meta *param = (slang_semantic_meta*)
694 &reflection->semantic_float_parameters[i];
695
696 if (!param)
697 continue;
698
699 if (param->uniform)
700 RARCH_LOG("[slang]: #%u (Offset: %u)\n", i,
701 (unsigned int)param->ubo_offset);
702 if (param->push_constant)
703 RARCH_LOG("[slang]: #%u (PushOffset: %u)\n", i,
704 (unsigned int)param->push_constant_offset);
705 }
706 #endif
707
708 return true;
709 }
710
slang_reflect_spirv(const std::vector<uint32_t> & vertex,const std::vector<uint32_t> & fragment,slang_reflection * reflection)711 bool slang_reflect_spirv(const std::vector<uint32_t> &vertex,
712 const std::vector<uint32_t> &fragment,
713 slang_reflection *reflection)
714 {
715 try
716 {
717 Compiler vertex_compiler(vertex);
718 Compiler fragment_compiler(fragment);
719 spirv_cross::ShaderResources
720 vertex_resources = vertex_compiler.get_shader_resources();
721 spirv_cross::ShaderResources
722 fragment_resources = fragment_compiler.get_shader_resources();
723
724 if (!slang_reflect(vertex_compiler, fragment_compiler,
725 vertex_resources, fragment_resources,
726 reflection))
727 {
728 RARCH_ERR("[slang]: Failed to reflect SPIR-V."
729 " Resource usage is inconsistent with expectations.\n");
730 return false;
731 }
732
733 return true;
734 }
735 catch (const std::exception &e)
736 {
737 RARCH_ERR("[slang]: SPIRV-Cross threw exception: %s.\n", e.what());
738 return false;
739 }
740 }
741