Skip to main content

aetna_wgpu/
msaa.rs

1//! MSAA color-attachment helper.
2//!
3//! Aetna's stock surfaces (rounded_rect, gradient, custom rect-shaped
4//! shaders) compute coverage analytically inside the fragment shader,
5//! so MSAA only helps when sample-rate shading is on — the SDF input
6//! varying carries `@interpolate(perspective, sample)` and the shader
7//! evaluates per sub-sample. Pair that with a [`Runner`](crate::Runner)
8//! built via [`Runner::with_sample_count`](crate::Runner::with_sample_count)
9//! and an [`MsaaTarget`] of matching `sample_count` for the attachment.
10//!
11//! The host always supplies the single-sample resolve target itself —
12//! a fresh texture in headless render binaries (so it can be read back
13//! / sampled), or the surface frame in windowed apps. `MsaaTarget` is
14//! deliberately just the multisampled side; bundling the resolve here
15//! would waste a fullscreen texture in the surface case.
16
17/// A multisampled color attachment.
18///
19/// Hosts allocate one of these to match their resolve target's extent
20/// and pass [`Self::view`] as the render pass `view` while binding
21/// their resolve target as `resolve_target`. On window resize, check
22/// [`Self::matches`] and reallocate when it returns false.
23pub struct MsaaTarget {
24    pub texture: wgpu::Texture,
25    pub view: wgpu::TextureView,
26    pub sample_count: u32,
27    pub format: wgpu::TextureFormat,
28    pub size: wgpu::Extent3d,
29}
30
31impl MsaaTarget {
32    /// Build a fresh multisampled color attachment sized to `size`.
33    /// Usage is `RENDER_ATTACHMENT` only — multisampled textures cannot
34    /// be sampled or copied directly; the resolve target is what the
35    /// host reads back, presents, or samples.
36    pub fn new(
37        device: &wgpu::Device,
38        format: wgpu::TextureFormat,
39        size: wgpu::Extent3d,
40        sample_count: u32,
41    ) -> Self {
42        let texture = device.create_texture(&wgpu::TextureDescriptor {
43            label: Some("aetna_wgpu::msaa_target"),
44            size,
45            mip_level_count: 1,
46            sample_count,
47            dimension: wgpu::TextureDimension::D2,
48            format,
49            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
50            view_formats: &[],
51        });
52        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
53        Self {
54            texture,
55            view,
56            sample_count,
57            format,
58            size,
59        }
60    }
61
62    /// True when this target's extent matches the requested size — the
63    /// idiomatic "do I need to reallocate after a resize?" check.
64    pub fn matches(&self, size: wgpu::Extent3d) -> bool {
65        self.size.width == size.width
66            && self.size.height == size.height
67            && self.size.depth_or_array_layers == size.depth_or_array_layers
68    }
69}