use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ptr;
use std::sync::Arc;
use std::sync::RwLock;
use std::sync::RwLockReadGuard;
use std::sync::RwLockWriteGuard;
use std::sync::TryLockError;
use smallvec::SmallVec;
use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::BufferUsage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
use buffer::traits::TypedBuffer;
use buffer::traits::TypedBufferAccess;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use instance::QueueFamily;
use memory::Content;
use memory::CpuAccess as MemCpuAccess;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;
use sync::AccessFlagBits;
use sync::PipelineStages;
use OomError;
#[derive(Debug)]
pub struct CpuAccessibleBuffer<T: ?Sized, A = Arc<StdMemoryPool>> where A: MemoryPool {
inner: UnsafeBuffer,
memory: A::Alloc,
access: RwLock<()>,
queue_families: SmallVec<[u32; 4]>,
marker: PhantomData<Box<T>>,
}
impl<T> CpuAccessibleBuffer<T> {
#[deprecated]
#[inline]
pub fn new<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
unsafe {
CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
}
}
pub fn from_data<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I, data: T)
-> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>,
T: Content + 'static,
{
unsafe {
let uninitialized = try!(
CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
);
{
let mut mapping = uninitialized.write().unwrap();
ptr::write::<T>(&mut *mapping, data)
}
Ok(uninitialized)
}
}
#[inline]
pub unsafe fn uninitialized<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
CpuAccessibleBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
}
}
impl<T> CpuAccessibleBuffer<[T]> {
pub fn from_iter<'a, I, Q>(device: Arc<Device>, usage: BufferUsage, queue_families: Q, data: I)
-> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
where I: ExactSizeIterator<Item = T>,
T: Content + 'static,
Q: IntoIterator<Item = QueueFamily<'a>>
{
unsafe {
let uninitialized = try!(
CpuAccessibleBuffer::uninitialized_array(device, data.len(), usage, queue_families)
);
{
let mut mapping = uninitialized.write().unwrap();
for (i, o) in data.zip(mapping.iter_mut()) {
ptr::write(o, i);
}
}
Ok(uninitialized)
}
}
#[inline]
#[deprecated]
pub fn array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage, queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
unsafe {
CpuAccessibleBuffer::uninitialized_array(device, len, usage, queue_families)
}
}
#[inline]
pub unsafe fn uninitialized_array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage,
queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<[T]>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
CpuAccessibleBuffer::raw(device, len * mem::size_of::<T>(), usage, queue_families)
}
}
impl<T: ?Sized> CpuAccessibleBuffer<T> {
pub unsafe fn raw<'a, I>(device: Arc<Device>, size: usize, usage: BufferUsage, queue_families: I)
-> Result<Arc<CpuAccessibleBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
let queue_families = queue_families.into_iter().map(|f| f.id())
.collect::<SmallVec<[u32; 4]>>();
let (buffer, mem_reqs) = {
let sharing = if queue_families.len() >= 2 {
Sharing::Concurrent(queue_families.iter().cloned())
} else {
Sharing::Exclusive
};
match UnsafeBuffer::new(device.clone(), size, usage, sharing, SparseLevel::none()) {
Ok(b) => b,
Err(BufferCreationError::OomError(err)) => return Err(err),
Err(_) => unreachable!() }
};
let mem_ty = device.physical_device().memory_types()
.filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
.filter(|t| t.is_host_visible())
.next().unwrap();
let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
mem_reqs.size, mem_reqs.alignment, AllocLayout::Linear));
debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
debug_assert!(mem.mapped_memory().is_some());
try!(buffer.bind_memory(mem.memory(), mem.offset()));
Ok(Arc::new(CpuAccessibleBuffer {
inner: buffer,
memory: mem,
access: RwLock::new(()),
queue_families: queue_families,
marker: PhantomData,
}))
}
}
impl<T: ?Sized, A> CpuAccessibleBuffer<T, A> where A: MemoryPool {
#[inline]
pub fn device(&self) -> &Arc<Device> {
self.inner.device()
}
#[inline]
pub fn queue_families(&self) -> Vec<QueueFamily> {
self.queue_families.iter().map(|&num| {
self.device().physical_device().queue_family_by_id(num).unwrap()
}).collect()
}
}
impl<T: ?Sized, A> CpuAccessibleBuffer<T, A> where T: Content + 'static, A: MemoryPool {
#[inline]
pub fn read(&self) -> Result<ReadLock<T>, TryLockError<RwLockReadGuard<()>>> {
let lock = try!(self.access.try_read());
let offset = self.memory.offset();
let range = offset .. offset + self.inner.size();
Ok(ReadLock {
inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
lock: lock,
})
}
#[inline]
pub fn write(&self) -> Result<WriteLock<T>, TryLockError<RwLockWriteGuard<()>>> {
let lock = try!(self.access.try_write());
let offset = self.memory.offset();
let range = offset .. offset + self.inner.size();
Ok(WriteLock {
inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
lock: lock,
})
}
}
unsafe impl<T: ?Sized, A> Buffer for Arc<CpuAccessibleBuffer<T, A>>
where T: 'static + Send + Sync, A: MemoryPool
{
type Access = Self;
#[inline]
fn access(self) -> Self {
self
}
#[inline]
fn size(&self) -> usize {
self.inner.size()
}
}
unsafe impl<T: ?Sized, A> TypedBuffer for Arc<CpuAccessibleBuffer<T, A>>
where T: 'static + Send + Sync, A: MemoryPool
{
type Content = T;
}
unsafe impl<T: ?Sized, A> BufferAccess for CpuAccessibleBuffer<T, A>
where T: 'static + Send + Sync, A: MemoryPool
{
#[inline]
fn inner(&self) -> BufferInner {
BufferInner {
buffer: &self.inner,
offset: 0,
}
}
#[inline]
fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
self.inner.key()
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
Ok(()) }
#[inline]
unsafe fn increase_gpu_lock(&self) {
}
}
unsafe impl<T: ?Sized, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
where T: 'static + Send + Sync, A: MemoryPool
{
type Content = T;
}
unsafe impl<T: ?Sized, A> DeviceOwned for CpuAccessibleBuffer<T, A>
where A: MemoryPool
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
pub struct CpuAccessibleBufferClState {
size: usize,
stages: PipelineStages,
access: AccessFlagBits,
first_stages: Option<PipelineStages>,
write: bool,
earliest_previous_transition: usize,
needs_flush_at_the_end: bool,
}
pub struct CpuAccessibleBufferFinished {
first_stages: PipelineStages,
write: bool,
}
pub struct ReadLock<'a, T: ?Sized + 'a> {
inner: MemCpuAccess<'a, T>,
lock: RwLockReadGuard<'a, ()>,
}
impl<'a, T: ?Sized + 'a> ReadLock<'a, T> {
#[inline]
pub fn map<U: ?Sized + 'a, F>(self, f: F) -> ReadLock<'a, U>
where F: FnOnce(&mut T) -> &mut U
{
ReadLock {
inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
lock: self.lock,
}
}
}
impl<'a, T: ?Sized + 'a> Deref for ReadLock<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.inner.deref()
}
}
pub struct WriteLock<'a, T: ?Sized + 'a> {
inner: MemCpuAccess<'a, T>,
lock: RwLockWriteGuard<'a, ()>,
}
impl<'a, T: ?Sized + 'a> WriteLock<'a, T> {
#[inline]
pub fn map<U: ?Sized + 'a, F>(self, f: F) -> WriteLock<'a, U>
where F: FnOnce(&mut T) -> &mut U
{
WriteLock {
inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
lock: self.lock,
}
}
}
impl<'a, T: ?Sized + 'a> Deref for WriteLock<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.inner.deref()
}
}
impl<'a, T: ?Sized + 'a> DerefMut for WriteLock<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.inner.deref_mut()
}
}