Rust着色器编译库shaderc的使用,shaderc提供高性能GLSL/HLSL到SPIR-V的跨平台编译功能

Rust着色器编译库shaderc的使用,shaderc提供高性能GLSL/HLSL到SPIR-V的跨平台编译功能

shaderc-rs是Google shaderc库的Rust绑定,提供高性能的GLSL/HLSL到SPIR-V的跨平台编译功能。

使用

首先在Cargo.toml中添加依赖:

[dependencies]
shaderc = "0.9"

然后在crate根中添加:

extern crate shaderc;

示例

以下是编译着色器为SPIR-V二进制模块和汇编文本的示例:

use shaderc;

let source = "#version 310 es\n void EP() {}";

let mut compiler = shaderc::Compiler::new().unwrap();
let mut options = shaderc::CompileOptions::new().unwrap();
options.add_macro_definition("EP", Some("main"));
let binary_result = compiler.compile_into_spirv(
    source, shaderc::ShaderKind::Vertex,
    "shader.glsl", "main", Some(&options)).unwrap();

assert_eq!(Some(&0x07230203), binary_result.as_binary().first());

let text_result = compiler.compile_into_spirv_assembly(
    source, shaderc::ShaderKind::Vertex,
    "shader.glsl", "main", Some(&options)).unwrap();

assert!(text_result.as_text().starts_with("; SPIR-V\n"));

完整示例

以下是一个更完整的示例,展示如何使用shaderc编译GLSL着色器:

use shaderc;

fn main() {
    // GLSL顶点着色器源代码
    let vertex_shader_source = r#"
        #version 450
        layout(location = 0) in vec3 position;
        layout(location = 1) in vec3 color;
        layout(location = 0) out vec3 fragColor;
        
        void main() {
            gl_Position = vec4(position, 1.0);
            fragColor = color;
        }
    "#;

    // 创建编译器实例
    let compiler = shaderc::Compiler::new().expect("Failed to create shader compiler");
    
    // 创建编译选项
    let mut compile_options = shaderc::CompileOptions::new().unwrap();
    compile_options.set_optimization_level(shaderc::OptimizationLevel::Performance);
    
    // 编译顶点着色器为SPIR-V
    let vertex_spirv = compiler.compile_into_spirv(
        vertex_shader_source,
        shaderc::ShaderKind::Vertex,
        "vertex_shader.glsl",  // 文件名,用于错误报告
        "main",                // 入口函数名
        Some(&compile_options)
    ).expect("Failed to compile vertex shader");
    
    // 输出编译结果
    println!("Vertex shader SPIR-V size: {} bytes", vertex_spirv.as_binary().len());
    println!("Vertex shader compilation warnings: {}", vertex_spirv.get_warning_messages());
    
    // 也可以编译为SPIR-V汇编文本
    let vertex_asm = compiler.compile_into_spirv_assembly(
        vertex_shader_source,
        shaderc::ShaderKind::Vertex,
        "vertex_shader.glsl",
        "main",
        Some(&compile_options)
    ).expect("Failed to compile vertex shader to assembly");
    
    println!("Vertex shader assembly:\n{}", vertex_asm.as_text());
}

设置

shaderc-rs需要C++ shaderc库,可以通过以下方式获取:

  1. 从Vulkan SDK中获取
  2. 通过Linux包管理器安装
  3. 从shaderc项目下载预编译版本
  4. 从源代码构建

构建脚本会按以下顺序尝试获取原生shaderc库:

  1. 如果指定了--features build-from-source,则从源代码构建
  2. 如果设置了SHADERC_LIB_DIR环境变量,则搜索该路径
  3. 如果设置了VULKAN_SDK环境变量,则搜索$VULKAN_SDK/lib
  4. 如果可用,使用pkg-config查找库路径
  5. 在Linux上,如果没有设置SHADERC_LIB_DIR,还会搜索系统库路径
  6. 如果以上步骤都找不到原生库,则从源代码构建

从源代码构建

要从源代码构建shaderc,需要以下工具:

  • CMake
  • Git
  • Python 3
  • C++11编译器

在Windows上还需要Ninja构建系统。


1 回复

Rust着色器编译库shaderc使用指南

shaderc是Rust中一个高性能的着色器编译库,提供了将GLSL和HLSL编译为SPIR-V字节码的功能。它是Google的Shaderc项目的Rust绑定,支持跨平台使用。

主要特性

  • 支持GLSL和HLSL到SPIR-V的编译
  • 跨平台支持(Windows/Linux/macOS)
  • 包含预编译的shaderc库,无需额外安装
  • 支持着色器优化
  • 提供详细的编译错误信息

安装

在Cargo.toml中添加依赖:

[dependencies]
shaderc = "0.7"

基本使用方法

1. 编译GLSL着色器

use shaderc;

fn compile_glsl_to_spirv() -> Result<Vec<u32>, shaderc::Error> {
    let source = r#"
        #version 450
        layout(location = 0) in vec3 position;
        layout(location = 0) out vec4 fragColor;
        
        void main() {
            fragColor = vec4(position, 1.0);
        }
    "#;
    
    let mut compiler = shaderc::Compiler::new().unwrap();
    let options = shaderc::CompileOptions::new().unwrap();
    
    let binary_result = compiler.compile_into_spirv(
        source,
        shaderc::ShaderKind::Fragment,
        "shader.glsl",
        "main",
        Some(&options),
    )?;
    
    Ok(binary_result.as_binary().to_vec())
}

2. 编译HLSL着色器

