use std::fmt;
use std::mem;
use std::borrow::Cow;
use std::ops::Range;
use std::cell::RefCell;
use std::ops::{Deref, DerefMut};
use std::marker::PhantomData;
use sync::{self, LinearSyncFence};
use texture::{PixelValue, Texture1dDataSink};
use gl;
use backend::Facade;
use BufferViewExt;
use BufferViewSliceExt;
use GlObject;
use context::Context;
use context::CommandContext;
use std::rc::Rc;
use ContextExt;
use buffer::BufferType;
use buffer::BufferCreationError;
use buffer::alloc::Buffer;
use buffer::alloc::Mapping as BufferMapping;
pub struct BufferView<T> where T: Copy + Send + 'static {
alloc: Option<Buffer>,
num_elements: usize,
fence: RefCell<Option<LinearSyncFence>>,
marker: PhantomData<T>,
}
impl<T> fmt::Debug for BufferView<T> where T: Copy + Send + 'static {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{:?}", self.alloc.as_ref().unwrap())
}
}
impl<T> Drop for BufferView<T> where T: Copy + Send + 'static {
fn drop(&mut self) {
let fence = self.fence.borrow_mut().take();
if let Some(fence) = fence {
let mut ctxt = self.alloc.as_ref().unwrap().get_context().make_current();
unsafe { sync::destroy_linear_sync_fence(&mut ctxt, fence) };
}
}
}
pub struct Mapping<'a, T> {
mapping: BufferMapping<'a, T>,
}
impl<'a, T> Deref for Mapping<'a, T> {
type Target = [T];
fn deref<'b>(&'b self) -> &'b [T] {
self.mapping.deref()
}
}
impl<'a, T> DerefMut for Mapping<'a, T> {
fn deref_mut<'b>(&'b mut self) -> &'b mut [T] {
self.mapping.deref_mut()
}
}
#[derive(Copy, Clone)]
pub struct BufferViewSlice<'a, T> where T: Copy + Send + 'static {
alloc: &'a Buffer,
offset_bytes: usize,
num_elements: usize,
fence: &'a RefCell<Option<LinearSyncFence>>,
marker: PhantomData<T>,
}
impl<'a, T> fmt::Debug for BufferViewSlice<'a, T> where T: Copy + Send + 'static {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{:?}", self.alloc)
}
}
pub struct BufferViewMutSlice<'a, T> where T: Copy + Send + 'static {
alloc: &'a mut Buffer,
offset_bytes: usize,
num_elements: usize,
fence: &'a RefCell<Option<LinearSyncFence>>,
marker: PhantomData<T>,
}
impl<'a, T> fmt::Debug for BufferViewMutSlice<'a, T> where T: Copy + Send + 'static {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{:?}", self.alloc)
}
}
pub struct BufferViewAny {
alloc: Buffer,
elements_size: usize,
elements_count: usize,
fence: RefCell<Option<LinearSyncFence>>,
}
impl Drop for BufferViewAny {
fn drop(&mut self) {
let fence = self.fence.borrow_mut().take();
if let Some(fence) = fence {
let mut ctxt = self.alloc.get_context().make_current();
unsafe { sync::destroy_linear_sync_fence(&mut ctxt, fence) };
}
}
}
impl fmt::Debug for BufferViewAny {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{:?}", self.alloc)
}
}
#[derive(Copy, Clone)]
pub struct BufferViewAnySlice<'a> {
alloc: &'a Buffer,
offset_bytes: usize,
elements_size: usize,
elements_count: usize,
fence: &'a RefCell<Option<LinearSyncFence>>,
}
impl<'a> fmt::Debug for BufferViewAnySlice<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{:?}", self.alloc)
}
}
impl<T> From<BufferView<T>> for BufferViewAny where T: Copy + Send + 'static {
fn from(mut buffer: BufferView<T>) -> BufferViewAny {
BufferViewAny {
alloc: buffer.alloc.take().unwrap(),
elements_size: mem::size_of::<T>(),
elements_count: buffer.num_elements,
fence: RefCell::new(buffer.fence.borrow_mut().take()),
}
}
}
impl<T> BufferView<T> where T: Copy + Send + 'static {
pub fn new<F>(facade: &F, data: &[T], ty: BufferType, dynamic: bool)
-> Result<BufferView<T>, BufferCreationError>
where F: Facade
{
let len = data.len();
Buffer::new(facade, data, ty, dynamic)
.map(|buffer| {
BufferView {
alloc: Some(buffer),
num_elements: len,
fence: RefCell::new(None),
marker: PhantomData,
}
})
}
pub fn empty<F>(facade: &F, ty: BufferType, len: usize, dynamic: bool)
-> Result<BufferView<T>, BufferCreationError> where F: Facade
{
Buffer::empty(facade, ty, len * mem::size_of::<T>(), dynamic)
.map(|buffer| {
BufferView {
alloc: Some(buffer),
num_elements: len,
fence: RefCell::new(None),
marker: PhantomData,
}
})
}
pub fn get_context(&self) -> &Rc<Context> {
self.alloc.as_ref().unwrap().get_context()
}
pub fn len(&self) -> usize {
self.num_elements
}
pub fn is_persistent(&self) -> bool {
self.alloc.as_ref().unwrap().uses_persistent_mapping()
}
pub fn write<P>(&self, data: P) where P: AsRef<[T]> {
self.as_slice().write(data);
}
pub fn invalidate(&self) {
self.as_slice().invalidate()
}
#[cfg(feature = "gl_read_buffer")]
pub fn read(&self) -> Vec<T> {
match self.read_if_supported() {
Some(buf) => buf,
None => unreachable!()
}
}
pub fn read_if_supported(&self) -> Option<Vec<T>> {
self.as_slice().read_if_supported()
}
pub fn map(&mut self) -> Mapping<T> {
self.as_mut_slice().map()
}
pub fn slice(&self, range: Range<usize>) -> Option<BufferViewSlice<T>> {
self.as_slice().slice(range)
}
pub fn slice_mut(&mut self, range: Range<usize>) -> Option<BufferViewMutSlice<T>> {
self.as_mut_slice().slice(range)
}
pub fn as_slice(&self) -> BufferViewSlice<T> {
BufferViewSlice {
alloc: self.alloc.as_ref().unwrap(),
offset_bytes: 0,
num_elements: self.num_elements,
fence: &self.fence,
marker: PhantomData,
}
}
pub fn as_mut_slice(&mut self) -> BufferViewMutSlice<T> {
BufferViewMutSlice {
alloc: self.alloc.as_mut().unwrap(),
offset_bytes: 0,
num_elements: self.num_elements,
fence: &self.fence,
marker: PhantomData,
}
}
pub fn as_slice_any(&self) -> BufferViewAnySlice {
BufferViewAnySlice {
alloc: self.alloc.as_ref().unwrap(),
offset_bytes: 0,
elements_size: mem::size_of::<T>(),
elements_count: self.num_elements,
fence: &self.fence,
}
}
}
impl<T> BufferView<T> where T: PixelValue {
#[cfg(feature = "gl_read_buffer")]
pub fn read_as_texture_1d<S>(&self) -> S where S: Texture1dDataSink<T> {
S::from_raw(Cow::Owned(self.read()), self.len() as u32)
}
pub fn read_as_texture_1d_if_supported<S>(&self) -> Option<S> where S: Texture1dDataSink<T> {
self.read_if_supported().map(|data| {
S::from_raw(Cow::Owned(data), self.len() as u32)
})
}
}
impl<'a, T> BufferViewSlice<'a, T> where T: Copy + Send + 'static {
pub fn len(&self) -> usize {
self.num_elements
}
pub fn write<P>(&self, data: P) where P: AsRef<[T]> {
let data = data.as_ref();
assert!(data.len() == self.num_elements);
consume_fence(self.alloc.get_context(), self.fence);
unsafe { self.alloc.upload(self.offset_bytes, data); }
}
pub fn invalidate(&self) {
self.alloc.invalidate(self.offset_bytes, self.num_elements * mem::size_of::<T>());
}
#[cfg(feature = "gl_read_buffer")]
pub fn read(&self) -> Vec<T> {
self.read_if_supported().unwrap()
}
pub fn read_if_supported(&self) -> Option<Vec<T>> {
consume_fence(self.alloc.get_context(), self.fence);
unsafe {
let mut data = Vec::with_capacity(self.num_elements);
data.set_len(self.num_elements);
match self.alloc.read_if_supported(self.offset_bytes, &mut data) {
Err(_) => return None,
Ok(_) => ()
};
Some(data)
}
}
pub fn slice(&self, range: Range<usize>) -> Option<BufferViewSlice<'a, T>> {
if range.start > self.num_elements || range.end > self.num_elements {
return None;
}
Some(BufferViewSlice {
alloc: self.alloc,
offset_bytes: self.offset_bytes + range.start * mem::size_of::<T>(),
num_elements: range.end - range.start,
fence: self.fence,
marker: PhantomData,
})
}
pub fn as_slice_any(&self) -> BufferViewAnySlice<'a> {
BufferViewAnySlice {
alloc: self.alloc,
offset_bytes: self.offset_bytes,
elements_size: mem::size_of::<T>(),
elements_count: self.num_elements,
fence: self.fence,
}
}
}
impl<'a, T> BufferViewSlice<'a, T> where T: PixelValue {
#[cfg(feature = "gl_read_buffer")]
pub fn read_as_texture_1d<S>(&self) -> S where S: Texture1dDataSink<T> {
S::from_raw(Cow::Owned(self.read()), self.len() as u32)
}
pub fn read_as_texture_1d_if_supported<S>(&self) -> Option<S> where S: Texture1dDataSink<T> {
self.read_if_supported().map(|data| {
S::from_raw(Cow::Owned(data), self.len() as u32)
})
}
}
impl<'a, T> BufferViewMutSlice<'a, T> where T: Copy + Send + 'static {
pub fn len(&self) -> usize {
self.num_elements
}
pub fn map(self) -> Mapping<'a, T> {
consume_fence(self.alloc.get_context(), self.fence);
unsafe {
Mapping {
mapping: self.alloc.map_mut(self.offset_bytes, self.num_elements),
}
}
}
pub fn write<P>(&self, data: P) where P: AsRef<[T]> {
let data = data.as_ref();
assert!(data.len() == self.num_elements);
consume_fence(self.alloc.get_context(), self.fence);
unsafe { self.alloc.upload(self.offset_bytes, data); }
}
pub fn invalidate(&self) {
self.alloc.invalidate(self.offset_bytes, self.num_elements * mem::size_of::<T>());
}
#[cfg(feature = "gl_read_buffer")]
pub fn read(&self) -> Vec<T> {
self.read_if_supported().unwrap()
}
pub fn read_if_supported(&self) -> Option<Vec<T>> {
unsafe {
let mut data = Vec::with_capacity(self.num_elements);
data.set_len(self.num_elements);
match self.alloc.read_if_supported(self.offset_bytes, &mut data) {
Err(_) => return None,
Ok(_) => ()
};
Some(data)
}
}
pub fn slice(self, range: Range<usize>) -> Option<BufferViewMutSlice<'a, T>> {
if range.start > self.num_elements || range.end > self.num_elements {
return None;
}
Some(BufferViewMutSlice {
alloc: self.alloc,
offset_bytes: self.offset_bytes + range.start * mem::size_of::<T>(),
num_elements: range.end - range.start,
fence: self.fence,
marker: PhantomData,
})
}
pub fn as_slice_any(self) -> BufferViewAnySlice<'a> {
BufferViewAnySlice {
alloc: self.alloc,
offset_bytes: self.offset_bytes,
elements_size: mem::size_of::<T>(),
elements_count: self.num_elements,
fence: self.fence,
}
}
}
impl<'a, T> BufferViewMutSlice<'a, T> where T: PixelValue {
#[cfg(feature = "gl_read_buffer")]
pub fn read_as_texture_1d<S>(&self) -> S where S: Texture1dDataSink<T> {
S::from_raw(Cow::Owned(self.read()), self.len() as u32)
}
pub fn read_as_texture_1d_if_supported<S>(&self) -> Option<S> where S: Texture1dDataSink<T> {
self.read_if_supported().map(|data| {
S::from_raw(Cow::Owned(data), self.len() as u32)
})
}
}
impl BufferViewAny {
pub fn as_slice_any(&self) -> BufferViewAnySlice {
BufferViewAnySlice {
alloc: &self.alloc,
offset_bytes: 0,
elements_size: self.elements_size,
elements_count: self.elements_count,
fence: &self.fence,
}
}
pub fn get_context(&self) -> &Rc<Context> {
self.alloc.get_context()
}
pub fn get_elements_size(&self) -> usize {
self.elements_size
}
pub fn get_elements_count(&self) -> usize {
self.elements_count
}
pub fn get_size(&self) -> usize {
self.elements_size * self.elements_count
}
pub fn invalidate(&self) {
self.alloc.invalidate(0, self.elements_count * self.elements_size);
}
pub unsafe fn read_if_supported<T>(&self) -> Option<Vec<T>> where T: Copy + Send + 'static {
assert!(self.get_size() % mem::size_of::<T>() == 0);
consume_fence(self.alloc.get_context(), &self.fence);
let len = self.get_size() / mem::size_of::<T>();
let mut data = Vec::with_capacity(len);
data.set_len(len);
match self.alloc.read_if_supported(0, &mut data) {
Err(_) => return None,
Ok(_) => ()
};
Some(data)
}
}
impl<'a> BufferViewAnySlice<'a> {
pub fn get_elements_size(&self) -> usize {
self.elements_size
}
pub fn get_elements_count(&self) -> usize {
self.elements_count
}
pub fn get_size(&self) -> usize {
self.elements_size * self.elements_count
}
pub fn invalidate(&self) {
self.alloc.invalidate(self.offset_bytes, self.get_size());
}
}
impl<T> BufferViewExt for BufferView<T> where T: Copy + Send + 'static {
fn get_offset_bytes(&self) -> usize {
0
}
fn get_buffer_id(&self) -> gl::types::GLuint {
let alloc = self.alloc.as_ref().unwrap();
alloc.get_id()
}
fn prepare_for_vertex_attrib_array(&self, ctxt: &mut CommandContext) {
let alloc = self.alloc.as_ref().unwrap();
alloc.prepare_for_vertex_attrib_array(ctxt);
}
fn prepare_for_element_array(&self, ctxt: &mut CommandContext) {
let alloc = self.alloc.as_ref().unwrap();
alloc.prepare_for_element_array(ctxt);
}
fn bind_to_element_array(&self, ctxt: &mut CommandContext) {
let alloc = self.alloc.as_ref().unwrap();
alloc.bind_to_element_array(ctxt);
}
fn prepare_and_bind_for_pixel_pack(&self, ctxt: &mut CommandContext) {
let alloc = self.alloc.as_ref().unwrap();
alloc.prepare_and_bind_for_pixel_pack(ctxt);
}
fn unbind_pixel_pack(ctxt: &mut CommandContext) {
Buffer::unbind_pixel_pack(ctxt)
}
fn prepare_and_bind_for_pixel_unpack(&self, ctxt: &mut CommandContext) {
let alloc = self.alloc.as_ref().unwrap();
alloc.prepare_and_bind_for_pixel_unpack(ctxt);
}
fn unbind_pixel_unpack(ctxt: &mut CommandContext) {
Buffer::unbind_pixel_unpack(ctxt)
}
fn prepare_and_bind_for_draw_indirect(&self, ctxt: &mut CommandContext) {
let alloc = self.alloc.as_ref().unwrap();
alloc.prepare_and_bind_for_draw_indirect(ctxt);
}
fn prepare_and_bind_for_uniform(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
let alloc = self.alloc.as_ref().unwrap();
alloc.prepare_and_bind_for_uniform(ctxt, index, 0 .. alloc.get_size());
}
fn prepare_and_bind_for_shared_storage(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
let alloc = self.alloc.as_ref().unwrap();
alloc.prepare_and_bind_for_shared_storage(ctxt, index, 0 .. alloc.get_size());
}
fn bind_to_transform_feedback(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
let alloc = self.alloc.as_ref().unwrap();
alloc.bind_to_transform_feedback(ctxt, index, 0 .. alloc.get_size());
}
}
impl<'a, T> BufferViewSliceExt<'a> for BufferViewSlice<'a, T> where T: Copy + Send + 'static {
fn add_fence(&self) -> Option<&'a RefCell<Option<LinearSyncFence>>> {
if !self.alloc.uses_persistent_mapping() {
return None;
}
Some(self.fence)
}
}
impl<'a, T> BufferViewExt for BufferViewSlice<'a, T> where T: Copy + Send + 'static {
fn get_offset_bytes(&self) -> usize {
self.offset_bytes
}
fn get_buffer_id(&self) -> gl::types::GLuint {
self.alloc.get_id()
}
fn prepare_for_vertex_attrib_array(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_for_vertex_attrib_array(ctxt);
}
fn prepare_for_element_array(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_for_element_array(ctxt);
}
fn bind_to_element_array(&self, ctxt: &mut CommandContext) {
self.alloc.bind_to_element_array(ctxt);
}
fn prepare_and_bind_for_pixel_pack(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_pixel_pack(ctxt);
}
fn unbind_pixel_pack(ctxt: &mut CommandContext) {
Buffer::unbind_pixel_pack(ctxt)
}
fn prepare_and_bind_for_pixel_unpack(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_pixel_unpack(ctxt);
}
fn unbind_pixel_unpack(ctxt: &mut CommandContext) {
Buffer::unbind_pixel_unpack(ctxt)
}
fn prepare_and_bind_for_draw_indirect(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_draw_indirect(ctxt);
}
fn prepare_and_bind_for_uniform(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.prepare_and_bind_for_uniform(ctxt, index, 0 .. self.alloc.get_size());
}
fn prepare_and_bind_for_shared_storage(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.prepare_and_bind_for_shared_storage(ctxt, index, 0 .. self.alloc.get_size());
}
fn bind_to_transform_feedback(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.bind_to_transform_feedback(ctxt, index, 0 .. self.alloc.get_size());
}
}
impl BufferViewExt for BufferViewAny {
fn get_offset_bytes(&self) -> usize {
0
}
fn get_buffer_id(&self) -> gl::types::GLuint {
self.alloc.get_id()
}
fn prepare_for_vertex_attrib_array(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_for_vertex_attrib_array(ctxt);
}
fn prepare_for_element_array(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_for_element_array(ctxt);
}
fn bind_to_element_array(&self, ctxt: &mut CommandContext) {
self.alloc.bind_to_element_array(ctxt);
}
fn prepare_and_bind_for_pixel_pack(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_pixel_pack(ctxt);
}
fn unbind_pixel_pack(ctxt: &mut CommandContext) {
Buffer::unbind_pixel_pack(ctxt)
}
fn prepare_and_bind_for_pixel_unpack(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_pixel_unpack(ctxt);
}
fn unbind_pixel_unpack(ctxt: &mut CommandContext) {
Buffer::unbind_pixel_unpack(ctxt)
}
fn prepare_and_bind_for_draw_indirect(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_draw_indirect(ctxt);
}
fn prepare_and_bind_for_uniform(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.prepare_and_bind_for_uniform(ctxt, index, 0 .. self.alloc.get_size());
}
fn prepare_and_bind_for_shared_storage(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.prepare_and_bind_for_shared_storage(ctxt, index, 0 .. self.alloc.get_size());
}
fn bind_to_transform_feedback(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.bind_to_transform_feedback(ctxt, index, 0 .. self.alloc.get_size());
}
}
impl<'a> BufferViewSliceExt<'a> for BufferViewAnySlice<'a> {
fn add_fence(&self) -> Option<&'a RefCell<Option<LinearSyncFence>>> {
if !self.alloc.uses_persistent_mapping() {
return None;
}
Some(self.fence)
}
}
impl<'a> BufferViewExt for BufferViewAnySlice<'a> {
fn get_offset_bytes(&self) -> usize {
self.offset_bytes
}
fn get_buffer_id(&self) -> gl::types::GLuint {
self.alloc.get_id()
}
fn prepare_for_vertex_attrib_array(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_for_vertex_attrib_array(ctxt);
}
fn prepare_for_element_array(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_for_element_array(ctxt);
}
fn bind_to_element_array(&self, ctxt: &mut CommandContext) {
self.alloc.bind_to_element_array(ctxt);
}
fn prepare_and_bind_for_pixel_pack(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_pixel_pack(ctxt);
}
fn unbind_pixel_pack(ctxt: &mut CommandContext) {
Buffer::unbind_pixel_pack(ctxt)
}
fn prepare_and_bind_for_pixel_unpack(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_pixel_unpack(ctxt);
}
fn unbind_pixel_unpack(ctxt: &mut CommandContext) {
Buffer::unbind_pixel_unpack(ctxt)
}
fn prepare_and_bind_for_draw_indirect(&self, ctxt: &mut CommandContext) {
self.alloc.prepare_and_bind_for_draw_indirect(ctxt);
}
fn prepare_and_bind_for_uniform(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.prepare_and_bind_for_uniform(ctxt, index, 0 .. self.alloc.get_size());
}
fn prepare_and_bind_for_shared_storage(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.prepare_and_bind_for_shared_storage(ctxt, index, 0 .. self.alloc.get_size());
}
fn bind_to_transform_feedback(&self, ctxt: &mut CommandContext, index: gl::types::GLuint) {
self.alloc.bind_to_transform_feedback(ctxt, index, 0 .. self.alloc.get_size());
}
}
fn consume_fence(context: &Rc<Context>, fence: &RefCell<Option<LinearSyncFence>>) {
let fence = fence.borrow_mut().take();
if let Some(fence) = fence {
fence.into_sync_fence(context).wait();
}
}