fyrox_graphics/buffer.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//! Buffer is a type-agnostic data storage located directly in GPU memory. It could be considered
22//! as a data block which content is a pile of bytes, whose meaning is defined externally.
23
24use crate::define_shared_wrapper;
25use crate::error::FrameworkError;
26use bytemuck::Pod;
27use fyrox_core::{array_as_u8_slice, array_as_u8_slice_mut, define_as_any_trait};
28
29/// Specifications for a buffer that are passed to [`crate::server::GraphicsServer::create_buffer`] so that the server
30/// knows what buffer to create.
31pub struct GpuBufferDescriptor<'a> {
32 /// A label for the buffer for debugging, as might be passed to `glObjectLabel` in an OpenGL server.
33 pub name: &'a str,
34 /// The size of the buffer in bytes, as might be passed to `glBufferData` in an OpenGL server.
35 pub size: usize,
36 /// What is stored in the buffer? Vertices, indices, uniforms, pixels, etc.
37 pub kind: BufferKind,
38 /// An efficiency hint for how the buffer will be used.
39 pub usage: BufferUsage,
40}
41
42/// GPU buffer kind, as used in [`GpuBufferDescriptor`].
43#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
44pub enum BufferKind {
45 /// Vertex buffer. It is used to supply vertex data (such as positions, normals, texture
46 /// coordinates, etc.) to GPU.
47 Vertex,
48 /// Index buffer. It is used to describe how vertices forms specific types of primitives.
49 /// For example a quad could be described by a set of 4 vertices, but 2 triangles which in their
50 /// turn consists of 6 indices (0,1,2,0,2,3 vertex indices).
51 Index,
52 /// Uniform buffer. It is used to supply context-specific data that is needed for rendering.
53 /// Usually it contains data that changes from frame-to-frame (world transform, color, etc.).
54 Uniform,
55 /// Pixel read buffer. It is a special buffer that is used to asynchronously read-back data
56 /// from GPU.
57 PixelRead,
58 /// Pixel write buffer. It is a special buffer that is used to write some data to GPU
59 /// asynchronously.
60 PixelWrite,
61}
62
63/// A hint for video driver that allows it to optimize buffer's content for more efficient use.
64#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
65pub enum BufferUsage {
66 /// The buffer contents will be modified once and used at most a few times.
67 /// The buffer contents are modified by the application, and used as the source for
68 /// drawing and image specification commands.
69 StreamDraw,
70 /// The buffer contents will be modified once and used at most a few times.
71 /// The buffer contents are modified by reading data from the GPU, and used to return that
72 /// data when queried by the application.
73 StreamRead,
74 /// The buffer contents will be modified once and used at most a few times.
75 /// The buffer contents are modified by the application, and used as the source for
76 /// drawing and image specification commands.
77 StreamCopy,
78 /// The buffer contents will be modified once and used many times.
79 /// The buffer contents are modified by the application, and used as the source for
80 /// drawing and image specification commands.
81 StaticDraw,
82 /// The buffer contents will be modified once and used many times.
83 /// The buffer contents are modified by reading data from the GPU, and used to return that
84 /// data when queried by the application.
85 StaticRead,
86 /// The buffer contents will be modified once and used many times.
87 /// The buffer contents are modified by reading data from the GPU, and used as the source for
88 /// drawing and image specification commands.
89 StaticCopy,
90 /// The buffer contents will be modified repeatedly and used many times.
91 /// The buffer contents are modified by the application, and used as the source for
92 /// drawing and image specification commands.
93 DynamicDraw,
94 /// The buffer contents will be modified repeatedly and used many times.
95 /// The buffer contents are modified by reading data from the GPU, and used to return that
96 /// data when queried by the application.
97 DynamicRead,
98 /// The buffer contents will be modified repeatedly and used many times.
99 /// The buffer contents are modified by reading data from the GPU, and used as the source for
100 /// drawing and image specification commands.
101 DynamicCopy,
102}
103
104define_as_any_trait!(GpuBufferAsAny => GpuBufferTrait);
105
106/// Buffer is a type-agnostic data storage located directly in GPU memory. It could be considered
107/// as a data block which content is a pile of bytes, whose meaning is defined externally.
108///
109/// ## Example
110///
111/// The following example shows how to create a uniform buffer, that could be used for rendering
112/// a static object.
113///
114/// ```rust
115/// use fyrox_graphics::{
116/// buffer::{GpuBuffer, BufferKind, BufferUsage},
117/// core::{algebra::Vector3, color::Color},
118/// error::FrameworkError,
119/// server::GraphicsServer,
120/// uniform::DynamicUniformBuffer,
121/// };///
122///
123/// use fyrox_graphics::buffer::GpuBufferDescriptor;
124///
125/// fn create_buffer(server: &dyn GraphicsServer) -> Result<GpuBuffer, FrameworkError> {
126/// let uniforms = DynamicUniformBuffer::new()
127/// .with(&Vector3::new(1.0, 2.0, 3.0))
128/// .with(&Color::WHITE)
129/// .with(&123.0f32)
130/// .finish();
131///
132/// let buffer = server.create_buffer(GpuBufferDescriptor{
133/// name: "MyBuffer",
134/// size: uniforms.len(),
135/// kind: BufferKind::Uniform,
136/// usage: BufferUsage::StaticDraw
137/// })?;
138///
139/// buffer.write_data(&uniforms)?;
140///
141/// Ok(buffer)
142/// }
143/// ```
144pub trait GpuBufferTrait: GpuBufferAsAny {
145 /// Returns usage kind of the buffer.
146 fn usage(&self) -> BufferUsage;
147 /// Returns buffer kind.
148 fn kind(&self) -> BufferKind;
149 /// Returns total size of the buffer in bytes.
150 fn size(&self) -> usize;
151 /// Writes an arbitrary number of bytes from the given slice.
152 fn write_data(&self, data: &[u8]) -> Result<(), FrameworkError>;
153 /// Read an arbitrary number of bytes from the buffer (GPU memory) to the given slice. The
154 /// amount of the data that will be attempted to read is defined by the length of the given
155 /// slice.
156 fn read_data(&self, data: &mut [u8]) -> Result<(), FrameworkError>;
157}
158
159impl dyn GpuBufferTrait {
160 /// Tries to write typed data to the buffer. The data type must implement [`Pod`] trait for
161 /// safe usage.
162 pub fn write_data_of_type<T: Pod>(&self, data: &[T]) -> Result<(), FrameworkError> {
163 let data = array_as_u8_slice(data);
164 GpuBufferTrait::write_data(self, data)
165 }
166
167 /// Tries to read data from the buffer and convert them to the given type. The data type must
168 /// implement [`Pod`] trait for safe usage. The amount of the data that will be attempted to
169 /// read is defined by the length of the given slice.
170 pub fn read_data_of_type<T: Pod>(&self, data: &mut [T]) -> Result<(), FrameworkError> {
171 let data = array_as_u8_slice_mut(data);
172 GpuBufferTrait::read_data(self, data)
173 }
174}
175
176define_shared_wrapper!(GpuBuffer<dyn GpuBufferTrait>);