cgl_rs/graphics/ssbo.rs
1//! The SSBO module for CGL
2
3#![allow(non_camel_case_types)]
4use libc::{c_void, c_int, size_t};
5
6/// The internal handle used by CGL
7#[repr(C)]
8pub(crate) struct CGL_ssbo {
9 _private: c_void
10}
11
12
13/// The Shader Storage Buffer Object
14pub struct ShaderStorageBufferObject {
15 pub(crate) handle: *mut CGL_ssbo,
16 pub(crate) has_been_destroyed: bool
17}
18
19// This is just an alias for ShaderStorageBufferObject
20pub type SSBO = ShaderStorageBufferObject;
21
22
23extern {
24 fn CGL_ssbo_create(binding: u32) -> *mut CGL_ssbo;
25 fn CGL_ssbo_destroy(ssbo: *mut CGL_ssbo);
26 fn CGL_ssbo_bind(ssbo: *mut CGL_ssbo);
27 fn CGL_ssbo_bind2(ssbo: *mut CGL_ssbo, binding: u32);
28 fn CGL_ssbo_set_data(ssbo: *mut CGL_ssbo, size: size_t, data: *mut c_void, static_draw: c_int);
29 fn CGL_ssbo_set_sub_data(ssbo: *mut CGL_ssbo, offset: size_t, size: size_t, data: *mut c_void, static_draw: c_int);
30 fn CGL_ssbo_get_data(ssbo: *mut CGL_ssbo, size: *mut size_t, data: *mut c_void);
31 fn CGL_ssbo_get_sub_data(ssbo: *mut CGL_ssbo, offset: size_t, size: size_t, data: *mut c_void);
32 fn CGL_ssbo_set_user_data(ssbo: *mut CGL_ssbo, user_data: *mut c_void);
33 fn CGL_ssbo_get_user_data(ssbo: *mut CGL_ssbo) -> *mut c_void;
34 fn CGL_ssbo_get_size(ssbo: *mut CGL_ssbo) -> size_t;
35 fn CGL_ssbo_copy(dst: *mut CGL_ssbo, src: *mut CGL_ssbo, src_offset: size_t, dst_offset: size_t, size: size_t);
36}
37
38
39
40impl ShaderStorageBufferObject {
41
42 /// Creates a new Shader Storage Buffer Object with the specified binding.
43 ///
44 /// # Arguments
45 ///
46 /// * `binding` - The binding point for the SSBO.
47 ///
48 /// # Returns
49 ///
50 /// A new instance of `ShaderStorageBufferObject` with the specified binding, or `Err(())` if the creation failed.
51 ///
52 /// # Example
53 ///
54 /// ```
55 /// cgl_rs::init();
56 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
57 /// cgl_rs::graphics::init();
58 /// {
59 /// let mut ssbo = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
60 /// }
61 /// cgl_rs::graphics::shutdown();
62 /// window.destroy();
63 /// cgl_rs::shutdown();
64 /// ```
65 pub fn new(binding: u32) -> Result<ShaderStorageBufferObject, ()> {
66 let handle = unsafe { CGL_ssbo_create(binding) };
67 if handle.is_null() {
68 Err(())
69 } else {
70 Ok(ShaderStorageBufferObject {
71 handle,
72 has_been_destroyed: false
73 })
74 }
75 }
76
77 /// Creates a new Shader Storage Buffer Object with the specified binding and sets its data to the provided byte slice.
78 ///
79 /// # Arguments
80 ///
81 /// * `data` - The byte slice containing the data to be set.
82 /// * `binding` - The binding point for the SSBO.
83 ///
84 /// # Returns
85 ///
86 /// A new instance of `ShaderStorageBufferObject` with the specified binding and data, or `Err(())` if the creation failed.
87 ///
88 /// # Example
89 ///
90 /// ```
91 /// cgl_rs::init();
92 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
93 /// cgl_rs::graphics::init();
94 /// {
95 /// let data = vec![0u8; 1024];
96 /// let ssbo = cgl_rs::graphics::ShaderStorageBufferObject::from(&data, 0).unwrap();
97 /// }
98 /// cgl_rs::graphics::shutdown();
99 /// window.destroy();
100 /// cgl_rs::shutdown();
101 /// ```
102 pub fn from(data: &[u8], binding: u32) -> Result<ShaderStorageBufferObject, ()> {
103 let mut ssbo = ShaderStorageBufferObject::new(binding)?;
104 ssbo.set_data(data.len(), data.as_ptr() as *mut u8, false);
105 Ok(ssbo)
106 }
107
108 /// Destroys the ssbo and frees its resources. If it has already been destroyed, this method does nothing.
109 ///
110 /// # Example
111 ///
112 /// ```
113 /// cgl_rs::init();
114 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
115 /// cgl_rs::graphics::init();
116 /// {
117 /// let mut texture = cgl_rs::graphics::Texture::dummy().unwrap();
118 /// texture.destroy(); // optional
119 /// }
120 /// cgl_rs::graphics::shutdown();
121 /// window.destroy();
122 /// cgl_rs::shutdown();
123 /// ```
124 pub fn destroy(&mut self) {
125 if !self.has_been_destroyed {
126 unsafe {
127 CGL_ssbo_destroy(self.handle);
128 }
129 self.has_been_destroyed = true;
130 }
131 }
132
133 /// Binds the Shader Storage Buffer Object to the current context.
134 ///
135 /// # Example
136 ///
137 /// ```
138 /// cgl_rs::init();
139 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
140 /// cgl_rs::graphics::init();
141 /// {
142 /// let ssbo = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
143 /// ssbo.bind();
144 /// }
145 /// cgl_rs::graphics::shutdown();
146 /// window.destroy();
147 /// cgl_rs::shutdown();
148 /// ```
149 pub fn bind(&self) {
150 unsafe {
151 CGL_ssbo_bind(self.handle);
152 }
153 }
154
155
156 /// Binds the Shader Storage Buffer (Base) to the specified binding point.
157 ///
158 /// # Arguments
159 ///
160 /// * `binding` - The binding point to bind the Shader Storage Buffer Object to.
161 ///
162 /// # Example
163 ///
164 /// ```
165 /// cgl_rs::init();
166 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
167 /// cgl_rs::graphics::init();
168 /// {
169 /// let mut ssbo = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
170 /// ssbo.bind2(1);
171 /// }
172 /// cgl_rs::graphics::shutdown();
173 /// window.destroy();
174 /// cgl_rs::shutdown();
175 /// ```
176 pub fn bind2(&mut self, binding: u32) {
177 unsafe {
178 CGL_ssbo_bind2(self.handle, binding);
179 }
180 }
181
182 /// Sets the data of the Shader Storage Buffer Object.
183 /// This also allocates the memory on the GPU if necessary.
184 ///
185 /// If you only want to update a part of the data, use `set_sub_data` instead.
186 ///
187 /// # Arguments
188 ///
189 /// * `size` - The size of the data in bytes.
190 /// * `data` - A pointer to the data.
191 /// * `static_draw` - A flag indicating whether the data is static or not.
192 ///
193 /// # Example
194 ///
195 /// ```
196 /// cgl_rs::init();
197 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
198 /// cgl_rs::graphics::init();
199 /// {
200 /// let mut ssbo = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
201 /// let data: [u8; 4] = [0, 1, 2, 3];
202 /// ssbo.set_data(data.len(), data.as_ptr() as *mut u8, true);
203 /// }
204 /// cgl_rs::graphics::shutdown();
205 /// window.destroy();
206 /// cgl_rs::shutdown();
207 /// ```
208 ///
209 /// # See also
210 ///
211 /// * `set_sub_data`
212 pub fn set_data(&mut self, size: usize, data: *mut u8, static_draw: bool) {
213 unsafe {
214 CGL_ssbo_set_data(self.handle, size, data as *mut c_void, static_draw as c_int);
215 }
216 }
217
218 /// Sets a portion of the data of the Shader Storage Buffer Object.
219 ///
220 /// Note: This does not allocate the memory on the GPU if necessary.
221 /// So, if the data is not allocated on the GPU, this method will do nothing.
222 /// To allocate the memory on the GPU, use `set_data` instead.
223 ///
224 /// # Arguments
225 ///
226 /// * `offset` - The offset in bytes from the beginning of the buffer where the data should be written.
227 /// * `size` - The size of the data in bytes.
228 /// * `data` - A pointer to the data.
229 ///
230 /// # Example
231 ///
232 /// ```
233 /// cgl_rs::init();
234 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
235 /// cgl_rs::graphics::init();
236 /// {
237 /// let mut ssbo = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
238 /// let data: [u8; 4] = [0, 1, 2, 3];
239 /// ssbo.set_data(data.len(), data.as_ptr() as *mut u8, true);
240 /// let sub_data: [u8; 2] = [4, 5];
241 /// ssbo.set_sub_data(2, sub_data.len(), sub_data.as_ptr() as *mut u8);
242 /// }
243 /// cgl_rs::graphics::shutdown();
244 /// window.destroy();
245 /// cgl_rs::shutdown();
246 /// ```
247 ///
248 /// # See also
249 ///
250 /// * `set_data`
251 pub fn set_sub_data(&mut self, offset: usize, size: usize, data: *mut u8) {
252 unsafe {
253 CGL_ssbo_set_sub_data(self.handle, offset, size, data as *mut c_void, false as c_int);
254 }
255 }
256
257 /// Gets the entire data of the Shader Storage Buffer Object.
258 ///
259 /// If you only want to get a part of the data, use `get_sub_data` instead.
260 ///
261 /// # Returns
262 ///
263 /// A vector containing the data of the Shader Storage Buffer Object.
264 ///
265 /// # Example
266 ///
267 /// ```
268 /// cgl_rs::init();
269 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
270 /// cgl_rs::graphics::init();
271 /// {
272 /// let mut ssbo = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
273 /// let data: [u8; 4] = [0, 1, 2, 3];
274 /// ssbo.set_data(data.len(), data.as_ptr() as *mut u8, true);
275 /// let retrieved_data = ssbo.get_data();
276 /// assert_eq!(data, retrieved_data.as_slice());
277 /// }
278 /// cgl_rs::graphics::shutdown();
279 /// window.destroy();
280 /// cgl_rs::shutdown();
281 /// ```
282 ///
283 /// # See also
284 ///
285 /// * `get_sub_data`
286 pub fn get_data(&self) -> Vec<u8> {
287 unsafe {
288 let mut size: usize = CGL_ssbo_get_size(self.handle);
289 let mut data: Vec<u8> = Vec::with_capacity(size);
290 CGL_ssbo_get_data(self.handle, &mut size, data.as_mut_ptr() as *mut c_void);
291 data.set_len(size);
292 data
293 }
294 }
295
296 /// Gets a part of the data of the Shader Storage Buffer Object.
297 ///
298 /// If you want to get the entire data, use `get_data` instead.
299 ///
300 /// # Arguments
301 ///
302 /// * `offset` - The offset in bytes from the beginning of the buffer where the data should be read.
303 /// * `size` - The size of the data in bytes.
304 ///
305 /// # Returns
306 ///
307 /// A vector containing the requested part of the data of the Shader Storage Buffer Object.
308 ///
309 /// # Example
310 ///
311 /// ```
312 /// cgl_rs::init();
313 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
314 /// cgl_rs::graphics::init();
315 /// {
316 /// let mut ssbo = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
317 /// let data: [u8; 4] = [0, 1, 2, 3];
318 /// ssbo.set_data(data.len(), data.as_ptr() as *mut u8, true);
319 /// let retrieved_data = ssbo.get_sub_data(1, 2);
320 /// assert_eq!(&data[1..3], retrieved_data.as_slice());
321 /// }
322 /// cgl_rs::graphics::shutdown();
323 /// window.destroy();
324 /// cgl_rs::shutdown();
325 /// ```
326 ///
327 /// # See also
328 ///
329 /// * `get_data`
330 pub fn get_sub_data(&self, offset: usize, size: usize) -> Vec<u8> {
331 unsafe {
332 let mut data: Vec<u8> = Vec::with_capacity(size);
333 CGL_ssbo_get_sub_data(self.handle, offset, size, data.as_mut_ptr() as *mut c_void);
334 data.set_len(size);
335 data
336 }
337 }
338
339 /// Gets the size of the Shader Storage Buffer Object.
340 ///
341 /// # Returns
342 ///
343 /// The size of the Shader Storage Buffer Object in bytes.
344 ///
345 /// # Example
346 ///
347 /// ```
348 /// cgl_rs::init();
349 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
350 /// cgl_rs::graphics::init();
351 /// {
352 /// let mut ssbo = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
353 /// let data: [u8; 4] = [0, 1, 2, 3];
354 /// ssbo.set_data(data.len(), data.as_ptr() as *mut u8, true);
355 /// assert_eq!(data.len(), ssbo.size());
356 /// }
357 /// cgl_rs::graphics::shutdown();
358 /// window.destroy();
359 /// cgl_rs::shutdown();
360 /// ```
361 pub fn size(&self) -> usize {
362 unsafe {
363 CGL_ssbo_get_size(self.handle) as usize
364 }
365 }
366
367 /// Copies a part of the data of the Shader Storage Buffer Object to another Shader Storage Buffer Object.
368 ///
369 /// Note: This does not allocate the memory if the destination buffer is not big enough.
370 /// In such a case nothing will happen.
371 ///
372 /// # Arguments
373 ///
374 /// * `other` - The destination Shader Storage Buffer Object.
375 /// * `src_offset` - The offset in bytes from the beginning of the source buffer where the data should be read.
376 /// * `dst_offset` - The offset in bytes from the beginning of the destination buffer where the data should be written.
377 /// * `size` - The size of the data in bytes.
378 ///
379 /// # Example
380 ///
381 /// ```
382 /// cgl_rs::init();
383 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
384 /// cgl_rs::graphics::init();
385 /// {
386 /// let mut ssbo1 = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
387 /// let mut ssbo2 = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
388 /// let data: [u8; 4] = [0, 1, 2, 3];
389 /// let data2: [u8; 2] = [4, 5];
390 /// ssbo1.set_data(data.len(), data.as_ptr() as *mut u8, true);
391 /// ssbo2.set_data(data2.len(), data2.as_ptr() as *mut u8, true);
392 /// ssbo1.copy_to(&ssbo2, 1, 0, 2);
393 /// let retrieved_data = ssbo2.get_data();
394 /// assert_eq!(&data[1..3], retrieved_data.as_slice());
395 /// }
396 /// cgl_rs::graphics::shutdown();
397 /// window.destroy();
398 /// cgl_rs::shutdown();
399 /// ```
400 pub fn copy_to(&self, other: &ShaderStorageBufferObject, src_offset: usize, dst_offset: usize, size: usize) {
401 unsafe {
402 CGL_ssbo_copy(other.handle, self.handle, src_offset, dst_offset, size);
403 }
404 }
405
406 /// Copies the entire data of the Shader Storage Buffer Object to another Shader Storage Buffer Object.
407 ///
408 /// Note: This does not allocate the memory if the destination buffer is not big enough.
409 /// In such a case nothing will happen.
410 ///
411 /// # Arguments
412 ///
413 /// * `other` - The destination Shader Storage Buffer Object.
414 ///
415 /// # Example
416 ///
417 /// ```
418 /// cgl_rs::init();
419 /// let mut window = cgl_rs::Window::new("Hello, World!", 800, 600).unwrap();
420 /// cgl_rs::graphics::init();
421 /// {
422 /// let mut ssbo1 = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
423 /// let mut ssbo2 = cgl_rs::graphics::ShaderStorageBufferObject::new(0).unwrap();
424 /// let data: [u8; 4] = [0, 1, 2, 3];
425 /// let data2: [u8; 4] = [4, 5, 6, 7];
426 /// ssbo1.set_data(data.len(), data.as_ptr() as *mut u8, true);
427 /// ssbo2.set_data(data2.len(), data2.as_ptr() as *mut u8, true);
428 /// ssbo1.copy_whole_to(&ssbo2);
429 /// let retrieved_data = ssbo2.get_data();
430 /// assert_eq!(data, retrieved_data.as_slice());
431 /// }
432 /// cgl_rs::graphics::shutdown();
433 /// window.destroy();
434 /// cgl_rs::shutdown();
435 /// ```
436 pub fn copy_whole_to(&self, other: &ShaderStorageBufferObject) {
437 unsafe {
438 CGL_ssbo_copy(other.handle, self.handle, 0, 0, self.size());
439 }
440 }
441
442
443}
444
445impl Drop for ShaderStorageBufferObject {
446 fn drop(&mut self) {
447 self.destroy();
448 }
449}
450
451
452impl Clone for ShaderStorageBufferObject {
453 /// Clones the ssbo.
454 ///
455 /// NOTE: The new instance will have the same handle, `has_been_destroyed` flag.
456 /// This means that the new instance will not be able to receive events nor will the internal window handle be
457 /// destroyed when the new instance is dropped. The internal window handle will be destroyed when the original
458 /// instance is dropped.
459 ///
460 ///
461 /// # Returns
462 ///
463 /// A new instance of `ShaderStorageBufferObject` with the same handle as the original ssbo.
464 fn clone(&self) -> Self {
465 ShaderStorageBufferObject {
466 handle: self.handle.clone(),
467 has_been_destroyed: true
468 }
469 }
470}