Skip to main content

rpfm_lib/files/hlsl_compiled/
mod.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! HLSL compiled shader file format support (FASTBIN0/DXBC).
12//!
13//! This module handles `.hlsl_compiled` files which contain compiled DirectX shaders
14//! (DXBC format) wrapped in a FASTBIN0 container with metadata.
15//!
16//! # File Format
17//!
18//! HLSL compiled files use the `FASTBIN0` signature and contain:
19//! - Serialization version
20//! - Shader metadata (API, source file, name, type, shader model, UUID)
21//! - Raw DXBC (DirectX Bytecode) shader data
22//!
23//! # Shader Metadata
24//!
25//! The wrapper format stores comprehensive shader compilation metadata:
26//! - **API**: Target graphics API (e.g., "dx11")
27//! - **Source**: Source `.hlsl` file path
28//! - **Shader Name**: Entry point function name
29//! - **Shader Type**: Vertex, pixel, compute, etc.
30//! - **Model**: Shader model version (e.g., "vs_5_0", "ps_5_0")
31//! - **UUID**: Unique identifier for this shader compilation
32//!
33//! # DXBC Data
34//!
35//! The actual shader bytecode is stored as raw DXBC format, which can be processed
36//! by DirectX shader tools or executed by the graphics driver.
37//!
38//! # Versioning
39//!
40//! Currently only version 1 of the FASTBIN0 format is supported.
41//!
42//! # Usage
43//!
44//! ```ignore
45//! use rpfm_lib::files::hlsl_compiled::HlslCompiled;
46//! use rpfm_lib::files::Decodeable;
47//!
48//! // Decode a compiled shader
49//! let shader = HlslCompiled::decode(&mut data, &None)?;
50//!
51//! // Access metadata
52//! println!("Shader: {} ({})", shader.shader_name(), shader.shader_type());
53//! println!("Model: {}", shader.model_long());
54//!
55//! // Access raw DXBC data
56//! let dxbc_bytes = shader.data();
57//! ```
58
59use getset::*;
60use serde_derive::{Serialize, Deserialize};
61
62use crate::binary::{ReadBytes, WriteBytes};
63use crate::error::{Result, RLibError};
64use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
65use crate::utils::check_size_mismatch;
66
67/// File extension for HLSL compiled shader files.
68pub const EXTENSION: &str = ".hlsl_compiled";
69
70/// FASTBIN0 file signature.
71///
72/// Identifies this as a FASTBIN0 container format (ASCII: "FASTBIN0").
73pub const SIGNATURE: &[u8; 8] = &[0x46, 0x41, 0x53, 0x54, 0x42, 0x49, 0x4E, 0x30];
74
75mod v1;
76
77#[cfg(test)] mod hlsl_compiled_test;
78
79//---------------------------------------------------------------------------//
80//                              Enum & Structs
81//---------------------------------------------------------------------------//
82
83/// Represents a compiled HLSL shader with metadata.
84///
85/// This structure wraps a DXBC shader with comprehensive metadata about its
86/// compilation, including source file, shader model, and unique identifiers.
87#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
88#[getset(get = "pub", get_mut = "pub", set = "pub")]
89pub struct HlslCompiled {
90    /// FASTBIN0 serialization version (currently always 1).
91    serialise_version: u16,
92
93    /// Target graphics API (e.g., "dx11", "dx12").
94    api: String,
95
96    /// Path to the source `.hlsl` file.
97    source: String,
98
99    /// Shader entry point function name.
100    shader_name: String,
101
102    /// Shader type (e.g., "VertexShader", "PixelShader", "ComputeShader").
103    shader_type: String,
104
105    /// Full shader model string (e.g., "vs_5_0", "ps_5_0").
106    model_long: String,
107
108    /// Unknown string field (purpose not yet identified).
109    no_idea_1: String,
110
111    /// Unique identifier for this shader compilation.
112    uuid: String,
113
114    /// Unknown u32 field (purpose not yet identified).
115    no_idea_2: u32,
116
117    /// Short shader model identifier.
118    model_short: String,
119
120    /// Unknown u16 field (purpose not yet identified).
121    no_idea_3: u16,
122
123    /// Unknown u32 field (purpose not yet identified).
124    no_idea_4: u32,
125
126    /// Raw DXBC (DirectX Bytecode) shader data.
127    ///
128    /// This is the compiled shader bytecode that can be executed by DirectX-compatible
129    /// graphics drivers. The format is standard DXBC and can be analyzed with DirectX
130    /// shader tools.
131    data: Vec<u8>,
132}
133
134//---------------------------------------------------------------------------//
135//                              Implementations
136//---------------------------------------------------------------------------//
137
138impl Decodeable for HlslCompiled {
139
140    fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
141        let signature_bytes = data.read_slice(8, false)?;
142        if signature_bytes.as_slice() != SIGNATURE {
143            return Err(RLibError::DecodingFastBinUnsupportedSignature(signature_bytes));
144        }
145
146        let mut fastbin = Self::default();
147        fastbin.serialise_version = data.read_u16()?;
148
149        match fastbin.serialise_version {
150            1 => fastbin.read_v1(data, extra_data)?,
151            _ => return Err(RLibError::DecodingFastBinUnsupportedVersion(String::from("HlslCompiled"), fastbin.serialise_version)),
152        }
153
154        // If we are not in the last byte, it means we didn't parse the entire file, which means this file is corrupt.
155        check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
156
157        Ok(fastbin)
158    }
159}
160
161impl Encodeable for HlslCompiled {
162
163    fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
164        buffer.write_all(SIGNATURE)?;
165        buffer.write_u16(self.serialise_version)?;
166
167        match self.serialise_version {
168            1 => self.write_v1(buffer, extra_data)?,
169            _ => return Err(RLibError::EncodingFastBinUnsupportedVersion(String::from("HlslCompiled"), self.serialise_version)),
170        }
171
172        Ok(())
173    }
174}