use gl::types::*;
use std::marker::PhantomData;
use std::cell::RefCell;
use std::rc::Rc;
use std::marker;
use std::slice;
use std::mem;
use ::Result;
use state::StateRef;
use crate::{Error, gl};
use super::buffer::{Buffer, Builder};
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
use super::shared_storage::SharedBufferStorage;
#[cfg(not(feature="webgl"))]
use super::map::*;
use super::traits::*;
use super::range::Range;
#[derive(Debug, Eq, PartialEq)]
pub struct SharedBuffer<T>{
buffer: Rc<RefCell<Buffer<u8>>>,
marker: marker::PhantomData<T>,
}
impl<T> Clone for SharedBuffer<T>{
fn clone(&self) -> SharedBuffer<T>{
SharedBuffer{
buffer: self.buffer.clone(),
marker: PhantomData,
}
}
}
fn to_u8<T>(data: &[T]) -> &[u8]{
let bytes = data.len() * mem::size_of::<T>();
unsafe{ slice::from_raw_parts(data.as_ptr() as *const u8, bytes) }
}
#[cfg(not(feature="webgl"))]
fn to_t<T>(data: &[u8]) -> &[T]{
let len = data.len() / mem::size_of::<T>();
unsafe{ slice::from_raw_parts(data.as_ptr() as *const T, len) }
}
#[cfg(not(feature="webgl"))]
fn to_t_mut<T>(data: &mut [u8]) -> &mut [T]{
let len = data.len() / mem::size_of::<T>();
unsafe{ slice::from_raw_parts_mut(data.as_mut_ptr() as *mut T, len) }
}
pub struct SharedBuilder<'a>(pub(crate) &'a StateRef);
impl<'a> SharedBuilder<'a>{
#[cfg(not(feature="webgl"))]
pub fn create<T>(&self, len: usize, usage: GLenum) -> Result<SharedBuffer<T>>{
Ok(SharedBuffer{
buffer: Rc::new(RefCell::new(Builder(self.0).create(len, usage)?)),
marker: PhantomData,
})
}
pub fn create_target<T>(&self, len: usize, usage: GLenum, target: GLenum) -> Result<SharedBuffer<T>>{
Ok(SharedBuffer{
buffer: Rc::new(RefCell::new(Builder(self.0).create_target(len * mem::size_of::<T>(), usage, target)?)),
marker: PhantomData
})
}
#[cfg(not(feature="webgl"))]
pub fn empty<T>(&self) -> Result<SharedBuffer<T>>{
Ok(SharedBuffer{
buffer: Rc::new(RefCell::new(Builder(self.0).empty()?)),
marker: PhantomData
})
}
pub fn empty_target<T>(&self, target: GLenum) -> Result<SharedBuffer<T>>{
Ok(SharedBuffer{
buffer: Rc::new(RefCell::new(Builder(self.0).empty_target(target)?)),
marker: PhantomData
})
}
#[cfg(not(feature="webgl"))]
pub fn from_data<T: 'static>(&self, data: &[T], usage: GLenum) -> Result<SharedBuffer<T>>{
let u8_data = to_u8(data);
Ok(SharedBuffer{
buffer: Rc::new(RefCell::new(Builder(self.0).from_data(u8_data, usage)?)),
marker: PhantomData
})
}
pub fn from_data_target<T: 'static>(&self, data: &[T], usage: GLenum, target: GLenum) -> Result<SharedBuffer<T>>{
let u8_data = to_u8(data);
Ok(SharedBuffer{
buffer: Rc::new(RefCell::new(Builder(self.0).from_data_target(u8_data, usage, target)?)),
marker: PhantomData
})
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn create_immutable<T>(&self, len: usize, flags: GLbitfield) -> Result<SharedBufferStorage<T>>
where T: 'static
{
Builder(self.0)
.create_immutable(len, flags)
.map(SharedBufferStorage::from)
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn create_immutable_target<T>(&self, len: usize, flags: GLbitfield, target: GLenum) -> Result<SharedBufferStorage<T>>
where T: 'static
{
Builder(self.0)
.create_immutable_target(len * mem::size_of::<T>(), flags, target)
.map(SharedBufferStorage::from)
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn immutable_from_data<T>(&self, data: &[T], flags: GLbitfield) -> Result<SharedBufferStorage<T>>
where T: 'static
{
Builder(self.0)
.immutable_from_data(data, flags)
.map(SharedBufferStorage::from)
}
}
impl<T: 'static> SharedBuffer<T>{
pub fn load(&mut self, data: &[T], usage: GLenum){
let u8_data = to_u8(data);
(*self.buffer).borrow_mut().load(u8_data, usage);
}
pub fn load_target(&mut self, data: &[T], usage: GLenum, target: GLenum){
let u8_data = to_u8(data);
(*self.buffer).borrow_mut().load_target(u8_data, usage, target);
}
pub fn reserve(&mut self, len: usize, usage: GLenum){
(*self.buffer).borrow_mut().reserve(len * mem::size_of::<T>(), usage);
}
pub fn reserve_target(&mut self, len: usize, usage: GLenum, target: GLenum){
(*self.buffer).borrow_mut().reserve_target(len * mem::size_of::<T>(), usage, target);
}
pub fn update(&mut self, data: &[T]){
let u8_data = to_u8(data);
(*self.buffer).borrow_mut().update(u8_data);
}
#[cfg(not(feature="webgl"))]
pub fn with_map_read<F: FnMut(&[T])>(&self, flags: MapReadFlags, mut f: F) -> Result<()>{
(*self.buffer).borrow_mut().with_map_read(flags, |u8_data| f(to_t(u8_data)))
}
#[cfg(not(feature="webgl"))]
pub unsafe fn map_write<F: FnMut(&mut [T])>(&mut self, flags: MapWriteFlags, mut f: F) -> Result<()>{
(*self.buffer).borrow_mut()
.map_write(flags)
.map(|mut m| f(to_t_mut(m.data_mut())))
}
#[cfg(not(feature="webgl"))]
pub fn map_read_write<F: FnMut(&mut [T])>(&mut self, flags: MapReadWriteFlags, mut f: F) -> Result<()>{
(*self.buffer).borrow_mut()
.map_read_write(flags)
.map(|mut m| f(to_t_mut(m.data_mut())))
}
pub fn copy_to<U,B:BufferRange<U> + WithBackendMut>(&self, dst: &mut B){
(*self.buffer).borrow().copy_to(dst);
}
pub fn len(&self) -> usize{
(*self.buffer).borrow().len() / mem::size_of::<T>()
}
pub fn is_empty(&self) -> bool{
(*self.buffer).borrow().is_empty()
}
pub fn capacity(&self) -> usize{
(*self.buffer).borrow().capacity() / mem::size_of::<T>()
}
pub fn bytes(&self) -> usize{
(*self.buffer).borrow().bytes()
}
pub fn capacity_bytes(&self) -> usize{
(*self.buffer).borrow().capacity_bytes()
}
pub fn id(&self) -> GLuint{
(*self.buffer).borrow().id()
}
pub fn stride(&self) -> usize{
(*self.buffer).borrow().stride()
}
pub fn range<R: InputRange>(&self, range: R) -> Range<T, SharedBuffer<T>, SharedBuffer<T>>{
Range{
buffer: self.clone(),
range: range.to_range(self),
marker_type: PhantomData,
marker_buffer: PhantomData,
}
}
pub fn range_mut<R: InputRange>(&mut self, range: R) -> Range<T, SharedBuffer<T>, SharedBuffer<T>>{
Range{
range: range.to_range(self),
buffer: self.clone(),
marker_type: PhantomData,
marker_buffer: PhantomData,
}
}
}
impl SharedBuffer<u8>{
pub fn cast<T>(self) -> SharedBuffer<T>{
SharedBuffer{
buffer: self.buffer,
marker: PhantomData,
}
}
}
impl<T: 'static> Cast<T> for SharedBuffer<u8>{
type CastTo = SharedBuffer<T>;
fn cast(self) -> SharedBuffer<T>{
SharedBuffer {
buffer: self.buffer,
marker: PhantomData,
}
}
}
impl<T: 'static> TypedBuffer<T> for SharedBuffer<T>{
fn id(&self) -> GLuint{
(*self).id()
}
fn len(&self) -> usize{
(*self).len()
}
fn capacity(&self) -> usize{
(*self).capacity()
}
#[cfg(not(feature="webgl"))]
fn with_map_read<F: FnMut(&[T])>(&self, flags: MapReadFlags, mut f: F) -> Result<()>{
(*self.buffer).borrow().with_map_read(flags, |u8_data| f(to_t(u8_data)))
}
fn copy_to<U,B:BufferRange<U> + WithBackendMut>(&self, dst: &mut B){
self.copy_to(dst)
}
#[cfg(not(feature="webgl"))]
unsafe fn unmap(&self){
self.buffer.borrow().unmap()
}
}
impl<'a, T: 'static> TypedBufferMut<T> for SharedBuffer<T> {
#[cfg(not(feature="webgl"))]
unsafe fn with_map_write<F: FnMut(&mut [T])>(&mut self,flags: MapWriteFlags, mut f: F) -> Result<()>{
(*self.buffer).borrow_mut()
.map_write(flags)
.map(|mut m| f(to_t_mut(m.data_mut())))
}
#[cfg(not(feature="webgl"))]
fn with_map_read_write<F: FnMut(&mut [T])>(&mut self, flags: MapReadWriteFlags, mut f: F) -> Result<()>{
(*self.buffer).borrow_mut()
.map_read_write(flags)
.map(|mut m| f(to_t_mut(m.data_mut())))
}
}
impl<T: 'static> BufferRange<T> for SharedBuffer<T>{
fn start(&self) -> usize{
0
}
fn end(&self) -> usize{
self.len()
}
fn into_range<R: InputRange>(self, range: R) -> super::Range<T, Self, Self> where Self: Sized{
Range{
range: range.to_range(&self),
buffer: self,
marker_type: PhantomData,
marker_buffer: PhantomData,
}
}
}
impl<T:'static> BufferRangeMut<T> for SharedBuffer<T>{
fn update(&mut self, data: &[T]){
self.update(data);
}
}
impl<T> WithBackend for SharedBuffer<T>{
fn with_backend<F:FnMut(&dyn Backend)->R, R>(&self, f:F) -> R{
(*self.buffer).borrow().with_backend(f)
}
}
impl<T> WithBackendMut for SharedBuffer<T>{
fn with_backend_mut<F:FnMut(&mut dyn Backend)->R, R>(&mut self, f:F) -> R{
(*self.buffer).borrow_mut().with_backend_mut(f)
}
}
#[cfg(not(feature="webgl"))]
impl<T> WithMapRange<T> for SharedBuffer<T>{
fn with_map_range_read<F: FnMut(&[T])>(&self, offset: usize, length: usize, flags: MapReadFlags, mut f: F) -> Result<()>{
(*self.buffer)
.borrow()
.with_map_range_read(offset, length, flags, |u8_data| f(to_t(u8_data)))
}
}
#[cfg(not(feature="webgl"))]
impl<T> WithMapRangeMut<T> for SharedBuffer<T>{
unsafe fn with_map_range_write<F: FnMut(&mut [T])>(&mut self, offset: usize, length: usize, flags: MapWriteFlags, mut f: F) -> Result<()>{
(*self.buffer)
.borrow_mut()
.with_map_range_write(offset, length, flags, |u8_data| f(to_t_mut(u8_data)))
}
fn with_map_range_read_write<F: FnMut(&mut [T])>(&mut self, offset: usize, length: usize, flags: MapReadWriteFlags, mut f: F) -> Result<()>{
(*self.buffer)
.borrow_mut()
.with_map_range_read_write(offset, length, flags, |u8_data| f(to_t_mut(u8_data)))
}
}
impl<T: 'static> From<Buffer<T>> for SharedBuffer<T>{
fn from(buffer: Buffer<T>) -> SharedBuffer<T>{
let buffer = Buffer{
len: buffer.bytes(),
reserved: buffer.capacity_bytes(),
backend: buffer.backend,
marker: marker::PhantomData,
};
SharedBuffer{
buffer: Rc::new(RefCell::new(buffer)),
marker: PhantomData,
}
}
}
impl<'a, T: 'static> TypedBuffer<T> for &SharedBuffer<T>{
fn id(&self) -> GLuint{
(*self).id()
}
fn len(&self) -> usize{
(*self).len()
}
fn capacity(&self) -> usize{
(*self).capacity()
}
#[cfg(not(feature="webgl"))]
fn with_map_read<F: FnMut(&[T])>(&self, flags: MapReadFlags, f: F) -> Result<()>{
(*self).with_map_read(flags, f)
}
fn copy_to<U, BB:BufferRange<U> + WithBackendMut>(&self, dst: &mut BB) where Self: Sized{
(*self).copy_to(dst)
}
#[cfg(not(feature="webgl"))]
unsafe fn unmap(&self){
(*self).unmap()
}
}
impl<'a, T: 'static> BufferRange<T> for &SharedBuffer<T>{
fn start(&self) -> usize{
0
}
fn end(&self) -> usize{
(*self).len()
}
fn into_range<R: InputRange>(self, range: R) -> super::Range<T, Self, Self> where Self: Sized{
Range{
range: range.to_range(&self),
buffer: self,
marker_type: PhantomData,
marker_buffer: PhantomData,
}
}
}
#[cfg(not(feature="webgl"))]
impl<'a, T> MapRange<T> for SharedBuffer<T>{
fn map_range_read(&mut self, offset: usize, length: usize, flags: MapReadFlags) -> Result<MapRead<T, Self>>{
if offset + length > self.capacity() {
return Err(Error::new(::ErrorKind::OutOfBounds,None));
}
let bytes_offset = offset * mem::size_of::<T>();
let length_offset = length * mem::size_of::<T>();
let data = unsafe{ self.buffer.borrow().backend.map_range(
bytes_offset as GLintptr,
length_offset as GLsizeiptr,
gl::MAP_READ_BIT | flags.bits()
) };
if data.is_null() {
Err(Error::new(::ErrorKind::MapError,None))
}else{
unsafe{
let slice = slice::from_raw_parts(data as *const T, length);
Ok(MapRead{
map: slice,
buffer: self
})
}
}
}
}
#[cfg(not(feature = "webgl"))]
impl<'a, T> MapRangeMut<T> for SharedBuffer<T>{
fn map_range_write(&mut self, offset: usize, length: usize, flags: MapWriteFlags) -> Result<MapWrite<T, Self>>{
if offset + length > self.capacity() {
return Err(Error::new(::ErrorKind::OutOfBounds,None));
}
let bytes_offset = offset * mem::size_of::<T>();
let length_offset = length * mem::size_of::<T>();
let data = unsafe{ self.buffer.borrow().backend.map_range(
bytes_offset as GLintptr,
length_offset as GLsizeiptr,
gl::MAP_WRITE_BIT | flags.bits()
) };
if data.is_null(){
Err(Error::new(::ErrorKind::MapError,None))
}else{
unsafe{
let slice = slice::from_raw_parts_mut(data as *mut T, length);
Ok(MapWrite{
map: slice,
dropper: MapDropper{ buffer: self }
})
}
}
}
fn map_range_read_write(&mut self, offset: usize, length: usize, flags: MapReadWriteFlags) -> Result<MapReadWrite<T, Self>>{
if offset + length > self.capacity(){
return Err(Error::new(::ErrorKind::OutOfBounds,None));
}
let bytes_offset = offset * mem::size_of::<T>();
let length_offset = length * mem::size_of::<T>();
let data = unsafe{ self.buffer.borrow().backend.map_range(
bytes_offset as GLintptr,
length_offset as GLsizeiptr,
gl::MAP_READ_BIT | gl::MAP_WRITE_BIT | flags.bits()
) };
if data.is_null(){
Err(Error::new(::ErrorKind::MapError,None))
}else{
unsafe{
let slice = slice::from_raw_parts_mut(data as *mut T, length);
Ok(MapReadWrite{
map: slice,
dropper: MapDropper{buffer: self}
})
}
}
}
}