1use crate::webgl2::{
4 state::{Bind, WebGL2State},
5 WebGL2,
6};
7use core::fmt;
8use luminance::tess::TessError;
9use std::{
10 cell::RefCell,
11 error,
12 marker::PhantomData,
13 mem,
14 ops::{Deref, DerefMut},
15 rc::Rc,
16 slice,
17};
18use web_sys::{WebGl2RenderingContext, WebGlBuffer};
19
20#[derive(Clone, Debug)]
22pub enum BufferError {
23 CannotCreate,
25}
26
27impl fmt::Display for BufferError {
28 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
29 match self {
30 BufferError::CannotCreate => f.write_str("cannot create buffer on the backend"),
31 }
32 }
33}
34
35impl error::Error for BufferError {}
36
37impl From<BufferError> for TessError {
38 fn from(e: BufferError) -> Self {
39 TessError::cannot_create(e.to_string())
40 }
41}
42
43#[derive(Clone, Debug)]
47struct BufferWrapper<const TARGET: u32> {
48 handle: WebGlBuffer,
49 state: Rc<RefCell<WebGL2State>>,
50}
51
52impl<const TARGET: u32> Drop for BufferWrapper<TARGET> {
53 fn drop(&mut self) {
54 let mut state = self.state.borrow_mut();
55
56 state.unbind_buffer(&self.handle);
57 state.ctx.delete_buffer(Some(&self.handle));
58 }
59}
60
61#[derive(Clone, Debug)]
63pub struct Buffer<T, const TARGET: u32> {
64 pub(crate) buf: Vec<T>,
66 gl_buf: BufferWrapper<TARGET>,
67}
68
69impl<T, const TARGET: u32> Buffer<T, TARGET>
70where
71 WebGL2State: BindBuffer<TARGET>,
72{
73 pub(crate) fn from_vec(webgl2: &mut WebGL2, vec: Vec<T>) -> Result<Self, BufferError> {
74 let mut state = webgl2.state.borrow_mut();
75 let len = vec.len();
76
77 let handle = state
78 .create_buffer()
79 .ok_or_else(|| BufferError::CannotCreate)?;
80
81 state.bind_buffer(&handle, Bind::Forced);
82
83 let bytes = mem::size_of::<T>() * len;
84 let data = unsafe { slice::from_raw_parts(vec.as_ptr() as *const _, bytes) };
85 state
86 .ctx
87 .buffer_data_with_u8_array(TARGET, data, WebGl2RenderingContext::STREAM_DRAW);
88
89 let gl_buf = BufferWrapper {
90 handle,
91 state: webgl2.state.clone(),
92 };
93
94 Ok(Buffer { gl_buf, buf: vec })
95 }
96
97 pub(crate) fn handle(&self) -> &WebGlBuffer {
98 &self.gl_buf.handle
99 }
100
101 pub(crate) fn slice_buffer(&self) -> BufferSlice<T> {
102 BufferSlice {
103 handle: &self.gl_buf.handle,
104 ptr: self.buf.as_ptr(),
105 len: self.buf.len(),
106 state: self.gl_buf.state.clone(),
107 }
108 }
109
110 pub(crate) fn slice_buffer_mut(&mut self) -> BufferSliceMut<T, TARGET> {
111 let raw = BufferSliceMutWrapper {
112 handle: &self.gl_buf.handle,
113 ptr: self.buf.as_mut_ptr() as *mut u8,
114 bytes: self.buf.len() * mem::size_of::<T>(),
115 state: self.gl_buf.state.clone(),
116 };
117
118 BufferSliceMut {
119 raw,
120 _phantom: PhantomData,
121 }
122 }
123}
124
125pub struct BufferSlice<'a, T> {
126 handle: &'a WebGlBuffer,
127 ptr: *const T,
128 len: usize,
129 state: Rc<RefCell<WebGL2State>>,
130}
131
132impl<'a> BufferSlice<'a, u8> {
133 pub(crate) unsafe fn transmute<T>(self) -> BufferSlice<'a, T> {
138 let handle = self.handle;
139 let ptr = self.ptr as *const T;
140 let len = self.len / mem::size_of::<T>();
141 let state = self.state;
142
143 BufferSlice {
144 handle,
145 ptr,
146 len,
147 state,
148 }
149 }
150}
151
152impl<T> Deref for BufferSlice<'_, T> {
153 type Target = [T];
154
155 fn deref(&self) -> &Self::Target {
156 unsafe { slice::from_raw_parts(self.ptr, self.len) }
157 }
158}
159
160pub struct BufferSliceMutWrapper<'a, const TARGET: u32>
165where
166 WebGL2State: BindBuffer<TARGET>,
167{
168 handle: &'a WebGlBuffer,
169 ptr: *mut u8,
170 bytes: usize,
171 state: Rc<RefCell<WebGL2State>>,
172}
173
174impl<const TARGET: u32> Drop for BufferSliceMutWrapper<'_, TARGET>
175where
176 WebGL2State: BindBuffer<TARGET>,
177{
178 fn drop(&mut self) {
179 let mut state = self.state.borrow_mut();
180 let _ = update_webgl_buffer::<TARGET>(&mut state, &self.handle, self.ptr, self.bytes, 0);
181 }
182}
183
184pub struct BufferSliceMut<'a, T, const TARGET: u32>
185where
186 WebGL2State: BindBuffer<TARGET>,
187{
188 raw: BufferSliceMutWrapper<'a, TARGET>,
189 _phantom: PhantomData<T>,
190}
191
192impl<'a, const TARGET: u32> BufferSliceMut<'a, u8, TARGET>
193where
194 WebGL2State: BindBuffer<TARGET>,
195{
196 pub(crate) unsafe fn transmute<T>(self) -> BufferSliceMut<'a, T, TARGET> {
201 BufferSliceMut {
202 raw: self.raw,
203 _phantom: PhantomData,
204 }
205 }
206}
207
208impl<T, const TARGET: u32> Deref for BufferSliceMut<'_, T, TARGET>
209where
210 WebGL2State: BindBuffer<TARGET>,
211{
212 type Target = [T];
213
214 fn deref(&self) -> &Self::Target {
215 unsafe {
216 slice::from_raw_parts(
217 self.raw.ptr as *const T,
218 self.raw.bytes / mem::size_of::<T>(),
219 )
220 }
221 }
222}
223
224impl<T, const TARGET: u32> DerefMut for BufferSliceMut<'_, T, TARGET>
225where
226 WebGL2State: BindBuffer<TARGET>,
227{
228 fn deref_mut(&mut self) -> &mut Self::Target {
229 unsafe {
230 slice::from_raw_parts_mut(self.raw.ptr as *mut T, self.raw.bytes / mem::size_of::<T>())
231 }
232 }
233}
234
235pub trait BindBuffer<const TARGET: u32> {
236 fn bind_buffer(&mut self, handle: &WebGlBuffer, bind_mode: Bind);
237}
238
239impl BindBuffer<{ WebGl2RenderingContext::ARRAY_BUFFER }> for WebGL2State {
240 fn bind_buffer(&mut self, handle: &WebGlBuffer, bind_mode: Bind) {
241 self.bind_array_buffer(Some(handle), bind_mode);
242 }
243}
244
245impl BindBuffer<{ WebGl2RenderingContext::ELEMENT_ARRAY_BUFFER }> for WebGL2State {
246 fn bind_buffer(&mut self, handle: &WebGlBuffer, bind_mode: Bind) {
247 self.bind_element_array_buffer(Some(handle), bind_mode);
248 }
249}
250
251impl BindBuffer<{ WebGl2RenderingContext::UNIFORM_BUFFER }> for WebGL2State {
252 fn bind_buffer(&mut self, handle: &WebGlBuffer, bind: Bind) {
253 self.bind_uniform_buffer(Some(handle), bind);
254 }
255}
256
257fn update_webgl_buffer<const TARGET: u32>(
259 state: &mut WebGL2State,
260 handle: &WebGlBuffer,
261 data: *const u8,
262 bytes: usize,
263 offset: usize,
264) -> Result<(), BufferError>
265where
266 WebGL2State: BindBuffer<TARGET>,
267{
268 state.bind_buffer(handle, Bind::Cached);
269
270 let data = unsafe { slice::from_raw_parts(data as _, bytes) };
271 state
272 .ctx
273 .buffer_sub_data_with_i32_and_u8_array_and_src_offset(TARGET, offset as _, data, 0);
274
275 Ok(())
276}