diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-01 13:57:32 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-01 13:57:32 +0200 |
| commit | e579ae120290329fd697b50ea9138ffccb65a805 (patch) | |
| tree | 12a63ee60b00e5004a1806ddf3ebd70c012e3e28 /rust/crates/gpu/src/shader_registry.rs | |
| parent | b048b739bd598f9d9ff97166f29bcb6e37c40607 (diff) | |
| download | opencut-e579ae120290329fd697b50ea9138ffccb65a805.tar.gz | |
feat: migrate GPU renderer from WebGL to wgpu/WASM
Diffstat (limited to 'rust/crates/gpu/src/shader_registry.rs')
| -rw-r--r-- | rust/crates/gpu/src/shader_registry.rs | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/rust/crates/gpu/src/shader_registry.rs b/rust/crates/gpu/src/shader_registry.rs new file mode 100644 index 00000000..b6af173e --- /dev/null +++ b/rust/crates/gpu/src/shader_registry.rs @@ -0,0 +1,183 @@ +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 + } +} |
