glium/buffer/mod.rs
1//! A buffer is a memory location accessible to the video card.
2//!
3//! The purpose of buffers is to serve as a space where the GPU can read from or write data to.
4//! It can contain a list of vertices, indices, uniform data, etc.
5//!
6//! # Buffers management in glium
7//!
8//! There are three levels of abstraction in glium:
9//!
10//! - An `Alloc` corresponds to an OpenGL buffer object and is unsafe to use.
11//! This type is not public.
12//! - A `Buffer` wraps around an `Alloc` and provides safety by handling the data type and fences.
13//! - The `VertexBuffer`, `IndexBuffer`, `UniformBuffer`, `PixelBuffer`, etc. types are
14//! abstractions over a `Buffer` indicating their specific purpose. They implement `Deref`
15//! for the `Buffer`. These types are in the `vertex`, `index`, etc. modules.
16//!
17//! # Unsized types
18//!
19//! In order to put some data in a buffer, it must implement the `Content` trait. This trait is
20//! automatically implemented on all `Sized` types and on slices (like `[u8]`). This means that
21//! you can create a `Buffer<Foo>` (if `Foo` is sized) or a `Buffer<[u8]>` for example without
22//! worrying about it.
23//!
24//! However unsized structs don't automatically implement this trait and you must call the
25//! `implement_buffer_content!` macro on them. You must then use the `empty_unsized` constructor.
26//!
27//! ```no_run
28//! # use glium::implement_buffer_content;
29//! # use glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
30//! # fn example<T>(display: glium::Display<T>) where T: SurfaceTypeTrait + ResizeableSurface {
31//! # use std::mem;
32//! # use glium::buffer::{BufferType, BufferMode};
33//! struct Data {
34//! data: [f32], // `[f32]` is unsized, therefore `Data` is unsized too
35//! }
36//!
37//! implement_buffer_content!(Data); // without this, you can't put `Data` in a glium buffer
38//!
39//! // creates a buffer of 64 bytes, which thus holds 8 f32s
40//! let mut buffer = glium::buffer::Buffer::<Data>::empty_unsized(&display, BufferType::UniformBuffer,
41//! 64, BufferMode::Default).unwrap();
42//!
43//! // you can then write to it like you normally would
44//! buffer.map().data[4] = 2.1;
45//! # }
46//! ```
47//!
48pub use self::view::{Buffer, BufferAny, BufferMutSlice};
49pub use self::view::{BufferSlice, BufferAnySlice};
50pub use self::alloc::{Mapping, WriteMapping, ReadMapping, ReadError, CopyError};
51pub use self::alloc::{is_buffer_read_supported};
52pub use self::fences::Inserter;
53
54/// DEPRECATED. Only here for backwards compatibility.
55#[deprecated(note = "Only here for backwards compatibility")]
56pub use self::view::Buffer as BufferView;
57/// DEPRECATED. Only here for backwards compatibility.
58#[deprecated(note = "Only here for backwards compatibility")]
59pub use self::view::BufferSlice as BufferViewSlice;
60/// DEPRECATED. Only here for backwards compatibility.
61#[deprecated(note = "Only here for backwards compatibility")]
62pub use self::view::BufferMutSlice as BufferViewMutSlice;
63/// DEPRECATED. Only here for backwards compatibility.
64#[deprecated(note = "Only here for backwards compatibility")]
65pub use self::view::BufferAny as BufferViewAny;
66/// DEPRECATED. Only here for backwards compatibility.
67#[deprecated(note = "Only here for backwards compatibility")]
68pub use self::view::BufferAnySlice as BufferViewAnySlice;
69
70use crate::gl;
71use std::error::Error;
72use std::fmt;
73use std::mem;
74use std::slice;
75
76mod alloc;
77mod fences;
78mod view;
79
80/// Trait for types of data that can be put inside buffers.
81pub unsafe trait Content {
82 /// A type that holds a sized version of the content.
83 type Owned;
84
85 /// Prepares an output buffer, then turns this buffer into an `Owned`.
86 /// User-provided closure `F` must only write to and not read from `&mut Self`.
87 unsafe fn read<F, E>(size: usize, _: F) -> Result<Self::Owned, E>
88 where F: FnOnce(&mut Self) -> Result<(), E>;
89
90 /// Returns the size of each element.
91 fn get_elements_size() -> usize;
92
93 /// Produces a pointer to the data.
94 fn to_void_ptr(&self) -> *const ();
95
96 /// Builds a pointer to this type from a raw pointer.
97 fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut Self>;
98
99 /// Returns true if the size is suitable to store a type like this.
100 fn is_size_suitable(_: usize) -> bool;
101}
102
103unsafe impl<T> Content for T where T: Copy {
104 type Owned = T;
105
106 #[inline]
107 unsafe fn read<F, E>(size: usize, f: F) -> Result<T, E> where F: FnOnce(&mut T) -> Result<(), E> {
108 assert!(size == mem::size_of::<T>());
109 // Note(Lokathor): This is brittle and dangerous if `T` isn't a type
110 // that can be zeroed. However, it's a breaking change to adjust the API
111 // here (eg: extra trait bound or something) so someone with more
112 // authority than me needs to look at and fix this.
113 let mut value = mem::zeroed();
114 f(&mut value)?;
115 Ok(value)
116 }
117
118 #[inline]
119 fn get_elements_size() -> usize {
120 mem::size_of::<T>()
121 }
122
123 #[inline]
124 fn to_void_ptr(&self) -> *const () {
125 self as *const T as *const ()
126 }
127
128 #[inline]
129 fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut T> {
130 if size != mem::size_of::<T>() {
131 return None;
132 }
133
134 Some(ptr as *mut T)
135 }
136
137 #[inline]
138 fn is_size_suitable(size: usize) -> bool {
139 size == mem::size_of::<T>()
140 }
141}
142
143unsafe impl<T> Content for [T] where T: Copy {
144 type Owned = Vec<T>;
145
146 #[inline]
147 unsafe fn read<F, E>(size: usize, f: F) -> Result<Vec<T>, E>
148 where F: FnOnce(&mut [T]) -> Result<(), E>
149 {
150 assert!(size % mem::size_of::<T>() == 0);
151 let len = size / mem::size_of::<T>();
152 let mut value = Vec::with_capacity(len);
153 value.set_len(len);
154 f(&mut value)?;
155 Ok(value)
156 }
157
158 #[inline]
159 fn get_elements_size() -> usize {
160 mem::size_of::<T>()
161 }
162
163 #[inline]
164 fn to_void_ptr(&self) -> *const () {
165 &self[0] as *const T as *const ()
166 }
167
168 #[inline]
169 fn ref_from_ptr<'a>(ptr: *mut (), size: usize) -> Option<*mut [T]> {
170 if size % mem::size_of::<T>() != 0 {
171 return None;
172 }
173
174 let ptr = ptr as *mut T;
175 let size = size / mem::size_of::<T>();
176 Some(unsafe { slice::from_raw_parts_mut(&mut *ptr, size) as *mut [T] })
177 }
178
179 #[inline]
180 fn is_size_suitable(size: usize) -> bool {
181 size % mem::size_of::<T>() == 0
182 }
183}
184
185/// Error that can happen when creating a buffer.
186#[derive(Debug, Copy, Clone)]
187pub enum BufferCreationError {
188 /// Not enough memory to create the buffer.
189 OutOfMemory,
190
191 /// This type of buffer is not supported.
192 BufferTypeNotSupported,
193}
194
195impl fmt::Display for BufferCreationError {
196 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
197 let desc = match self {
198 BufferCreationError::OutOfMemory => "Not enough memory to create the buffer",
199 BufferCreationError::BufferTypeNotSupported => "This type of buffer is not supported",
200 };
201 fmt.write_str(desc)
202 }
203}
204
205impl Error for BufferCreationError {}
206
207/// How the buffer is created.
208#[derive(Debug, Copy, Clone, PartialEq, Eq)]
209pub enum BufferMode {
210 /// This is the default mode suitable for any usage. Will never be slow, will never be fast
211 /// either.
212 ///
213 /// Other modes should always be preferred, but you can use this one if you don't know what
214 /// will happen to the buffer.
215 ///
216 /// # Implementation
217 ///
218 /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` flag.
219 ///
220 /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
221 ///
222 Default,
223
224 /// The mode to use when you modify a buffer multiple times per frame. Similar to `Default` in
225 /// that it is suitable for most usages.
226 ///
227 /// Use this if you do a quick succession of modify the buffer, draw, modify, draw, etc. This
228 /// is something that you shouldn't do by the way.
229 ///
230 /// With this mode, the OpenGL driver automatically manages the buffer for us. It will try to
231 /// find the most appropriate storage depending on how we use it. It is guaranteed to never be
232 /// too slow, but it won't be too fast either.
233 ///
234 /// # Implementation
235 ///
236 /// Tries to use `glBufferStorage` with the `GL_DYNAMIC_STORAGE_BIT` and
237 /// `GL_CLIENT_STORAGE_BIT` flags.
238 ///
239 /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
240 ///
241 Dynamic,
242
243 /// Optimized for when you modify a buffer exactly once per frame. You can modify it more than
244 /// once per frame, but if you modify it too often things will slow down.
245 ///
246 /// With this mode, glium automatically handles synchronization to prevent the buffer from
247 /// being access by both the GPU and the CPU simultaneously. If you try to modify the buffer,
248 /// the execution will block until the GPU has finished using it. For this reason, a quick
249 /// succession of modifying and drawing using the same buffer will be very slow.
250 ///
251 /// When using persistent mapping, it is recommended to use triple buffering. This is done by
252 /// creating a buffer that has three times the capacity that it would normally have. You modify
253 /// and draw the first third, then modify and draw the second third, then the last part, then
254 /// go back to the first third, etc.
255 ///
256 /// # Implementation
257 ///
258 /// Tries to use `glBufferStorage` with `GL_MAP_PERSISTENT_BIT`. Sync fences are automatically
259 /// managed by glium.
260 ///
261 /// If this function is not available, falls back to `glBufferData` with `GL_DYNAMIC_DRAW`.
262 ///
263 Persistent,
264
265 /// Optimized when you will never touch the content of the buffer.
266 ///
267 /// Immutable buffers should be created once and never touched again. Modifying their content
268 /// is permitted, but is very slow.
269 ///
270 /// # Implementation
271 ///
272 /// Tries to use `glBufferStorage` without any flag. Modifications are done by creating
273 /// temporary buffers and making the GPU copy the data from the temporary buffer to the real
274 /// one.
275 ///
276 /// If this function is not available, falls back to `glBufferData` with `GL_STATIC_DRAW`.
277 ///
278 Immutable,
279}
280
281impl Default for BufferMode {
282 fn default() -> BufferMode {
283 BufferMode::Default
284 }
285}
286
287/// Type of a buffer.
288#[derive(Debug, Copy, Clone, PartialEq, Eq)]
289#[allow(missing_docs)]
290pub enum BufferType {
291 ArrayBuffer,
292 PixelPackBuffer,
293 PixelUnpackBuffer,
294 UniformBuffer,
295 CopyReadBuffer,
296 CopyWriteBuffer,
297 AtomicCounterBuffer,
298 DispatchIndirectBuffer,
299 DrawIndirectBuffer,
300 QueryBuffer,
301 ShaderStorageBuffer,
302 TextureBuffer,
303 TransformFeedbackBuffer,
304 ElementArrayBuffer,
305}
306
307impl BufferType {
308 fn to_glenum(&self) -> gl::types::GLenum {
309 match *self {
310 BufferType::ArrayBuffer => gl::ARRAY_BUFFER,
311 BufferType::PixelPackBuffer => gl::PIXEL_PACK_BUFFER,
312 BufferType::PixelUnpackBuffer => gl::PIXEL_UNPACK_BUFFER,
313 BufferType::UniformBuffer => gl::UNIFORM_BUFFER,
314 BufferType::CopyReadBuffer => gl::COPY_READ_BUFFER,
315 BufferType::CopyWriteBuffer => gl::COPY_WRITE_BUFFER,
316 BufferType::AtomicCounterBuffer => gl::ATOMIC_COUNTER_BUFFER,
317 BufferType::DispatchIndirectBuffer => gl::DISPATCH_INDIRECT_BUFFER,
318 BufferType::DrawIndirectBuffer => gl::DRAW_INDIRECT_BUFFER,
319 BufferType::QueryBuffer => gl::QUERY_BUFFER,
320 BufferType::ShaderStorageBuffer => gl::SHADER_STORAGE_BUFFER,
321 BufferType::TextureBuffer => gl::TEXTURE_BUFFER,
322 BufferType::TransformFeedbackBuffer => gl::TRANSFORM_FEEDBACK_BUFFER,
323 BufferType::ElementArrayBuffer => gl::ELEMENT_ARRAY_BUFFER,
324 }
325 }
326}