rafx_framework/resources/
material.rs

1use crate::{
2    DescriptorSetWriteSet, FixedFunctionState, MaterialPassResource, MaterialPassVertexInput,
3    RafxResult, ReflectedShader, ResourceArc, ResourceContext, ShaderModuleResource,
4    SlotNameLookup,
5};
6use rafx_api::{RafxReflectedEntryPoint, RafxShaderStageFlags};
7use serde::{Deserialize, Serialize};
8use std::ops::Deref;
9use std::sync::Arc;
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum MaterialShaderStage {
13    Vertex,
14    TessellationControl,
15    TessellationEvaluation,
16    Geometry,
17    Fragment,
18    Compute,
19}
20
21impl Into<RafxShaderStageFlags> for MaterialShaderStage {
22    fn into(self) -> RafxShaderStageFlags {
23        match self {
24            MaterialShaderStage::Vertex => RafxShaderStageFlags::VERTEX,
25            MaterialShaderStage::TessellationControl => RafxShaderStageFlags::TESSELLATION_CONTROL,
26            MaterialShaderStage::TessellationEvaluation => {
27                RafxShaderStageFlags::TESSELLATION_EVALUATION
28            }
29            MaterialShaderStage::Geometry => RafxShaderStageFlags::GEOMETRY,
30            MaterialShaderStage::Fragment => RafxShaderStageFlags::FRAGMENT,
31            MaterialShaderStage::Compute => RafxShaderStageFlags::COMPUTE,
32        }
33    }
34}
35
36pub struct MaterialPassInner {
37    pub shader_modules: Vec<ResourceArc<ShaderModuleResource>>,
38
39    // Info required to recreate the pipeline for new swapchains
40    pub material_pass_resource: ResourceArc<MaterialPassResource>,
41
42    // Data this material pass expects to receive via bound vertex buffers
43    pub vertex_inputs: Arc<Vec<MaterialPassVertexInput>>,
44
45    //TODO: Use hash instead of string. Probably want to have a "hashed string" type that keeps the
46    // string around only in debug mode. Maybe this could be generalized to a HashOfThing<T>.
47    pub pass_slot_name_lookup: Arc<SlotNameLookup>,
48    // This is a hint of what render phase we should register a material with in the pipeline cache
49    // It is optional and the pipeline cache can handle materials used in any render phase
50    //pub render_phase_index: Option<RenderPhaseIndex>,
51}
52
53#[derive(Clone)]
54pub struct MaterialPass {
55    inner: Arc<MaterialPassInner>,
56}
57
58impl MaterialPass {
59    pub fn new(
60        resource_context: &ResourceContext,
61        debug_name: Option<&str>,
62        fixed_function_state: Arc<FixedFunctionState>,
63        shader_modules: Vec<ResourceArc<ShaderModuleResource>>,
64        entry_points: &[&RafxReflectedEntryPoint],
65    ) -> RafxResult<MaterialPass> {
66        let reflected_shader =
67            ReflectedShader::new(resource_context.resources(), &shader_modules, entry_points)?;
68
69        let material_pass = reflected_shader.load_material_pass(
70            resource_context.resources(),
71            fixed_function_state,
72            debug_name,
73        )?;
74
75        let vertex_inputs = reflected_shader
76            .metadata
77            .vertex_inputs
78            .ok_or_else(|| "The material pass does not specify a vertex shader")?;
79
80        let inner = MaterialPassInner {
81            shader_modules,
82            material_pass_resource: material_pass.clone(),
83            pass_slot_name_lookup: Arc::new(reflected_shader.metadata.slot_name_lookup),
84            vertex_inputs,
85        };
86
87        Ok(MaterialPass {
88            inner: Arc::new(inner),
89        })
90    }
91
92    pub fn create_uninitialized_write_sets_for_material_pass(&self) -> Vec<DescriptorSetWriteSet> {
93        // The metadata for the descriptor sets within this pass, one for each set within the pass
94        let pass_descriptor_set_writes: Vec<_> = self
95            .inner
96            .material_pass_resource
97            .get_raw()
98            .descriptor_set_layouts
99            .iter()
100            .map(|layout| {
101                super::descriptor_sets::create_uninitialized_write_set_for_layout(
102                    &layout.get_raw().descriptor_set_layout_def,
103                )
104            })
105            .collect();
106
107        pass_descriptor_set_writes
108    }
109}
110
111impl Deref for MaterialPass {
112    type Target = MaterialPassInner;
113
114    fn deref(&self) -> &Self::Target {
115        &*self.inner
116    }
117}