use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use buffer::BufferAccess;
use command_buffer::submit::SubmitAnyBuilder;
use command_buffer::submit::SubmitCommandBufferBuilder;
use command_buffer::submit::SubmitSemaphoresWaitBuilder;
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 sync::Semaphore;
#[inline]
pub fn then_signal_semaphore<F>(future: F) -> SemaphoreSignalFuture<F>
where F: GpuFuture
{
let device = future.device().clone();
assert!(future.queue().is_some());
SemaphoreSignalFuture {
previous: future,
semaphore: Semaphore::from_pool(device).unwrap(),
wait_submitted: Mutex::new(false),
finished: AtomicBool::new(false),
}
}
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished \
processing the submission"]
pub struct SemaphoreSignalFuture<F>
where F: GpuFuture
{
previous: F,
semaphore: Semaphore,
wait_submitted: Mutex<bool>,
finished: AtomicBool,
}
unsafe impl<F> GpuFuture for SemaphoreSignalFuture<F>
where F: GpuFuture
{
#[inline]
fn cleanup_finished(&mut self) {
self.previous.cleanup_finished();
}
#[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
self.flush()?;
let mut sem = SubmitSemaphoresWaitBuilder::new();
sem.add_wait_semaphore(&self.semaphore);
Ok(SubmitAnyBuilder::SemaphoresWait(sem))
}
fn flush(&self) -> Result<(), FlushError> {
unsafe {
let mut wait_submitted = self.wait_submitted.lock().unwrap();
if *wait_submitted {
return Ok(());
}
let queue = self.previous.queue().unwrap().clone();
match self.previous.build_submission()? {
SubmitAnyBuilder::Empty => {
let mut builder = SubmitCommandBufferBuilder::new();
builder.add_signal_semaphore(&self.semaphore);
builder.submit(&queue)?;
},
SubmitAnyBuilder::SemaphoresWait(sem) => {
let mut builder: SubmitCommandBufferBuilder = sem.into();
builder.add_signal_semaphore(&self.semaphore);
builder.submit(&queue)?;
},
SubmitAnyBuilder::CommandBuffer(mut builder) => {
debug_assert_eq!(builder.num_signal_semaphores(), 0);
builder.add_signal_semaphore(&self.semaphore);
builder.submit(&queue)?;
},
SubmitAnyBuilder::BindSparse(_) => {
unimplemented!()
},
SubmitAnyBuilder::QueuePresent(present) => {
present.submit(&queue)?;
let mut builder = SubmitCommandBufferBuilder::new();
builder.add_signal_semaphore(&self.semaphore);
builder.submit(&queue)?; },
};
*wait_submitted = true;
Ok(())
}
}
#[inline]
unsafe fn signal_finished(&self) {
debug_assert!(*self.wait_submitted.lock().unwrap());
self.finished.store(true, Ordering::SeqCst);
self.previous.signal_finished();
}
#[inline]
fn queue_change_allowed(&self) -> bool {
true
}
#[inline]
fn queue(&self) -> Option<Arc<Queue>> {
self.previous.queue()
}
#[inline]
fn check_buffer_access(
&self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
self.previous
.check_buffer_access(buffer, exclusive, queue)
.map(|_| None)
}
#[inline]
fn check_image_access(&self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool,
queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
self.previous
.check_image_access(image, layout, exclusive, queue)
.map(|_| None)
}
}
unsafe impl<F> DeviceOwned for SemaphoreSignalFuture<F>
where F: GpuFuture
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.semaphore.device()
}
}
impl<F> Drop for SemaphoreSignalFuture<F>
where F: GpuFuture
{
fn drop(&mut self) {
unsafe {
if !*self.finished.get_mut() {
self.flush().unwrap();
self.queue().unwrap().wait().unwrap();
self.previous.signal_finished();
}
}
}
}