184 lines
7.8 KiB
Rust
184 lines
7.8 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use crate::{GPU_TEXTURE_FORMAT, GpuError};
|
|
|
|
const FULLSCREEN_SHADER_SOURCE: &str = include_str!("shaders/fullscreen.wgsl");
|
|
const GAUSSIAN_BLUR_SHADER_SOURCE: &str = include_str!("shaders/gaussian_blur.wgsl");
|
|
const BLIT_SHADER_SOURCE: &str = include_str!("shaders/blit.wgsl");
|
|
pub const GAUSSIAN_BLUR_SHADER_ID: &str = "gaussian-blur";
|
|
|
|
pub struct ShaderRegistry {
|
|
effect_texture_bind_group_layout: wgpu::BindGroupLayout,
|
|
effect_uniform_bind_group_layout: wgpu::BindGroupLayout,
|
|
effect_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
|
blit_pipeline: wgpu::RenderPipeline,
|
|
}
|
|
|
|
impl ShaderRegistry {
|
|
pub fn new(device: &wgpu::Device) -> Self {
|
|
let effect_texture_bind_group_layout =
|
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
label: Some("gpu-effect-texture-bind-group-layout"),
|
|
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,
|
|
},
|
|
],
|
|
});
|
|
let effect_uniform_bind_group_layout =
|
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
label: Some("gpu-effect-uniform-bind-group-layout"),
|
|
entries: &[wgpu::BindGroupLayoutEntry {
|
|
binding: 0,
|
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
ty: wgpu::BindingType::Buffer {
|
|
ty: wgpu::BufferBindingType::Uniform,
|
|
has_dynamic_offset: false,
|
|
min_binding_size: None,
|
|
},
|
|
count: None,
|
|
}],
|
|
});
|
|
|
|
let vertex_shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
label: Some("gpu-fullscreen-shader"),
|
|
source: wgpu::ShaderSource::Wgsl(FULLSCREEN_SHADER_SOURCE.into()),
|
|
});
|
|
let gaussian_blur_shader_module =
|
|
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
label: Some("gpu-gaussian-blur-shader"),
|
|
source: wgpu::ShaderSource::Wgsl(GAUSSIAN_BLUR_SHADER_SOURCE.into()),
|
|
});
|
|
let blit_shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
label: Some("gpu-blit-shader"),
|
|
source: wgpu::ShaderSource::Wgsl(BLIT_SHADER_SOURCE.into()),
|
|
});
|
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
label: Some("gpu-effect-pipeline-layout"),
|
|
bind_group_layouts: &[
|
|
Some(&effect_texture_bind_group_layout),
|
|
Some(&effect_uniform_bind_group_layout),
|
|
],
|
|
immediate_size: 0,
|
|
});
|
|
let blit_pipeline_layout =
|
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
label: Some("gpu-blit-pipeline-layout"),
|
|
bind_group_layouts: &[Some(&effect_texture_bind_group_layout)],
|
|
immediate_size: 0,
|
|
});
|
|
let gaussian_blur_pipeline =
|
|
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
label: Some("gpu-gaussian-blur-pipeline"),
|
|
layout: Some(&pipeline_layout),
|
|
vertex: wgpu::VertexState {
|
|
module: &vertex_shader_module,
|
|
entry_point: Some("vertex_main"),
|
|
buffers: &[wgpu::VertexBufferLayout {
|
|
array_stride: std::mem::size_of::<[f32; 2]>() as u64,
|
|
step_mode: wgpu::VertexStepMode::Vertex,
|
|
attributes: &[wgpu::VertexAttribute {
|
|
format: wgpu::VertexFormat::Float32x2,
|
|
offset: 0,
|
|
shader_location: 0,
|
|
}],
|
|
}],
|
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
|
},
|
|
fragment: Some(wgpu::FragmentState {
|
|
module: &gaussian_blur_shader_module,
|
|
entry_point: Some("fragment_main"),
|
|
targets: &[Some(wgpu::ColorTargetState {
|
|
format: GPU_TEXTURE_FORMAT,
|
|
blend: None,
|
|
write_mask: wgpu::ColorWrites::ALL,
|
|
})],
|
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
|
}),
|
|
primitive: wgpu::PrimitiveState::default(),
|
|
depth_stencil: None,
|
|
multisample: wgpu::MultisampleState::default(),
|
|
multiview_mask: None,
|
|
cache: None,
|
|
});
|
|
let blit_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
label: Some("gpu-blit-pipeline"),
|
|
layout: Some(&blit_pipeline_layout),
|
|
vertex: wgpu::VertexState {
|
|
module: &vertex_shader_module,
|
|
entry_point: Some("vertex_main"),
|
|
buffers: &[wgpu::VertexBufferLayout {
|
|
array_stride: std::mem::size_of::<[f32; 2]>() as u64,
|
|
step_mode: wgpu::VertexStepMode::Vertex,
|
|
attributes: &[wgpu::VertexAttribute {
|
|
format: wgpu::VertexFormat::Float32x2,
|
|
offset: 0,
|
|
shader_location: 0,
|
|
}],
|
|
}],
|
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
|
},
|
|
fragment: Some(wgpu::FragmentState {
|
|
module: &blit_shader_module,
|
|
entry_point: Some("fragment_main"),
|
|
targets: &[Some(wgpu::ColorTargetState {
|
|
format: GPU_TEXTURE_FORMAT,
|
|
blend: None,
|
|
write_mask: wgpu::ColorWrites::ALL,
|
|
})],
|
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
|
}),
|
|
primitive: wgpu::PrimitiveState::default(),
|
|
depth_stencil: None,
|
|
multisample: wgpu::MultisampleState::default(),
|
|
multiview_mask: None,
|
|
cache: None,
|
|
});
|
|
|
|
let effect_pipelines = HashMap::from([(
|
|
GAUSSIAN_BLUR_SHADER_ID.to_string(),
|
|
gaussian_blur_pipeline,
|
|
)]);
|
|
|
|
Self {
|
|
effect_texture_bind_group_layout,
|
|
effect_uniform_bind_group_layout,
|
|
effect_pipelines,
|
|
blit_pipeline,
|
|
}
|
|
}
|
|
|
|
pub fn get_effect_pipeline(&self, shader: &str) -> Result<&wgpu::RenderPipeline, GpuError> {
|
|
self.effect_pipelines
|
|
.get(shader)
|
|
.ok_or_else(|| GpuError::UnknownEffectShader {
|
|
shader: shader.to_string(),
|
|
})
|
|
}
|
|
|
|
pub fn effect_texture_bind_group_layout(&self) -> &wgpu::BindGroupLayout {
|
|
&self.effect_texture_bind_group_layout
|
|
}
|
|
|
|
pub fn effect_uniform_bind_group_layout(&self) -> &wgpu::BindGroupLayout {
|
|
&self.effect_uniform_bind_group_layout
|
|
}
|
|
|
|
pub fn blit_pipeline(&self) -> &wgpu::RenderPipeline {
|
|
&self.blit_pipeline
|
|
}
|
|
}
|