tessera_ui_basic_components/pipelines/
mean.rs1use tessera_ui::{
20 BarrierRequirement, PxRect,
21 compute::{ComputeResourceRef, resource::ComputeResourceManager},
22 renderer::compute::{ComputablePipeline, command::ComputeCommand},
23 wgpu::{self, util::DeviceExt},
24};
25
26#[derive(Debug, Clone, Copy, PartialEq)]
30pub struct MeanCommand {
38 result_buffer_ref: ComputeResourceRef,
39}
40
41impl MeanCommand {
42 pub fn new(gpu: &wgpu::Device, compute_resource_manager: &mut ComputeResourceManager) -> Self {
48 let result_buffer = gpu.create_buffer(&wgpu::BufferDescriptor {
49 label: Some("Mean Result Buffer"),
50 size: 8, usage: wgpu::BufferUsages::STORAGE
52 | wgpu::BufferUsages::COPY_SRC
53 | wgpu::BufferUsages::COPY_DST,
54 mapped_at_creation: false,
55 });
56
57 let result_buffer_ref = compute_resource_manager.push(result_buffer);
58 MeanCommand { result_buffer_ref }
59 }
60
61 pub fn result_buffer_ref(&self) -> ComputeResourceRef {
63 self.result_buffer_ref
64 }
65}
66
67impl ComputeCommand for MeanCommand {
68 fn barrier(&self) -> BarrierRequirement {
69 BarrierRequirement::ZERO_PADDING_LOCAL
70 }
71}
72
73#[repr(C)]
74#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
75struct AreaUniform {
76 area_x: u32,
77 area_y: u32,
78 area_width: u32,
79 area_height: u32,
80}
81
82pub struct MeanPipeline {
92 pipeline: wgpu::ComputePipeline,
93 bind_group_layout: wgpu::BindGroupLayout,
94}
95
96impl MeanPipeline {
97 pub fn new(device: &wgpu::Device) -> Self {
98 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
99 label: Some("Mean Shader"),
100 source: wgpu::ShaderSource::Wgsl(include_str!("mean/mean.wgsl").into()),
101 });
102
103 let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
104 entries: &[
105 wgpu::BindGroupLayoutEntry {
107 binding: 0,
108 visibility: wgpu::ShaderStages::COMPUTE,
109 ty: wgpu::BindingType::Buffer {
110 ty: wgpu::BufferBindingType::Uniform,
111 has_dynamic_offset: false,
112 min_binding_size: Some(std::num::NonZeroU64::new(16).unwrap()),
113 },
114 count: None,
115 },
116 wgpu::BindGroupLayoutEntry {
118 binding: 1,
119 visibility: wgpu::ShaderStages::COMPUTE,
120 ty: wgpu::BindingType::Texture {
121 sample_type: wgpu::TextureSampleType::Float { filterable: false },
122 view_dimension: wgpu::TextureViewDimension::D2,
123 multisampled: false,
124 },
125 count: None,
126 },
127 wgpu::BindGroupLayoutEntry {
129 binding: 2,
130 visibility: wgpu::ShaderStages::COMPUTE,
131 ty: wgpu::BindingType::Buffer {
132 ty: wgpu::BufferBindingType::Storage { read_only: false },
133 has_dynamic_offset: false,
134 min_binding_size: Some(std::num::NonZeroU64::new(8).unwrap()),
135 },
136 count: None,
137 },
138 wgpu::BindGroupLayoutEntry {
140 binding: 3,
141 visibility: wgpu::ShaderStages::COMPUTE,
142 ty: wgpu::BindingType::StorageTexture {
143 access: wgpu::StorageTextureAccess::WriteOnly,
144 format: wgpu::TextureFormat::Rgba8Unorm,
145 view_dimension: wgpu::TextureViewDimension::D2,
146 },
147 count: None,
148 },
149 ],
150 label: Some("mean_bind_group_layout"),
151 });
152
153 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
154 label: Some("Mean Pipeline Layout"),
155 bind_group_layouts: &[&bind_group_layout],
156 push_constant_ranges: &[],
157 });
158
159 let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
160 label: Some("Mean Pipeline"),
161 layout: Some(&pipeline_layout),
162 module: &shader,
163 entry_point: Some("main"),
164 compilation_options: Default::default(),
165 cache: None,
166 });
167
168 Self {
169 pipeline,
170 bind_group_layout,
171 }
172 }
173}
174
175impl ComputablePipeline<MeanCommand> for MeanPipeline {
176 fn dispatch(
190 &mut self,
191 device: &wgpu::Device,
192 queue: &wgpu::Queue,
193 config: &wgpu::SurfaceConfiguration,
194 compute_pass: &mut wgpu::ComputePass<'_>,
195 command: &MeanCommand,
196 resource_manager: &mut ComputeResourceManager,
197 target_area: PxRect,
198 input_view: &wgpu::TextureView,
199 output_view: &wgpu::TextureView,
200 ) {
201 let result_buffer = resource_manager.get(&command.result_buffer_ref).unwrap();
202 queue.write_buffer(result_buffer, 0, bytemuck::cast_slice(&[0u32, 0u32]));
203 let area_uniform = AreaUniform {
204 area_x: target_area.x.0 as u32,
205 area_y: target_area.y.0 as u32,
206 area_width: target_area.width.0 as u32,
207 area_height: target_area.height.0 as u32,
208 };
209 let area_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
210 label: Some("Mean Area Uniform Buffer"),
211 contents: bytemuck::bytes_of(&area_uniform),
212 usage: wgpu::BufferUsages::UNIFORM,
213 });
214 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
215 layout: &self.bind_group_layout,
216 entries: &[
217 wgpu::BindGroupEntry {
218 binding: 0,
219 resource: area_buffer.as_entire_binding(),
220 },
221 wgpu::BindGroupEntry {
222 binding: 1,
223 resource: wgpu::BindingResource::TextureView(input_view),
224 },
225 wgpu::BindGroupEntry {
226 binding: 2,
227 resource: result_buffer.as_entire_binding(),
228 },
229 wgpu::BindGroupEntry {
230 binding: 3,
231 resource: wgpu::BindingResource::TextureView(output_view),
232 },
233 ],
234 label: Some("mean_bind_group"),
235 });
236
237 compute_pass.set_pipeline(&self.pipeline);
238 compute_pass.set_bind_group(0, &bind_group, &[]);
239 compute_pass.dispatch_workgroups(config.width.div_ceil(8), config.height.div_ceil(8), 1);
240 }
241}