tessera_ui_basic_components/pipelines/
contrast.rs1use tessera_ui::{
2 BarrierRequirement, PxRect,
3 compute::{ComputeResourceRef, resource::ComputeResourceManager},
4 renderer::compute::{ComputablePipeline, command::ComputeCommand},
5 wgpu::{self, util::DeviceExt},
6};
7
8#[derive(Debug, Clone, Copy, PartialEq)]
22pub struct ContrastCommand {
23 pub contrast: f32,
25 pub mean_result_handle: ComputeResourceRef,
27}
28
29impl ContrastCommand {
30 pub fn new(contrast: f32, mean_result_handle: ComputeResourceRef) -> Self {
36 Self {
37 contrast,
38 mean_result_handle,
39 }
40 }
41}
42
43impl ComputeCommand for ContrastCommand {
44 fn barrier(&self) -> tessera_ui::BarrierRequirement {
45 BarrierRequirement::ZERO_PADDING_LOCAL
46 }
47}
48
49#[repr(C)]
52#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
53struct Uniforms {
54 contrast: f32,
55 area_x: u32,
56 area_y: u32,
57 area_width: u32,
58 area_height: u32,
59}
60
61pub struct ContrastPipeline {
69 pipeline: wgpu::ComputePipeline,
70 bind_group_layout: wgpu::BindGroupLayout,
71}
72
73impl ContrastPipeline {
74 pub fn new(device: &wgpu::Device) -> Self {
75 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
76 label: Some("Contrast Shader"),
77 source: wgpu::ShaderSource::Wgsl(include_str!("contrast/contrast.wgsl").into()),
78 });
79
80 let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
81 entries: &[
82 wgpu::BindGroupLayoutEntry {
84 binding: 0,
85 visibility: wgpu::ShaderStages::COMPUTE,
86 ty: wgpu::BindingType::Buffer {
87 ty: wgpu::BufferBindingType::Uniform,
88 has_dynamic_offset: false,
89 min_binding_size: Some(std::num::NonZeroU64::new(20).unwrap()),
90 },
91 count: None,
92 },
93 wgpu::BindGroupLayoutEntry {
95 binding: 1,
96 visibility: wgpu::ShaderStages::COMPUTE,
97 ty: wgpu::BindingType::Texture {
98 sample_type: wgpu::TextureSampleType::Float { filterable: false },
99 view_dimension: wgpu::TextureViewDimension::D2,
100 multisampled: false,
101 },
102 count: None,
103 },
104 wgpu::BindGroupLayoutEntry {
106 binding: 2,
107 visibility: wgpu::ShaderStages::COMPUTE,
108 ty: wgpu::BindingType::StorageTexture {
109 access: wgpu::StorageTextureAccess::WriteOnly,
110 format: wgpu::TextureFormat::Rgba8Unorm,
111 view_dimension: wgpu::TextureViewDimension::D2,
112 },
113 count: None,
114 },
115 wgpu::BindGroupLayoutEntry {
117 binding: 3,
118 visibility: wgpu::ShaderStages::COMPUTE,
119 ty: wgpu::BindingType::Buffer {
120 ty: wgpu::BufferBindingType::Storage { read_only: true },
121 has_dynamic_offset: false,
122 min_binding_size: Some(std::num::NonZeroU64::new(8).unwrap()),
123 },
124 count: None,
125 },
126 ],
127 label: Some("contrast_bind_group_layout"),
128 });
129
130 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
131 label: Some("Contrast Pipeline Layout"),
132 bind_group_layouts: &[&bind_group_layout],
133 push_constant_ranges: &[],
134 });
135
136 let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
137 label: Some("Contrast Pipeline"),
138 layout: Some(&pipeline_layout),
139 module: &shader,
140 entry_point: Some("main"),
141 compilation_options: Default::default(),
142 cache: None,
143 });
144
145 Self {
146 pipeline,
147 bind_group_layout,
148 }
149 }
150}
151
152impl ComputablePipeline<ContrastCommand> for ContrastPipeline {
153 fn dispatch(
156 &mut self,
157 device: &wgpu::Device,
158 _queue: &wgpu::Queue,
159 config: &wgpu::SurfaceConfiguration,
160 compute_pass: &mut wgpu::ComputePass<'_>,
161 command: &ContrastCommand,
162 resource_manager: &mut ComputeResourceManager,
163 target_area: PxRect,
164 input_view: &wgpu::TextureView,
165 output_view: &wgpu::TextureView,
166 ) {
167 if let Some(mean_buffer) = resource_manager.get(&command.mean_result_handle) {
168 let uniforms = Uniforms {
169 contrast: command.contrast,
170 area_x: target_area.x.0 as u32,
171 area_y: target_area.y.0 as u32,
172 area_width: target_area.width.0 as u32,
173 area_height: target_area.height.0 as u32,
174 };
175
176 let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
177 label: Some("Contrast Uniform Buffer"),
178 contents: bytemuck::cast_slice(&[uniforms]),
179 usage: wgpu::BufferUsages::UNIFORM,
180 });
181
182 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
183 layout: &self.bind_group_layout,
184 entries: &[
185 wgpu::BindGroupEntry {
186 binding: 0,
187 resource: uniform_buffer.as_entire_binding(),
188 },
189 wgpu::BindGroupEntry {
190 binding: 1,
191 resource: wgpu::BindingResource::TextureView(input_view),
192 },
193 wgpu::BindGroupEntry {
194 binding: 2,
195 resource: wgpu::BindingResource::TextureView(output_view),
196 },
197 wgpu::BindGroupEntry {
198 binding: 3,
199 resource: mean_buffer.as_entire_binding(),
200 },
201 ],
202 label: Some("contrast_bind_group"),
203 });
204
205 compute_pass.set_pipeline(&self.pipeline);
206 compute_pass.set_bind_group(0, &bind_group, &[]);
207 compute_pass.dispatch_workgroups(
208 config.width.div_ceil(8),
209 config.height.div_ceil(8),
210 1,
211 );
212 }
213 }
214}