use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
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::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;
use OomError;
use SafeDeref;
#[derive(Debug)]
pub struct DeviceLocalBuffer<T: ?Sized, A = Arc<StdMemoryPool>> where A: MemoryPool {
inner: UnsafeBuffer,
memory: A::Alloc,
queue_families: SmallVec<[u32; 4]>,
gpu_lock: AtomicUsize,
marker: PhantomData<Box<T>>,
}
impl<T> DeviceLocalBuffer<T> {
#[inline]
pub fn new<'a, I>(device: Arc<Device>, usage: BufferUsage, queue_families: I)
-> Result<Arc<DeviceLocalBuffer<T>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
unsafe {
DeviceLocalBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
}
}
}
impl<T> DeviceLocalBuffer<[T]> {
#[inline]
pub fn array<'a, I>(device: Arc<Device>, len: usize, usage: BufferUsage, queue_families: I)
-> Result<Arc<DeviceLocalBuffer<[T]>>, OomError>
where I: IntoIterator<Item = QueueFamily<'a>>
{
unsafe {
DeviceLocalBuffer::raw(device, len * mem::size_of::<T>(), usage, queue_families)
}
}
}
impl<T: ?Sized> DeviceLocalBuffer<T> {
pub unsafe fn raw<'a, I>(device: Arc<Device>, size: usize, usage: BufferUsage, queue_families: I)
-> Result<Arc<DeviceLocalBuffer<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 = {
let device_local = device.physical_device().memory_types()
.filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
.filter(|t| t.is_device_local());
let any = device.physical_device().memory_types()
.filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
device_local.chain(any).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);
try!(buffer.bind_memory(mem.memory(), mem.offset()));
Ok(Arc::new(DeviceLocalBuffer {
inner: buffer,
memory: mem,
queue_families: queue_families,
gpu_lock: AtomicUsize::new(0),
marker: PhantomData,
}))
}
}
impl<T: ?Sized, A> DeviceLocalBuffer<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()
}
}
#[derive(Debug, Copy, Clone)]
pub struct DeviceLocalBufferAccess<P>(P);
unsafe impl<T: ?Sized, A> Buffer for Arc<DeviceLocalBuffer<T, A>>
where T: 'static + Send + Sync,
A: MemoryPool + 'static
{
type Access = DeviceLocalBufferAccess<Arc<DeviceLocalBuffer<T, A>>>;
#[inline]
fn access(self) -> Self::Access {
DeviceLocalBufferAccess(self)
}
#[inline]
fn size(&self) -> usize {
self.inner.size()
}
}
unsafe impl<T: ?Sized, A> TypedBuffer for Arc<DeviceLocalBuffer<T, A>>
where T: 'static + Send + Sync,
A: MemoryPool + 'static
{
type Content = T;
}
unsafe impl<P, T: ?Sized, A> BufferAccess for DeviceLocalBufferAccess<P>
where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
T: 'static + Send + Sync,
A: MemoryPool + 'static
{
#[inline]
fn inner(&self) -> BufferInner {
BufferInner {
buffer: &self.0.inner,
offset: 0,
}
}
#[inline]
fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
self.0.inner.key()
}
#[inline]
fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
Ok(())
}
#[inline]
unsafe fn increase_gpu_lock(&self) {
}
}
unsafe impl<P, T: ?Sized, A> TypedBufferAccess for DeviceLocalBufferAccess<P>
where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
T: 'static + Send + Sync,
A: MemoryPool + 'static
{
type Content = T;
}
unsafe impl<P, T: ?Sized, A> DeviceOwned for DeviceLocalBufferAccess<P>
where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
T: 'static + Send + Sync,
A: MemoryPool + 'static
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.0.inner.device()
}
}