SPIRV-Reflect is a lightweight library that provides a C/C++ reflection API for SPIR-V shader bytecode in Vulkan applications.

Overview

SPIRV-Reflect

SPIRV-Reflect is a lightweight library that provides a C/C++ reflection API for SPIR-V shader bytecode in Vulkan applications.

SPIRV-Reflect has been tested on Linux and Windows.

Features

  • Extract descriptor bindings from SPIR-V bytecode, to assist in the generation of Vulkan descriptor set and pipeline layouts.
  • Extract push constant block size from SPIR-V bytecode to assist in the generation of pipeline layouts.
  • Extract full layout data for uniform buffer and push constant blocks from SPIR-V bytecode, to assist in application updates of these structures.
  • Extract input/output variables from SPIR-V bytecode (including semantic decorations for HLSL shaders), to assist in validation of pipeline input/output settings.
  • Remap descriptor bindings at runtime, and update the source SPIR-V bytecode accordingly.
  • Log all reflection data as human-readable text.

Integration

SPIRV-Reflect is designed to make integration as easy as possible. The only external dependency is the Vulkan SDK.

To integrate SPIRV-Reflect into a project, simply add spirv_reflect.h and spirv_reflect.c in the project's build, and include spirv_reflect.h from the necessary source files.

Building Samples

This step is only necessary when building/running SPIRV-Reflect's example applications.

SPIRV-Reflect includes a collection of sample programs in the examples/ directory which demonstrate various use cases:

  • descriptors: This sample demonstrates the retrieval of descriptor bindings, including the population of VkDescriptorSetLayoutCreateInfo structures from reflection data.
  • hlsl_resource_types: This sample shows how various HLSL resource types are represented in SPIR-V.
  • io_variables: This sample demonstrates the retrieval of input/output variables, including the population of VkPipelineVertexInputStateCreateInfo structures from reflection data.

To build the included sample applications, use CMake to generate the appropriate project files for your platform, then build them as usual.

Note that you can set VulkanSDK directory as your preference. For example, on Linux:

VULKAN_SDK=$HOME/VulkanSDK/1.1.70.1/x86_64 cmake -G Ninja  ..

Usage

SPIRV-Reflect's core C API should be familiar to Vulkan developers:

#include "spirv_reflect.h"

int SpirvReflectExample(const void* spirv_code, size_t spirv_nbytes)
{
  // Generate reflection data for a shader
  SpvReflectShaderModule module;
  SpvReflectResult result = spvReflectCreateShaderModule(spirv_nbytes, spirv_code, &module);
  assert(result == SPV_REFLECT_RESULT_SUCCESS);

  // Enumerate and extract shader's input variables
  uint32_t var_count = 0;
  result = spvReflectEnumerateInputVariables(&module, &var_count, NULL);
  assert(result == SPV_REFLECT_RESULT_SUCCESS);
  SpvReflectInterfaceVariable** input_vars =
    (SpvReflectInterfaceVariable**)malloc(var_count * sizeof(SpvReflectInterfaceVariable*));
  result = spvReflectEnumerateInputVariables(&module, &var_count, input_vars);
  assert(result == SPV_REFLECT_RESULT_SUCCESS);

  // Output variables, descriptor bindings, descriptor sets, and push constants
  // can be enumerated and extracted using a similar mechanism.

  // Destroy the reflection data when no longer required.
  spvReflectDestroyShaderModule(&module);
}

A C++ wrapper is also provided.

Building Self-Test Suite

SPIRV-Reflect uses googletest for self-testing. This component is optional, and generally only of interest to developers modifying SPIRV-Reflect. To run the self-tests:

  • git submodule init
  • git submodule update
  • Enable SPIRV_REFLECT_BUILD_TESTS in CMake
  • Build and run the test-spirv-reflect project.

Bazel build

We tested the following bazel build command using Linux Bazel 1.2.1.

bazel build :all

License

