Rust的DirectX编译器封装库mach-dxcompiler-rs,实现高性能GPU着色器编译与跨平台图形开发

mach-dxcompiler-rs

该库允许将来自mach-dxcompiler的预构建二进制文件静态链接到Rust项目中。mach-dxcompiler存储库是微软DirectXShaderCompiler的一个分支,用Zig替换了CMake构建系统。这使得可以静态构建项目并将其链接到现有应用程序中——但核心逻辑仍然来自原始的DXC库。

使用方法

该crate的构建脚本需要curl.exetar.exe命令行工具,Windows 10和11应该默认安装了这些工具。

首先,将crate添加到项目中:cargo add mach-dxcompiler-rs

接下来,使用DxcCreateInstance函数创建DXC COM对象。创建后,这些对象可以与常规的COM Windows API一起使用。

use windows::Win32::Graphics::Direct3D::Dxc;

let mut dxcompiler = std::ptr::null_mut();
mach_dxcompiler_rs::DxcCreateInstance(&Dxc::CLSID_DxcCompiler, &Dxc::IDxcCompiler3::IID, &mut dxcompiler);
// ... 使用着色器编译器 ...

Visual Studio 要求

对于MSVC用户,请确保你的Visual Studio版本至少为17.11或更高。这是为了与本项目使用的构建工具和库兼容。

完整示例

下面是一个完整的示例,展示如何使用mach-dxcompiler-rs编译HLSL着色器:

use windows::{
    core::Interface,
    Win32::Graphics::Direct3D::Dxc::{self, IDxcBlob, IDxcCompiler3, IDxcUtils},
};

fn compile_shader() -> windows::core::Result<()> {
    // 创建编译器实例
    let mut compiler: Option<IDxcCompiler3> = None;
    unsafe {
        mach_dxcompiler_rs::DxcCreateInstance(
            &Dxc::CLSID_DxcCompiler,
            &IDxcCompiler3::IID,
            &mut compiler as *mut _ as *mut *mut _,
        )
    }?;

    // 创建实用工具实例
    let mut utils: Option<IDxcUtils> = None;
    unsafe {
        mach_dxcompiler_rs::DxcCreateInstance(
            &Dxc::CLSID_DxcUtils,
            &IDxcUtils::IID,
            &mut utils as *mut _ as *mut *mut _,
        )
    }?;
    let utils = utils.unwrap();

    // HLSL源代码
    let shader_source = r"
        struct PSInput {
            float4 position : SV_POSITION;
            float4 color : COLOR;
        };

        float4 PSMain(PSInput input) : SV_TARGET {
            return input.color;
        }
    ";

    // 将源代码转换为Blob
    let mut source_blob: Option<IDxcBlob> = None;
    unsafe {
        utils.CreateBlobFromPinned(
            shader_source.as_ptr() as *const _,
            shader_source.len() as u32,
            Dxc::DXC_CP_UTF8,
            &mut source_blob,
        )
    }?;
    let source_blob = source_blob.unwrap();

    // 编译参数
    let args = [
        "-T".as_ptr() as *const i8,    // 着色器目标
        "ps_6_0".as_ptr() as *const i8,
        "-E".as_ptr() as *const i8,    // 入口点
        "PSMain".as_ptr() as *const i8,
    ];

    // 编译着色器
    let mut result: Option<IDxcBlob> = None;
    unsafe {
        compiler.unwrap().Compile(
            &source_blob,
            std::ptr::null(),
            std::ptr::null(),
            args.as_ptr(),
            args.len() as u32,
            std::ptr::null_mut(),
            0,
            std::ptr::null_mut(),
            &mut result,
        )
    }?;

    if let Some(blob) = result {
        // 获取编译后的二进制数据
        let buffer = unsafe { std::slice::from_raw_parts(blob.GetBufferPointer() as *const u8, blob.GetBufferSize() as usize) };
        println!("Shader compiled successfully! Size: {} bytes", buffer.len());
    }

    Ok(())
}

fn main() {
    if let Err(e) = compile_shader() {
        eprintln!("Failed to compile shader: {}", e);
    }
}

这个示例展示了如何:

  1. 创建DXC编译器实例
  2. 创建实用工具实例
  3. 将HLSL源代码转换为Blob
  4. 设置编译参数
  5. 编译着色器并获取结果

注意:实际使用中你可能需要添加更多的错误处理和功能,如包含文件、定义宏等。


1 回复

Rust的DirectX编译器封装库mach-dxcompiler-rs

介绍

mach-dxcompiler-rs是Rust语言对微软DirectX Shader Compiler(DXC)的封装库,它提供了高性能的GPU着色器编译能力,支持跨平台图形开发。这个库是Mach引擎生态系统的一部分,旨在为Rust开发者提供现代化的着色器编译工具链。

