globject_rs/
glbuffer.rs

1
2use crate::prelude::*;
3use std::{
4	cmp::min,
5	ffi::c_void,
6	fmt::{self, Debug, Formatter},
7	mem::size_of,
8	rc::Rc,
9};
10
11/// The OpenGL buffer binding targets
12#[derive(Clone, Copy, PartialEq)]
13pub enum BufferTarget {
14	ArrayBuffer = GL_ARRAY_BUFFER as isize,
15	AtomicCounterBuffer = GL_ATOMIC_COUNTER_BUFFER as isize,
16	CopyReadBuffer = GL_COPY_READ_BUFFER as isize,
17	CopyWriteBuffer = GL_COPY_WRITE_BUFFER as isize,
18	DispatchIndirectBuffer = GL_DISPATCH_INDIRECT_BUFFER as isize,
19	DrawIndirectBuffer = GL_DRAW_INDIRECT_BUFFER as isize,
20	ElementArrayBuffer = GL_ELEMENT_ARRAY_BUFFER as isize,
21	PixelPackBuffer = GL_PIXEL_PACK_BUFFER as isize,
22	PixelUnpackBuffer = GL_PIXEL_UNPACK_BUFFER as isize,
23	QueryBuffer = GL_QUERY_BUFFER as isize,
24	ShaderStorageBuffer = GL_SHADER_STORAGE_BUFFER as isize,
25	TextureBuffer = GL_TEXTURE_BUFFER as isize,
26	TransformFeedbackBuffer = GL_TRANSFORM_FEEDBACK_BUFFER as isize,
27	UniformBuffer = GL_UNIFORM_BUFFER as isize,
28}
29
30/// The usage for the buffer
31#[derive(Clone, Copy, PartialEq)]
32pub enum BufferUsage {
33	StreamDraw = GL_STREAM_DRAW as isize,
34	StreamRead = GL_STREAM_READ as isize,
35	StreamCopy = GL_STREAM_COPY as isize,
36	StaticDraw = GL_STATIC_DRAW as isize,
37	StaticRead = GL_STATIC_READ as isize,
38	StaticCopy = GL_STATIC_COPY as isize,
39	DynamicDraw = GL_DYNAMIC_DRAW as isize,
40	DynamicRead = GL_DYNAMIC_READ as isize,
41	DynamicCopy = GL_DYNAMIC_COPY as isize,
42}
43
44/// The access flags for `glMapBuffers()`
45#[derive(Clone, Copy, PartialEq)]
46pub enum MapAccess {
47	ReadOnly = GL_READ_ONLY as isize,
48	WriteOnly = GL_WRITE_ONLY as isize,
49	ReadWrite = GL_READ_WRITE as isize,
50}
51
52/// The OpenGL buffer object
53pub struct Buffer {
54	pub glcore: Rc<GLCore>,
55	name: u32,
56	usage: BufferUsage,
57	target: BufferTarget,
58	size: usize,
59}
60
61/// When to use a buffer, must bind the buffer first. The RAII system could help automatically unbind the buffer.
62#[derive(Debug)]
63pub struct BufferBind<'a> {
64	pub buffer: &'a Buffer,
65	target: BufferTarget,
66}
67
68/// When to modify the buffer or retrieve the data from the buffer, use map to update the buffer.
69#[derive(Debug)]
70pub struct BufferMapping<'a> {
71	pub buffer: &'a Buffer,
72	target: BufferTarget,
73	access: MapAccess,
74	address: *mut c_void,
75}
76
77impl Buffer {
78	/// Get the internal name
79	pub fn get_name(&self) -> u32 {
80		self.name
81	}
82
83	/// # Safety
84	///
85	/// Release the OpenGL handle of the buffer object, consuming the `Buffer` struct.
86	/// You have to delete the buffer object manually.
87	pub unsafe fn to_raw(mut self) -> u32 {
88		let ret = self.name;
89		self.name = 0;
90		ret
91	}
92
93	/// # Safety
94	///
95	/// Create a `Buffer` struct from an OpenGL handle to the buffer object.
96	/// After the call, the OpenGL handle is managed by this struct.
97	/// On `drop()`, the OpenGL handle is deleted.
98	pub unsafe fn from_raw(glcore: Rc<GLCore>, name: u32, target: BufferTarget) -> Result<Self, GLCoreError> {
99		glcore.glBindBuffer(target as u32, name)?;
100		let mut size = 0;
101		let mut usage = 0;
102		glcore.glGetBufferParameteriv(target as u32, GL_BUFFER_SIZE, &mut size as *mut _)?;
103		glcore.glGetBufferParameteriv(target as u32, GL_BUFFER_USAGE, &mut usage as *mut _)?;
104		glcore.glBindBuffer(target as u32, 0)?;
105		let usage = match usage as u32 {
106			GL_STREAM_DRAW  => BufferUsage::StreamDraw,
107			GL_STREAM_READ  => BufferUsage::StreamRead,
108			GL_STREAM_COPY  => BufferUsage::StreamCopy,
109			GL_STATIC_DRAW  => BufferUsage::StaticDraw,
110			GL_STATIC_READ  => BufferUsage::StaticRead,
111			GL_STATIC_COPY  => BufferUsage::StaticCopy,
112			GL_DYNAMIC_DRAW => BufferUsage::DynamicDraw,
113			GL_DYNAMIC_READ => BufferUsage::DynamicRead,
114			GL_DYNAMIC_COPY => BufferUsage::DynamicCopy,
115			_ => panic!("Unknown buffer usage: `{usage}`"),
116		};
117		Ok(Self {
118			glcore,
119			name,
120			usage,
121			target,
122			size: size as usize,
123		})
124	}
125
126	/// Create a new OpenGL buffer with the specified size and data. The data could be `NULL`, indicating no initialization to the buffer.
127	pub fn new(glcore: Rc<GLCore>, target: BufferTarget, size: usize, usage: BufferUsage, data_ptr: *const c_void) -> Result<Self, GLCoreError> {
128		let mut name: u32 = 0;
129		glcore.glGenBuffers(1, &mut name as *mut u32)?;
130		glcore.glBindBuffer(target as u32, name)?;
131		glcore.glBufferData(target as u32, size, data_ptr, usage as u32)?;
132		glcore.glBindBuffer(target as u32, 0)?;
133		Ok(Self {
134			glcore,
135			name,
136			usage,
137			target,
138			size,
139		})
140	}
141
142	/// Get the size of the buffer in bytes
143	pub fn size(&self) -> usize {
144		self.size
145	}
146
147	/// Get the default binding target
148	pub fn get_target(&self) -> BufferTarget {
149		self.target
150	}
151
152	/// Get the usage when initializing
153	pub fn get_usage(&self) -> BufferUsage {
154		self.usage
155	}
156
157	/// Resize the buffer. Actually, this operation will reallocate the buffer and copy the data.
158	pub fn resize<T: Copy + Sized>(&mut self, new_len: usize, value: T) -> Result<(), GLCoreError> {
159		let new_len = min(self.size, new_len);
160		let data = vec![value; new_len / size_of::<T>()];
161		let mut name: u32 = 0;
162		self.glcore.glGenBuffers(1, &mut name as *mut u32)?;
163		self.glcore.glBindBuffer(BufferTarget::CopyReadBuffer as u32, self.name)?;
164		self.glcore.glBindBuffer(BufferTarget::CopyWriteBuffer as u32, name)?;
165		self.glcore.glBufferData(BufferTarget::CopyWriteBuffer as u32, new_len,
166			if new_len > self.size {
167				data.as_ptr() as *const c_void
168			} else {
169				std::ptr::null()
170			},
171			self.usage as u32)?;
172		self.glcore.glCopyBufferSubData(BufferTarget::CopyReadBuffer as u32, BufferTarget::CopyWriteBuffer as u32, 0, 0, new_len)?;
173		self.glcore.glBindBuffer(BufferTarget::CopyReadBuffer as u32, 0)?;
174		self.glcore.glBindBuffer(BufferTarget::CopyWriteBuffer as u32, 0)?;
175		self.glcore.glDeleteBuffers(1, &self.name as *const u32)?;
176		self.name = name;
177		Ok(())
178	}
179
180	/// Set the default binding target
181	pub fn set_target(&mut self, target: BufferTarget) {
182		self.target = target;
183	}
184
185	/// Create a `BufferBind` to use the RAII system to manage the binding state.
186	pub fn bind<'a>(&'a self) -> Result<BufferBind<'a>, GLCoreError> {
187		BufferBind::new(self, self.target)
188	}
189
190	/// Bind to a specific target. WILL NOT change the default target of the buffer. Create a `BufferBind` to use the RAII system to manage the binding state.
191	pub fn bind_to<'a>(&'a self, target: BufferTarget) -> Result<BufferBind<'a>, GLCoreError> {
192		BufferBind::new(self, target)
193	}
194}
195
196impl Drop for Buffer {
197	/// Delete the OpenGL buffer on `drop()` called.
198	fn drop(&mut self) {
199		if self.name != 0 {
200			self.glcore.glDeleteBuffers(1, &self.name as *const u32).unwrap();
201		}
202	}
203}
204
205impl Clone for Buffer {
206	fn clone(&self) -> Self {
207		let mut name: u32 = 0;
208		self.glcore.glGenBuffers(1, &mut name as *mut u32).unwrap();
209		self.glcore.glBindBuffer(self.target as u32, name).unwrap();
210		self.glcore.glBindBuffer(BufferTarget::CopyReadBuffer as u32, self.name).unwrap();
211		self.glcore.glBufferData(BufferTarget::CopyWriteBuffer as u32, self.size, std::ptr::null(), self.usage as u32).unwrap();
212		self.glcore.glCopyBufferSubData(BufferTarget::CopyReadBuffer as u32, self.target as u32, 0, 0, self.size).unwrap();
213		self.glcore.glBindBuffer(self.target as u32, 0).unwrap();
214		self.glcore.glBindBuffer(BufferTarget::CopyReadBuffer as u32, 0).unwrap();
215		Self {
216			glcore: self.glcore.clone(),
217			name,
218			usage: self.usage,
219			target: self.target,
220			size: self.size,
221		}
222	}
223}
224
225impl Debug for Buffer {
226	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
227		f.debug_struct("Buffer")
228		.field("name", &self.name)
229		.field("usage", &self.usage)
230		.field("target", &self.target)
231		.field("size", &self.size)
232		.finish()
233	}
234}
235
236impl<'a> BufferBind<'a> {
237	/// Bind the buffer to the target
238	fn new(buffer: &'a Buffer, target: BufferTarget) -> Result<Self, GLCoreError> {
239		buffer.glcore.glBindBuffer(target as u32, buffer.name)?;
240		Ok(Self {
241			buffer,
242			target,
243		})
244	}
245
246	/// Unbind the buffer
247	pub fn unbind(self) {} // Unbind by owning it in the function and `drop()`
248
249	/// Create a `BufferMapping` to use the RAII system to manage the mapping state.
250	pub fn map(&self, access: MapAccess) -> Result<(BufferMapping<'a>, *mut c_void), GLCoreError> {
251		BufferMapping::new(self.buffer, self.target, access)
252	}
253
254	/// Create a `BufferMapping` to use the RAII system to manage the mapping state, with partially mapped range.
255	pub fn map_ranged(&self, offset: usize, length: usize, access: MapAccess) -> Result<(BufferMapping<'a>, *mut c_void), GLCoreError> {
256		BufferMapping::new_ranged(self.buffer, self.target, offset, length, access)
257	}
258
259	/// Get the binding target
260	pub fn get_target(&self) -> BufferTarget {
261		self.target
262	}
263}
264
265impl<'a> Drop for BufferBind<'a> {
266	/// Unbind if dropped
267	fn drop(&mut self) {
268		self.buffer.glcore.glBindBuffer(self.target as u32, 0).unwrap();
269	}
270}
271
272impl<'a> BufferMapping<'a> {
273	/// Map to the buffer to modify or retrieve the data of the buffer
274	fn new(buffer: &'a Buffer, target: BufferTarget, access: MapAccess) -> Result<(Self, *mut c_void), GLCoreError> {
275		let address = buffer.glcore.glMapBuffer(target as u32, access as u32)?;
276		Ok((Self {
277			buffer,
278			target,
279			access,
280			address,
281		}, address))
282	}
283
284	/// Map to the buffer partially to modify or retrieve the data of the buffer
285	fn new_ranged(buffer: &'a Buffer, target: BufferTarget, offset: usize, length: usize, access: MapAccess) -> Result<(Self, *mut c_void), GLCoreError> {
286		let address = buffer.glcore.glMapBufferRange(target as u32, offset, length, access as u32)?;
287		Ok((Self {
288			buffer,
289			target,
290			access,
291			address,
292		}, address))
293	}
294
295	/// Unmap the buffer
296	pub fn unmap(self) {} // Unmap by owning it in the function and `drop()`
297
298	/// Get the mapped target
299	pub fn get_target(&self) -> BufferTarget {
300		self.target
301	}
302
303	/// Get the mapped access
304	pub fn get_access(&self) -> MapAccess {
305		self.access
306	}
307
308	/// Get the mapping address
309	pub fn get_mapping_address(&self) -> *mut c_void {
310		self.address
311	}
312}
313
314impl<'a> Drop for BufferMapping<'a> {
315	/// Unmap the buffer when dropped
316	fn drop(&mut self) {
317		self.buffer.glcore.glUnmapBuffer(self.target as u32).unwrap();
318	}
319}
320
321impl Debug for BufferTarget {
322	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
323		match self {
324			Self::ArrayBuffer => write!(f, "ArrayBuffer"),
325			Self::AtomicCounterBuffer => write!(f, "AtomicCounterBuffer"),
326			Self::CopyReadBuffer => write!(f, "CopyReadBuffer"),
327			Self::CopyWriteBuffer => write!(f, "CopyWriteBuffer"),
328			Self::DispatchIndirectBuffer => write!(f, "DispatchIndirectBuffer"),
329			Self::DrawIndirectBuffer => write!(f, "DrawIndirectBuffer"),
330			Self::ElementArrayBuffer => write!(f, "ElementArrayBuffer"),
331			Self::PixelPackBuffer => write!(f, "PixelPackBuffer"),
332			Self::PixelUnpackBuffer => write!(f, "PixelUnpackBuffer"),
333			Self::QueryBuffer => write!(f, "QueryBuffer"),
334			Self::ShaderStorageBuffer => write!(f, "ShaderStorageBuffer"),
335			Self::TextureBuffer => write!(f, "TextureBuffer"),
336			Self::TransformFeedbackBuffer => write!(f, "TransformFeedbackBuffer"),
337			Self::UniformBuffer => write!(f, "UniformBuffer"),
338		}
339	}
340}
341
342impl Debug for BufferUsage {
343	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
344		match self {
345			Self::StreamDraw => write!(f, "StreamDraw"),
346			Self::StreamRead => write!(f, "StreamRead"),
347			Self::StreamCopy => write!(f, "StreamCopy"),
348			Self::StaticDraw => write!(f, "StaticDraw"),
349			Self::StaticRead => write!(f, "StaticRead"),
350			Self::StaticCopy => write!(f, "StaticCopy"),
351			Self::DynamicDraw => write!(f, "DynamicDraw"),
352			Self::DynamicRead => write!(f, "DynamicRead"),
353			Self::DynamicCopy => write!(f, "DynamicCopy"),
354		}
355	}
356}
357
358impl Debug for MapAccess {
359	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
360		match self {
361			Self::ReadOnly => write!(f, "StreamDraw"),
362			Self::WriteOnly => write!(f, "StreamRead"),
363			Self::ReadWrite => write!(f, "StreamCopy"),
364		}
365	}
366}