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::CpuAccessible;
use memory::CpuWriteAccessible; use memory::CpuWriteAccessible;
use memory::ChunkProperties; use memory::ChunkProperties;
use memory::ChunkRange;
use memory::MemorySource; use memory::MemorySource;
use memory::MemorySourceChunk; use memory::MemorySourceChunk;
use sync::Fence; use sync::Fence;
@ -235,7 +236,7 @@ unsafe impl<T: ?Sized, M> Resource for Buffer<T, M> where M: MemorySourceChunk {
semaphore: Option<Arc<Semaphore>>) semaphore: Option<Arc<Semaphore>>)
-> (Option<Arc<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) (out, None)
} }
} }
@ -401,7 +402,7 @@ unsafe impl<'a, T: ?Sized + 'a, M: 'a> Resource for BufferSlice<'a, T, M>
semaphore: Option<Arc<Semaphore>>) semaphore: Option<Arc<Semaphore>>)
-> (Option<Arc<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); queue, fence, semaphore);
(out, None) (out, None)
} }

View File

@ -24,6 +24,7 @@ use device::Device;
use device::Queue; use device::Queue;
use formats::FormatMarker; use formats::FormatMarker;
use memory::ChunkProperties; use memory::ChunkProperties;
use memory::ChunkRange;
use memory::MemorySource; use memory::MemorySource;
use memory::MemorySourceChunk; use memory::MemorySourceChunk;
use sync::Fence; use sync::Fence;
@ -392,7 +393,7 @@ unsafe impl<Ty, F, M> Resource for Image<Ty, F, M>
semaphore: Option<Arc<Semaphore>>) semaphore: Option<Arc<Semaphore>>)
-> (Option<Arc<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 // FIXME: if the image is in its initial transition phase, we need to return a second semaphore
(out, None) (out, None)
} }

View File

@ -118,9 +118,6 @@ pub unsafe trait MemorySourceChunk {
/// Returns the properties of this chunk. /// Returns the properties of this chunk.
fn properties(&self) -> ChunkProperties; 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. /// Returns true if the `gpu_access` function should be passed a fence.
#[inline] #[inline]
fn requires_fence(&self) -> bool { 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 /// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
/// be written. /// 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. /// `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 /// 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 /// 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, /// semaphore being returned is usually one that has been previously passed to this function,
/// but it doesn't need to be the case. /// 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>>) fence: Option<Arc<Fence>>, semaphore: Option<Arc<Semaphore>>)
-> Option<Arc<Semaphore>>; -> Option<Arc<Semaphore>>;
@ -171,6 +168,11 @@ pub unsafe trait MemorySourceChunk {
fn may_alias(&self) -> bool; fn may_alias(&self) -> bool;
} }
pub enum ChunkRange {
All,
Range { offset: usize, size: usize }
}
pub enum ChunkProperties<'a> { pub enum ChunkProperties<'a> {
Regular { Regular {
memory: &'a DeviceMemory, memory: &'a DeviceMemory,

View File

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

View File

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