iced_wgpu/triangle/
msaa.rs

1use crate::core::{Size, Transformation};
2use crate::graphics;
3
4use std::num::NonZeroU64;
5
6#[derive(Debug)]
7pub struct Blit {
8    format: wgpu::TextureFormat,
9    pipeline: wgpu::RenderPipeline,
10    constants: wgpu::BindGroup,
11    ratio: wgpu::Buffer,
12    texture_layout: wgpu::BindGroupLayout,
13    sample_count: u32,
14    targets: Option<Targets>,
15    last_region: Option<Size<u32>>,
16}
17
18impl Blit {
19    pub fn new(
20        device: &wgpu::Device,
21        format: wgpu::TextureFormat,
22        antialiasing: graphics::Antialiasing,
23    ) -> Blit {
24        let sampler =
25            device.create_sampler(&wgpu::SamplerDescriptor::default());
26
27        let ratio = device.create_buffer(&wgpu::BufferDescriptor {
28            label: Some("iced-wgpu::triangle::msaa ratio"),
29            size: std::mem::size_of::<Ratio>() as u64,
30            usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,
31            mapped_at_creation: false,
32        });
33
34        let constant_layout =
35            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
36                label: Some("iced_wgpu::triangle:msaa uniforms layout"),
37                entries: &[
38                    wgpu::BindGroupLayoutEntry {
39                        binding: 0,
40                        visibility: wgpu::ShaderStages::FRAGMENT,
41                        ty: wgpu::BindingType::Sampler(
42                            wgpu::SamplerBindingType::NonFiltering,
43                        ),
44                        count: None,
45                    },
46                    wgpu::BindGroupLayoutEntry {
47                        binding: 1,
48                        visibility: wgpu::ShaderStages::VERTEX,
49                        ty: wgpu::BindingType::Buffer {
50                            ty: wgpu::BufferBindingType::Uniform,
51                            has_dynamic_offset: false,
52                            min_binding_size: None,
53                        },
54                        count: None,
55                    },
56                ],
57            });
58
59        let constant_bind_group =
60            device.create_bind_group(&wgpu::BindGroupDescriptor {
61                label: Some("iced_wgpu::triangle::msaa uniforms bind group"),
62                layout: &constant_layout,
63                entries: &[
64                    wgpu::BindGroupEntry {
65                        binding: 0,
66                        resource: wgpu::BindingResource::Sampler(&sampler),
67                    },
68                    wgpu::BindGroupEntry {
69                        binding: 1,
70                        resource: ratio.as_entire_binding(),
71                    },
72                ],
73            });
74
75        let texture_layout =
76            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
77                label: Some("iced_wgpu::triangle::msaa texture layout"),
78                entries: &[wgpu::BindGroupLayoutEntry {
79                    binding: 0,
80                    visibility: wgpu::ShaderStages::FRAGMENT,
81                    ty: wgpu::BindingType::Texture {
82                        sample_type: wgpu::TextureSampleType::Float {
83                            filterable: false,
84                        },
85                        view_dimension: wgpu::TextureViewDimension::D2,
86                        multisampled: false,
87                    },
88                    count: None,
89                }],
90            });
91
92        let layout =
93            device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
94                label: Some("iced_wgpu::triangle::msaa pipeline layout"),
95                push_constant_ranges: &[],
96                bind_group_layouts: &[&constant_layout, &texture_layout],
97            });
98
99        let shader =
100            device.create_shader_module(wgpu::ShaderModuleDescriptor {
101                label: Some("iced_wgpu triangle blit_shader"),
102                source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
103                    include_str!("../shader/blit.wgsl"),
104                )),
105            });
106
107        let pipeline =
108            device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
109                label: Some("iced_wgpu::triangle::msaa pipeline"),
110                layout: Some(&layout),
111                vertex: wgpu::VertexState {
112                    module: &shader,
113                    entry_point: Some("vs_main"),
114                    buffers: &[],
115                    compilation_options:
116                        wgpu::PipelineCompilationOptions::default(),
117                },
118                fragment: Some(wgpu::FragmentState {
119                    module: &shader,
120                    entry_point: Some("fs_main"),
121                    targets: &[Some(wgpu::ColorTargetState {
122                        format,
123                        blend: Some(
124                            wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING,
125                        ),
126                        write_mask: wgpu::ColorWrites::ALL,
127                    })],
128                    compilation_options:
129                        wgpu::PipelineCompilationOptions::default(),
130                }),
131                primitive: wgpu::PrimitiveState {
132                    topology: wgpu::PrimitiveTopology::TriangleList,
133                    front_face: wgpu::FrontFace::Cw,
134                    ..Default::default()
135                },
136                depth_stencil: None,
137                multisample: wgpu::MultisampleState {
138                    count: 1,
139                    mask: !0,
140                    alpha_to_coverage_enabled: false,
141                },
142                multiview: None,
143                cache: None,
144            });
145
146        Blit {
147            format,
148            pipeline,
149            constants: constant_bind_group,
150            ratio,
151            texture_layout,
152            sample_count: antialiasing.sample_count(),
153            targets: None,
154            last_region: None,
155        }
156    }
157
158    pub fn prepare(
159        &mut self,
160        device: &wgpu::Device,
161        encoder: &mut wgpu::CommandEncoder,
162        belt: &mut wgpu::util::StagingBelt,
163        region_size: Size<u32>,
164    ) -> Transformation {
165        match &mut self.targets {
166            Some(targets)
167                if region_size.width <= targets.size.width
168                    && region_size.height <= targets.size.height => {}
169            _ => {
170                self.targets = Some(Targets::new(
171                    device,
172                    self.format,
173                    &self.texture_layout,
174                    self.sample_count,
175                    region_size,
176                ));
177            }
178        }
179
180        let targets = self.targets.as_mut().unwrap();
181
182        if Some(region_size) != self.last_region {
183            let ratio = Ratio {
184                u: region_size.width as f32 / targets.size.width as f32,
185                v: region_size.height as f32 / targets.size.height as f32,
186            };
187
188            belt.write_buffer(
189                encoder,
190                &self.ratio,
191                0,
192                NonZeroU64::new(std::mem::size_of::<Ratio>() as u64)
193                    .expect("non-empty ratio"),
194                device,
195            )
196            .copy_from_slice(bytemuck::bytes_of(&ratio));
197
198            self.last_region = Some(region_size);
199        }
200
201        Transformation::orthographic(targets.size.width, targets.size.height)
202    }
203
204    pub fn targets(&self) -> (&wgpu::TextureView, &wgpu::TextureView) {
205        let targets = self.targets.as_ref().unwrap();
206
207        (&targets.attachment, &targets.resolve)
208    }
209
210    pub fn draw(
211        &self,
212        encoder: &mut wgpu::CommandEncoder,
213        target: &wgpu::TextureView,
214    ) {
215        let mut render_pass =
216            encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
217                label: Some("iced_wgpu::triangle::msaa render pass"),
218                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
219                    view: target,
220                    resolve_target: None,
221                    ops: wgpu::Operations {
222                        load: wgpu::LoadOp::Load,
223                        store: wgpu::StoreOp::Store,
224                    },
225                })],
226                depth_stencil_attachment: None,
227                timestamp_writes: None,
228                occlusion_query_set: None,
229            });
230
231        render_pass.set_pipeline(&self.pipeline);
232        render_pass.set_bind_group(0, &self.constants, &[]);
233        render_pass.set_bind_group(
234            1,
235            &self.targets.as_ref().unwrap().bind_group,
236            &[],
237        );
238        render_pass.draw(0..6, 0..1);
239    }
240}
241
242#[derive(Debug)]
243struct Targets {
244    attachment: wgpu::TextureView,
245    resolve: wgpu::TextureView,
246    bind_group: wgpu::BindGroup,
247    size: Size<u32>,
248}
249
250impl Targets {
251    pub fn new(
252        device: &wgpu::Device,
253        format: wgpu::TextureFormat,
254        texture_layout: &wgpu::BindGroupLayout,
255        sample_count: u32,
256        size: Size<u32>,
257    ) -> Targets {
258        let extent = wgpu::Extent3d {
259            width: size.width,
260            height: size.height,
261            depth_or_array_layers: 1,
262        };
263
264        let attachment = device.create_texture(&wgpu::TextureDescriptor {
265            label: Some("iced_wgpu::triangle::msaa attachment"),
266            size: extent,
267            mip_level_count: 1,
268            sample_count,
269            dimension: wgpu::TextureDimension::D2,
270            format,
271            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
272            view_formats: &[],
273        });
274
275        let resolve = device.create_texture(&wgpu::TextureDescriptor {
276            label: Some("iced_wgpu::triangle::msaa resolve target"),
277            size: extent,
278            mip_level_count: 1,
279            sample_count: 1,
280            dimension: wgpu::TextureDimension::D2,
281            format,
282            usage: wgpu::TextureUsages::RENDER_ATTACHMENT
283                | wgpu::TextureUsages::TEXTURE_BINDING,
284            view_formats: &[],
285        });
286
287        let attachment =
288            attachment.create_view(&wgpu::TextureViewDescriptor::default());
289
290        let resolve =
291            resolve.create_view(&wgpu::TextureViewDescriptor::default());
292
293        let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
294            label: Some("iced_wgpu::triangle::msaa texture bind group"),
295            layout: texture_layout,
296            entries: &[wgpu::BindGroupEntry {
297                binding: 0,
298                resource: wgpu::BindingResource::TextureView(&resolve),
299            }],
300        });
301
302        Targets {
303            attachment,
304            resolve,
305            bind_group,
306            size,
307        }
308    }
309}
310
311#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
312#[repr(C)]
313struct Ratio {
314    u: f32,
315    v: f32,
316}