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> {
try!(self.first.flush());
try!(self.second.flush());
Ok(())
}
#[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
let first = try!(self.first.build_submission());
let second = try!(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)) => {
try!(b.submit(&self.second.queue().clone().unwrap()));
SubmitAnyBuilder::SemaphoresWait(a)
},
(SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
try!(a.submit(&self.first.queue().clone().unwrap()));
SubmitAnyBuilder::SemaphoresWait(b)
},
(SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(b)) => {
try!(b.submit(&self.second.queue().clone().unwrap()));
SubmitAnyBuilder::SemaphoresWait(a)
},
(SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
try!(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)) => {
try!(a.submit(&self.first.queue().clone().unwrap()));
try!(b.submit(&self.second.queue().clone().unwrap()));
SubmitAnyBuilder::Empty
},
(SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::QueuePresent(b)) => {
unimplemented!()
},
(SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::CommandBuffer(b)) => {
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: &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: &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)))
},
}
}
}