d3dasm 0.1.0

Generic Direct3D shader disassembly interface
Documentation
  • Coverage
  • 100%
    19 out of 19 items documented0 out of 18 items with examples
  • Size
  • Source code size: 19.7 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 212.9 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 10s Average build duration of successful builds.
  • all releases: 10s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • coconutbird/d3dasm
    7 2 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • coconutbird

d3dasm

Direct3D shader bytecode disassembler and encoder written in Rust.

Parses DXBC containers, decodes SM4/SM5 shader bytecode into a fully typed intermediate representation, and produces fxc.exe-compatible disassembly output. The IR can be re-encoded to byte-identical bytecode, enabling shader inspection and modification workflows.

Features

  • Full SM4/SM5 bytecode round-trip — Decode → IR → encode produces bit-identical output across all 217+ opcodes. Verified against 1,152 real-world shader chunks with zero failures.
  • Typed IR with no raw bit hacks — Every opcode field (GS primitives, topologies, component selection modes, sample counts, test conditions) is represented as a proper Rust enum. No raw bit buckets.
  • 18 chunk types parsed — RDEF, ISGN/ISG1, OSGN/OSG1/OSG5, PCSG/PSG1, SHEX/SHDR, STAT, RTS0, SFI0, HASH/XHSH, ILDN, ILDB, PRIV, DXIL, PSV0, RDAT, LIBF, LFS0, LIBH. Unknown chunks are preserved for lossless container rebuilds.
  • Zero-copy reads, copy-on-write mutation — Metadata strings and raw blobs borrow directly from the input buffer via Cow<'a, T>. Assigning Cow::Owned(...) transparently enables shader patching without touching the original data.
  • Lazy chunk parsing — Non-program chunks (RDEF, signatures, STAT, etc.) are parsed on first access via OnceCell. Callers that only need the shader program pay zero overhead for metadata.
  • Container scanning — Automatically finds DXBC containers in arbitrary byte streams (raw files, fxb0 wrappers, custom game archives).
  • no_std core — The dxbc crate uses only core and alloc, no filesystem or I/O.
  • All shader stages — VS, PS, GS, HS, DS, CS.

Crates

Crate Type Purpose
dxbc lib (no_std) DXBC container parser/writer, chunk decoders, SM4/SM5 bytecode decode/encode/format
d3dasm lib High-level disassembly interface — wraps dxbc with typed accessors and Display formatting
d3dasm-cli bin Command-line disassembler

Usage

cargo run -- <shader.bin>

As a library

let data = std::fs::read("shader.bin").unwrap();
for shader in d3dasm::parse(&data) {
    // Typed access to parsed chunks.
    if let Some(program) = shader.program() {
        println!("SM {}.{}", program.version_major, program.version_minor);
    }

    // fxc.exe-compatible disassembly via Display.
    print!("{shader}");
}

Lower-level access via dxbc

let container = dxbc::DxbcContainer::parse(bytes).unwrap();
for chunk in &container.chunks {
    match chunk.parse() {
        dxbc::ChunkData::Shader(program) => {
            // Round-trip: decode → encode → identical bytes.
            let encoded = dxbc::shex::encode(&program);
            assert_eq!(chunk.data, &encoded[..]);
        }
        _ => {}
    }
}

Example Output

// Compiled with: Microsoft (R) HLSL Shader Compiler 10.0.10011.0
//
// Resource Bindings:
// Name            Type         Dim      Slot Count Flags
// --------------- ------------ -------- ---- ----- -----
// gPointSampler0  sampler      NA       0    1
// gPointTexture0  texture      2dMS     0    1     comparisonSampler;texComp0
//
// Input Signature:
//   TEXCOORD      float v0.xy
//   TEXCOORD1     float v0.zw
//   SV_Position   float v1.xyzw
//
// Output Signature:
//   SV_Target   float v0.xyzw
//
ps_5_0
dcl_globalFlags refactoringAllowed
dcl_sampler s0, mode_default
dcl_resource_texture2d (float,float,float,float) t0
dcl_input_ps linear v0.xy
dcl_input_ps linear v0.zw
dcl_output o0.xyzw
dcl_temps 1
sample r0.xyzw, v0.xyxx, t0.xyzw, s0
mov o0.xyzw, r0.xyzw
ret

Project Structure

d3dasm/
├── Cargo.toml                        # Workspace root (resolver = "3")
├── crates/
│   ├── dxbc/                         # no_std DXBC library
│   │   └── src/
│   │       ├── container.rs          # DXBC container parser, writer, scanner
│   │       ├── chunks/               # Per-chunk parsers (rdef, signature, stat, …)
│   │       ├── shex/                 # SM4/SM5 bytecode
│   │       │   ├── ir.rs             # Typed intermediate representation
│   │       │   ├── decode.rs         # Bytes → IR
│   │       │   ├── encode.rs         # IR → bytes
│   │       │   ├── fmt.rs            # IR → disassembly text
│   │       │   └── opcodes.rs        # Opcode enum (217+ opcodes)
│   │       └── util.rs              # Shared helpers
│   ├── d3dasm/                       # High-level disassembly API
│   │   └── src/lib.rs
│   └── d3dasm-cli/                   # CLI binary
│       └── src/main.rs

Building

cargo build

Requires Rust 1.85+ (edition 2024, core::cell::OnceCell stable since 1.70).

Testing

cargo test --workspace

Round-trip verification across all test shaders:

cargo run --release --example roundtrip -- shaders/shaders-pc/**/*.bin