Skip to main content

oxide_renderer/
pipeline.rs

1//! Pipeline creation utilities
2
3use wgpu::{
4    BindGroupLayout, ColorTargetState, ColorWrites, CompareFunction, DepthStencilState, Device,
5    FragmentState, PipelineLayoutDescriptor, PrimitiveState, PrimitiveTopology, RenderPipeline,
6    RenderPipelineDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource, StencilState,
7    TextureFormat, VertexState,
8};
9
10use crate::mesh::{Vertex, Vertex3D};
11
12pub fn create_shader(device: &Device, source: &str, label: Option<&str>) -> ShaderModule {
13    // Parse once to surface syntax issues early in logs before pipeline creation.
14    match naga::front::wgsl::parse_str(source) {
15        Ok(_) => {}
16        Err(e) => {
17            tracing::warn!(
18                "Failed to parse WGSL source for '{}' during validation: {:?}",
19                label.unwrap_or("unnamed"),
20                e
21            );
22        }
23    }
24
25    device.create_shader_module(ShaderModuleDescriptor {
26        label,
27        source: ShaderSource::Wgsl(source.into()),
28    })
29}
30
31pub fn create_basic_pipeline(
32    device: &Device,
33    shader: &ShaderModule,
34    format: TextureFormat,
35) -> RenderPipeline {
36    let layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
37        label: Some("Basic Pipeline Layout"),
38        bind_group_layouts: &[],
39        immediate_size: 0,
40    });
41
42    device.create_render_pipeline(&RenderPipelineDescriptor {
43        label: Some("Basic Pipeline"),
44        layout: Some(&layout),
45        vertex: VertexState {
46            module: shader,
47            entry_point: Some("vs_main"),
48            buffers: &[Vertex::desc()],
49            compilation_options: Default::default(),
50        },
51        fragment: Some(FragmentState {
52            module: shader,
53            entry_point: Some("fs_main"),
54            targets: &[Some(ColorTargetState {
55                format,
56                blend: None,
57                write_mask: ColorWrites::ALL,
58            })],
59            compilation_options: Default::default(),
60        }),
61        primitive: PrimitiveState {
62            topology: PrimitiveTopology::TriangleList,
63            strip_index_format: None,
64            front_face: wgpu::FrontFace::Ccw,
65            cull_mode: Some(wgpu::Face::Back),
66            polygon_mode: wgpu::PolygonMode::Fill,
67            unclipped_depth: false,
68            conservative: false,
69        },
70        depth_stencil: None,
71        multisample: wgpu::MultisampleState {
72            count: 1,
73            mask: !0,
74            alpha_to_coverage_enabled: false,
75        },
76        multiview_mask: None,
77        cache: None,
78    })
79}
80
81pub fn create_lit_pipeline(
82    device: &Device,
83    shader: &ShaderModule,
84    format: TextureFormat,
85    camera_layout: &BindGroupLayout,
86    material_layout: &BindGroupLayout,
87    light_layout: &BindGroupLayout,
88) -> RenderPipeline {
89    let layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
90        label: Some("Lit Pipeline Layout"),
91        bind_group_layouts: &[camera_layout, material_layout, light_layout],
92        immediate_size: 0,
93    });
94
95    let depth_stencil = Some(DepthStencilState {
96        format: TextureFormat::Depth24PlusStencil8,
97        depth_write_enabled: true,
98        depth_compare: CompareFunction::Less,
99        stencil: StencilState::default(),
100        bias: wgpu::DepthBiasState::default(),
101    });
102
103    device.create_render_pipeline(&RenderPipelineDescriptor {
104        label: Some("Lit Pipeline"),
105        layout: Some(&layout),
106        vertex: VertexState {
107            module: shader,
108            entry_point: Some("vs_main"),
109            buffers: &[Vertex3D::desc()],
110            compilation_options: Default::default(),
111        },
112        fragment: Some(FragmentState {
113            module: shader,
114            entry_point: Some("fs_main"),
115            targets: &[Some(ColorTargetState {
116                format,
117                blend: None,
118                write_mask: ColorWrites::ALL,
119            })],
120            compilation_options: Default::default(),
121        }),
122        primitive: PrimitiveState {
123            topology: PrimitiveTopology::TriangleList,
124            strip_index_format: None,
125            front_face: wgpu::FrontFace::Ccw,
126            cull_mode: Some(wgpu::Face::Back),
127            polygon_mode: wgpu::PolygonMode::Fill,
128            unclipped_depth: false,
129            conservative: false,
130        },
131        depth_stencil,
132        multisample: wgpu::MultisampleState {
133            count: 1,
134            mask: !0,
135            alpha_to_coverage_enabled: false,
136        },
137        multiview_mask: None,
138        cache: None,
139    })
140}
141
142pub fn create_unlit_pipeline(
143    device: &Device,
144    shader: &ShaderModule,
145    format: TextureFormat,
146    camera_layout: &BindGroupLayout,
147    material_layout: &BindGroupLayout,
148) -> RenderPipeline {
149    let layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
150        label: Some("Unlit Pipeline Layout"),
151        bind_group_layouts: &[camera_layout, material_layout],
152        immediate_size: 0,
153    });
154
155    let depth_stencil = Some(DepthStencilState {
156        format: TextureFormat::Depth24PlusStencil8,
157        depth_write_enabled: true,
158        depth_compare: CompareFunction::Less,
159        stencil: StencilState::default(),
160        bias: wgpu::DepthBiasState::default(),
161    });
162
163    device.create_render_pipeline(&RenderPipelineDescriptor {
164        label: Some("Unlit Pipeline"),
165        layout: Some(&layout),
166        vertex: VertexState {
167            module: shader,
168            entry_point: Some("vs_main"),
169            buffers: &[Vertex3D::desc()],
170            compilation_options: Default::default(),
171        },
172        fragment: Some(FragmentState {
173            module: shader,
174            entry_point: Some("fs_main"),
175            targets: &[Some(ColorTargetState {
176                format,
177                blend: None,
178                write_mask: ColorWrites::ALL,
179            })],
180            compilation_options: Default::default(),
181        }),
182        primitive: PrimitiveState {
183            topology: PrimitiveTopology::TriangleList,
184            strip_index_format: None,
185            front_face: wgpu::FrontFace::Ccw,
186            cull_mode: Some(wgpu::Face::Back),
187            polygon_mode: wgpu::PolygonMode::Fill,
188            unclipped_depth: false,
189            conservative: false,
190        },
191        depth_stencil,
192        multisample: wgpu::MultisampleState {
193            count: 1,
194            mask: !0,
195            alpha_to_coverage_enabled: false,
196        },
197        multiview_mask: None,
198        cache: None,
199    })
200}