use std::sync::Arc;
use crate::buffer::BufferAccess;
use crate::command_buffer::submit::SubmitAnyBuilder;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::sync::AccessCheckError;
use crate::sync::AccessFlags;
use crate::sync::FlushError;
use crate::sync::GpuFuture;
use crate::sync::PipelineStages;
use crate::VulkanObject;
#[inline]
pub fn join<F, S>(first: F, second: S) -> JoinFuture<F, S>
where
F: GpuFuture,
S: GpuFuture,
{
assert_eq!(
first.device().internal_object(),
second.device().internal_object()
);
if !first.queue_change_allowed() && !second.queue_change_allowed() {
assert!(first.queue().unwrap().is_same(&second.queue().unwrap()));
}
JoinFuture {
first: first,
second: second,
}
}
#[must_use]
pub struct JoinFuture<A, B> {
first: A,
second: B,
}
unsafe impl<A, B> DeviceOwned for JoinFuture<A, B>
where
A: DeviceOwned,
B: DeviceOwned,
{
#[inline]
fn device(&self) -> &Arc<Device> {
let device = self.first.device();
debug_assert_eq!(
self.second.device().internal_object(),
device.internal_object()
);
device
}
}
unsafe impl<A, B> GpuFuture for JoinFuture<A, B>
where
A: GpuFuture,
B: GpuFuture,
{
#[inline]
fn cleanup_finished(&mut self) {
self.first.cleanup_finished();
self.second.cleanup_finished();
}
#[inline]
fn flush(&self) -> Result<(), FlushError> {
self.first.flush()?;
self.second.flush()?;
Ok(())
}
#[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
let first = self.first.build_submission()?;
let second = self.second.build_submission()?;
Ok(match (first, second) {
(SubmitAnyBuilder::Empty, b) => b,
(a, SubmitAnyBuilder::Empty) => a,
(SubmitAnyBuilder::SemaphoresWait(mut a), SubmitAnyBuilder::SemaphoresWait(b)) => {
a.merge(b);
SubmitAnyBuilder::SemaphoresWait(a)
}
(SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::CommandBuffer(b)) => {
self.second.flush()?;
SubmitAnyBuilder::SemaphoresWait(a)
}
(SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
self.first.flush()?;
SubmitAnyBuilder::SemaphoresWait(b)
}
(SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(b)) => {
self.second.flush()?;
SubmitAnyBuilder::SemaphoresWait(a)
}
(SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
self.first.flush()?;
SubmitAnyBuilder::SemaphoresWait(b)
}
(SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::BindSparse(b)) => {
self.second.flush()?;
SubmitAnyBuilder::SemaphoresWait(a)
}
(SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
self.first.flush()?;
SubmitAnyBuilder::SemaphoresWait(b)
}
(SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::CommandBuffer(b)) => {
let new = a.merge(b);
SubmitAnyBuilder::CommandBuffer(new)
}
(SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::QueuePresent(b)) => {
self.first.flush()?;
self.second.flush()?;
SubmitAnyBuilder::Empty
}
(SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::QueuePresent(b)) => {
unimplemented!()
}
(SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::CommandBuffer(b)) => {
unimplemented!()
}
(SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::QueuePresent(b)) => {
unimplemented!()
}
(SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::BindSparse(b)) => {
unimplemented!()
}
(SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::CommandBuffer(b)) => {
unimplemented!()
}
(SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::BindSparse(b)) => {
unimplemented!()
}
(SubmitAnyBuilder::BindSparse(mut a), SubmitAnyBuilder::BindSparse(b)) => {
match a.merge(b) {
Ok(()) => SubmitAnyBuilder::BindSparse(a),
Err(_) => {
unimplemented!()
}
}
}
})
}
#[inline]
unsafe fn signal_finished(&self) {
self.first.signal_finished();
self.second.signal_finished();
}
#[inline]
fn queue_change_allowed(&self) -> bool {
self.first.queue_change_allowed() && self.second.queue_change_allowed()
}
#[inline]
fn queue(&self) -> Option<Arc<Queue>> {
match (self.first.queue(), self.second.queue()) {
(Some(q1), Some(q2)) => {
if q1.is_same(&q2) {
Some(q1)
} else if self.first.queue_change_allowed() {
Some(q2)
} else if self.second.queue_change_allowed() {
Some(q1)
} else {
None
}
}
(Some(q), None) => Some(q),
(None, Some(q)) => Some(q),
(None, None) => None,
}
}
#[inline]
fn check_buffer_access(
&self,
buffer: &dyn BufferAccess,
exclusive: bool,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
let first = self.first.check_buffer_access(buffer, exclusive, queue);
let second = self.second.check_buffer_access(buffer, exclusive, queue);
debug_assert!(
!exclusive || !(first.is_ok() && second.is_ok()),
"Two futures gave exclusive access to the same resource"
);
match (first, second) {
(v, Err(AccessCheckError::Unknown)) => v,
(Err(AccessCheckError::Unknown), v) => v,
(Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(e2))) => {
Err(AccessCheckError::Denied(e1))
}
(Ok(_), Err(AccessCheckError::Denied(_)))
| (Err(AccessCheckError::Denied(_)), Ok(_)) => panic!(
"Contradictory information \
between two futures"
),
(Ok(None), Ok(None)) => Ok(None),
(Ok(Some(a)), Ok(None)) | (Ok(None), Ok(Some(a))) => Ok(Some(a)),
(Ok(Some((a1, a2))), Ok(Some((b1, b2)))) => Ok(Some((a1 | b1, a2 | b2))),
}
}
#[inline]
fn check_image_access(
&self,
image: &dyn ImageAccess,
layout: ImageLayout,
exclusive: bool,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
let first = self
.first
.check_image_access(image, layout, exclusive, queue);
let second = self
.second
.check_image_access(image, layout, exclusive, queue);
debug_assert!(
!exclusive || !(first.is_ok() && second.is_ok()),
"Two futures gave exclusive access to the same resource"
);
match (first, second) {
(v, Err(AccessCheckError::Unknown)) => v,
(Err(AccessCheckError::Unknown), v) => v,
(Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(e2))) => {
Err(AccessCheckError::Denied(e1))
}
(Ok(_), Err(AccessCheckError::Denied(_)))
| (Err(AccessCheckError::Denied(_)), Ok(_)) => panic!(
"Contradictory information \
between two futures"
),
(Ok(None), Ok(None)) => Ok(None),
(Ok(Some(a)), Ok(None)) | (Ok(None), Ok(Some(a))) => Ok(Some(a)),
(Ok(Some((a1, a2))), Ok(Some((b1, b2)))) => Ok(Some((a1 | b1, a2 | b2))),
}
}
}