fyrox_graphics/gl/
buffer.rsuse crate::gl::server::GlGraphicsServer;
use crate::gl::ToGlConstant;
use crate::{
buffer::{Buffer, BufferKind, BufferUsage},
error::FrameworkError,
};
use glow::HasContext;
use std::{cell::Cell, rc::Weak};
impl ToGlConstant for BufferKind {
fn into_gl(self) -> u32 {
match self {
BufferKind::Vertex => glow::ARRAY_BUFFER,
BufferKind::Index => glow::ELEMENT_ARRAY_BUFFER,
BufferKind::Uniform => glow::UNIFORM_BUFFER,
BufferKind::PixelRead => glow::PIXEL_PACK_BUFFER,
BufferKind::PixelWrite => glow::PIXEL_UNPACK_BUFFER,
}
}
}
impl ToGlConstant for BufferUsage {
fn into_gl(self) -> u32 {
match self {
BufferUsage::StaticDraw => glow::STATIC_DRAW,
BufferUsage::StaticCopy => glow::STATIC_COPY,
BufferUsage::DynamicDraw => glow::DYNAMIC_DRAW,
BufferUsage::DynamicCopy => glow::DYNAMIC_COPY,
BufferUsage::StreamDraw => glow::STREAM_DRAW,
BufferUsage::StreamRead => glow::STREAM_READ,
BufferUsage::StreamCopy => glow::STREAM_COPY,
BufferUsage::StaticRead => glow::STATIC_READ,
BufferUsage::DynamicRead => glow::DYNAMIC_READ,
}
}
}
pub struct GlBuffer {
pub state: Weak<GlGraphicsServer>,
pub id: glow::Buffer,
pub size: Cell<usize>,
pub kind: BufferKind,
pub usage: BufferUsage,
}
impl GlBuffer {
pub fn new(
server: &GlGraphicsServer,
size_bytes: usize,
kind: BufferKind,
usage: BufferUsage,
) -> Result<Self, FrameworkError> {
unsafe {
let gl_kind = kind.into_gl();
let gl_usage = usage.into_gl();
let id = server.gl.create_buffer()?;
server.gl.bind_buffer(gl_kind, Some(id));
if size_bytes > 0 {
server
.gl
.buffer_data_size(gl_kind, size_bytes as i32, gl_usage);
}
server.gl.bind_buffer(gl_kind, None);
Ok(Self {
state: server.weak(),
id,
size: Cell::new(size_bytes),
kind,
usage,
})
}
}
}
impl Drop for GlBuffer {
fn drop(&mut self) {
unsafe {
if let Some(state) = self.state.upgrade() {
state.gl.delete_buffer(self.id);
}
}
}
}
impl Buffer for GlBuffer {
fn usage(&self) -> BufferUsage {
self.usage
}
fn kind(&self) -> BufferKind {
self.kind
}
fn size(&self) -> usize {
self.size.get()
}
fn write_data(&self, data: &[u8]) -> Result<(), FrameworkError> {
if data.is_empty() {
return Ok(());
}
let Some(server) = self.state.upgrade() else {
return Err(FrameworkError::GraphicsServerUnavailable);
};
let gl_kind = self.kind.into_gl();
let gl_usage = self.usage.into_gl();
unsafe {
server.gl.bind_buffer(gl_kind, Some(self.id));
if data.len() <= self.size.get() {
server.gl.buffer_sub_data_u8_slice(gl_kind, 0, data);
} else {
server.gl.buffer_data_u8_slice(gl_kind, data, gl_usage);
self.size.set(data.len());
}
}
Ok(())
}
fn read_data(&self, data: &mut [u8]) -> Result<(), FrameworkError> {
let Some(server) = self.state.upgrade() else {
return Err(FrameworkError::GraphicsServerUnavailable);
};
let gl_kind = self.kind.into_gl();
unsafe {
server.gl.bind_buffer(gl_kind, Some(self.id));
#[cfg(not(target_arch = "wasm32"))]
{
let gl_storage =
server
.gl
.map_buffer_range(gl_kind, 0, data.len() as i32, glow::MAP_READ_BIT);
assert_ne!(gl_storage, std::ptr::null_mut());
std::ptr::copy_nonoverlapping(gl_storage, data.as_mut_ptr(), data.len());
server.gl.unmap_buffer(gl_kind);
}
#[cfg(target_arch = "wasm32")]
{
server.gl.get_buffer_sub_data(gl_kind, 0, data);
}
server.gl.bind_buffer(gl_kind, None);
}
Ok(())
}
}