主要特性:

  • 封装了微软的DXC编译器(原HLSL编译器)
  • 支持HLSL和SPIR-V着色器编译
  • 跨平台支持(Windows/Linux/macOS)
  • 提供类型安全的Rust接口
  • 支持着色器模型6.0+的高级特性
  • 可集成到各种图形API后端(Vulkan、Direct3D 12等)

完整示例

下面是一个完整的使用mach-dxcompiler-rs编译HLSL着色器并集成到wgpu图形管线的示例:

use mach_dxcompiler::*;
use wgpu;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 初始化wgpu
    let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
        backends: wgpu::Backends::VULKAN,
        ..Default::default()
    });
    
    let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions::default()).await.unwrap();
    let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor::default(), None).await.unwrap();

    // 2. 定义HLSL顶点和片段着色器
    let vertex_shader = r#"
        struct VertexInput {
            float3 position : POSITION;
            float3 normal : NORMAL;
        };

        struct VertexOutput {
            float4 position : SV_POSITION;
            float3 normal : NORMAL;
        };

        [shader("vertex")]
        VertexOutput vs_main(VertexInput input) {
            VertexOutput output;
            output.position = float4(input.position, 1.0);
            output.normal = input.normal;
            return output;
        }
    "#;

    let fragment_shader = r#"
        struct FragmentInput {
            float4 position : SV_POSITION;
            float3 normal : NORMAL;
        };

        [shader("fragment")]
        float4 ps_main(FragmentInput input) : SV_TARGET {
            return float4(input.normal * 0.5 + 0.5, 1.0);
        }
    "#;

    // 3. 使用mach-dxcompiler编译着色器
    let dxcompiler = DxCompiler::new()?;
    
    // 编译顶点着色器为SPIR-V
    let vs_result = dxcompiler.compile(
        vertex_shader,
        &CompileOptions {
            entry_point: "vs_main".to_string(),
            target_profile: "vs_6_0".to_string(),
            output_format: OutputFormat::SpirV,
            optimization_level: OptimizationLevel::Level3,
            ..Default::default()
        },
    )?;

    // 编译片段着色器为SPIR-V
    let fs_result = dxcompiler.compile(
        fragment_shader,
        &CompileOptions {
            entry_point: "ps_main".to_string(),
            target_profile: "ps_6_0".to_string(),
            output_format: OutputFormat::SpirV,
            optimization_level: OptimizationLevel::Level3,
            ..Default::default()
        },
    )?;

    // 4. 创建wgpu着色器模块
    let vs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
        label: Some("Vertex Shader"),
        source: wgpu::ShaderSource::SpirV(vs_result.data.into()),
    });

    let fs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
        label: Some("Fragment Shader"),
        source: wgpu::ShaderSource::SpirV(fs_result.data.into()),
    });

    // 5. 创建渲染管线
    let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
        label: None,
        bind_group_layouts: &[],
        push_constant_ranges: &[],
    });

    let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
        label: None,
        layout: Some(&pipeline_layout),
        vertex: wgpu::VertexState {
            module: &vs_module,
            entry_point: "vs_main",
            buffers: &[],
        },
        fragment: Some(wgpu::FragmentState {
            module: &fs_module,
            entry_point: "ps_main",
            targets: &[Some(wgpu::ColorTargetState {
                format: wgpu::TextureFormat::Rgba8Unorm,
                blend: Some(wgpu::BlendState::REPLACE),
                write_mask: wgpu::ColorWrites::ALL,
            })],
        }),
        primitive: wgpu::PrimitiveState::default(),
        depth_stencil: None,
        multisample: wgpu::MultisampleState::default(),
        multiview: None,
    });

    println!("渲染管线创建成功!");
    Ok(())
}

示例说明

  1. 初始化wgpu:创建wgpu实例和设备,准备图形渲染环境。

  2. 定义HLSL着色器:定义了顶点和片段着色器的HLSL源代码,包含基本的顶点变换和法线显示逻辑。

  3. 编译着色器

    • 使用DxCompiler::new()初始化DXC编译器
    • 使用compile()方法将HLSL编译为SPIR-V
    • 为顶点和片段着色器分别设置编译选项(入口点、目标profile等)
  4. 创建wgpu着色器模块:将编译后的SPIR-V字节码转换为wgpu可用的着色器模块。

  5. 创建渲染管线:使用编译好的着色器创建完整的渲染管线。

跨平台注意事项

  1. Windows:需要安装DirectX SDK或Windows SDK
  2. Linux/macOS:需要从源码构建DXC或使用预构建版本
  3. 运行时需要dxcompiler.dll/libdxcompiler.so/libdxcompiler.dylib在库路径中
回到顶部