use std::error;
use std::fmt;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use buffer::BufferAccess;
use command_buffer::cb::UnsafeCommandBuffer;
use command_buffer::pool::CommandPool;
use command_buffer::submit::SubmitAnyBuilder;
use command_buffer::submit::SubmitCommandBufferBuilder;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::ImageLayout;
use image::ImageAccess;
use instance::QueueFamily;
use sync::now;
use sync::AccessError;
use sync::AccessCheckError;
use sync::AccessFlagBits;
use sync::FlushError;
use sync::NowFuture;
use sync::GpuFuture;
use sync::PipelineStages;
use SafeDeref;
use VulkanObject;
pub unsafe trait CommandBuffer: DeviceOwned {
type Pool: CommandPool;
fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool>;
#[inline]
fn queue_family(&self) -> QueueFamily {
self.inner().queue_family()
}
fn prepare_submit(&self, future: &GpuFuture, queue: &Queue)
-> Result<(), CommandBufferExecError>;
#[inline]
fn execute(self, queue: Arc<Queue>)
-> Result<CommandBufferExecFuture<NowFuture, Self>, CommandBufferExecError>
where Self: Sized + 'static
{
let device = queue.device().clone();
self.execute_after(now(device), queue)
}
#[inline]
fn execute_after<F>(self, future: F, queue: Arc<Queue>)
-> Result<CommandBufferExecFuture<F, Self>, CommandBufferExecError>
where Self: Sized + 'static, F: GpuFuture
{
assert_eq!(self.device().internal_object(), future.device().internal_object());
self.prepare_submit(&future, &queue)?;
if !future.queue_change_allowed() {
assert!(future.queue().unwrap().is_same(&queue));
}
Ok(CommandBufferExecFuture {
previous: future,
command_buffer: self,
queue: queue,
submitted: Mutex::new(false),
finished: AtomicBool::new(false),
})
}
fn check_buffer_access(&self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;
}
pub unsafe trait CommandBufferBuild {
type Out;
type Err;
fn build(self) -> Result<Self::Out, Self::Err>;
}
unsafe impl<T> CommandBuffer for T where T: SafeDeref, T::Target: CommandBuffer {
type Pool = <T::Target as CommandBuffer>::Pool;
#[inline]
fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool> {
(**self).inner()
}
#[inline]
fn prepare_submit(&self, future: &GpuFuture, queue: &Queue) -> Result<(), CommandBufferExecError> {
(**self).prepare_submit(future, queue)
}
#[inline]
fn check_buffer_access(&self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
(**self).check_buffer_access(buffer, exclusive, queue)
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
(**self).check_image_access(image, layout, exclusive, queue)
}
}
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct CommandBufferExecFuture<F, Cb> where F: GpuFuture, Cb: CommandBuffer {
previous: F,
command_buffer: Cb,
queue: Arc<Queue>,
submitted: Mutex<bool>,
finished: AtomicBool,
}
unsafe impl<F, Cb> GpuFuture for CommandBufferExecFuture<F, Cb>
where F: GpuFuture, Cb: CommandBuffer
{
#[inline]
fn cleanup_finished(&mut self) {
self.previous.cleanup_finished();
}
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
Ok(match try!(self.previous.build_submission()) {
SubmitAnyBuilder::Empty => {
let mut builder = SubmitCommandBufferBuilder::new();
builder.add_command_buffer(self.command_buffer.inner());
SubmitAnyBuilder::CommandBuffer(builder)
},
SubmitAnyBuilder::SemaphoresWait(sem) => {
let mut builder: SubmitCommandBufferBuilder = sem.into();
builder.add_command_buffer(self.command_buffer.inner());
SubmitAnyBuilder::CommandBuffer(builder)
},
SubmitAnyBuilder::CommandBuffer(mut builder) => {
builder.add_command_buffer(self.command_buffer.inner());
SubmitAnyBuilder::CommandBuffer(builder)
},
SubmitAnyBuilder::QueuePresent(present) => {
unimplemented!()
},
})
}
#[inline]
fn flush(&self) -> Result<(), FlushError> {
unsafe {
let mut submitted = self.submitted.lock().unwrap();
if *submitted {
return Ok(());
}
let queue = self.queue.clone();
match try!(self.build_submission()) {
SubmitAnyBuilder::Empty => {},
SubmitAnyBuilder::CommandBuffer(builder) => {
try!(builder.submit(&queue));
},
_ => unreachable!(),
};
*submitted = true;
Ok(())
}
}
#[inline]
unsafe fn signal_finished(&self) {
self.finished.store(true, Ordering::SeqCst);
self.previous.signal_finished();
}
#[inline]
fn queue_change_allowed(&self) -> bool {
false
}
#[inline]
fn queue(&self) -> Option<Arc<Queue>> {
Some(self.queue.clone())
}
#[inline]
fn check_buffer_access(&self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
match self.command_buffer.check_buffer_access(buffer, exclusive, queue) {
Ok(v) => Ok(v),
Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
Err(AccessCheckError::Unknown) => {
self.previous.check_buffer_access(buffer, exclusive, queue)
},
}
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
match self.command_buffer.check_image_access(image, layout, exclusive, queue) {
Ok(v) => Ok(v),
Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
Err(AccessCheckError::Unknown) => {
self.previous.check_image_access(image, layout, exclusive, queue)
},
}
}
}
unsafe impl<F, Cb> DeviceOwned for CommandBufferExecFuture<F, Cb>
where F: GpuFuture, Cb: CommandBuffer
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.command_buffer.device()
}
}
impl<F, Cb> Drop for CommandBufferExecFuture<F, Cb> where F: GpuFuture, Cb: CommandBuffer {
fn drop(&mut self) {
unsafe {
if !*self.finished.get_mut() {
self.flush().unwrap();
self.queue.wait().unwrap();
self.previous.signal_finished();
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CommandBufferExecError {
AccessError(AccessError),
}
impl error::Error for CommandBufferExecError {
#[inline]
fn description(&self) -> &str {
match *self {
CommandBufferExecError::AccessError(_) => "access to a resource has been denied",
}
}
#[inline]
fn cause(&self) -> Option<&error::Error> {
match *self {
CommandBufferExecError::AccessError(ref err) => Some(err),
}
}
}
impl fmt::Display for CommandBufferExecError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<AccessError> for CommandBufferExecError {
#[inline]
fn from(err: AccessError) -> CommandBufferExecError {
CommandBufferExecError::AccessError(err)
}
}