use std::sync::Arc;
use buffer::BufferAccess;
use command_buffer::submit::SubmitAnyBuilder;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use image::ImageLayout;
use sync::AccessCheckError;
use sync::AccessFlagBits;
use sync::FlushError;
use sync::GpuFuture;
use sync::PipelineStages;
use 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)) => {
b.submit(&self.second.queue().clone().unwrap())?;
SubmitAnyBuilder::SemaphoresWait(a)
},
(SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
a.submit(&self.first.queue().clone().unwrap())?;
SubmitAnyBuilder::SemaphoresWait(b)
},
(SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(b)) => {
b.submit(&self.second.queue().clone().unwrap())?;
SubmitAnyBuilder::SemaphoresWait(a)
},
(SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
a.submit(&self.first.queue().clone().unwrap())?;
SubmitAnyBuilder::SemaphoresWait(b)
},
(SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::BindSparse(b)) => {
b.submit(&self.second.queue().clone().unwrap())?;
SubmitAnyBuilder::SemaphoresWait(a)
},
(SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
a.submit(&self.first.queue().clone().unwrap())?;
SubmitAnyBuilder::SemaphoresWait(b)
},
(SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::CommandBuffer(b)) => {
let new = a.merge(b);
SubmitAnyBuilder::CommandBuffer(new)
},
(SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::QueuePresent(b)) => {
a.submit(&self.first.queue().clone().unwrap())?;
b.submit(&self.second.queue().clone().unwrap())?;
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, AccessFlagBits)>, 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, AccessFlagBits)>, 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)))
},
}
}
}