summaryrefslogtreecommitdiff
path: root/rust/crates/gpu/src/shader_registry.rs
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-01 13:57:32 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-01 13:57:32 +0200
commite579ae120290329fd697b50ea9138ffccb65a805 (patch)
tree12a63ee60b00e5004a1806ddf3ebd70c012e3e28 /rust/crates/gpu/src/shader_registry.rs
parentb048b739bd598f9d9ff97166f29bcb6e37c40607 (diff)
downloadopencut-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.rs183
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
+ }
+}