use super::*;
use super::errors::*;
use std;
use std::os::raw::c_void;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BufferId(u32);
impl BufferId {
pub fn empty() -> BufferId {
BufferId(0)
}
}
impl From<BufferId> for u32 {
fn from(buffer_id: BufferId) -> Self {
buffer_id.0
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BlockIndex(pub u32);
impl From<BlockIndex> for u32 {
fn from(block_index: BlockIndex) -> Self {
block_index.0
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BufferMutability {
Mutable,
Immutable,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BufferMap {
Read,
Write,
ReadWrite,
}
#[derive(Debug, Copy, Clone)]
pub enum BufferData<'a, T: 'a> {
Empty(usize),
Data(&'a [T]),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BindBufferTarget {
DispatchIndirectBuffer,
DrawIndirectBuffer,
PixelPackBuffer,
PixelUnpackBuffer,
ElementArrayBuffer,
}
impl From<BindBufferTarget> for u32 {
fn from(target: BindBufferTarget) -> Self {
match target {
BindBufferTarget::DispatchIndirectBuffer => gl::DISPATCH_INDIRECT_BUFFER,
BindBufferTarget::DrawIndirectBuffer => gl::DRAW_INDIRECT_BUFFER,
BindBufferTarget::PixelPackBuffer => gl::PIXEL_PACK_BUFFER,
BindBufferTarget::PixelUnpackBuffer => gl::PIXEL_UNPACK_BUFFER,
BindBufferTarget::ElementArrayBuffer => gl::ELEMENT_ARRAY_BUFFER,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum BufferBaseTarget {
AtomicCounter,
TransformFeedback,
Uniform,
ShaderStorage,
}
impl From<BufferBaseTarget> for u32 {
fn from(target: BufferBaseTarget) -> Self {
match target {
BufferBaseTarget::AtomicCounter => gl::ATOMIC_COUNTER_BUFFER,
BufferBaseTarget::TransformFeedback => gl::TRANSFORM_FEEDBACK_BUFFER,
BufferBaseTarget::Uniform => gl::UNIFORM_BUFFER,
BufferBaseTarget::ShaderStorage => gl::SHADER_STORAGE_BUFFER,
}
}
}
impl<'a> From<&'a BufferBaseTarget> for u32 {
fn from(target: &'a BufferBaseTarget) -> Self {
match *target {
BufferBaseTarget::AtomicCounter => gl::ATOMIC_COUNTER_BUFFER,
BufferBaseTarget::TransformFeedback => gl::TRANSFORM_FEEDBACK_BUFFER,
BufferBaseTarget::Uniform => gl::UNIFORM_BUFFER,
BufferBaseTarget::ShaderStorage => gl::SHADER_STORAGE_BUFFER,
}
}
}
pub fn create_buffer() -> BufferId {
let mut buffer_id: u32 = 0;
let buffer_id_ptr: *mut u32 = &mut buffer_id;
unsafe {
gl::CreateBuffers(1, buffer_id_ptr);
}
BufferId(buffer_id)
}
pub unsafe fn named_buffer_storage<T, M>(
id: BufferId,
data: BufferData<T>,
mutability: BufferMutability,
map: M,
) -> Result<()>
where
M: Into<Option<BufferMap>>,
{
let mut flags: u32 = match mutability {
BufferMutability::Mutable => gl::DYNAMIC_STORAGE_BIT,
_ => 0,
};
flags |= match map.into() {
None => 0,
Some(BufferMap::Read) => gl::MAP_READ_BIT | gl::MAP_COHERENT_BIT | gl::MAP_PERSISTENT_BIT,
Some(BufferMap::Write) => gl::MAP_WRITE_BIT | gl::MAP_COHERENT_BIT | gl::MAP_PERSISTENT_BIT,
Some(BufferMap::ReadWrite) => {
gl::MAP_READ_BIT | gl::MAP_WRITE_BIT | gl::MAP_COHERENT_BIT | gl::MAP_PERSISTENT_BIT
}
};
match data {
BufferData::Data(data) => {
let size = (std::mem::size_of::<T>() * data.len()) as isize;
let buffer_ptr = data.as_ptr() as *const c_void;
gl::NamedBufferStorage(id.into(), size, buffer_ptr, flags);
}
BufferData::Empty(size) => {
gl::NamedBufferStorage(id.into(), size as isize, std::ptr::null(), flags);
}
}
get_error(())
}
pub unsafe fn named_buffer_sub_data<T>(buffer_id: BufferId, offset: usize, data: &[T]) -> Result<()> {
let size = (std::mem::size_of::<T>() * data.len()) as isize;
let buffer_ptr = data.as_ptr() as *const c_void;
gl::NamedBufferSubData(buffer_id.into(), offset as isize, size, buffer_ptr);
get_error(())
}
pub unsafe fn map_named_buffer_range(
id: BufferId,
offset: usize,
length: usize,
access: BufferMap,
) -> Result<*mut c_void> {
let flags = match access {
BufferMap::Read => gl::MAP_READ_BIT | gl::MAP_COHERENT_BIT | gl::MAP_PERSISTENT_BIT,
BufferMap::Write => gl::MAP_WRITE_BIT | gl::MAP_COHERENT_BIT | gl::MAP_PERSISTENT_BIT,
BufferMap::ReadWrite => gl::MAP_WRITE_BIT | gl::MAP_READ_BIT | gl::MAP_COHERENT_BIT | gl::MAP_PERSISTENT_BIT,
};
let pointer: *mut c_void = gl::MapNamedBufferRange(id.into(), offset as isize, length as isize, flags);
get_error(pointer)
}
pub unsafe fn get_named_buffer_sub_data<T>(id: BufferId, offset: usize, size: usize, data: &mut [T]) -> Result<()> {
gl::GetNamedBufferSubData(
id.into(),
offset as isize,
size as isize,
data.as_mut_ptr() as *mut c_void,
);
get_error(())
}
pub unsafe fn bind_buffer(target: BindBufferTarget, id: BufferId) -> Result<()> {
gl::BindBuffer(target.into(), id.into());
get_error(())
}
pub unsafe fn bind_buffer_base(target: BufferBaseTarget, block_index: BlockIndex, buffer_id: BufferId) -> Result<()> {
gl::BindBufferBase(target.into(), block_index.into(), buffer_id.into());
get_error(())
}
pub unsafe fn bind_buffer_range(
target: BufferBaseTarget,
block_index: BlockIndex,
buffer_id: BufferId,
offset: usize,
size: usize,
) -> Result<()> {
gl::BindBufferRange(
target.into(),
block_index.into(),
buffer_id.into(),
offset as isize,
size as isize,
);
get_error(())
}
pub unsafe fn bind_buffers_base(
target: BufferBaseTarget,
first_ubo_index: BlockIndex,
buffers_id: &[BufferId],
) -> Result<()> {
gl::BindBuffersBase(
target.into(),
first_ubo_index.into(),
buffers_id.len() as i32,
buffers_id.iter().map(|id| id.0).collect::<Vec<u32>>().as_ptr(),
);
get_error(())
}
pub unsafe fn delete_buffer(id: BufferId) {
let buffer_id_ptr: *const u32 = &id.into();
gl::DeleteBuffers(1, buffer_id_ptr);
}
pub unsafe fn clear_buffer_data(id: BufferId) -> Result<()> {
let zero: u8 = 0;
let zero_ptr: *const u8 = &zero;
gl::ClearNamedBufferData(
id.into(),
gl::R8UI,
gl::RED,
gl::UNSIGNED_BYTE,
zero_ptr as *const c_void,
);
get_error(())
}
pub unsafe fn clear_buffer_sub_data(id: BufferId, size: usize, offset: usize) -> Result<()> {
let zero: u8 = 0;
let zero_ptr: *const u8 = &zero;
gl::ClearNamedBufferSubData(
id.into(),
gl::R8UI,
offset as isize,
size as isize,
gl::RED,
gl::UNSIGNED_BYTE,
zero_ptr as *const c_void,
);
get_error(())
}
pub unsafe fn copy_named_buffer_sub_data(
read_buffer_id: BufferId,
write_buffer_id: BufferId,
read_offset: usize,
write_offset: usize,
size: usize,
) -> Result<()> {
gl::CopyNamedBufferSubData(
read_buffer_id.into(),
write_buffer_id.into(),
read_offset as isize,
write_offset as isize,
size as isize,
);
get_error(())
}