spirv-cross2 0.6.0

Safe Rust bindings to SPIRV-Cross
Documentation
use glslang::SpirvVersion::{SPIRV1_0, SPIRV1_1, SPIRV1_6};
use glslang::{
    CompilerOptions, OpenGlVersion, ShaderInput, ShaderSource, ShaderStage, Target, VulkanVersion,
};
use spirv_cross2::reflect::TypeInner;
use spirv_cross2::SpirvCrossError;
use spirv_cross2::{Compiler, Module};

#[test]
pub fn spec_constant() -> Result<(), SpirvCrossError> {
    const SHADER: &str = r##"#version 450

layout (local_size_x_id = 0, local_size_y = 1, local_size_z = 1) in;


layout(set = 0, binding = 0) uniform Config{
    mat4 transform;
    int matrixCount;
} opData;

layout(set = 0, binding = 1) readonly buffer  InputBuffer{
    mat4 matrices[];
} sourceData;

layout(set = 0, binding = 2) buffer  OutputBuffer{
    mat4 matrices[];
} outputData;

void main()
{
    //grab global ID
	uint gID = gl_GlobalInvocationID.x;
    //make sure we don't access past the buffer size
    if(gID < opData.matrixCount)
    {
        // do math
        outputData.matrices[gID] = sourceData.matrices[gID] * opData.transform;
    }
}
"##;

    let glslang = glslang::Compiler::acquire().unwrap();

    let src = ShaderSource::from(SHADER);
    let mut opts = CompilerOptions::default();

    opts.target = Target::Vulkan {
        version: VulkanVersion::Vulkan1_3,
        spirv_version: SPIRV1_6,
    };

    let shader = ShaderInput::new(&src, ShaderStage::Compute, &opts, None, None).unwrap();
    let spv = glslang.create_shader(shader).unwrap().compile().unwrap();

    let mut compiler = Compiler::<spirv_cross2::targets::None>::new(Module::from_words(&spv))?;

    let spec_workgroup = compiler.work_group_size_specialization_constants();
    eprintln!("{:?}", spec_workgroup);

    let Some(args) = compiler.execution_mode_arguments(spirv::ExecutionMode::LocalSize)? else {
        panic!("unexpected")
    };

    let id = spec_workgroup.x.unwrap().id;

    // compiler.set_specialization_constant_value::<u32>(id, 100, 100, 10)?;
    compiler.set_specialization_constant_value(id, 4u32)?;
    let id = compiler.specialization_constant_value::<u32>(id)?;

    eprintln!("{:?}", args);
    eprintln!("{:?}", id);

    Ok(())
}

#[test]
pub fn workgroup_size() -> Result<(), SpirvCrossError> {
    const SHADER: &str = r##"#version 450

layout (local_size_x_id = 0, local_size_y = 1, local_size_z = 1) in;


layout(set = 0, binding = 0) uniform Config{
    mat4 transform;
    int matrixCount;
} opData;

layout(set = 0, binding = 1) readonly buffer  InputBuffer{
    mat4 matrices[];
} sourceData;

layout(set = 0, binding = 2) buffer  OutputBuffer{
    mat4 matrices[];
} outputData;

void main()
{
    //grab global ID
	uint gID = gl_GlobalInvocationID.x;
    //make sure we don't access past the buffer size
    if(gID < opData.matrixCount)
    {
        // do math
        outputData.matrices[gID] = sourceData.matrices[gID] * opData.transform;
    }
}
"##;

    let glslang = glslang::Compiler::acquire().unwrap();

    let src = ShaderSource::from(SHADER);
    let mut opts = CompilerOptions::default();

    opts.target = Target::Vulkan {
        version: VulkanVersion::Vulkan1_3,
        spirv_version: SPIRV1_6,
    };

    let shader = ShaderInput::new(&src, ShaderStage::Compute, &opts, None, None).unwrap();
    let spv = glslang.create_shader(shader).unwrap().compile().unwrap();

    let compiler = Compiler::<spirv_cross2::targets::None>::new(Module::from_words(&spv))?;

    let spec_workgroup = compiler.work_group_size_specialization_constants();
    eprintln!("{:?}", spec_workgroup);

    let Some(args) = compiler.execution_mode_arguments(spirv::ExecutionMode::LocalSize)? else {
        panic!("unexpected")
    };

    let id = spec_workgroup.x.unwrap().id;

    // compiler.set_specialization_constant_value::<u32>(id, 100, 100, 10)?;
    let id = compiler.specialization_constant_scalar::<u32>(id, 0, 0)?;

    eprintln!("{:?}", args);
    eprintln!("{:?}", id);

    Ok(())
}

