shdrlib 0.2.0

High-level shader compilation and rendering library built on wgpu and naga
Documentation
use super::WGPUShader;
use wgpu;

/// Builder for creating render pipelines
/// Makes it easier to set up pipelines without remembering all the wgpu boilerplate
pub struct RenderPipelineBuilder {
    vertex_shader: Option<WGPUShader>,
    fragment_shader: Option<WGPUShader>,
    vertex_buffers: Vec<wgpu::VertexBufferLayout<'static>>,
    targets: Vec<Option<wgpu::ColorTargetState>>,
    primitive: wgpu::PrimitiveState,
    depth_stencil: Option<wgpu::DepthStencilState>,
    multisample: wgpu::MultisampleState,
}

impl RenderPipelineBuilder {
    pub fn new() -> Self {
        Self {
            vertex_shader: None,
            fragment_shader: None,
            vertex_buffers: Vec::new(),
            targets: vec![Some(wgpu::ColorTargetState {
                format: wgpu::TextureFormat::Bgra8UnormSrgb,
                blend: Some(wgpu::BlendState::REPLACE),
                write_mask: wgpu::ColorWrites::ALL,
            })],
            primitive: 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,
            },
            depth_stencil: None,
            multisample: wgpu::MultisampleState {
                count: 1,
                mask: !0,
                alpha_to_coverage_enabled: false,
            },
        }
    }

    pub fn vertex_shader(mut self, shader: WGPUShader) -> Self {
        self.vertex_shader = Some(shader);
        self
    }

    pub fn fragment_shader(mut self, shader: WGPUShader) -> Self {
        self.fragment_shader = Some(shader);
        self
    }

    pub fn vertex_buffers(mut self, buffers: Vec<wgpu::VertexBufferLayout<'static>>) -> Self {
        self.vertex_buffers = buffers;
        self
    }

    pub fn color_target_format(mut self, format: wgpu::TextureFormat) -> Self {
        self.targets = vec![Some(wgpu::ColorTargetState {
            format,
            blend: Some(wgpu::BlendState::REPLACE),
            write_mask: wgpu::ColorWrites::ALL,
        })];
        self
    }

    pub fn primitive_topology(mut self, topology: wgpu::PrimitiveTopology) -> Self {
        self.primitive.topology = topology;
        self
    }

    pub fn depth_stencil(mut self, depth_stencil: wgpu::DepthStencilState) -> Self {
        self.depth_stencil = Some(depth_stencil);
        self
    }

    pub fn build(
        self,
        device: &wgpu::Device,
        layout: &wgpu::PipelineLayout,
    ) -> Result<wgpu::RenderPipeline, String> {
        let vertex_shader = self.vertex_shader
            .ok_or("Vertex shader is required")?;
        
        let fragment_shader = self.fragment_shader;

        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
            label: Some("shdrlib render pipeline"),
            layout: Some(layout),
            vertex: wgpu::VertexState {
                module: &vertex_shader.module,
                entry_point: &vertex_shader.entry_point,
                buffers: &self.vertex_buffers,
                compilation_options: Default::default(),
            },
            fragment: fragment_shader.as_ref().map(|fs| wgpu::FragmentState {
                module: &fs.module,
                entry_point: &fs.entry_point,
                targets: &self.targets,
                compilation_options: Default::default(),
            }),
            primitive: self.primitive,
            depth_stencil: self.depth_stencil,
            multisample: self.multisample,
            multiview: None,
            cache: None,
        });

        Ok(pipeline)
    }
}

impl Default for RenderPipelineBuilder {
    fn default() -> Self {
        Self::new()
    }
}