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