Copyright 2017-2018 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Comments
  • Building as Release/RelWithDebInfo will throw a warning (warnings are treated as errors)

    Building as Release/RelWithDebInfo will throw a warning (warnings are treated as errors)

    Building using cmake version 3.16.3 and setting the build type flag as -DCMAKE_BUILD_TYPE=Release will throw a warning.

    [ 29%] Building CXX object CMakeFiles/spirv-reflect.dir/common/output_stream.cpp.o
    /home/john/Development/SPIRV-Reflect/common/output_stream.cpp: In function ‘void WriteReflection(const spv_reflect::ShaderModule&, bool, std::ostream&)’:
    /home/john/Development/SPIRV-Reflect/common/output_stream.cpp:945:20: error: variable ‘result’ set but not used [-Werror=unused-but-set-variable]
      945 |  
    cc1plus: all warnings being treated as errors
    make[2]: *** [CMakeFiles/spirv-reflect.dir/build.make:115: CMakeFiles/spirv-reflect.dir/common/output_stream.cpp.o] Error 1
    make[1]: *** [CMakeFiles/Makefile2:121: CMakeFiles/spirv-reflect.dir/all] Error 2
    make[1]: *** Waiting for unfinished jobs....
    
    opened by johnzupin 11
  • GLSL Storage buffers don't seem to get reflected properly

    GLSL Storage buffers don't seem to get reflected properly

    A resource binding with the following syntax doesn't show up properly.

    layout(binding = 1, std430, set = 0) buffer TriangleCounts { uint g_triangleCounts[]; };

    I think the bug is two-fold; it doesn't show up because of the various (p_node->storage_class != SpvStorageClassUniform) && (p_node->storage_class != SpvStorageClassUniformConstant) checks, but after improving them with a SpvStorageClassStorageBuffer check it's still broken (shows up as a uniform buffer).

    opened by Jasper-Bekkers 9
  • Issue parsing SPIRV with function taking struct parameter.

    Issue parsing SPIRV with function taking struct parameter.

    I've found an unusual issue where the library returns SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_BLOCK_MEMBER_REFERENCE. This is caused by accessing past the end of the p_access_chain->indexes[] array.

    I've narrowed it down to a descriptor block which has a struct in, and a function is called which takes the struct as a parameter. The glsl for this minimal repro looks like this:

    struct B {
    	float a;
    };
    layout (binding = 0) uniform Test {
    	B b;
    } test;
    float dothing(const in B b) {
    	return b.a;
    }
    layout(location = 0) out vec4 outColor;
    void main() {
    	outColor = vec4(0);
    	// this is fine
    	outColor.z = test.b.a;
    	// this line causes SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_BLOCK_MEMBER_REFERENCE
    	outColor.z = dothing(test.b);
    }
    

    I'm using glslc.exe to compile the shader. I've attached the spirv for this version (test-broken.frag.spv) and also a version with the last line commented out (test-works.frag.spv).

    I'm sorry, I was not able to understand why it is broken yet, maybe someone else could take a look too?

    test-spv.zip

    opened by noggs 8
  • $Global constant buffer is not reflected

    $Global constant buffer is not reflected

    When building from HLSL SPRIV-Reflect ignores $Global constant buffer.

    glslangValidator -V -D -e main test.frag

    uniform float4 u_test0;
    
    cbuffer : register(b0)
    {
        float4 u_test1;
    };
    
    void main(out float4 fragColor : SV_TARGET0)
    {
        fragColor = u_test0 * u_test1;
    }
    

    spirv-reflect frag.spv

    will output only descriptor binding for unnamed constant buffer that contains u_test1.

    opened by bkaradzic 8
  • Fix unused variables for Release Linux builds.

    Fix unused variables for Release Linux builds.

    asserts are no ops for Release compilations, and thus are not counted as uses. So any variables used only in asserts, as here, are considered unused and cause warnings, and consequently errors for Release Linux builds.

    opened by greg-lunarg 7
  • Support for AccelerationStructure

    Support for AccelerationStructure

    Hello,

    Can we expect to get the AccelerationStructure types being reflected in the future? I want to migrate from SPIRV-Cross library's reflection as this library is smaller and I only need reflection. Is this library going to be maintained in the future, or is it preferred to use Spirv-Cross?

    opened by turanszkij 6
  • Support for NVidia RTX extension

    Support for NVidia RTX extension

    Hi,

    would it be possible to add support for RTX shader extensions (ray generation, miss, closest hit, intersection and any hit shader types) ?

    How hard or easy would that be ?

    If I had to do it on my own, do you have any pointers where to start ?

    opened by jcxz 6
  • spirv-reflect dumping wrong info for $Global block

    spirv-reflect dumping wrong info for $Global block

    Input HLSL:

    struct VSInput
    {
        float2 pos : POSITION;
        float4 color : COLOR0;
        float2 uv : TEXCOORD0;
    };
    
    struct VSOutput
    {
        float4 pos : SV_POSITION;
        float4 color : COLOR0;
        float2 uv : TEXCOORD0;
    };
    
    cbuffer myconstants : register(b0)
    {
        float delta;
        float delta2;
    };
    
    float himom : register(b1);
    float byemom : register(b2);
    
    VSOutput main(VSInput input)
    {
        VSOutput o;
        o.pos = float4(input.pos, 0.f, 1.f);
        o.color = input.color + float4(delta, delta2, delta + byemom, delta + himom);
        o.uv = input.uv;
    
        return o;
    }
    

    Compiling with dxc -spirv -fspv-reflect -fspv-target-env=vulkan1.1 and running spirv-reflect on the output, I see the following bit:

      Descriptor bindings: 2
        0:
          binding : 0
          set     : 0
          type    : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER (CBV)
          name    : myconstants (type.myconstants)
              // offset = 0, abs offset = 0, size = 16, padded size = 16
              struct type.myconstants {
                  float delta;          // offset = 0, abs offset = 0, size =  4, padded size =  4
                  float delta2;         // offset = 4, abs offset = 4, size =  4, padded size = 12
              } type.myconstants;
    
        1:
          binding : 1
          set     : 0
          type    : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER (CBV)
          name    : $Globals (type.myconstants)
              // offset = 0, abs offset = 0, size = 16, padded size = 16
              struct type.myconstants {
                  float delta;          // offset = 0, abs offset = 0, size =  4, padded size =  4
                  float delta2;         // offset = 4, abs offset = 4, size =  4, padded size = 12
              } type.myconstants;
    

    It looks like it's dumping the myconstants block twice, instead of dumping $Globals the second time around.

    opened by nsubtil 5
  • constify ShaderReflection::Get*() methods

    constify ShaderReflection::Get*() methods

    GetDescriptor(), GetDescriptorSet(), GetInputVariable(), and GetOutputVariable() aren't tagged as const. Any reason they couldn't be? Also, why do they return "Foo* const" instead of "const Foo*"?

    opened by cdwfs 5
  • Add support for SPV_NV_ray_tracing

    Add support for SPV_NV_ray_tracing

    • updated spirv.h to the latest version
    • added SpvReflectShaderStageFlagBits for the 6 new raytracing shader stages
    • added SpvReflectDescriptorType for acceleration structures
    • added SpvReflectTypeFlagBits for SPV_REFLECT_TYPE_FLAG_EXTERNAL_OPAQUE which is newly introduced for acceleration structures
    • parse SpvOpTypeAccelerationStructureNV correctly in ParseNodes
    • flag acceleration structures as a SPV_REFLECT_TYPE_FLAG_EXTERNAL_OPAQUE type in ParseTypes
    • mark acceleration structures as SRVs and translate them into the correct descriptor type

    This resolves #85

    NOTE: these changes were made to reflect descriptors from DXC-compiled raytracing libraries, and to modify descriptor sets. there are likely missing features.

    opened by jkunstwald 4
  • [i]samplerbuffer identified as VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER

    [i]samplerbuffer identified as VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER

    In the following GLSL shader, both bindings are categorized as combined image samplers instead of uniform texel buffers.

    #version 450
    #pragma shader_stage(vertex)
    layout (set = 0, binding = 1) uniform isamplerBuffer texel_buffer_i;
    layout (set = 0, binding = 2) uniform samplerBuffer texel_buffer_f;
    
    void main() {
      int i = texelFetch(texel_buffer_i, gl_InstanceIndex).x;
      float f = texelFetch(texel_buffer_f, gl_InstanceIndex).x;
      gl_Position = vec4(i, f, 0, 1);
    }
    

    Quick exploratory debugging revealed that on line 1181 of spirv_reflect.c, p_descriptor->image.dim is SpvDimImage1D, not SpvDimBuffer. The latter would put the descriptor into the texel buffer path; the former makes it a combined image sampler. Root cause left as an exercise for the author.

    opened by cdwfs 4
  • Adding word offset to SpvReflectBlockVariable

    Adding word offset to SpvReflectBlockVariable

    This change adds the word offset, of UBO offsets to the SpvReflectBlockVariable struct as part of #158.

    I kept it in the word_offset struct, simply because you said you didn't have a strong opinion, but I can of course pop it out.

    opened by alister-chowdhury 0
  • Use same .clang-format as SPIRV-Tools

    Use same .clang-format as SPIRV-Tools

    This is just a suggestion, but SPIRV-Tools has a .clang-format and it might be nice to use the same formatting (and eventually maybe enforce it on PRs).

    opened by cassiebeckley 1
  • Support for CooperativeMatrix extension?

    Support for CooperativeMatrix extension?

    I know this is Nvidia only extension at the moment, but is there a plan to support cooperative matrix extensions (GL_NV_cooperative_matrix, GL_NV_integer_cooperative_matrix)?

    Examples are here: https://github.com/jeffbolznv/vk_cooperative_matrix_perf/tree/master/shaders

    More and more shaders are using this extension.

    opened by ib00 1
  • Adding additional word offsets to `SpvReflectBlockVariable`

    Adding additional word offsets to `SpvReflectBlockVariable`

    Hey there,

    It would be useful to be able to reflect the word offset of offset in UBOs, this allows you to reorder and compact structs. (This is mostly for dealing with floating hlsl $Globals)

    This was a very trivial patch for me to implement locally, if it's something you wouldn't be against I can quickly put together a PR.

    --- aspirv_reflect/spirv_reflect.c
    +++ bspirv_reflect/spirv_reflect.c
    @@ -2272,6 +2272,8 @@ static SpvReflectResult ParseDescriptorBlockVariable(
             ApplyArrayTraits(p_member_type, &p_member_var->array);
           }
    
    +      p_member_var->word_offset.offset = p_type_node->member_decorations[member_index].offset.word_offset;
    +
           p_member_var->type_description = p_member_type;
         }
       }
    
    --- aspirv_reflect/spirv_reflect.h
    +++ bspirv_reflect/spirv_reflect.h
    @@ -378,6 +378,10 @@ typedef struct SpvReflectBlockVariable {
       uint32_t                          member_count;
       struct SpvReflectBlockVariable*   members;
    
    +  struct {
    +    uint32_t                          offset;
    +  } word_offset;
    +
       SpvReflectTypeDescription*        type_description;
     } SpvReflectBlockVariable;
    
    opened by alister-chowdhury 2
  • Descriptor binding name?

    Descriptor binding name?

    It appears that descriptor binding name is always empty.

    It appears that the name has to be obtained from SpvReflectTypeDescription* type_description; field.

    Feature or a bug?

    opened by ib00 3
  • Adding preliminary `SpecConstant` support

    Adding preliminary `SpecConstant` support

    Used code form godot/godot as starting point. See https://github.com/KhronosGroup/SPIRV-Reflect/issues/121

    Next steps: 64 bit types need 2 words as operand, SpecConstantOp need implementation for evaluating spec constant (spirv-cross has an implementation for uint https://github.com/KhronosGroup/SPIRV-Cross/pull/1463). Also maybe composite type evaluation support?

    opened by shangjiaxuan 17
Owner
The Khronos Group
Connecting Software to Silicon
The Khronos Group
The DirectX Shader Compiler project includes a compiler and related tools used to compile High-Level Shader Language (HLSL) programs into DirectX Intermediate Language (DXIL) representation

DirectX Shader Compiler The DirectX Shader Compiler project includes a compiler and related tools used to compile High-Level Shader Language (HLSL) pr

Microsoft 2.4k Jan 3, 2023
Open-Source Vulkan C++ API

Vulkan-Hpp: C++ Bindings for Vulkan The goal of the Vulkan-Hpp is to provide header only C++ bindings for the Vulkan C API to improve the developers V

The Khronos Group 2.5k Jan 8, 2023
SPIR-V extension for Visual Studio

SPIR-V extension for Visual Studio (VSIX) About This VSIX extension adds SPIR-V related commands to the context menu of GLSL shader files (and folders

Sascha Willems 89 Oct 27, 2022
Pathway is an Android library that provides new functionalities around the graphics Path API.

Pathway is an Android library that provides new functionalities around the graphics Path API.

Romain Guy 148 Jan 5, 2023
Legion Low Level Rendering Interface provides a graphics API agnostic rendering interface with minimal CPU overhead and low level access to verbose GPU operations.

Legion-LLRI Legion-LLRI, or “Legion Low Level Rendering Interface” is a rendering API that aims to provide a graphics API agnostic approach to graphic

Rythe Interactive 25 Dec 6, 2022
An immediate-mode, renderer agnostic, lightweight debug drawing API for C++

Debug Draw An immediate-mode, renderer agnostic, lightweight debug drawing API for C++. License This software is in the public domain. Where that dedi

Guilherme Lampert 457 Dec 24, 2022
A multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input

GLFW Introduction GLFW is an Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan application development. It provides a simple, platf

GLFW 10k Jan 1, 2023
Low Level Graphics Library (LLGL) is a thin abstraction layer for the modern graphics APIs OpenGL, Direct3D, Vulkan, and Metal

Low Level Graphics Library (LLGL) Documentation NOTE: This repository receives bug fixes only, but no major updates. Pull requests may still be accept

Lukas Hermanns 1.5k Jan 8, 2023
My computer graphics playground. Currently has a raytracer implemented with D3D11 compute shader.

Graphics Playground I use this project as my "toy" engine. I'll be implementing various graphics projects in this repository. The code here is not sui

Berk Emre Sarıbaş 4 Aug 26, 2021
Blend text in a HLSL shader and have it look like native DirectWrite

dwrite-hlsl This project demonstrates how to blend text in a HLSL shader and have it look like native DirectWrite. License This project is an extract

Leonard Hecker 11 May 24, 2022
A physically based shader for woven cloth

ThunderLoom A physically based shader for woven cloth This projects consits of three main parts: Irawan shading model At its core is an implementation

null 92 Oct 29, 2022
Basic framework for D3D11 init, model/texture loading, shader compilation and camera movement.

reed-framework Basic framework for D3D11 init, model/texture loading, camera movement, etc. Instructions: #include <framework.h> Link with framework.l

Nathan Reed 34 May 18, 2022
基于 Vulkan 实现的 GPUImage

Vulkan-GPUImage 基于 Vulkan 渲染的 GPUImage 版本,实现渲染链机制,复刻 GPUImage 上的多个效果(逐渐增加中)。 更多技术实现,详见源码~~ Vulkan 学习文章 进击的 Vulkan 移动开发(一)之今生前世 进击的 Vulkan 移动开发之 Instan

glumes 143 Nov 15, 2022
Minimal pathtracer using Vulkan RayTracing

Single File Vulkan Pathtracing Minimal pathtracer using Vulkan RayTracing Environment Vulkan SDK 1.2.162.0 GPU / Driver that support Vulkan Ray Tracin

Yuki Nishidate 29 Dec 21, 2022
OBS Linux Vulkan/OpenGL game capture

OBS Linux Vulkan/OpenGL game capture OBS plugin for Vulkan/OpenGL game capture on Linux. Requires OBS with EGL support (currently unreleased, you need

David Rosca 290 Jan 1, 2023
Vulkan physically based raytracer including denoising

VulkanPBRT Vulkan physically based raytracer including denoising. The GPU raytracer is based on Vulkan only, as well as for the denoising only the Vul

null 18 Nov 25, 2022
Axel Gneiting 1.5k Dec 31, 2022
A toy renderer written in C using Vulkan to perform real-time ray tracing research.

This is a toy renderer written in C using Vulkan. It is intentionally minimalist. It has been developed and used for the papers "BRDF Importance Sampl

Christoph Peters 290 Dec 19, 2022
This repository accompanies Ray Tracing Gems II: Next Generation Rendering with DXR, Vulkan, and OptiX

Apress Source Code This repository accompanies Ray Tracing Gems II: Next Generation Rendering with DXR, Vulkan, and OptiX by Adam Marrs, Peter Shirley

Apress 684 Dec 29, 2022