use crate::gpu::context::Error;
pub struct Pipelines {
pub quad: wgpu::RenderPipeline,
pub shadow: wgpu::RenderPipeline,
pub underline: wgpu::RenderPipeline,
pub monochrome: wgpu::RenderPipeline,
pub polychrome: wgpu::RenderPipeline,
pub globals_layout: wgpu::BindGroupLayout,
pub instances_layout: wgpu::BindGroupLayout,
pub atlas_layout: wgpu::BindGroupLayout,
pub(crate) shader: wgpu::ShaderModule,
pub(crate) layout: wgpu::PipelineLayout,
}
pub const GLOBALS_SIZE: u64 = 48;
fn buffer_entry(binding: u32, kind: wgpu::BufferBindingType, stage: wgpu::ShaderStages) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding,
visibility: stage,
ty: wgpu::BindingType::Buffer { ty: kind, has_dynamic_offset: false, min_binding_size: None },
count: None,
}
}
impl Pipelines {
pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Result<Self, Error> {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("aura_uber_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
});
let globals_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("aura_globals_layout"),
entries: &[wgpu::BindGroupLayoutEntry {
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: wgpu::BufferSize::new(GLOBALS_SIZE),
},
..buffer_entry(
0,
wgpu::BufferBindingType::Uniform,
wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
)
}],
});
let instances_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("aura_instances_layout"),
entries: &[buffer_entry(
0,
wgpu::BufferBindingType::Storage { read_only: true },
wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
)],
});
let atlas_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("aura_atlas_layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
});
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("aura_pipeline_layout"),
bind_group_layouts: &[Some(&globals_layout), Some(&instances_layout), Some(&atlas_layout)],
immediate_size: 0,
});
let build = |label: &str, vertex: &str, fragment: &str| {
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some(label),
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some(vertex),
compilation_options: Default::default(),
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some(fragment),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
format,
blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleStrip,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
})
};
let quad = build("aura_quads", "vs_quad", "fs_quad");
let shadow = build("aura_shadows", "vs_shadow", "fs_shadow");
let underline = build("aura_underlines", "vs_underline", "fs_underline");
let monochrome = build("aura_monochrome", "vs_sprite", "fs_monochrome");
let polychrome = build("aura_polychrome", "vs_sprite", "fs_polychrome");
Ok(Self {
quad,
shadow,
underline,
monochrome,
polychrome,
globals_layout,
instances_layout,
atlas_layout,
shader,
layout,
})
}
}