use std::error;
use std::fmt;
use std::sync::Arc;
use crate::buffer::BufferAccess;
use crate::command_buffer::submit::SubmitAnyBuilder;
use crate::command_buffer::submit::SubmitBindSparseError;
use crate::command_buffer::submit::SubmitCommandBufferError;
use crate::command_buffer::submit::SubmitPresentError;
use crate::command_buffer::CommandBuffer;
use crate::command_buffer::CommandBufferExecError;
use crate::command_buffer::CommandBufferExecFuture;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::swapchain;
use crate::swapchain::PresentFuture;
use crate::swapchain::PresentRegion;
use crate::swapchain::Swapchain;
use crate::sync::AccessFlagBits;
use crate::sync::FenceWaitError;
use crate::sync::PipelineStages;
use crate::OomError;
pub use self::fence_signal::{FenceSignalFuture, FenceSignalFutureBehavior};
pub use self::join::JoinFuture;
pub use self::now::{now, NowFuture};
pub use self::semaphore_signal::SemaphoreSignalFuture;
mod fence_signal;
mod join;
mod now;
mod semaphore_signal;
pub unsafe trait GpuFuture: DeviceOwned {
fn cleanup_finished(&mut self);
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>;
fn flush(&self) -> Result<(), FlushError>;
unsafe fn signal_finished(&self);
fn queue(&self) -> Option<Arc<Queue>>;
fn queue_change_allowed(&self) -> bool;
fn check_buffer_access(
&self,
buffer: &dyn BufferAccess,
exclusive: bool,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;
fn check_image_access(
&self,
image: &dyn ImageAccess,
layout: ImageLayout,
exclusive: bool,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>;
fn join<F>(self, other: F) -> JoinFuture<Self, F>
where
Self: Sized,
F: GpuFuture,
{
join::join(self, other)
}
#[inline]
fn then_execute<Cb>(
self,
queue: Arc<Queue>,
command_buffer: Cb,
) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError>
where
Self: Sized,
Cb: CommandBuffer + 'static,
{
command_buffer.execute_after(self, queue)
}
#[inline]
fn then_execute_same_queue<Cb>(
self,
command_buffer: Cb,
) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError>
where
Self: Sized,
Cb: CommandBuffer + 'static,
{
let queue = self.queue().unwrap().clone();
command_buffer.execute_after(self, queue)
}
#[inline]
fn then_signal_semaphore(self) -> SemaphoreSignalFuture<Self>
where
Self: Sized,
{
semaphore_signal::then_signal_semaphore(self)
}
#[inline]
fn then_signal_semaphore_and_flush(self) -> Result<SemaphoreSignalFuture<Self>, FlushError>
where
Self: Sized,
{
let f = self.then_signal_semaphore();
f.flush()?;
Ok(f)
}
#[inline]
fn then_signal_fence(self) -> FenceSignalFuture<Self>
where
Self: Sized,
{
fence_signal::then_signal_fence(self, FenceSignalFutureBehavior::Continue)
}
#[inline]
fn then_signal_fence_and_flush(self) -> Result<FenceSignalFuture<Self>, FlushError>
where
Self: Sized,
{
let f = self.then_signal_fence();
f.flush()?;
Ok(f)
}
#[inline]
fn then_swapchain_present<W>(
self,
queue: Arc<Queue>,
swapchain: Arc<Swapchain<W>>,
image_index: usize,
) -> PresentFuture<Self, W>
where
Self: Sized,
{
swapchain::present(swapchain, self, queue, image_index)
}
#[inline]
fn then_swapchain_present_incremental<W>(
self,
queue: Arc<Queue>,
swapchain: Arc<Swapchain<W>>,
image_index: usize,
present_region: PresentRegion,
) -> PresentFuture<Self, W>
where
Self: Sized,
{
swapchain::present_incremental(swapchain, self, queue, image_index, present_region)
}
fn boxed(self) -> Box<dyn GpuFuture>
where
Self: Sized + 'static,
{
Box::new(self) as _
}
}
unsafe impl<F: ?Sized> GpuFuture for Box<F>
where
F: GpuFuture,
{
#[inline]
fn cleanup_finished(&mut self) {
(**self).cleanup_finished()
}
#[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
(**self).build_submission()
}
#[inline]
fn flush(&self) -> Result<(), FlushError> {
(**self).flush()
}
#[inline]
unsafe fn signal_finished(&self) {
(**self).signal_finished()
}
#[inline]
fn queue_change_allowed(&self) -> bool {
(**self).queue_change_allowed()
}
#[inline]
fn queue(&self) -> Option<Arc<Queue>> {
(**self).queue()
}
#[inline]
fn check_buffer_access(
&self,
buffer: &dyn BufferAccess,
exclusive: bool,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
(**self).check_buffer_access(buffer, exclusive, queue)
}
#[inline]
fn check_image_access(
&self,
image: &dyn ImageAccess,
layout: ImageLayout,
exclusive: bool,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
(**self).check_image_access(image, layout, exclusive, queue)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AccessError {
ExclusiveDenied,
AlreadyInUse,
UnexpectedImageLayout {
allowed: ImageLayout,
requested: ImageLayout,
},
ImageNotInitialized {
requested: ImageLayout,
},
BufferNotInitialized,
SwapchainImageAcquireOnly,
}
impl error::Error for AccessError {}
impl fmt::Display for AccessError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
AccessError::ExclusiveDenied => "only shared access is allowed for this resource",
AccessError::AlreadyInUse => {
"the resource is already in use, and there is no tracking of concurrent usages"
}
AccessError::UnexpectedImageLayout { .. } => {
unimplemented!() }
AccessError::ImageNotInitialized { .. } => {
"trying to use an image without transitioning it from the undefined or \
preinitialized layouts first"
}
AccessError::BufferNotInitialized => {
"trying to use a buffer that still contains garbage data"
}
AccessError::SwapchainImageAcquireOnly => {
"trying to use a swapchain image without depending on a corresponding acquire \
image future"
}
}
)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AccessCheckError {
Denied(AccessError),
Unknown,
}
impl error::Error for AccessCheckError {}
impl fmt::Display for AccessCheckError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
AccessCheckError::Denied(_) => "access to the resource has been denied",
AccessCheckError::Unknown => "the resource is unknown",
}
)
}
}
impl From<AccessError> for AccessCheckError {
#[inline]
fn from(err: AccessError) -> AccessCheckError {
AccessCheckError::Denied(err)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FlushError {
AccessError(AccessError),
OomError(OomError),
DeviceLost,
SurfaceLost,
OutOfDate,
FullscreenExclusiveLost,
Timeout,
}
impl error::Error for FlushError {
#[inline]
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
FlushError::AccessError(ref err) => Some(err),
FlushError::OomError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for FlushError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
FlushError::AccessError(_) => "access to a resource has been denied",
FlushError::OomError(_) => "not enough memory",
FlushError::DeviceLost => "the connection to the device has been lost",
FlushError::SurfaceLost => "the surface of this swapchain is no longer valid",
FlushError::OutOfDate => "the swapchain needs to be recreated",
FlushError::FullscreenExclusiveLost => {
"the swapchain no longer has fullscreen exclusivity"
}
FlushError::Timeout => {
"the flush operation needed to block, but the timeout has \
elapsed"
}
}
)
}
}
impl From<AccessError> for FlushError {
#[inline]
fn from(err: AccessError) -> FlushError {
FlushError::AccessError(err)
}
}
impl From<SubmitPresentError> for FlushError {
#[inline]
fn from(err: SubmitPresentError) -> FlushError {
match err {
SubmitPresentError::OomError(err) => FlushError::OomError(err),
SubmitPresentError::DeviceLost => FlushError::DeviceLost,
SubmitPresentError::SurfaceLost => FlushError::SurfaceLost,
SubmitPresentError::OutOfDate => FlushError::OutOfDate,
SubmitPresentError::FullscreenExclusiveLost => FlushError::FullscreenExclusiveLost,
}
}
}
impl From<SubmitCommandBufferError> for FlushError {
#[inline]
fn from(err: SubmitCommandBufferError) -> FlushError {
match err {
SubmitCommandBufferError::OomError(err) => FlushError::OomError(err),
SubmitCommandBufferError::DeviceLost => FlushError::DeviceLost,
}
}
}
impl From<SubmitBindSparseError> for FlushError {
#[inline]
fn from(err: SubmitBindSparseError) -> FlushError {
match err {
SubmitBindSparseError::OomError(err) => FlushError::OomError(err),
SubmitBindSparseError::DeviceLost => FlushError::DeviceLost,
}
}
}
impl From<FenceWaitError> for FlushError {
#[inline]
fn from(err: FenceWaitError) -> FlushError {
match err {
FenceWaitError::OomError(err) => FlushError::OomError(err),
FenceWaitError::Timeout => FlushError::Timeout,
FenceWaitError::DeviceLostError => FlushError::DeviceLost,
}
}
}