luminance_gl/gl33/
buffer.rs

1//! OpenGL buffer implementation.
2
3use crate::gl33::{
4  state::{Bind, GLState},
5  GL33,
6};
7use gl;
8use gl::types::*;
9use luminance::tess::TessMapError;
10use std::{
11  cell::RefCell,
12  error, fmt, mem,
13  ops::{Deref, DerefMut},
14  rc::Rc,
15  slice,
16};
17
18#[derive(Debug, Eq, PartialEq)]
19pub enum SliceBufferError {
20  /// Buffer mapping failed.
21  MapFailed,
22}
23
24impl fmt::Display for SliceBufferError {
25  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
26    match self {
27      SliceBufferError::MapFailed => f.write_str("buffer mapping failed"),
28    }
29  }
30}
31
32impl error::Error for SliceBufferError {}
33
34impl From<SliceBufferError> for TessMapError {
35  fn from(_: SliceBufferError) -> Self {
36    TessMapError::CannotMap
37  }
38}
39
40/// Wrapped OpenGL buffer.
41///
42/// Used to drop the buffer.
43#[derive(Debug)]
44struct BufferWrapper {
45  handle: GLuint,
46  state: Rc<RefCell<GLState>>,
47}
48
49impl Drop for BufferWrapper {
50  fn drop(&mut self) {
51    unsafe {
52      self.state.borrow_mut().unbind_buffer(self.handle);
53      gl::DeleteBuffers(1, &self.handle);
54    }
55  }
56}
57
58/// OpenGL buffer.
59#[derive(Debug)]
60pub struct Buffer<T> {
61  /// A cached version of the GPU buffer; emulate persistent mapping.
62  pub(crate) buf: Vec<T>,
63  gl_buf: BufferWrapper,
64}
65
66impl<T> Buffer<T> {
67  pub(crate) unsafe fn from_vec(gl33: &mut GL33, vec: Vec<T>) -> Self {
68    let mut handle: GLuint = 0;
69
70    gl::GenBuffers(1, &mut handle);
71    gl33
72      .state
73      .borrow_mut()
74      .bind_array_buffer(handle, Bind::Forced);
75
76    let len = vec.len();
77    let bytes = mem::size_of::<T>() * len;
78    gl::BufferData(
79      gl::ARRAY_BUFFER,
80      bytes as isize,
81      vec.as_ptr() as _,
82      gl::STREAM_DRAW,
83    );
84    let state = gl33.state.clone();
85    let gl_buf = BufferWrapper { handle, state };
86
87    Buffer { gl_buf, buf: vec }
88  }
89
90  pub(crate) fn handle(&self) -> GLuint {
91    self.gl_buf.handle
92  }
93
94  /// Length of the buffer (number of elements).
95  #[inline]
96  pub fn len(&self) -> usize {
97    self.buf.len()
98  }
99
100  pub(crate) fn slice_buffer(&self) -> Result<BufferSlice<T>, SliceBufferError> {
101    unsafe {
102      self
103        .gl_buf
104        .state
105        .borrow_mut()
106        .bind_array_buffer(self.handle(), Bind::Cached);
107    }
108
109    mapping_buffer(gl::ARRAY_BUFFER, gl::READ_ONLY, |ptr| {
110      let handle = self.handle();
111      let state = &self.gl_buf.state;
112      let raw = BufferSliceWrapper { handle, state };
113      let len = self.buf.len();
114
115      BufferSlice { raw, len, ptr }
116    })
117  }
118
119  pub(crate) fn slice_buffer_mut(&mut self) -> Result<BufferSliceMut<T>, SliceBufferError> {
120    unsafe {
121      self
122        .gl_buf
123        .state
124        .borrow_mut()
125        .bind_array_buffer(self.handle(), Bind::Cached);
126    }
127
128    mapping_buffer(gl::ARRAY_BUFFER, gl::READ_WRITE, move |ptr| {
129      let handle = self.handle();
130      let state = &self.gl_buf.state;
131      let raw = BufferSliceWrapper { handle, state };
132      let len = self.buf.len();
133
134      BufferSliceMut { raw, len, ptr }
135    })
136  }
137}
138
139/// Wrapper to drop buffer slices.
140struct BufferSliceWrapper<'a> {
141  handle: GLuint,
142  // we use a &'a to the state to prevent cloning it when creating a buffer slice and keep the lifetime around
143  state: &'a Rc<RefCell<GLState>>,
144}
145
146impl Drop for BufferSliceWrapper<'_> {
147  fn drop(&mut self) {
148    unsafe {
149      self
150        .state
151        .borrow_mut()
152        .bind_array_buffer(self.handle, Bind::Cached);
153
154      gl::UnmapBuffer(gl::ARRAY_BUFFER);
155    }
156  }
157}
158
159pub struct BufferSlice<'a, T> {
160  raw: BufferSliceWrapper<'a>,
161  len: usize,
162  ptr: *const T,
163}
164
165impl<T> Deref for BufferSlice<'_, T> {
166  type Target = [T];
167
168  fn deref(&self) -> &Self::Target {
169    unsafe { slice::from_raw_parts(self.ptr, self.len) }
170  }
171}
172
173impl<'a> BufferSlice<'a, u8> {
174  /// Transmute to another type.
175  ///
176  /// This method is highly unsafe and should only be used when certain the target type is the
177  /// one actually represented by the raw bytes.
178  pub(crate) unsafe fn transmute<T>(self) -> BufferSlice<'a, T> {
179    let len = self.len / mem::size_of::<T>();
180    let ptr = self.ptr as _;
181
182    BufferSlice {
183      raw: self.raw,
184      len,
185      ptr,
186    }
187  }
188}
189
190pub struct BufferSliceMut<'a, T> {
191  raw: BufferSliceWrapper<'a>,
192  len: usize,
193  ptr: *mut T,
194}
195
196impl<T> Deref for BufferSliceMut<'_, T> {
197  type Target = [T];
198
199  fn deref(&self) -> &Self::Target {
200    unsafe { slice::from_raw_parts(self.ptr as *const _, self.len) }
201  }
202}
203
204impl<T> DerefMut for BufferSliceMut<'_, T> {
205  fn deref_mut(&mut self) -> &mut Self::Target {
206    unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
207  }
208}
209
210impl<'a> BufferSliceMut<'a, u8> {
211  /// Transmute to another type.
212  ///
213  /// This method is highly unsafe and should only be used when certain the target type is the
214  /// one actually represented by the raw bytes.
215  pub(crate) unsafe fn transmute<T>(self) -> BufferSliceMut<'a, T> {
216    let len = self.len / mem::size_of::<T>();
217    let ptr = self.ptr as _;
218
219    BufferSliceMut {
220      raw: self.raw,
221      len,
222      ptr,
223    }
224  }
225}
226
227/// Map a buffer and execute an action if correctly mapped; otherwise, return an error.
228fn mapping_buffer<A, T>(
229  target: GLenum,
230  access: GLenum,
231  f: impl FnOnce(*mut T) -> A,
232) -> Result<A, SliceBufferError> {
233  let ptr = unsafe { gl::MapBuffer(target, access) } as *mut T;
234
235  if ptr.is_null() {
236    Err(SliceBufferError::MapFailed)
237  } else {
238    Ok(f(ptr))
239  }
240}