Perform reflection on SPIR-V bytecode.
Uses SPIRV-Cross library to extract bindings, push constants, workgroup sizes, etc. Falls back to basic parsing if library unavailable.
430{
431 try {
432 spirv_cross::Compiler compiler(spirv_code);
433 spirv_cross::ShaderResources resources = compiler.get_shader_resources();
434
435 auto reflect_resources = [&](const spirv_cross::SmallVector<spirv_cross::Resource>& res_vec,
436 bool is_storage = false) {
437 for (const auto& resource : res_vec) {
438 ShaderReflection::DescriptorBinding desc;
439 desc.set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
440 desc.binding = compiler.get_decoration(resource.id, spv::DecorationBinding);
442 desc.name = resource.name;
443
444 const auto& type = compiler.get_type(resource.type_id);
445 desc.count = type.array.empty() ? 1 : type.array[0];
446 desc.type = spirv_to_vk_descriptor_type(type.basetype, type, is_storage);
447
449 }
450 };
451
452 reflect_resources(resources.uniform_buffers, false);
453
454 reflect_resources(resources.storage_buffers, true);
455
456 reflect_resources(resources.sampled_images, false);
457
458 reflect_resources(resources.storage_images, true);
459
460 reflect_resources(resources.separate_images, false);
461 reflect_resources(resources.separate_samplers, false);
462
466 }
467
468 for (const auto& pc_buffer : resources.push_constant_buffers) {
469 const auto& type = compiler.get_type(pc_buffer.type_id);
470
471 ShaderReflection::PushConstantRange
range;
474 range.size =
static_cast<uint32_t
>(compiler.get_declared_struct_size(type));
475
477 }
478
482 }
483
484 auto spec_constants = compiler.get_specialization_constants();
485 for (const auto& spec : spec_constants) {
486 ShaderReflection::SpecializationConstant sc;
487 sc.constant_id = spec.constant_id;
488 sc.name = compiler.get_name(spec.id);
489
490 const auto& type = compiler.get_type(compiler.get_constant(spec.id).constant_type);
491 sc.size = static_cast<uint32_t>(compiler.get_declared_struct_size(type));
492
494 }
495
498 "Reflected {} specialization constants",
500 }
501
502 if (
m_stage == vk::ShaderStageFlagBits::eCompute
503 ||
m_stage == vk::ShaderStageFlagBits::eMeshEXT
504 ||
m_stage == vk::ShaderStageFlagBits::eTaskEXT) {
505 auto entry_points = compiler.get_entry_points_and_stages();
506
507 for (const auto& ep : entry_points) {
508 if (ep.name ==
m_entry_point && ep.execution_model == spv::ExecutionModelGLCompute) {
509
510 std::array<uint32_t, 3> workgroup_size {
511 compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 0),
512 compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 1),
513 compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 2)
514 };
515
516 if (!workgroup_size.empty() && workgroup_size.size() >= 3) {
518 workgroup_size[0],
519 workgroup_size[1],
520 workgroup_size[2]
521 };
522
524 "Compute shader workgroup size: [{}, {}, {}]",
525 workgroup_size[0], workgroup_size[1], workgroup_size[2]);
526 }
527 break;
528 }
529 }
530 }
531
532 if (
m_stage == vk::ShaderStageFlagBits::eVertex) {
533 for (
const auto&
input : resources.stage_inputs) {
534 uint32_t location = compiler.get_decoration(
input.id, spv::DecorationLocation);
535 const auto& type = compiler.get_type(
input.type_id);
536
537 vk::VertexInputAttributeDescription attr;
538 attr.location = location;
539 attr.binding = 0;
541 attr.offset = 0;
542
544 }
545
548 "Reflected {} vertex input attributes",
550 }
551 }
552
553 return true;
554
555 } catch (const spirv_cross::CompilerError& e) {
557 "SPIRV-Cross reflection failed: {}", e.what());
558 return false;
559 }
560}
#define MF_ERROR(comp, ctx,...)
#define MF_DEBUG(comp, ctx,...)
Core::GlobalInputConfig input
vk::ShaderStageFlagBits m_stage
ShaderReflection m_reflection
static vk::Format spirv_type_to_vk_format(const spirv_cross::SPIRType &type)
Convert SPIRV-Cross type to Vulkan vertex attribute format.
std::string m_entry_point
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ Core
Core engine, backend, subsystems.
std::vector< double > range(std::span< const double > data, size_t n_windows, uint32_t hop_size, uint32_t window_size)
Value range (max - min) per window.
std::vector< SpecializationConstant > specialization_constants
std::vector< DescriptorBinding > bindings
std::vector< PushConstantRange > push_constants
std::vector< vk::VertexInputAttributeDescription > vertex_attributes
std::optional< std::array< uint32_t, 3 > > workgroup_size
local_size_x/y/z