use std::rc::Rc; use wgpu; use crate::vertexbuffer::VertexBuffer; use crate::{SHADER_MAIN_FRAGMENT, SHADER_MAIN_VERTEX}; pub struct PipelineBuilder<'a> { // These are provided with new() label: &'a str, device: &'a wgpu::Device, // These have empty defaults triangle: bool, bind_group_layouts: &'a [&'a wgpu::BindGroupLayout], // These must be provided shader: Option<&'a str>, format: Option, vertex_buffer: Option<&'a Rc>, } impl<'a> PipelineBuilder<'a> { pub fn new(label: &'a str, device: &'a wgpu::Device) -> Self { Self { label, device, triangle: true, vertex_buffer: None, bind_group_layouts: &[], shader: None, format: None, } } pub fn set_shader(mut self, shader: &'a str) -> Self { self.shader = Some(shader); self } pub fn set_format(mut self, format: wgpu::TextureFormat) -> Self { self.format = Some(format); self } pub fn set_triangle(mut self, triangle: bool) -> Self { self.triangle = triangle; self } pub fn set_vertex_buffer(mut self, vertex_buffer: &'a Rc) -> Self { self.vertex_buffer = Some(vertex_buffer); self } pub fn set_bind_group_layouts( mut self, bind_group_layouts: &'a [&'a wgpu::BindGroupLayout], ) -> Self { self.bind_group_layouts = bind_group_layouts; self } pub fn build(self) -> wgpu::RenderPipeline { // All fields should be set. // Nones are not checked, they will panic. let shader = self .device .create_shader_module(wgpu::ShaderModuleDescriptor { label: Some(&format!("pipeline [{}] shader", self.label)), source: wgpu::ShaderSource::Wgsl(self.shader.unwrap().into()), }); let pipeline_layout = self .device .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some(&format!("pipeline [{}] layout", self.label)), bind_group_layouts: self.bind_group_layouts, push_constant_ranges: &[], }); let pipeline = self .device .create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some(&format!("pipeline [{}]", self.label)), layout: Some(&pipeline_layout), depth_stencil: None, multiview: None, multisample: wgpu::MultisampleState { count: 1, mask: !0, alpha_to_coverage_enabled: false, }, vertex: wgpu::VertexState { module: &shader, entry_point: SHADER_MAIN_VERTEX, buffers: &self.vertex_buffer.unwrap().layout, }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: SHADER_MAIN_FRAGMENT, targets: &[Some(wgpu::ColorTargetState { format: self.format.unwrap(), blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, })], }), primitive: if self.triangle { wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, strip_index_format: None, front_face: wgpu::FrontFace::Ccw, cull_mode: Some(wgpu::Face::Back), polygon_mode: wgpu::PolygonMode::Fill, unclipped_depth: false, conservative: false, } } else { wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::PointList, strip_index_format: None, front_face: wgpu::FrontFace::Ccw, cull_mode: None, polygon_mode: wgpu::PolygonMode::Fill, unclipped_depth: false, conservative: false, } }, }); return pipeline; } }