Extract Push Constants from SPIR-V Binaries

When configuring graphics pipelines in modern APIs like Vulkan, applications must match pipeline layout definitions precisely to the push constant ranges and shader stage flags declared in shader code. This article explains the primary tools used to inspect compiled GLSL SPIR-V binaries to extract push constant offsets, byte sizes, and execution stage flags, focusing on the industry standard, SPIRV-Reflect, alongside alternatives like SPIRV-Cross.

The Primary Tool: SPIRV-Reflect

The most direct and lightweight tool for extracting push constant data and stage flags from SPIR-V bytecode is SPIRV-Reflect, an open-source C/C++ library maintained by Khronos Group. Designed specifically for runtime reflection, it parses SPIR-V modules without requiring a full compiler infrastructure.

When inspecting a compiled SPIR-V binary, SPIRV-Reflect populates internal structures representing shader resources. For push constants, it identifies:

  • Byte Offsets and Sizes: Extracted via SpvReflectBlockVariable, detailing the relative byte offset and total size of each push constant member or block.
  • Stage Flags: Extracted via the module's execution model, which directly translates to Vulkan VkShaderStageFlagBits (such as vertex, fragment, or compute).

Using its C API, developers can call spvReflectEnumeratePushConstantBlocks() on an initialized SpvReflectShaderModule to retrieve an array of push constant blocks. Each block reports its offset, size, padded_size, and the associated shader stage, allowing automated generation of VkPushConstantRange structs at runtime.

Alternative Option: SPIRV-Cross

While primarily an intermediate language transpiler, SPIRV-Cross is another widely used tool capable of static shader reflection.

Through its Compiler API, calling get_shader_resources().push_constant_buffers returns all push constant declarations in the module. Developers can inspect individual struct members using get_active_buffer_ranges() to resolve explicit byte ranges, offsets, and member types, while checking the active spv::ExecutionModel to determine the target stage flag.

Command-Line Inspection: spirv-dis

For manual debugging without programmatic integration, the spirv-dis disassembler from the official SPIRV-Tools suite can be used. Running spirv-dis converts the binary into human-readable SPIR-V assembly text:

  • Push constants appear under the OpTypePointer PushConstant declaration.
  • Byte layouts appear as OpMemberDecorate instructions specifying the Offset decoration for each struct field.
  • Pipeline stages are specified at the top of the file via OpEntryPoint directives.