use gl::types::*;
use gl;
use std::ptr;
use std::os::raw::c_void;
use ::Result;
use ::Error;
use std::fmt::{self, Debug};
use super::traits::Backend;
use state::StateRef;
pub struct BindBackend{
id: GLuint,
last_target: GLenum,
gl: StateRef,
}
impl PartialEq for BindBackend{
fn eq(&self, other: &BindBackend) -> bool{
self.id == other.id
}
}
impl Eq for BindBackend{}
impl Drop for BindBackend{
fn drop(&mut self){
unsafe{
self.gl.DeleteBuffers(1, &self.id);
}
}
}
impl Debug for BindBackend{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result{
fmt.debug_struct("glin::buffer_object::BindBackend")
.field("id", &self.id)
.finish()
}
}
impl BindBackend{
pub fn new(gl: &StateRef, size: GLsizeiptr, usage: GLenum, target: GLenum) -> Result<BindBackend>{
BindBackend::empty(gl, target).and_then(|mut backend| unsafe{
backend.load(ptr::null(), size as usize, usage);
let allocated = backend.get_parameter_iv(gl::BUFFER_SIZE, 1)[0];
if allocated as GLsizeiptr != size{
Err(Error::new(::ErrorKind::OutOfMemory, None))
}else{
Ok(backend)
}
})
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn new_immutable(gl: &StateRef, size: GLsizeiptr, flags: GLbitfield, target: GLenum) -> Result<BindBackend>{
BindBackend::empty(gl, target).and_then(|backend| unsafe{
backend.bind(backend.last_target);
gl.BufferStorage(backend.last_target, size, ptr::null(), flags);
let allocated = backend.get_parameter_iv(gl::BUFFER_SIZE, 1)[0];
if allocated as GLsizeiptr != size{
Err(Error::new(::ErrorKind::OutOfMemory, None))
}else{
Ok(backend)
}
})
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn immutable_from_data(gl: &StateRef, data: *const c_void, size: GLsizeiptr, flags: GLbitfield, target: GLenum) -> Result<BindBackend>{
BindBackend::empty(gl, target).and_then(|backend| unsafe{
backend.bind(backend.last_target);
gl.BufferStorage(backend.last_target, size, data, flags);
let allocated = backend.get_parameter_iv(gl::BUFFER_SIZE, 1)[0];
if allocated as GLsizeiptr != size{
Err(Error::new(::ErrorKind::OutOfMemory, None))
}else{
Ok(backend)
}
})
}
pub fn empty(gl: &StateRef, target: GLenum) -> Result<BindBackend>{
let mut id = 0;
unsafe{
gl.GenBuffers(1, &mut id);
if id != 0{
Ok(BindBackend{id: id, last_target: target, gl: gl.clone()})
}else{
gl.DeleteBuffers(1, &id);
Err(Error::new(::ErrorKind::OutOfMemory, None))
}
}
}
}
impl Backend for BindBackend{
fn id(&self) -> GLuint{
self.id
}
fn bind(&self, target: GLenum){
self.gl.state_mut().bind_buffer(target, self.id);
}
fn unbind(&self, target: GLenum){
self.gl.state_mut().bind_buffer(target, 0);
}
unsafe fn load(&mut self, data: *const c_void, len: usize, usage: GLenum){
self.bind(self.last_target);
self.gl.BufferData(self.last_target,
len as GLsizeiptr,
data,
usage);
self.unbind(self.last_target);
}
unsafe fn load_target(&mut self, data: *const c_void, len: usize, usage: GLenum, target: GLenum){
self.last_target = target;
self.bind(self.last_target);
self.gl.BufferData(self.last_target,
len as GLsizeiptr,
data,
usage);
self.unbind(self.last_target);
}
unsafe fn update(&mut self, data: *const c_void, len: usize, offset: usize){
self.bind(self.last_target);
self.gl.BufferSubData(self.last_target,
offset as GLintptr,
len as GLsizeiptr,
data);
self.unbind(self.last_target);
}
#[cfg(not(feature="webgl"))]
unsafe fn unmap(&self){
self.bind(self.last_target);
self.gl.UnmapBuffer(self.last_target);
self.unbind(self.last_target);
}
#[cfg(not(feature="webgl"))]
unsafe fn map_range(&self, offset: GLintptr, length: GLsizeiptr, access: GLenum) -> *const c_void{
self.bind(self.last_target);
let ret = self.gl.MapBufferRange(self.last_target, offset, length, access);
self.unbind(self.last_target);
ret
}
fn copy_to(&self, dst: &mut dyn Backend, read_offset: usize, write_offset: usize, size: usize){
self.bind(gl::COPY_READ_BUFFER);
dst.bind(gl::COPY_WRITE_BUFFER);
unsafe{
self.gl.CopyBufferSubData(
gl::COPY_READ_BUFFER,
gl::COPY_WRITE_BUFFER,
read_offset as GLintptr,
write_offset as GLintptr,
size as GLsizeiptr);
}
self.unbind(gl::COPY_READ_BUFFER);
dst.unbind(gl::COPY_WRITE_BUFFER);
}
unsafe fn get_parameter_iv(&self, parameter: GLenum, len: usize) -> Vec<GLint>{
let mut ret = Vec::with_capacity(len);
ret.set_len(len);
self.bind(self.last_target);
self.gl.GetBufferParameteriv(self.last_target, parameter, ret.as_mut_ptr());
self.unbind(self.last_target);
ret
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[derive(Eq, PartialEq)]
pub struct DsaBackend{
id: GLuint,
gl: StateRef,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl Debug for DsaBackend{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result{
fmt.debug_struct("glin::buffer_object::DsaBackend")
.field("id", &self.id)
.finish()
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl Drop for DsaBackend{
fn drop(&mut self){
unsafe{
self.gl.DeleteBuffers(1, &self.id);
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl DsaBackend{
pub fn new(gl: &StateRef, size: GLsizeiptr, usage: GLenum) -> Result<DsaBackend>{
DsaBackend::empty(gl).and_then(|mut backend| unsafe{
backend.load(ptr::null(), size as usize, usage);
let allocated = backend.get_parameter_iv(gl::BUFFER_SIZE, 1)[0];
if allocated as GLsizeiptr != size{
Err(Error::new(::ErrorKind::OutOfMemory, None))
}else{
Ok(backend)
}
})
}
pub fn new_immutable(gl: &StateRef, size: GLsizeiptr, flags: GLbitfield) -> Result<DsaBackend>{
DsaBackend::empty(gl).and_then(|backend| unsafe{
gl.NamedBufferStorage(backend.id, size, ptr::null(), flags);
let allocated = backend.get_parameter_iv(gl::BUFFER_SIZE, 1)[0];
if allocated as GLsizeiptr != size{
Err(Error::new(::ErrorKind::OutOfMemory, None))
}else{
Ok(backend)
}
})
}
pub fn immutable_from_data(gl: &StateRef, data: *const c_void, size: GLsizeiptr, flags: GLbitfield) -> Result<DsaBackend>{
DsaBackend::empty(gl).and_then(|backend| unsafe{
gl.NamedBufferStorage(backend.id, size, data, flags);
let allocated = backend.get_parameter_iv(gl::BUFFER_SIZE, 1)[0];
if allocated as GLsizeiptr != size{
Err(Error::new(::ErrorKind::OutOfMemory, None))
}else{
Ok(backend)
}
})
}
pub fn empty(gl: &StateRef) -> Result<DsaBackend>{
let mut id = 0;
unsafe{
gl.CreateBuffers(1, &mut id);
if id != 0{
Ok(DsaBackend{id, gl: gl.clone()})
}else{
Err(Error::new(::ErrorKind::OutOfMemory, None))
}
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl Backend for DsaBackend{
fn id(&self) -> GLuint{
self.id
}
fn bind(&self, _: GLenum){
unimplemented!()
}
fn unbind(&self, _target: GLenum){
unimplemented!()
}
unsafe fn load(&mut self, data: *const c_void, len: usize, usage: GLenum){
self.gl.NamedBufferData(self.id,
len as GLsizeiptr,
data,
usage);
}
unsafe fn load_target(&mut self, data: *const c_void, len: usize, usage: GLenum, _: GLenum){
self.gl.NamedBufferData(self.id,
len as GLsizeiptr,
data,
usage);
}
unsafe fn update(&mut self, data: *const c_void, len: usize, offset: usize){
self.gl.NamedBufferSubData(self.id,
offset as GLintptr,
len as GLsizeiptr,
data);
}
unsafe fn unmap(&self){
self.gl.UnmapNamedBuffer(self.id);
}
unsafe fn map_range(&self, offset: GLintptr, length: GLsizeiptr, flags: GLenum) -> *const c_void{
self.gl.MapNamedBufferRange(self.id, offset, length, flags)
}
fn copy_to(&self, dst: &mut dyn Backend, read_offset: usize, write_offset: usize, size: usize){
unsafe{
self.gl.CopyNamedBufferSubData(
self.id,
dst.id(),
read_offset as GLintptr,
write_offset as GLintptr,
size as GLsizeiptr);
}
}
unsafe fn get_parameter_iv(&self, parameter: GLenum, len: usize) -> Vec<GLint>{
let mut ret = Vec::with_capacity(len);
ret.set_len(len);
self.gl.GetNamedBufferParameteriv(self.id, parameter, ret.as_mut_ptr());
ret
}
}