use crate::define_store;
use crate::errors::AleaticoResult;
use crate::renderer::vertex::DescribableVertex;
use wgpu::{BindGroupLayout, Device, ShaderSource};
define_store!(Pipeline);
pub struct Pipeline {
pub(crate) render_pipeline: wgpu::RenderPipeline,
}
pub struct PipelineDescriptor<'a> {
pub label: Option<&'a str>,
pub shader: String,
pub format: wgpu::TextureFormat,
pub vertex_layouts: Vec<wgpu::VertexBufferLayout<'a>>,
pub vertex_entry_point: &'a str,
pub fragment_entry_point: &'a str,
pub topology: wgpu::PrimitiveTopology,
pub front_face: wgpu::FrontFace,
pub cull_mode: Option<wgpu::Face>,
pub polygon_mode: wgpu::PolygonMode,
pub blend: Option<wgpu::BlendState>,
pub write_mask: wgpu::ColorWrites,
pub depth_stencil: Option<wgpu::DepthStencilState>,
pub multisample: wgpu::MultisampleState,
}
impl<'a> PipelineDescriptor<'a> {
pub fn from_wgsl<V: DescribableVertex<'a>>(format: wgpu::TextureFormat, shader: &'a str) -> Self {
Self {
label: Some("Render Pipeline"),
shader: shader.to_string(),
format,
vertex_layouts: vec![V::desc()],
vertex_entry_point: "vs_main",
fragment_entry_point: "fs_main",
topology: wgpu::PrimitiveTopology::TriangleList,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
}
}
pub fn with_label(mut self, label: &'a str) -> Self {
self.label = Some(label);
self
}
pub fn with_vertex_layouts(
mut self,
vertex_layouts: Vec<wgpu::VertexBufferLayout<'a>>,
) -> Self {
self.vertex_layouts = vertex_layouts;
self
}
pub fn with_entry_points(
mut self,
vertex_entry_point: &'a str,
fragment_entry_point: &'a str,
) -> Self {
self.vertex_entry_point = vertex_entry_point;
self.fragment_entry_point = fragment_entry_point;
self
}
pub fn with_topology(mut self, topology: wgpu::PrimitiveTopology) -> Self {
self.topology = topology;
self
}
pub fn with_cull_mode(mut self, cull_mode: Option<wgpu::Face>) -> Self {
self.cull_mode = cull_mode;
self
}
pub fn with_blend(mut self, blend: Option<wgpu::BlendState>) -> Self {
self.blend = blend;
self
}
pub fn with_depth_stencil(mut self, depth_stencil: Option<wgpu::DepthStencilState>) -> Self {
self.depth_stencil = depth_stencil;
self
}
}
impl Pipeline {
pub fn new(device: &Device, descriptor: PipelineDescriptor<'_>, camera_layout: &BindGroupLayout) -> AleaticoResult<Self> {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: descriptor.label,
source: ShaderSource::Wgsl(descriptor.shader.as_str().into()),
});
let texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
label: Some("texture_bind_group_layout"),
});
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[Some(&texture_bind_group_layout), Some(&camera_layout)],
immediate_size: 0,
});
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: descriptor.label,
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some(descriptor.vertex_entry_point),
buffers: &descriptor.vertex_layouts,
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
primitive: wgpu::PrimitiveState {
topology: descriptor.topology,
strip_index_format: None,
front_face: descriptor.front_face,
cull_mode: descriptor.cull_mode,
polygon_mode: descriptor.polygon_mode,
unclipped_depth: false,
conservative: false,
},
depth_stencil: descriptor.depth_stencil,
multisample: descriptor.multisample,
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some(descriptor.fragment_entry_point),
targets: &[Some(wgpu::ColorTargetState {
format: descriptor.format,
blend: descriptor.blend,
write_mask: descriptor.write_mask,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
multiview_mask: None,
cache: None,
});
Ok(Self { render_pipeline })
}
pub fn raw(&self) -> &wgpu::RenderPipeline {
&self.render_pipeline
}
}