#[test]
pub fn sandbox() -> Result<(), SpirvCrossError> {
    const SHADER: &str = r##"#version 450

layout(binding = 0) uniform UBO
{
    float value;
};

layout(location = 0) out vec4 color;
layout(binding = 1) uniform sampler2D tex;

void main() {
    color = texture(tex, vec2(value));
}"##;

    let glslang = glslang::Compiler::acquire().unwrap();

    let src = ShaderSource::from(SHADER);
    let mut opts = CompilerOptions::default();

    opts.target = Target::Vulkan {
        version: VulkanVersion::Vulkan1_0,
        spirv_version: SPIRV1_0,
    };

    let shader = ShaderInput::new(&src, ShaderStage::Vertex, &opts, None, None).unwrap();
    let spv = glslang.create_shader(shader).unwrap().compile().unwrap();

    let compiler = Compiler::<spirv_cross2::targets::None>::new(Module::from_words(&spv))?;

    let res = compiler.shader_resources()?.all_resources()?;

    let counter = &res.uniform_buffers[0];

    let ranges = compiler.active_buffer_ranges(counter.id)?;
    eprintln!("{:?}", ranges);

    Ok(())
}

#[test]
pub fn runtime_size_array() -> Result<(), SpirvCrossError> {
    const SHADER: &str = r##"#version 450

layout(std430, binding = 0) buffer SSBO
{
    float data[];
};

layout(location = 0) out vec4 color;
layout(binding = 1) uniform sampler2D tex;

void main() {
    color = texture(tex, vec2(0.0));
}"##;

    let glslang = glslang::Compiler::acquire().unwrap();

    let src = ShaderSource::from(SHADER);
    let mut opts = CompilerOptions::default();

    opts.target = Target::Vulkan {
        version: VulkanVersion::Vulkan1_0,
        spirv_version: SPIRV1_0,
    };

    let shader = ShaderInput::new(&src, ShaderStage::Vertex, &opts, None, None).unwrap();
    let spv = glslang.create_shader(shader).unwrap().compile().unwrap();

    let compiler = Compiler::<spirv_cross2::targets::None>::new(Module::from_words(&spv))?;

    let res = compiler.shader_resources()?.all_resources()?;

    eprintln!("{:?}", res.builtin_inputs);
    let counter = &res.storage_buffers[0];

    let TypeInner::Struct(struct_ty) = compiler.type_description(counter.base_type_id)?.inner
    else {
        panic!("unknown type")
    };

    eprintln!("{:?}", struct_ty);

    Ok(())
}

