three_d/core/render_target/
multisample.rs

1use crate::core::*;
2
3///
4/// A multisampled render target for color and depth data. Use this if you want to avoid aliasing, ie. jagged edges, when rendering to a [RenderTarget].
5///
6/// After rendering into this target, it needs to be resolved to a non-multisample texture to be able to sample it in a shader.
7/// To do this, use the [RenderTargetMultisample::resolve], [RenderTargetMultisample::resolve_to], [RenderTargetMultisample::resolve_color_to]
8/// or [RenderTargetMultisample::resolve_depth_to] methods.
9///
10/// Also see [ColorTargetMultisample] and [DepthTargetMultisample].
11///
12pub struct RenderTargetMultisample<C: TextureDataType, D: DepthTextureDataType> {
13    pub(crate) context: Context,
14    color: Texture2DMultisample,
15    depth: DepthTexture2DMultisample,
16    _c: std::marker::PhantomData<C>,
17    _d: std::marker::PhantomData<D>,
18}
19
20impl<C: TextureDataType, D: DepthTextureDataType> RenderTargetMultisample<C, D> {
21    ///
22    /// Constructs a new multisample render target with the given dimensions and number of samples.
23    /// The number of samples must be larger than 0, less than or equal to the maximum number of samples supported by the hardware and power of two.
24    ///
25    pub fn new(context: &Context, width: u32, height: u32, number_of_samples: u32) -> Self {
26        #[cfg(debug_assertions)]
27        super::multisample_sanity_check(context, number_of_samples);
28        Self {
29            context: context.clone(),
30            color: Texture2DMultisample::new::<C>(context, width, height, number_of_samples),
31            depth: DepthTexture2DMultisample::new::<D>(context, width, height, number_of_samples),
32            _c: std::marker::PhantomData,
33            _d: std::marker::PhantomData,
34        }
35    }
36
37    ///
38    /// Clears the color and depth of this target as defined by the given clear state.
39    ///
40    pub fn clear(&self, clear_state: ClearState) -> &Self {
41        self.clear_partially(self.scissor_box(), clear_state)
42    }
43
44    ///
45    /// Clears the color and depth of the part of this target that is inside the given scissor box.
46    ///
47    pub fn clear_partially(&self, scissor_box: ScissorBox, clear_state: ClearState) -> &Self {
48        self.as_render_target()
49            .clear_partially(scissor_box, clear_state);
50        self
51    }
52
53    ///
54    /// Writes whatever rendered in the `render` closure into this target.
55    ///
56    pub fn write<E: std::error::Error>(
57        &self,
58        render: impl FnOnce() -> Result<(), E>,
59    ) -> Result<&Self, E> {
60        self.write_partially(self.scissor_box(), render)
61    }
62
63    ///
64    /// Writes whatever rendered in the `render` closure into the part of this target defined by the scissor box.
65    ///
66    pub fn write_partially<E: std::error::Error>(
67        &self,
68        scissor_box: ScissorBox,
69        render: impl FnOnce() -> Result<(), E>,
70    ) -> Result<&Self, E> {
71        self.as_render_target()
72            .write_partially(scissor_box, render)?;
73        Ok(self)
74    }
75
76    /// The width of this target.
77    pub fn width(&self) -> u32 {
78        self.color.width()
79    }
80
81    /// The height of this target.
82    pub fn height(&self) -> u32 {
83        self.color.height()
84    }
85
86    /// The number of samples for each fragment.
87    pub fn number_of_samples(&self) -> u32 {
88        self.color.number_of_samples()
89    }
90
91    pub(super) fn as_render_target(&self) -> RenderTarget<'_> {
92        RenderTarget::new(
93            ColorTarget::new_texture_2d_multisample(&self.context, &self.color),
94            DepthTarget::new_texture_2d_multisample(&self.context, &self.depth),
95        )
96    }
97
98    ///
99    /// Resolves the color of the multisample render target into the given non-multisample color target.
100    /// The target must have the same width, height and [TextureDataType] as the color part of this target.
101    ///
102    pub fn resolve_color_to(&self, target: &ColorTarget<'_>) {
103        ColorTarget::new_texture_2d_multisample(&self.context, &self.color)
104            .as_render_target()
105            .blit_to(&target.as_render_target());
106    }
107
108    ///
109    /// Resolves the depth of the multisample render target into the given non-multisample depth target.
110    /// The target must have the same width, height and [DepthTextureDataType] as the depth part of this target.
111    ///
112    pub fn resolve_depth_to(&self, target: &DepthTarget<'_>) {
113        DepthTarget::new_texture_2d_multisample(&self.context, &self.depth)
114            .as_render_target()
115            .blit_to(&target.as_render_target());
116    }
117
118    ///
119    /// Resolves the multisample render target into the given non-multisample render target.
120    /// The target must have the same width, height, [TextureDataType] and [DepthTextureDataType] as this target.
121    /// If the given render target is the screen render target, it must be non-multisampled or have the same number of samples as this target.
122    ///
123    pub fn resolve_to(&self, target: &RenderTarget<'_>) {
124        self.as_render_target().blit_to(target);
125    }
126
127    ///
128    /// Resolves the color of the multisample render target to a default non-multisample [Texture2D].
129    /// Use [RenderTargetMultisample::resolve_color_to] to resolve to a custom non-multisample texture.
130    ///
131    pub fn resolve_color(&self) -> Texture2D {
132        let mut color_texture = Texture2D::new_empty::<C>(
133            &self.context,
134            self.color.width(),
135            self.color.height(),
136            Interpolation::Linear,
137            Interpolation::Linear,
138            None,
139            Wrapping::ClampToEdge,
140            Wrapping::ClampToEdge,
141        );
142        self.resolve_color_to(&color_texture.as_color_target(None));
143        color_texture
144    }
145
146    ///
147    /// Resolves the depth of the multisample render target to a default non-multisample [DepthTexture2D].
148    /// Use [RenderTargetMultisample::resolve_depth_to] to resolve to a custom non-multisample texture.
149    ///
150    pub fn resolve_depth(&self) -> DepthTexture2D {
151        let mut depth_texture = DepthTexture2D::new::<D>(
152            &self.context,
153            self.width(),
154            self.height(),
155            Wrapping::ClampToEdge,
156            Wrapping::ClampToEdge,
157        );
158        self.resolve_depth_to(&depth_texture.as_depth_target());
159        depth_texture
160    }
161
162    ///
163    /// Resolves the multisample render target to default non-multisample [Texture2D] and [DepthTexture2D].
164    /// Use [RenderTargetMultisample::resolve_to] to resolve to custom non-multisample textures.
165    ///
166    pub fn resolve(&self) -> (Texture2D, DepthTexture2D) {
167        let mut color_texture = Texture2D::new_empty::<C>(
168            &self.context,
169            self.color.width(),
170            self.color.height(),
171            Interpolation::Linear,
172            Interpolation::Linear,
173            None,
174            Wrapping::ClampToEdge,
175            Wrapping::ClampToEdge,
176        );
177        let mut depth_texture = DepthTexture2D::new::<D>(
178            &self.context,
179            self.width(),
180            self.height(),
181            Wrapping::ClampToEdge,
182            Wrapping::ClampToEdge,
183        );
184        self.resolve_to(&RenderTarget::new(
185            color_texture.as_color_target(None),
186            depth_texture.as_depth_target(),
187        ));
188        (color_texture, depth_texture)
189    }
190}