fn compile_hlsl_to_spirv() -> Result<Vec<u32>, shaderc::Error> {
    let source = r#"
        struct PSInput {
            float4 position : SV_POSITION;
            float4 color : COLOR;
        };
        
        float4 PSMain(PSInput input) : SV_TARGET {
            return input.color;
        }
    "#;
    
    let mut compiler = shaderc::Compiler::new().unwrap();
    let mut options = shaderc::CompileOptions::new().unwrap();
    options.set_source_language(shaderc::SourceLanguage::HLSL);
    
    let binary_result = compiler.compile_into_spirv(
        source,
        shaderc::ShaderKind::Fragment,
        "shader.hlsl",
        "PSMain",
        Some(&options),
    )?;
    
    Ok(binary_result.as_binary().to_vec())
}

高级功能

1. 设置优化级别

let mut options = shaderc::CompileOptions::new().unwrap();
options.set_optimization_level(shaderc::OptimizationLevel::Performance);

2. 添加宏定义

options.add_macro_definition("USE_TEXTURE", Some("1"));

3. 包含目录设置

options.set_include_callback(|requested_source, _, _, _| {
    match requested_source {
        "common.glsl" => Ok(shaderc::ResolvedInclude {
            resolved_name: "common.glsl".to_string(),
            content: "#define PI 3.14159265359".to_string(),
        }),
        _ => Err("File not found".to_string()),
    }
});

4. 获取编译警告和错误

match compiler.compile_into_spirv(source, kind, filename, entry, Some(&options)) {
    Ok(result) => {
        if !result.get_num_warnings() == 0 {
            println!("Compilation warnings: {}", result.get_warning_messages());
        }
        Ok(result.as_binary().to_vec())
    }
    Err(e) => {
        eprintln!("Shader compilation failed: {}", e);
        Err(e)
    }
}

使用场景示例

Vulkan应用程序中的着色器加载

use vulkano::shader::ShaderModule;

fn load_shader(device: Arc<Device>) -> Arc<ShaderModule> {
    let spirv = compile_glsl_to_spirv().unwrap();
    
    unsafe {
        ShaderModule::from_words(device, &spirv).unwrap()
    }
}

完整示例代码

下面是一个完整的Vulkan应用程序中使用shaderc编译和加载着色器的示例:

use shaderc;
use vulkano::{
    device::{Device, DeviceExtensions},
    instance::{Instance, InstanceExtensions},
    shader::ShaderModule,
    Version,
};
use std::sync::Arc;

fn main() {
    // 1. 初始化Vulkan实例
    let instance = Instance::new(
        None,
        Version::V1_1,
        &InstanceExtensions::none(),
        None,
    ).unwrap();

    // 2. 编译GLSL着色器
    let vert_shader = compile_vertex_shader().unwrap();
    let frag_shader = compile_fragment_shader().unwrap();

    // 3. 创建逻辑设备
    let physical = instance.enumerate_physical_devices().unwrap().next().unwrap();
    let queue_family = physical.queue_families().next().unwrap();
    let (device, mut queues) = Device::new(
        physical,
        physical.supported_features(),
        &DeviceExtensions::none(),
        [(queue_family, 0.5)].iter().cloned(),
    ).unwrap();

    // 4. 加载着色器模块
    let vert_shader_module = unsafe {
        ShaderModule::from_words(device.clone(), &vert_shader).unwrap()
    };
    
    let frag_shader_module = unsafe {
        ShaderModule::from_words(device.clone(), &frag_shader).unwrap()
    };

    println!("Shader modules loaded successfully!");
}

// 编译顶点着色器
fn compile_vertex_shader() -> Result<Vec<u32>, shaderc::Error> {
    let source = r#"
        #version 450
        layout(location = 0) in vec2 position;
        layout(location = 1) in vec3 color;
        
        layout(location = 0) out vec3 v_color;
        
        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
            v_color = color;
        }
    "#;
    
    let mut compiler = shaderc::Compiler::new().unwrap();
    let mut options = shaderc::CompileOptions::new().unwrap();
    options.set_optimization_level(shaderc::OptimizationLevel::Performance);
    
    compiler.compile_into_spirv(
        source,
        shaderc::ShaderKind::Vertex,
        "vert.glsl",
        "main",
        Some(&options),
    ).map(|res| res.as_binary().to_vec())
}

// 编译片段着色器
fn compile_fragment_shader() -> Result<Vec<u32>, shaderc::Error> {
    let source = r#"
        #version 450
        layout(location = 0) in vec3 v_color;
        layout(location = 0) out vec4 f_color;
        
        void main() {
            f_color = vec4(v_color, 1.0);
        }
    "#;
    
    let mut compiler = shaderc::Compiler::new().unwrap();
    let mut options = shaderc::CompileOptions::new().unwrap();
    options.set_optimization_level(shaderc::OptimizationLevel::Performance);
    
    compiler.compile_into_spirv(
        source,
        shaderc::ShaderKind::Fragment,
        "frag.glsl",
        "main",
        Some(&options),
    ).map(|res| res.as_binary().to_vec())
}

注意事项

  1. shaderc会链接预编译的库,在Windows上可能需要Visual C++运行时
  2. 对于复杂的着色器项目,考虑使用include_str!宏来管理着色器代码文件
  3. 发布构建时可以考虑缓存编译后的SPIR-V字节码以提高加载速度

shaderc为Rust开发者提供了强大的着色器编译能力,特别适合需要跨平台着色器支持的图形应用程序开发。

回到顶部