rafx_api/types/
shader.rs

1use fnv::FnvHasher;
2use std::hash::{Hash, Hasher};
3
4use crate::{RafxApiType, RafxReflectedEntryPoint};
5#[cfg(feature = "serde-support")]
6use serde::{Deserialize, Serialize};
7
8/// GL ES 2.0-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is
9/// used to initialize a shader module GPU object
10///
11/// It is a struct rather than an enum because these are not mutually exclusive
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
14pub enum RafxShaderPackageGles2 {
15    /// Raw uncompiled OpenGL ES 2.0 source code. Will be compiled at runtime.
16    Src(String),
17}
18
19/// GL ES 3.0-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is
20/// used to initialize a shader module GPU object
21///
22/// It is a struct rather than an enum because these are not mutually exclusive
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
25pub enum RafxShaderPackageGles3 {
26    /// Raw uncompiled OpenGL ES 3.0 source code. Will be compiled at runtime.
27    Src(String),
28}
29
30/// Metal-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is
31/// used to initialize a shader module GPU object
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
34pub enum RafxShaderPackageDx12 {
35    /// Raw uncompiled source code. Will be compiled at runtime.
36    Src(String),
37    // DXIL compiles from dxc
38    //Dxil(Vec<u8>)
39}
40
41/// Metal-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is
42/// used to initialize a shader module GPU object
43#[derive(Debug, Clone, PartialEq, Eq, Hash)]
44#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
45pub enum RafxShaderPackageMetal {
46    /// Raw uncompiled source code. Will be compiled at runtime.
47    Src(String),
48    /// Pre-built binary "metallib" file loaded into memory
49    #[cfg_attr(feature = "serde-support", serde(with = "serde_bytes"))]
50    LibBytes(Vec<u8>),
51}
52
53/// Vulkan-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is
54/// used to initialize a shader module GPU object
55#[derive(Debug, Clone, PartialEq, Eq, Hash)]
56#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
57pub enum RafxShaderPackageVulkan {
58    /// Raw SPV bytes, no alignment or endianness requirements.
59    #[cfg_attr(feature = "serde-support", serde(with = "serde_bytes"))]
60    SpvBytes(Vec<u8>),
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Hash)]
64#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
65#[doc(hidden)]
66pub enum RafxShaderPackageEmpty {
67    Empty,
68}
69
70/// Owns data necessary to create a shader module in (optionally) multiple APIs.
71///
72/// This struct can be serialized/deserialized and is intended to allow asset pipeline to store
73/// a shader module to be created at runtime. The package can optionally include data for multiple
74/// APIs allowing a single file to be used with whatever API is found at runtime.
75///
76/// Optionally, reflection data can be packaged along with shaders. Shaders may have
77/// platform-specific changes that produce different reflection data, so reflection is stored
78/// per-api
79#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
80#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
81pub struct RafxShaderPackage {
82    pub gles2: Option<RafxShaderPackageGles2>,
83    pub gles3: Option<RafxShaderPackageGles3>,
84    pub dx12: Option<RafxShaderPackageDx12>,
85    pub metal: Option<RafxShaderPackageMetal>,
86    pub vk: Option<RafxShaderPackageVulkan>,
87
88    pub vk_reflection: Option<Vec<RafxReflectedEntryPoint>>,
89    pub dx12_reflection: Option<Vec<RafxReflectedEntryPoint>>,
90    pub metal_reflection: Option<Vec<RafxReflectedEntryPoint>>,
91    pub gles2_reflection: Option<Vec<RafxReflectedEntryPoint>>,
92    pub gles3_reflection: Option<Vec<RafxReflectedEntryPoint>>,
93
94    pub debug_name: Option<String>,
95}
96
97/// Provides a stable has for contents of a shader package
98#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
99#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
100pub struct RafxShaderPackageHash(u64);
101impl RafxShaderPackageHash {
102    pub fn new(shader_package: &RafxShaderPackage) -> Self {
103        let mut hasher = FnvHasher::default();
104        shader_package.hash(&mut hasher);
105        let hash = hasher.finish();
106        RafxShaderPackageHash(hash)
107    }
108}
109
110/// A shader package and its hash. This allows storing the package with a pre-generated hash to
111/// file. The shader package is immutable to ensure the hash is never stale.
112#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
113#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
114pub struct RafxHashedShaderPackage {
115    shader_package_hash: RafxShaderPackageHash,
116    shader_package: RafxShaderPackage,
117}
118
119impl RafxHashedShaderPackage {
120    pub fn new(shader_package: RafxShaderPackage) -> Self {
121        let shader_package_hash = RafxShaderPackageHash::new(&shader_package);
122        RafxHashedShaderPackage {
123            shader_package_hash,
124            shader_package,
125        }
126    }
127
128    pub fn shader_package_hash(&self) -> RafxShaderPackageHash {
129        self.shader_package_hash
130    }
131
132    pub fn shader_package(&self) -> &RafxShaderPackage {
133        &self.shader_package
134    }
135}
136
137impl RafxShaderPackage {
138    pub fn reflection(
139        &self,
140        api_type: RafxApiType,
141    ) -> Option<&Vec<RafxReflectedEntryPoint>> {
142        match api_type {
143            RafxApiType::Vk => self.vk_reflection.as_ref(),
144            RafxApiType::Dx12 => self.dx12_reflection.as_ref(),
145            RafxApiType::Metal => self.metal_reflection.as_ref(),
146            RafxApiType::Gles2 => self.gles2_reflection.as_ref(),
147            RafxApiType::Gles3 => self.gles3_reflection.as_ref(),
148            RafxApiType::Empty => None,
149        }
150    }
151
152    pub fn find_entry_point(
153        &self,
154        api_type: RafxApiType,
155        entry_point_name: &str,
156    ) -> Option<&RafxReflectedEntryPoint> {
157        self.reflection(api_type)
158            .map(|x| {
159                x.iter()
160                    .find(|&x| x.rafx_api_reflection.entry_point_name == entry_point_name)
161            })
162            .flatten()
163    }
164
165    /// Create a shader module def for use with a GL RafxDevice. Returns none if the package does
166    /// not contain data necessary for GL ES 2.0
167    #[cfg(feature = "rafx-gles2")]
168    pub fn gles2_module_def(&self) -> Option<RafxShaderModuleDefGles2> {
169        if let Some(gl) = self.gles2.as_ref() {
170            Some(match gl {
171                RafxShaderPackageGles2::Src(src) => RafxShaderModuleDefGles2::GlSrc(src),
172            })
173        } else {
174            None
175        }
176    }
177
178    /// Create a shader module def for use with a GL RafxDevice. Returns none if the package does
179    /// not contain data necessary for GL ES 2.0
180    #[cfg(feature = "rafx-gles3")]
181    pub fn gles3_module_def(&self) -> Option<RafxShaderModuleDefGles3> {
182        if let Some(gl) = self.gles3.as_ref() {
183            Some(match gl {
184                RafxShaderPackageGles3::Src(src) => RafxShaderModuleDefGles3::GlSrc(src),
185            })
186        } else {
187            None
188        }
189    }
190
191    /// Create a shader module def for use with a dx12 RafxDevice. Returns none if the package does
192    /// not contain data necessary for metal
193    #[cfg(feature = "rafx-dx12")]
194    pub fn dx12_module_def(&self) -> Option<RafxShaderModuleDefDx12> {
195        if let Some(dx12) = self.dx12.as_ref() {
196            Some(match dx12 {
197                RafxShaderPackageDx12::Src(src) => RafxShaderModuleDefDx12::HlslSrc(src),
198                //RafxShaderPackageDx12::Dxil(dxil) => RafxShaderModuleDefDx12::Dxil(dxil.as_slice()),
199            })
200        } else {
201            None
202        }
203    }
204
205    /// Create a shader module def for use with a metal RafxDevice. Returns none if the package does
206    /// not contain data necessary for metal
207    #[cfg(feature = "rafx-metal")]
208    pub fn metal_module_def(&self) -> Option<RafxShaderModuleDefMetal> {
209        if let Some(metal) = self.metal.as_ref() {
210            Some(match metal {
211                RafxShaderPackageMetal::Src(src) => RafxShaderModuleDefMetal::MetalSrc(src),
212                RafxShaderPackageMetal::LibBytes(lib) => {
213                    RafxShaderModuleDefMetal::MetalLibBytes(lib)
214                }
215            })
216        } else {
217            None
218        }
219    }
220
221    /// Create a shader module def for use with a vulkan RafxDevice. Returns none if the package
222    /// does not contain data necessary for vulkan
223    #[cfg(feature = "rafx-vulkan")]
224    pub fn vulkan_module_def(&self) -> Option<RafxShaderModuleDefVulkan> {
225        if let Some(vk) = self.vk.as_ref() {
226            Some(match vk {
227                RafxShaderPackageVulkan::SpvBytes(bytes) => {
228                    RafxShaderModuleDefVulkan::VkSpvBytes(bytes)
229                }
230            })
231        } else {
232            None
233        }
234    }
235
236    /// Create a shader module def for use with a vulkan RafxDevice. Returns none if the package
237    /// does not contain data necessary for vulkan
238    #[cfg(any(
239        feature = "rafx-empty",
240        not(any(
241            feature = "rafx-dx12",
242            feature = "rafx-metal",
243            feature = "rafx-vulkan",
244            feature = "rafx-gles2",
245            feature = "rafx-gles3"
246        ))
247    ))]
248    #[doc(hidden)]
249    pub fn empty_module_def(&self) -> Option<RafxShaderModuleDefEmpty> {
250        Some(RafxShaderModuleDefEmpty::Empty(Default::default()))
251    }
252
253    pub fn module_def(&self) -> RafxShaderModuleDef {
254        RafxShaderModuleDef {
255            #[cfg(feature = "rafx-gles2")]
256            gles2: self.gles2_module_def(),
257            #[cfg(feature = "rafx-gles3")]
258            gles3: self.gles3_module_def(),
259            #[cfg(feature = "rafx-dx12")]
260            dx12: self.dx12_module_def(),
261            #[cfg(feature = "rafx-metal")]
262            metal: self.metal_module_def(),
263            #[cfg(feature = "rafx-vulkan")]
264            vk: self.vulkan_module_def(),
265            #[cfg(any(
266                feature = "rafx-empty",
267                not(any(
268                    feature = "rafx-dx12",
269                    feature = "rafx-metal",
270                    feature = "rafx-vulkan",
271                    feature = "rafx-gles2",
272                    feature = "rafx-gles3"
273                ))
274            ))]
275            empty: self.empty_module_def(),
276        }
277    }
278}
279
280/// Used to create a RafxShaderModule
281///
282/// This enum may be populated manually or created from a RafxShaderPackage.
283#[derive(Copy, Clone, Hash)]
284#[cfg(feature = "rafx-gles2")]
285pub enum RafxShaderModuleDefGles2<'a> {
286    /// GL source code
287    GlSrc(&'a str),
288}
289
290/// Used to create a RafxShaderModule
291///
292/// This enum may be populated manually or created from a RafxShaderPackage.
293#[derive(Copy, Clone, Hash)]
294#[cfg(feature = "rafx-gles3")]
295pub enum RafxShaderModuleDefGles3<'a> {
296    /// GL source code
297    GlSrc(&'a str),
298}
299
300/// Used to create a RafxShaderModule
301///
302/// This enum may be populated manually or created from a RafxShaderPackage.
303#[derive(Copy, Clone, Hash)]
304#[cfg(feature = "rafx-dx12")]
305pub enum RafxShaderModuleDefDx12<'a> {
306    /// HLSL source code
307    HlslSrc(&'a str),
308    // Compiled DXIL from dxc
309    //Dxil(&'a [u8]),
310}
311
312/// Used to create a RafxShaderModule
313///
314/// This enum may be populated manually or created from a RafxShaderPackage.
315#[derive(Copy, Clone, Hash)]
316#[cfg(feature = "rafx-metal")]
317pub enum RafxShaderModuleDefMetal<'a> {
318    /// Metal source code
319    MetalSrc(&'a str),
320    /// Pre-compiled library loaded as bytes
321    MetalLibBytes(&'a [u8]),
322}
323
324/// Used to create a RafxShaderModule
325///
326/// This enum may be populated manually or created from a RafxShaderPackage.
327#[derive(Copy, Clone, Hash)]
328#[cfg(feature = "rafx-vulkan")]
329pub enum RafxShaderModuleDefVulkan<'a> {
330    /// Raw SPV bytes, no alignment or endianness requirements.
331    VkSpvBytes(&'a [u8]),
332    /// Prepared SPV that's aligned and correct endian. No validation.
333    VkSpvPrepared(&'a [u32]),
334}
335
336#[cfg(any(
337    feature = "rafx-empty",
338    not(any(
339        feature = "rafx-dx12",
340        feature = "rafx-metal",
341        feature = "rafx-vulkan",
342        feature = "rafx-gles2",
343        feature = "rafx-gles3"
344    ))
345))]
346#[derive(Copy, Clone, Hash)]
347#[doc(hidden)]
348pub enum RafxShaderModuleDefEmpty<'a> {
349    Empty(std::marker::PhantomData<&'a u32>),
350}
351
352/// Used to create a RafxShaderModule
353///
354/// This enum may be populated manually or created from a RafxShaderPackage.
355#[derive(Copy, Clone, Hash, Default)]
356pub struct RafxShaderModuleDef<'a> {
357    #[cfg(feature = "rafx-gles2")]
358    pub gles2: Option<RafxShaderModuleDefGles2<'a>>,
359    #[cfg(feature = "rafx-gles3")]
360    pub gles3: Option<RafxShaderModuleDefGles3<'a>>,
361    #[cfg(feature = "rafx-dx12")]
362    pub dx12: Option<RafxShaderModuleDefDx12<'a>>,
363    #[cfg(feature = "rafx-metal")]
364    pub metal: Option<RafxShaderModuleDefMetal<'a>>,
365    #[cfg(feature = "rafx-vulkan")]
366    pub vk: Option<RafxShaderModuleDefVulkan<'a>>,
367    #[cfg(any(
368        feature = "rafx-empty",
369        not(any(
370            feature = "rafx-dx12",
371            feature = "rafx-metal",
372            feature = "rafx-vulkan",
373            feature = "rafx-gles2",
374            feature = "rafx-gles3"
375        ))
376    ))]
377    #[doc(hidden)]
378    pub empty: Option<RafxShaderModuleDefEmpty<'a>>,
379}