1#[repr(C)]
8#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
9pub struct BackdropUniforms {
10 pub radius: [f32; 4],
11 pub rect_pos: [f32; 2],
12 pub rect_size: [f32; 2],
13 pub screen_size: [f32; 2],
14 pub time: f32,
15 pub brightness: f32,
16 pub saturation: f32,
17 pub contrast: f32,
18 pub blur_type: f32,
19 pub opacity: f32,
20 pub padding: [f32; 2],
21 pub _end_padding: [f32; 2],
22}
23
24pub struct BlitPipeline {
25 pub pipeline: wgpu::RenderPipeline,
26 pub backdrop_pipeline: wgpu::RenderPipeline,
27 pub bgl: wgpu::BindGroupLayout,
28 pub backdrop_bgl: wgpu::BindGroupLayout,
29 pub sampler: wgpu::Sampler,
30}
31
32impl BlitPipeline {
33 pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
34 let shader = device.create_shader_module(wgpu::include_wgsl!("shaders/blit.wgsl"));
35
36 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
37 label: Some("Blit BGL"),
38 entries: &[
39 wgpu::BindGroupLayoutEntry {
40 binding: 0,
41 visibility: wgpu::ShaderStages::FRAGMENT,
42 ty: wgpu::BindingType::Texture {
43 sample_type: wgpu::TextureSampleType::Float { filterable: true },
44 view_dimension: wgpu::TextureViewDimension::D2,
45 multisampled: false,
46 },
47 count: None,
48 },
49 wgpu::BindGroupLayoutEntry {
50 binding: 1,
51 visibility: wgpu::ShaderStages::FRAGMENT,
52 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
53 count: None,
54 },
55 ],
56 });
57
58 let backdrop_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
59 label: Some("Blit Backdrop BGL"),
60 entries: &[
61 wgpu::BindGroupLayoutEntry {
62 binding: 0,
63 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
64 ty: wgpu::BindingType::Buffer {
65 ty: wgpu::BufferBindingType::Uniform,
66 has_dynamic_offset: false,
67 min_binding_size: None,
68 },
69 count: None,
70 },
71 ],
72 });
73
74 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
75 label: Some("Blit Pipeline Layout"),
76 bind_group_layouts: &[Some(&bgl)],
77 immediate_size: 0,
78 });
79
80 let backdrop_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
81 label: Some("Blit Backdrop Pipeline Layout"),
82 bind_group_layouts: &[Some(&bgl), Some(&backdrop_bgl)],
83 immediate_size: 0,
84 });
85
86 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
87 label: Some("Blit Pipeline"),
88 layout: Some(&layout),
89 vertex: wgpu::VertexState {
90 module: &shader,
91 entry_point: Some("vs_main"),
92 buffers: &[],
93 compilation_options: Default::default(),
94 },
95 fragment: Some(wgpu::FragmentState {
96 module: &shader,
97 entry_point: Some("fs_main"),
98 targets: &[Some(wgpu::ColorTargetState {
99 format,
100 blend: None, write_mask: wgpu::ColorWrites::ALL,
102 })],
103 compilation_options: Default::default(),
104 }),
105 primitive: wgpu::PrimitiveState::default(),
106 depth_stencil: None,
107 multisample: wgpu::MultisampleState::default(),
108 multiview_mask: None,
109 cache: None,
110 });
111
112 let backdrop_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
113 label: Some("Blit Backdrop Pipeline"),
114 layout: Some(&backdrop_layout),
115 vertex: wgpu::VertexState {
116 module: &shader,
117 entry_point: Some("vs_backdrop"),
118 buffers: &[],
119 compilation_options: Default::default(),
120 },
121 fragment: Some(wgpu::FragmentState {
122 module: &shader,
123 entry_point: Some("fs_backdrop"),
124 targets: &[Some(wgpu::ColorTargetState {
125 format,
126 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
127 write_mask: wgpu::ColorWrites::ALL,
128 })],
129 compilation_options: Default::default(),
130 }),
131 primitive: wgpu::PrimitiveState::default(),
132 depth_stencil: None,
133 multisample: wgpu::MultisampleState::default(),
134 multiview_mask: None,
135 cache: None,
136 });
137
138 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
139 label: Some("Blit Sampler"),
140 address_mode_u: wgpu::AddressMode::ClampToEdge,
141 address_mode_v: wgpu::AddressMode::ClampToEdge,
142 mag_filter: wgpu::FilterMode::Linear,
143 min_filter: wgpu::FilterMode::Linear,
144 ..Default::default()
145 });
146
147 Self { pipeline, backdrop_pipeline, bgl, backdrop_bgl, sampler }
148 }
149
150 pub fn blit<'a>(
153 &'a self,
154 device: &wgpu::Device,
155 pass: &mut wgpu::RenderPass<'a>,
156 src_view: &wgpu::TextureView,
157 ) {
158 let bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
159 label: Some("Blit BG"),
160 layout: &self.bgl,
161 entries: &[
162 wgpu::BindGroupEntry {
163 binding: 0,
164 resource: wgpu::BindingResource::TextureView(src_view),
165 },
166 wgpu::BindGroupEntry {
167 binding: 1,
168 resource: wgpu::BindingResource::Sampler(&self.sampler),
169 },
170 ],
171 });
172 pass.set_pipeline(&self.pipeline);
173 pass.set_bind_group(0, &bg, &[]);
174 pass.draw(0..3, 0..1);
175 }
176
177 pub fn blit_to(
179 &self,
180 device: &wgpu::Device,
181 encoder: &mut wgpu::CommandEncoder,
182 src_view: &wgpu::TextureView,
183 dst_view: &wgpu::TextureView,
184 load: wgpu::LoadOp<wgpu::Color>,
185 ) {
186 let bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
187 label: Some("Blit BG"),
188 layout: &self.bgl,
189 entries: &[
190 wgpu::BindGroupEntry {
191 binding: 0,
192 resource: wgpu::BindingResource::TextureView(src_view),
193 },
194 wgpu::BindGroupEntry {
195 binding: 1,
196 resource: wgpu::BindingResource::Sampler(&self.sampler),
197 },
198 ],
199 });
200
201 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
202 label: Some("Blit Pass"),
203 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
204 view: dst_view,
205 resolve_target: None,
206 ops: wgpu::Operations { load, store: wgpu::StoreOp::Store },
207 depth_slice: None,
208 })],
209 depth_stencil_attachment: None,
210 timestamp_writes: None,
211 occlusion_query_set: None,
212 multiview_mask: None,
213 });
214
215 pass.set_pipeline(&self.pipeline);
216 pass.set_bind_group(0, &bg, &[]);
217 pass.draw(0..3, 0..1);
218 }
219
220 pub fn blit_to_clipped(
222 &self,
223 device: &wgpu::Device,
224 encoder: &mut wgpu::CommandEncoder,
225 src_view: &wgpu::TextureView,
226 dst_view: &wgpu::TextureView,
227 rect_pos: [f32; 2],
228 rect_size: [f32; 2],
229 radius: [f32; 4],
230 surface_w: u32,
231 surface_h: u32,
232 brightness: f32,
233 saturation: f32,
234 contrast: f32,
235 blur_type: f32,
236 opacity: f32,
237 ) {
238 use wgpu::util::DeviceExt;
239
240 let bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
241 label: Some("Blit Clipped BG"),
242 layout: &self.bgl,
243 entries: &[
244 wgpu::BindGroupEntry {
245 binding: 0,
246 resource: wgpu::BindingResource::TextureView(src_view),
247 },
248 wgpu::BindGroupEntry {
249 binding: 1,
250 resource: wgpu::BindingResource::Sampler(&self.sampler),
251 },
252 ],
253 });
254
255 let uniforms = BackdropUniforms {
256 radius,
257 rect_pos,
258 rect_size,
259 screen_size: [surface_w as f32, surface_h as f32],
260 time: 0.0,
261 brightness,
262 saturation,
263 contrast,
264 blur_type,
265 opacity,
266 padding: [0.0; 2],
267 _end_padding: [0.0; 2],
268 };
269
270 let uniform_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
271 label: Some("Blit Backdrop Uniform Buffer"),
272 contents: bytemuck::bytes_of(&uniforms),
273 usage: wgpu::BufferUsages::UNIFORM,
274 });
275
276 let uniform_bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
277 label: Some("Blit Backdrop Uniform BG"),
278 layout: &self.backdrop_bgl,
279 entries: &[
280 wgpu::BindGroupEntry {
281 binding: 0,
282 resource: uniform_buf.as_entire_binding(),
283 },
284 ],
285 });
286
287 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
288 label: Some("Blit Clipped Pass"),
289 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
290 view: dst_view,
291 resolve_target: None,
292 ops: wgpu::Operations { load: wgpu::LoadOp::Load, store: wgpu::StoreOp::Store },
294 depth_slice: None,
295 })],
296 depth_stencil_attachment: None,
297 timestamp_writes: None,
298 occlusion_query_set: None,
299 multiview_mask: None,
300 });
301
302 pass.set_pipeline(&self.backdrop_pipeline);
303 pass.set_bind_group(0, &bg, &[]);
304 pass.set_bind_group(1, &uniform_bg, &[]);
305 pass.draw(0..6, 0..1);
306 }
307}