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>);