#[test]
pub fn image_type_sandbox() -> Result<(), SpirvCrossError> {
    const SHADER: &str = r##"#version 450

layout (constant_id = 0) const int SSAO_KERNEL_SIZE = 13;

layout(set = 0, binding = 0, std140) uniform UBO
{
    float data[SSAO_KERNEL_SIZE];
    mat4 matrix;
    vec2 vec;
};



layout(location = 0) out vec4[SSAO_KERNEL_SIZE] color;
layout(binding = 1) uniform sampler2D tex;
layout(binding = 1, rgba32f) writeonly uniform image3D threeD;
layout(binding = 2) uniform texture2DMSArray texArrayMs[4];
layout(binding = 3, rgba32f) uniform readonly imageBuffer arrayBuf;
layout(binding = 3) uniform samplerBuffer arrayBufA;
layout(binding = 3, rgba32f) uniform readonly imageBuffer arrayBufAS;

layout(binding = 3) uniform samplerCubeArrayShadow depth;

void main() {
    color[0] = texture(tex, vec2(0.0));
}"##;

    let glslang = glslang::Compiler::acquire().unwrap();

    let src = ShaderSource::from(SHADER);
    let mut opts = CompilerOptions::default();

    opts.target = Target::Vulkan {
        version: VulkanVersion::Vulkan1_0,
        spirv_version: SPIRV1_0,
    };

    let shader = ShaderInput::new(&src, ShaderStage::Vertex, &opts, None, None).unwrap();
    let spv = glslang.create_shader(shader).unwrap().compile().unwrap();

    let compiler = Compiler::<spirv_cross2::targets::None>::new(Module::from_words(&spv))?;

    let res = compiler.shader_resources()?.all_resources()?;

    let counter = &res.uniform_buffers[0];

    let TypeInner::Struct(stru) = compiler.type_description(counter.base_type_id)?.inner else {
        panic!("unexpected")
    };

    eprintln!("{:#?}", stru);
    let arrdesc = compiler.type_description(stru.members[1].id)?;

    eprintln!("{:?}", arrdesc);

    Ok(())
}

#[test]
pub fn const_id_array_dim() -> Result<(), SpirvCrossError> {
    const SHADER: &str = r##"#version 450

layout (constant_id = 0) const int SSAO_KERNEL_SIZE = 2;
layout(location = 0) out vec4[SSAO_KERNEL_SIZE][4] color;
layout(binding = 1) uniform sampler2D tex;

void main() {
    color[0][0] = texture(tex, vec2(0.0));
}"##;

    let glslang = glslang::Compiler::acquire().unwrap();

    let src = ShaderSource::from(SHADER);
    let mut opts = CompilerOptions::default();

    opts.target = Target::Vulkan {
        version: VulkanVersion::Vulkan1_0,
        spirv_version: SPIRV1_0,
    };

    let shader = ShaderInput::new(&src, ShaderStage::Vertex, &opts, None, None).unwrap();
    let spv = glslang.create_shader(shader).unwrap().compile().unwrap();

    let compiler = Compiler::<spirv_cross2::targets::None>::new(Module::from_words(&spv))?;

    let res = compiler.shader_resources()?.all_resources()?;

    let counter = &res.stage_outputs[0];

    eprintln!("{:?}", compiler.type_description(counter.type_id));

    Ok(())
}

#[test]
pub fn atomic_counters() -> Result<(), SpirvCrossError> {
    const SHADER: &str = r##"#version 450

layout(binding = 0) uniform atomic_uint one;

layout(location = 0) out vec4 color;
layout(binding = 1) uniform sampler2D tex;

void main() {
    color = texture(tex, vec2(0.0));
}"##;

    let glslang = glslang::Compiler::acquire().unwrap();

    let src = ShaderSource::from(SHADER);
    let mut opts = CompilerOptions::default();

    opts.target = Target::OpenGL {
        version: OpenGlVersion::OpenGL4_5,
        spirv_version: Some(SPIRV1_1),
    };

    let shader = ShaderInput::new(&src, ShaderStage::Vertex, &opts, None, None).unwrap();
    let spv = glslang.create_shader(shader).unwrap().compile().unwrap();

    let compiler = Compiler::<spirv_cross2::targets::None>::new(Module::from_words(&spv))?;

    let res = compiler.shader_resources()?.all_resources()?;

    let counter = &res.atomic_counters[0];

    eprintln!("{:?}", compiler.type_description(counter.base_type_id));

    Ok(())
}