fyrox_graphics/
framebuffer.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21#![warn(missing_docs)]
22
23//! Frame buffer is a set of images that is used as a storage for an image generated by a renderer.
24//! It consists of one or more color buffers and an optional depth/stencil buffer. See [`GpuFrameBufferTrait`]
25//! docs for more info.
26
27use crate::{
28    buffer::GpuBuffer,
29    core::{color::Color, math::Rect, Downcast},
30    define_shared_wrapper,
31    error::FrameworkError,
32    geometry_buffer::GpuGeometryBuffer,
33    gpu_program::GpuProgram,
34    gpu_texture::{CubeMapFace, GpuTexture},
35    DrawParameters, ElementRange,
36};
37
38/// Frame buffer attachment kind.
39#[derive(Copy, Clone, PartialOrd, PartialEq, Hash, Debug, Eq)]
40pub enum AttachmentKind {
41    /// Color attachment, it should have a format that supports rendering (for example it cannot be
42    /// a compressed texture format).
43    Color,
44    /// Combined depth + stencil (usually it is 24 bits for depth and 8 for stencil) attachment.
45    DepthStencil,
46    /// Depth-only attachment. Usually it is 16 or 32 bits texture.
47    Depth,
48}
49
50/// Frame buffer attachment.
51pub struct Attachment {
52    /// Current kind of attachment. Tells the renderer how the texture should be used.
53    pub kind: AttachmentKind,
54    /// A texture that is used to write the rendered image to.
55    pub texture: GpuTexture,
56}
57
58impl Attachment {
59    /// Creates a new [`AttachmentKind::Color`] attachment with the given texture.
60    pub fn color(texture: GpuTexture) -> Self {
61        Self {
62            kind: AttachmentKind::Color,
63            texture,
64        }
65    }
66
67    /// Creates a new [`AttachmentKind::Depth`] attachment with the given texture.
68    pub fn depth(texture: GpuTexture) -> Self {
69        Self {
70            kind: AttachmentKind::Depth,
71            texture,
72        }
73    }
74
75    /// Creates a new [`AttachmentKind::DepthStencil`] attachment with the given texture.
76    pub fn depth_stencil(texture: GpuTexture) -> Self {
77        Self {
78            kind: AttachmentKind::DepthStencil,
79            texture,
80        }
81    }
82}
83
84/// Defines a range of data in a particular buffer.
85#[derive(Default)]
86pub enum BufferDataUsage {
87    /// Use everything at once.
88    #[default]
89    UseEverything,
90    /// Use just a segment of data starting from the given `offset` with `size` bytes. It is used
91    /// in cases where you have a large buffer with lots of small blocks of information about
92    /// different objects. Instead of having a number of small buffers (which is memory- and performance
93    /// inefficient), you put everything into a large buffer and fill it lots of info at once and then
94    /// binding segments of the data the to the pipeline.
95    UseSegment {
96        /// Offset from the beginning of the buffer in bytes.
97        offset: usize,
98        /// Size of the data block in bytes.
99        size: usize,
100    },
101}
102
103/// A resource binding defines where to bind specific GPU resources.
104pub enum ResourceBinding {
105    /// Texture binding.
106    Texture {
107        /// A shared reference to a texture.
108        texture: GpuTexture,
109        /// Binding mode for the texture.
110        binding: usize,
111    },
112    /// Generic data buffer binding.
113    Buffer {
114        /// A shared reference to a buffer.
115        buffer: GpuBuffer,
116        /// Binding mode for the buffer.
117        binding: usize,
118        /// Data portion to use.
119        data_usage: BufferDataUsage,
120    },
121}
122
123impl ResourceBinding {
124    /// Creates a new explicit texture binding.
125    pub fn texture(texture: &GpuTexture, binding: usize) -> Self {
126        Self::Texture {
127            texture: texture.clone(),
128            binding,
129        }
130    }
131
132    /// Creates a new explicit buffer binding.
133    pub fn buffer(buffer: &GpuBuffer, binding: usize, data_usage: BufferDataUsage) -> Self {
134        Self::Buffer {
135            buffer: buffer.clone(),
136            binding,
137            data_usage,
138        }
139    }
140}
141
142/// Resource binding group defines a set of bindings.
143pub struct ResourceBindGroup<'a> {
144    /// A reference to resource bindings array.
145    pub bindings: &'a [ResourceBinding],
146}
147
148/// Statistics for a single GPU draw call.
149#[derive(Debug, Copy, Clone, Default)]
150#[must_use]
151pub struct DrawCallStatistics {
152    /// Total number of rendered triangles.
153    pub triangles: usize,
154}
155
156/// Frame buffer is a set of images that is used as a storage for an image generated by a renderer.
157/// It consists of one or more color buffers and an optional depth/stencil buffer. Frame buffer is
158/// a high level abstraction that consolidates multiple images and supports drawing meshes to them
159/// with various drawing options.
160pub trait GpuFrameBufferTrait: Downcast {
161    /// Returns a list of color attachments.
162    fn color_attachments(&self) -> &[Attachment];
163
164    /// Returns an optional depth/stencil attachment.
165    fn depth_attachment(&self) -> Option<&Attachment>;
166
167    /// Sets an active face of a cube map (only for frame buffers that using cube maps for rendering).
168    fn set_cubemap_face(&self, attachment_index: usize, face: CubeMapFace);
169
170    /// Performs data transfer from one frame buffer to another with scaling. It copies a region
171    /// defined by `src_x0`, `src_y0`, `src_x1`, `src_y1` coordinates from the frame buffer and
172    /// "pastes" it to the other frame buffer into a region defined by `dst_x0`, `dst_y0`, `dst_x1`,
173    /// `dst_y1` coordinates. If the source rectangle does not match the destination, the image will
174    /// be interpolated using nearest interpolation.
175    ///
176    /// This method can copy only specific parts of the image: `copy_color` tells the method to copy
177    /// the data from
178    fn blit_to(
179        &self,
180        dest: &GpuFrameBuffer,
181        src_x0: i32,
182        src_y0: i32,
183        src_x1: i32,
184        src_y1: i32,
185        dst_x0: i32,
186        dst_y0: i32,
187        dst_x1: i32,
188        dst_y1: i32,
189        copy_color: bool,
190        copy_depth: bool,
191        copy_stencil: bool,
192    );
193
194    /// Clears the frame buffer in the given viewport with the given set of optional values. This
195    /// method clears multiple attachments at once. What will be cleared defined by the provided
196    /// values. If `color` is not [`None`], then all the color attachments will be cleared with the
197    /// given color. The same applies to depth and stencil buffers.
198    fn clear(
199        &self,
200        viewport: Rect<i32>,
201        color: Option<Color>,
202        depth: Option<f32>,
203        stencil: Option<i32>,
204    );
205
206    /// Draws the specified geometry buffer using the given GPU program and a set of resources. This
207    /// method the main method to draw anything.
208    ///
209    /// `geometry` - defines a [`GpuGeometryBuffer`], that contains vertices and index buffers and
210    /// essentially defines a mesh to render.
211    /// `viewport` - defines an area on screen that will be used to draw.
212    /// `program` - a [`GpuProgram`] defines a set of shaders (usually a pair of vertex + fragment)
213    /// that will define how the mesh will be rendered.
214    /// `params` - [`DrawParameters`] defines the state of graphics pipeline and essentially sets
215    /// a bunch of various parameters (such as backface culling, blending mode, various tests, etc.)
216    /// that will define how the rendering process is performed.
217    /// `resources` - a set of resource bind groups, that in their turn provides a set of resources
218    /// that bound to specific binding points.
219    /// `element_range` - defines which range of elements to draw.
220    fn draw(
221        &self,
222        geometry: &GpuGeometryBuffer,
223        viewport: Rect<i32>,
224        program: &GpuProgram,
225        params: &DrawParameters,
226        resources: &[ResourceBindGroup],
227        element_range: ElementRange,
228    ) -> Result<DrawCallStatistics, FrameworkError>;
229
230    /// Almost the same as [`Self::draw`], but draws multiple instances at once. The caller must
231    /// supply all the required data per each instance, it could be done in different ways. The data
232    /// could be supplied in vertex attributes, uniform buffers, textures, etc.
233    fn draw_instances(
234        &self,
235        instance_count: usize,
236        geometry: &GpuGeometryBuffer,
237        viewport: Rect<i32>,
238        program: &GpuProgram,
239        params: &DrawParameters,
240        resources: &[ResourceBindGroup],
241        element_range: ElementRange,
242    ) -> Result<DrawCallStatistics, FrameworkError>;
243}
244
245define_shared_wrapper!(GpuFrameBuffer<dyn GpuFrameBufferTrait>);