use super::*; use crate::alignment::pad_raw_slice; impl WebGpuContext { pub fn new_vertex_buffer( &mut self, data: &[VertexBufferElement], storage_type: BufferStorageType, _ext: Option, ) -> GResult { let size = data.len() * std::mem::size_of::(); let buffer = WebGpuBuffer::new( &self.device, size as u32, GpuBufferUsageFlags::Vertex as u32 | match storage_type { BufferStorageType::Dynamic => GpuBufferUsageFlags::CopyDst as u32, _ => 0, }, unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, size) }, false, ); self.vbos.push(buffer); Ok(VertexBufferId::from_id(self.vbos.len() - 1)) } pub fn new_index_buffer( &mut self, data: &[IndexBufferElement], storage_type: BufferStorageType, _ext: Option, ) -> GResult { let size = data.len() * std::mem::size_of::(); let buffer = WebGpuBuffer::new( &self.device, size as u32, GpuBufferUsageFlags::Index as u32 | match storage_type { BufferStorageType::Dynamic => GpuBufferUsageFlags::CopyDst as u32, _ => 0, }, unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, size) }, false, ); self.ibos.push(buffer); Ok(IndexBufferId::from_id(self.ibos.len() - 1)) } pub fn new_uniform_buffer( &mut self, data: &T, _ext: Option, ) -> GResult { let size = std::mem::size_of::(); let buffer = WebGpuBuffer::new( &self.device, size as u32, GpuBufferUsageFlags::Uniform as u32 | GpuBufferUsageFlags::CopyDst as u32, unsafe { std::slice::from_raw_parts(data as *const T as *const u8, size) }, false, ); self.ubos.push(buffer); Ok(UniformBufferId::from_id(self.ubos.len() - 1)) } pub fn new_dynamic_uniform_buffer( &mut self, data: &[T], _ext: Option, ) -> GResult { let min_ubo_alignment = self.device.limits().min_uniform_buffer_offset_alignment() as usize; let buffer = WebGpuDynamicBuffer::new( &self.device, GpuBufferUsageFlags::Uniform as u32 | GpuBufferUsageFlags::CopyDst as u32, min_ubo_alignment, data, ); self.dyn_ubos.push(buffer); Ok(DynamicUniformBufferId::from_id(self.dyn_ubos.len() - 1)) } } pub struct WebGpuBuffer { pub size: u32, pub buffer: GpuBuffer, pub readable_buffer: Option, } impl WebGpuBuffer { pub fn new( device: &GpuDevice, size: u32, usage: u32, data: &[u8], create_readable_buffer: bool, ) -> Self { let mut buffer_info = GpuBufferDescriptor::new(size as f64, usage); buffer_info.mapped_at_creation(true); let buffer = device.create_buffer(&buffer_info); let mapped_range = Uint8Array::new(&buffer.get_mapped_range().into()); for (idx, &val) in data.iter().enumerate() { mapped_range.set_index(idx as u32, val); } buffer.unmap(); let readable_buffer = create_readable_buffer.then(|| { let buffer_info = GpuBufferDescriptor::new( size as f64, GpuBufferUsageFlags::CopyDst as u32 | GpuBufferUsageFlags::MapRead as u32, ); device.create_buffer(&buffer_info) }); WebGpuBuffer { size, buffer, readable_buffer, } } } pub struct WebGpuDynamicBuffer { pub buffer: WebGpuBuffer, pub per_index_offset: usize, } impl WebGpuDynamicBuffer { pub fn new(device: &GpuDevice, usage: u32, min_alignment: usize, data: &[T]) -> Self { let each_size = std::mem::size_of::(); let byte_slice = unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, each_size * data.len()) }; let padded = unsafe { pad_raw_slice(byte_slice, min_alignment, each_size, data.len()) }; let buffer = WebGpuBuffer::new(device, padded.len() as u32, usage, &padded, false); WebGpuDynamicBuffer { buffer, per_index_offset: min_alignment, } } pub fn write_buffer(&self, queue: &GpuQueue, data: &[u8], index: usize) { queue.write_buffer_with_u32_and_u8_array_and_u32( &self.buffer.buffer, (index * self.per_index_offset) as u32, data, 0, ); } }