Better synchronization handling

This commit is contained in:
Pierre Krieger 2016-02-19 07:17:34 +01:00
parent cdc573a5d7
commit c644b76346
5 changed files with 63 additions and 42 deletions

View File

@ -25,6 +25,7 @@ use device::Queue;
use memory::CpuAccessible;
use memory::CpuWriteAccessible;
use memory::ChunkProperties;
use memory::ChunkRange;
use memory::MemorySource;
use memory::MemorySourceChunk;
use sync::Fence;
@ -235,7 +236,7 @@ unsafe impl<T: ?Sized, M> Resource for Buffer<T, M> where M: MemorySourceChunk {
semaphore: Option<Arc<Semaphore>>)
-> (Option<Arc<Semaphore>>, Option<Arc<Semaphore>>)
{
let out = self.inner.memory.gpu_access(write, 0, self.size(), queue, fence, semaphore);
let out = self.inner.memory.gpu_access(write, ChunkRange::All, queue, fence, semaphore);
(out, None)
}
}
@ -401,7 +402,7 @@ unsafe impl<'a, T: ?Sized + 'a, M: 'a> Resource for BufferSlice<'a, T, M>
semaphore: Option<Arc<Semaphore>>)
-> (Option<Arc<Semaphore>>, Option<Arc<Semaphore>>)
{
let out = self.inner.memory.gpu_access(write, self.offset, self.size,
let out = self.inner.memory.gpu_access(write, ChunkRange::Range { offset: self.offset, size: self.size },
queue, fence, semaphore);
(out, None)
}

View File

@ -24,6 +24,7 @@ use device::Device;
use device::Queue;
use formats::FormatMarker;
use memory::ChunkProperties;
use memory::ChunkRange;
use memory::MemorySource;
use memory::MemorySourceChunk;
use sync::Fence;
@ -392,7 +393,7 @@ unsafe impl<Ty, F, M> Resource for Image<Ty, F, M>
semaphore: Option<Arc<Semaphore>>)
-> (Option<Arc<Semaphore>>, Option<Arc<Semaphore>>)
{
let out = self.memory.gpu_access(write, 0, self.memory.size(), queue, fence, semaphore);
let out = self.memory.gpu_access(write, ChunkRange::All, queue, fence, semaphore);
// FIXME: if the image is in its initial transition phase, we need to return a second semaphore
(out, None)
}

View File

