tessera_ui_basic_components/pipelines/blur/
pipeline.rs1use encase::{ShaderType, UniformBuffer};
2use tessera_ui::{
3 PxRect,
4 renderer::compute::ComputablePipeline,
5 wgpu::{self, util::DeviceExt},
6};
7
8use super::command::BlurCommand;
9
10#[derive(ShaderType)]
11struct BlurUniforms {
12 radius: f32,
13 direction_x: f32,
14 direction_y: f32,
15 area_x: u32,
16 area_y: u32,
17 area_width: u32,
18 area_height: u32,
19}
20
21pub struct BlurPipeline {
22 pipeline: wgpu::ComputePipeline,
23 bind_group_layout: wgpu::BindGroupLayout,
24}
25
26impl BlurPipeline {
27 pub fn new(device: &wgpu::Device) -> Self {
28 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
29 label: Some("Blur Shader"),
30 source: wgpu::ShaderSource::Wgsl(include_str!("blur.wgsl").into()),
31 });
32
33 let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
34 entries: &[
35 wgpu::BindGroupLayoutEntry {
37 binding: 0,
38 visibility: wgpu::ShaderStages::COMPUTE,
39 ty: wgpu::BindingType::Buffer {
40 ty: wgpu::BufferBindingType::Uniform,
41 has_dynamic_offset: false,
42 min_binding_size: None,
43 },
44 count: None,
45 },
46 wgpu::BindGroupLayoutEntry {
48 binding: 1,
49 visibility: wgpu::ShaderStages::COMPUTE,
50 ty: wgpu::BindingType::Texture {
51 sample_type: wgpu::TextureSampleType::Float { filterable: true },
52 view_dimension: wgpu::TextureViewDimension::D2,
53 multisampled: false,
54 },
55 count: None,
56 },
57 wgpu::BindGroupLayoutEntry {
59 binding: 2,
60 visibility: wgpu::ShaderStages::COMPUTE,
61 ty: wgpu::BindingType::StorageTexture {
62 access: wgpu::StorageTextureAccess::WriteOnly,
63 format: wgpu::TextureFormat::Rgba8Unorm,
67 view_dimension: wgpu::TextureViewDimension::D2,
68 },
69 count: None,
70 },
71 ],
72 label: Some("blur_bind_group_layout"),
73 });
74
75 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
76 label: Some("Blur Pipeline Layout"),
77 bind_group_layouts: &[&bind_group_layout],
78 push_constant_ranges: &[],
79 });
80
81 let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
82 label: Some("Blur Pipeline"),
83 layout: Some(&pipeline_layout),
84 module: &shader,
85 entry_point: Some("main"),
86 compilation_options: Default::default(),
87 cache: None,
88 });
89
90 Self {
91 pipeline,
92 bind_group_layout,
93 }
94 }
95}
96
97impl ComputablePipeline<BlurCommand> for BlurPipeline {
98 fn dispatch(
101 &mut self,
102 device: &wgpu::Device,
103 _queue: &wgpu::Queue,
104 config: &wgpu::SurfaceConfiguration,
105 compute_pass: &mut wgpu::ComputePass<'_>,
106 command: &BlurCommand,
107 _resource_manager: &mut tessera_ui::ComputeResourceManager,
108 target_area: PxRect,
109 input_view: &wgpu::TextureView,
110 output_view: &wgpu::TextureView,
111 ) {
112 let uniforms = BlurUniforms {
113 radius: command.radius,
114 direction_x: command.direction.0,
115 direction_y: command.direction.1,
116 area_x: target_area.x.0 as u32,
117 area_y: target_area.y.0 as u32,
118 area_width: target_area.width.0 as u32,
119 area_height: target_area.height.0 as u32,
120 };
121 let mut buffer = UniformBuffer::new(Vec::new());
122 buffer.write(&uniforms).unwrap();
123 let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
124 label: Some("Blur Uniform Buffer"),
125 contents: &buffer.into_inner(),
126 usage: wgpu::BufferUsages::UNIFORM,
127 });
128
129 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
130 layout: &self.bind_group_layout,
131 entries: &[
132 wgpu::BindGroupEntry {
133 binding: 0,
134 resource: uniform_buffer.as_entire_binding(),
135 },
136 wgpu::BindGroupEntry {
137 binding: 1,
138 resource: wgpu::BindingResource::TextureView(input_view),
139 },
140 wgpu::BindGroupEntry {
141 binding: 2,
142 resource: wgpu::BindingResource::TextureView(output_view),
143 },
144 ],
145 label: Some("blur_bind_group"),
146 });
147
148 compute_pass.set_pipeline(&self.pipeline);
149 compute_pass.set_bind_group(0, &bind_group, &[]);
150 compute_pass.dispatch_workgroups(config.width.div_ceil(8), config.height.div_ceil(8), 1);
151 }
152}