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}