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