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}