@ -118,9 +118,6 @@ pub unsafe trait MemorySourceChunk {
/// Returns the properties of this chunk.
fn properties(&self) -> ChunkProperties;
/// Size in bytes of the chunk.
fn size(&self) -> usize;
/// Returns true if the `gpu_access` function should be passed a fence.
#[inline]
fn requires_fence(&self) -> bool {
@ -140,7 +137,7 @@ pub unsafe trait MemorySourceChunk {
/// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
/// be written.
///
/// `offset` and `size` indicate the part of the chunk that is concerned.
/// `range` indicates the part of the chunk that is concerned.
///
/// `queue` is the queue where the command buffer that accesses the memory will be submitted.
/// If the `gpu_access` function submits something to that queue, it will thus be submitted
@ -158,7 +155,7 @@ pub unsafe trait MemorySourceChunk {
/// return a semaphore that must be waited upon by the GPU before the access can start. The
/// semaphore being returned is usually one that has been previously passed to this function,
/// but it doesn't need to be the case.
fn gpu_access(&self, write: bool, offset: usize, size: usize, queue: &mut Queue,
fn gpu_access(&self, write: bool, range: ChunkRange, queue: &mut Queue,
fence: Option<Arc<Fence>>, semaphore: Option<Arc<Semaphore>>)
-> Option<Arc<Semaphore>>;
@ -171,6 +168,11 @@ pub unsafe trait MemorySourceChunk {
fn may_alias(&self) -> bool;
}
pub enum ChunkRange {
All,
Range { offset: usize, size: usize }
}
pub enum ChunkProperties<'a> {
Regular {
memory: &'a DeviceMemory,

View File

@ -14,6 +14,7 @@ use memory::MemorySource;
use memory::MemorySourceChunk;
use memory::DeviceMemory;
use memory::MappedDeviceMemory;
use memory::ChunkRange;
use sync::Fence;
use sync::Semaphore;
@ -68,12 +69,7 @@ pub struct DeviceLocalChunk {
unsafe impl MemorySourceChunk for DeviceLocalChunk {
#[inline]
fn size(&self) -> usize {
self.mem.size()
}
#[inline]
fn gpu_access(&self, _write: bool, _offset: usize, _size: usize, _: &mut Queue,
fn gpu_access(&self, _write: bool, _range: ChunkRange, _: &mut Queue,
_: Option<Arc<Fence>>, mut semaphore: Option<Arc<Semaphore>>)
-> Option<Arc<Semaphore>>
{
@ -153,12 +149,7 @@ pub struct HostVisibleChunk {
unsafe impl MemorySourceChunk for HostVisibleChunk {
#[inline]
fn size(&self) -> usize {
self.mem.memory().size()
}
#[inline]
fn gpu_access(&self, _write: bool, _offset: usize, _size: usize, _: &mut Queue,
fn gpu_access(&self, _write: bool, _range: ChunkRange, _: &mut Queue,
fence: Option<Arc<Fence>>, mut semaphore: Option<Arc<Semaphore>>)
-> Option<Arc<Semaphore>>
{

View File

@ -3,6 +3,7 @@ use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use device::Device;
use device::Queue;
@ -12,6 +13,7 @@ use image::ImagePrototype;
use image::Type2d;
use image::Usage as ImageUsage;
use memory::ChunkProperties;
use memory::ChunkRange;
use memory::MemorySourceChunk;
use swapchain::CompositeAlpha;
use swapchain::PresentMode;
@ -34,6 +36,8 @@ pub struct Swapchain {
device: Arc<Device>,
surface: Arc<Surface>,
swapchain: vk::SwapchainKHR,
images_semaphores: Mutex<Vec<Option<Arc<Semaphore>>>>,
}
impl Swapchain {
@ -111,6 +115,7 @@ impl Swapchain {
device: device.clone(),
surface: surface.clone(),
swapchain: swapchain,
images_semaphores: Mutex::new(Vec::new()),
});
let images = unsafe {
@ -127,11 +132,18 @@ impl Swapchain {
images
};
let images = images.into_iter().map(|image| unsafe {
let mem = SwapchainAllocatedChunk { swapchain: swapchain.clone() };
let images = images.into_iter().enumerate().map(|(id, image)| unsafe {
let mem = SwapchainAllocatedChunk { swapchain: swapchain.clone(), id: id };
Image::from_raw_unowned(&device, image, mem, sharing.clone(), usage, dimensions, (), 1)
}).collect::<Vec<_>>();
{
let mut semaphores = swapchain.images_semaphores.lock().unwrap();
for _ in 0 .. images.len() {
semaphores.push(None);
}
}
Ok((swapchain, images))
}
@ -146,18 +158,26 @@ impl Swapchain {
let vk = self.device.pointers();
unsafe {
let semaphore = Semaphore::new(&self.device).unwrap(); // TODO: error
let mut out = mem::uninitialized();
let r = try!(check_errors(vk.AcquireNextImageKHR(self.device.internal_object(),
self.swapchain, 1000000, 0, 0, // TODO: timeout
self.swapchain, 1000000,
semaphore.internal_object(), 0, // TODO: timeout
&mut out)));
match r {
Success::Success => Ok(out as usize),
Success::Suboptimal => Ok(out as usize), // TODO: give that info to the user
Success::NotReady => Err(AcquireError::Timeout),
Success::Timeout => Err(AcquireError::Timeout),
let id = match r {
Success::Success => out as usize,
Success::Suboptimal => out as usize, // TODO: give that info to the user
Success::NotReady => return Err(AcquireError::Timeout),
Success::Timeout => return Err(AcquireError::Timeout),
s => panic!("unexpected success value: {:?}", s)
}
};
let mut images_semaphores = self.images_semaphores.lock().unwrap();
images_semaphores[id] = Some(semaphore);
Ok(id)
}
}
@ -170,16 +190,23 @@ impl Swapchain {
/// swapchain.
pub fn present(&self, queue: &mut Queue, index: usize) -> Result<(), OomError> { // FIXME: wrong error
let vk = self.device.pointers();
let index = index as u32;
let wait_semaphore = {
let mut images_semaphores = self.images_semaphores.lock().unwrap();
images_semaphores[index].take()
};
// FIXME: the semaphore will be destroyed ; need to return it
unsafe {
let mut result = mem::uninitialized();
let index = index as u32;
let infos = vk::PresentInfoKHR {
sType: vk::STRUCTURE_TYPE_PRESENT_INFO_KHR,
pNext: ptr::null(),
waitSemaphoreCount: 0,
pWaitSemaphores: ptr::null(),
waitSemaphoreCount: if let Some(_) = wait_semaphore { 1 } else { 0 },
pWaitSemaphores: if let Some(ref sem) = wait_semaphore { &sem.internal_object() } else { ptr::null() },
swapchainCount: 1,
pSwapchains: &self.swapchain,
pImageIndices: &index,
@ -243,8 +270,8 @@ impl From<Error> for AcquireError {
/// "Dummy" object used for images that indicates that they were allocated as part of a swapchain.
pub struct SwapchainAllocatedChunk {
// the dummy object is also used to keep ownership of the swapchain
swapchain: Arc<Swapchain>,
id: usize,
}
// FIXME: needs correct synchronization as well
@ -254,22 +281,21 @@ unsafe impl MemorySourceChunk for SwapchainAllocatedChunk {
unreachable!()
}
#[inline]
fn size(&self) -> usize {
1
}
#[inline]
fn requires_fence(&self) -> bool { false }
#[inline]
fn requires_semaphore(&self) -> bool { false }
fn requires_semaphore(&self) -> bool { true }
#[inline]
fn may_alias(&self) -> bool { false }
#[inline]
fn gpu_access(&self, _: bool, _: usize, _: usize, _: &mut Queue, _: Option<Arc<Fence>>,
_: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
fn gpu_access(&self, _: bool, _: ChunkRange, _: &mut Queue, _: Option<Arc<Fence>>,
post_semaphore: Option<Arc<Semaphore>>) -> Option<Arc<Semaphore>>
{
None
assert!(post_semaphore.is_some());
// FIXME: must also check that image has been acquired
let mut semaphores = self.swapchain.images_semaphores.lock().unwrap();
let pre_semaphore = mem::replace(&mut semaphores[self.id], post_semaphore);
pre_semaphore
}
}