pub use self::{
fence_signal::{FenceSignalFuture, FenceSignalFutureBehavior},
join::JoinFuture,
now::{now, NowFuture},
semaphore_signal::SemaphoreSignalFuture,
};
use super::{fence::Fence, semaphore::Semaphore};
use crate::{
buffer::Buffer,
command_buffer::{
CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract, SubmitInfo,
},
device::{DeviceOwned, Queue},
image::{Image, ImageLayout},
memory::BindSparseInfo,
swapchain::{self, PresentFuture, PresentInfo, Swapchain, SwapchainPresentInfo},
DeviceSize, Validated, VulkanError,
};
use smallvec::SmallVec;
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
ops::Range,
sync::Arc,
};
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, Validated<VulkanError>>;
fn flush(&self) -> Result<(), Validated<VulkanError>>;
unsafe fn signal_finished(&self);
fn queue(&self) -> Option<Arc<Queue>>;
fn queue_change_allowed(&self) -> bool;
fn check_buffer_access(
&self,
buffer: &Buffer,
range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
) -> Result<(), AccessCheckError>;
fn check_image_access(
&self,
image: &Image,
range: Range<DeviceSize>,
exclusive: bool,
expected_layout: ImageLayout,
queue: &Queue,
) -> Result<(), AccessCheckError>;
fn check_swapchain_image_acquired(
&self,
swapchain: &Swapchain,
image_index: u32,
before: bool,
) -> Result<(), AccessCheckError>;
fn join<F>(self, other: F) -> JoinFuture<Self, F>
where
Self: Sized,
F: GpuFuture,
{
join::join(self, other)
}
fn then_execute(
self,
queue: Arc<Queue>,
command_buffer: Arc<impl PrimaryCommandBufferAbstract + 'static>,
) -> Result<CommandBufferExecFuture<Self>, CommandBufferExecError>
where
Self: Sized,
{
command_buffer.execute_after(self, queue)
}
fn then_execute_same_queue(
self,
command_buffer: Arc<impl PrimaryCommandBufferAbstract + 'static>,
) -> Result<CommandBufferExecFuture<Self>, CommandBufferExecError>
where
Self: Sized,
{
let queue = self.queue().unwrap();
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>, Validated<VulkanError>>
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>, Validated<VulkanError>>
where
Self: Sized,
{
let f = self.then_signal_fence();
f.flush()?;
Ok(f)
}
#[inline]
fn then_swapchain_present(
self,
queue: Arc<Queue>,
swapchain_info: SwapchainPresentInfo,
) -> PresentFuture<Self>
where
Self: Sized,
{
swapchain::present(self, queue, swapchain_info)
}
#[inline]
fn boxed(self) -> Box<dyn GpuFuture>
where
Self: Sized + 'static,
{
Box::new(self) as _
}
#[inline]
fn boxed_send(self) -> Box<dyn GpuFuture + Send>
where
Self: Sized + Send + 'static,
{
Box::new(self) as _
}
#[inline]
fn boxed_sync(self) -> Box<dyn GpuFuture + Sync>
where
Self: Sized + Sync + 'static,
{
Box::new(self) as _
}
#[inline]
fn boxed_send_sync(self) -> Box<dyn GpuFuture + Send + Sync>
where
Self: Sized + Send + Sync + 'static,
{
Box::new(self) as _
}
}
unsafe impl<F: ?Sized> GpuFuture for Box<F>
where
F: GpuFuture,
{
fn cleanup_finished(&mut self) {
(**self).cleanup_finished()
}
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, Validated<VulkanError>> {
(**self).build_submission()
}
fn flush(&self) -> Result<(), Validated<VulkanError>> {
(**self).flush()
}
unsafe fn signal_finished(&self) {
(**self).signal_finished()
}
fn queue_change_allowed(&self) -> bool {
(**self).queue_change_allowed()
}
fn queue(&self) -> Option<Arc<Queue>> {
(**self).queue()
}
fn check_buffer_access(
&self,
buffer: &Buffer,
range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
) -> Result<(), AccessCheckError> {
(**self).check_buffer_access(buffer, range, exclusive, queue)
}
fn check_image_access(
&self,
image: &Image,
range: Range<DeviceSize>,
exclusive: bool,
expected_layout: ImageLayout,
queue: &Queue,
) -> Result<(), AccessCheckError> {
(**self).check_image_access(image, range, exclusive, expected_layout, queue)
}
#[inline]
fn check_swapchain_image_acquired(
&self,
swapchain: &Swapchain,
image_index: u32,
before: bool,
) -> Result<(), AccessCheckError> {
(**self).check_swapchain_image_acquired(swapchain, image_index, before)
}
}
#[derive(Debug)]
pub enum SubmitAnyBuilder {
Empty,
SemaphoresWait(SmallVec<[Arc<Semaphore>; 8]>),
CommandBuffer(SubmitInfo, Option<Arc<Fence>>),
QueuePresent(PresentInfo),
BindSparse(SmallVec<[BindSparseInfo; 1]>, Option<Arc<Fence>>),
}
impl SubmitAnyBuilder {
#[inline]
pub fn is_empty(&self) -> bool {
matches!(self, SubmitAnyBuilder::Empty)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AccessError {
AlreadyInUse,
UnexpectedImageLayout {
allowed: ImageLayout,
requested: ImageLayout,
},
ImageNotInitialized {
requested: ImageLayout,
},
SwapchainImageNotAcquired,
}
impl Error for AccessError {}
impl Display for AccessError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
let value = match self {
AccessError::AlreadyInUse => {
"the resource is already in use, and there is no tracking of concurrent usages"
}
AccessError::UnexpectedImageLayout { allowed, requested } => {
return write!(
f,
"unexpected image layout: requested {:?}, allowed {:?}",
allowed, requested
)
}
AccessError::ImageNotInitialized { .. } => {
"trying to use an image without transitioning it from the undefined or \
preinitialized layouts first"
}
AccessError::SwapchainImageNotAcquired => {
"trying to use a swapchain image without depending on a corresponding acquire \
image future"
}
};
write!(f, "{}", value,)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AccessCheckError {
Denied(AccessError),
Unknown,
}
impl Error for AccessCheckError {}
impl Display for AccessCheckError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
AccessCheckError::Denied(err) => {
write!(f, "access to the resource has been denied: {}", err)
}
AccessCheckError::Unknown => write!(f, "the resource is unknown"),
}
}
}
impl From<AccessError> for AccessCheckError {
fn from(err: AccessError) -> AccessCheckError {
AccessCheckError::Denied(err)
}
}