hal/vk: enable timeline semaphores

This commit is contained in:
Dzmitry Malyshau
2021-07-04 00:49:57 -04:00
parent 8ae7d51c82
commit 3de1681eb0
4 changed files with 200 additions and 87 deletions

View File

@@ -801,6 +801,17 @@ impl crate::Adapter<super::Api> for super::Adapter {
} else {
None
};
let timeline_semaphore_fn = if enabled_extensions.contains(&khr::TimelineSemaphore::name())
{
Some(super::ExtensionFn::Extension(khr::TimelineSemaphore::new(
&self.instance.entry,
&self.instance.raw,
)))
} else if self.phd_capabilities.properties.api_version >= vk::API_VERSION_1_2 {
Some(super::ExtensionFn::Promoted)
} else {
None
};
let naga_options = {
use naga::back::spv;
@@ -834,6 +845,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
instance: Arc::clone(&self.instance),
extension_fns: super::DeviceExtensionFunctions {
draw_indirect_count: indirect_count_fn,
timeline_semaphore: timeline_semaphore_fn,
},
vendor_id: self.phd_capabilities.properties.vendor_id,
downlevel_flags: self.downlevel_flags,

View File

@@ -1,7 +1,11 @@
use super::conv;
use arrayvec::ArrayVec;
use ash::{extensions::khr, version::DeviceV1_0, vk};
use ash::{
extensions::khr,
version::{DeviceV1_0, DeviceV1_2},
vk,
};
use inplace_it::inplace_or_alloc_from_iter;
use parking_lot::Mutex;
@@ -1390,26 +1394,49 @@ impl crate::Device<super::Api> for super::Device {
unsafe fn destroy_query_set(&self, set: super::QuerySet) {
self.shared.raw.destroy_query_pool(set.raw, None);
}
unsafe fn create_fence(&self) -> Result<super::Fence, crate::DeviceError> {
Ok(super::Fence {
last_completed: 0,
active: Vec::new(),
free: Vec::new(),
Ok(if self.shared.private_caps.timeline_semaphores {
let mut sem_type_info =
vk::SemaphoreTypeCreateInfo::builder().semaphore_type(vk::SemaphoreType::TIMELINE);
let vk_info = vk::SemaphoreCreateInfo::builder().push_next(&mut sem_type_info);
let raw = self.shared.raw.create_semaphore(&vk_info, None)?;
super::Fence::TimelineSemaphore(raw)
} else {
super::Fence::FencePool {
last_completed: 0,
active: Vec::new(),
free: Vec::new(),
}
})
}
unsafe fn destroy_fence(&self, fence: super::Fence) {
for (_, raw) in fence.active {
self.shared.raw.destroy_fence(raw, None);
}
for raw in fence.free {
self.shared.raw.destroy_fence(raw, None);
match fence {
super::Fence::TimelineSemaphore(raw) => {
self.shared.raw.destroy_semaphore(raw, None);
}
super::Fence::FencePool {
active,
free,
last_completed: _,
} => {
for (_, raw) in active {
self.shared.raw.destroy_fence(raw, None);
}
for raw in free {
self.shared.raw.destroy_fence(raw, None);
}
}
}
}
unsafe fn get_fence_value(
&self,
fence: &super::Fence,
) -> Result<crate::FenceValue, crate::DeviceError> {
fence.get_latest(&self.shared.raw)
fence.get_latest(
&self.shared.raw,
self.shared.extension_fns.timeline_semaphore.as_ref(),
)
}
unsafe fn wait(
&self,
@@ -1417,21 +1444,50 @@ impl crate::Device<super::Api> for super::Device {
wait_value: crate::FenceValue,
timeout_ms: u32,
) -> Result<bool, crate::DeviceError> {
if wait_value <= fence.last_completed {
Ok(true)
} else {
match fence.active.iter().find(|&&(value, _)| value >= wait_value) {
Some(&(_, raw)) => {
let timeout_us = timeout_ms as u64 * super::MILLIS_TO_NANOS;
match self.shared.raw.wait_for_fences(&[raw], true, timeout_us) {
Ok(()) => Ok(true),
Err(vk::Result::TIMEOUT) => Ok(false),
Err(other) => Err(other.into()),
let timeout_us = timeout_ms as u64 * super::MILLIS_TO_NANOS;
match *fence {
super::Fence::TimelineSemaphore(raw) => {
let semaphores = [raw];
let values = [wait_value];
let vk_info = vk::SemaphoreWaitInfo::builder()
.semaphores(&semaphores)
.values(&values);
let result = match self.shared.extension_fns.timeline_semaphore {
Some(super::ExtensionFn::Extension(ref ext)) => {
ext.wait_semaphores(self.shared.raw.handle(), &vk_info, timeout_us)
}
Some(super::ExtensionFn::Promoted) => {
self.shared.raw.wait_semaphores(&vk_info, timeout_us)
}
None => unreachable!(),
};
match result {
Ok(()) => Ok(true),
Err(vk::Result::TIMEOUT) => Ok(false),
Err(other) => Err(other.into()),
}
None => {
log::error!("No signals reached value {}", wait_value);
Err(crate::DeviceError::Lost)
}
super::Fence::FencePool {
last_completed,
ref active,
free: _,
} => {
if wait_value <= last_completed {
Ok(true)
} else {
match active.iter().find(|&&(value, _)| value >= wait_value) {
Some(&(_, raw)) => {
match self.shared.raw.wait_for_fences(&[raw], true, timeout_us) {
Ok(()) => Ok(true),
Err(vk::Result::TIMEOUT) => Ok(false),
Err(other) => Err(other.into()),
}
}
None => {
log::error!("No signals reached value {}", wait_value);
Err(crate::DeviceError::Lost)
}
}
}
}
}

View File

@@ -125,7 +125,7 @@ impl super::Instance {
}
let surface = {
let xlib_loader = khr::XlibSurface::new(&self.entry, &self.shared.raw);
let xlib_loader = khr::XlibSurface::new(&self.shared.entry, &self.shared.raw);
let info = vk::XlibSurfaceCreateInfoKHR::builder()
.flags(vk::XlibSurfaceCreateFlagsKHR::empty())
.window(window)
@@ -149,7 +149,7 @@ impl super::Instance {
}
let surface = {
let xcb_loader = khr::XcbSurface::new(&self.entry, &self.shared.raw);
let xcb_loader = khr::XcbSurface::new(&self.shared.entry, &self.shared.raw);
let info = vk::XcbSurfaceCreateInfoKHR::builder()
.flags(vk::XcbSurfaceCreateFlagsKHR::empty())
.window(window)
@@ -173,7 +173,7 @@ impl super::Instance {
}
let surface = {
let w_loader = khr::WaylandSurface::new(&self.entry, &self.shared.raw);
let w_loader = khr::WaylandSurface::new(&self.shared.entry, &self.shared.raw);
let info = vk::WaylandSurfaceCreateInfoKHR::builder()
.flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
.display(display)
@@ -188,7 +188,7 @@ impl super::Instance {
#[allow(dead_code)]
fn create_surface_android(&self, window: *const c_void) -> super::Surface {
let surface = {
let a_loader = khr::AndroidSurface::new(&self.entry, &self.shared.raw);
let a_loader = khr::AndroidSurface::new(&self.shared.entry, &self.shared.raw);
let info = vk::AndroidSurfaceCreateInfoKHR::builder()
.flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
.window(window as *mut _);
@@ -214,7 +214,7 @@ impl super::Instance {
.flags(vk::Win32SurfaceCreateFlagsKHR::empty())
.hinstance(hinstance)
.hwnd(hwnd);
let win32_loader = khr::Win32Surface::new(&self.entry, &self.shared.raw);
let win32_loader = khr::Win32Surface::new(&self.shared.entry, &self.shared.raw);
unsafe {
win32_loader
.create_win32_surface(&info, None)
@@ -277,7 +277,7 @@ impl super::Instance {
}
fn create_surface_from_vk_surface_khr(&self, surface: vk::SurfaceKHR) -> super::Surface {
let functor = khr::Surface::new(&self.entry, &self.shared.raw);
let functor = khr::Surface::new(&self.shared.entry, &self.shared.raw);
super::Surface {
raw: surface,
functor,
@@ -287,21 +287,14 @@ impl super::Instance {
}
}
impl Drop for super::Instance {
impl Drop for super::InstanceShared {
fn drop(&mut self) {
match Arc::get_mut(&mut self.shared) {
Some(shared) => unsafe {
if let Some(du) = shared.debug_utils.take() {
du.extension
.destroy_debug_utils_messenger(du.messenger, None);
}
},
None => {
log::error!("Unable to drop Instance: something created from it is still alive");
}
}
unsafe {
self.shared.raw.destroy_instance(None);
if let Some(du) = self.debug_utils.take() {
du.extension
.destroy_debug_utils_messenger(du.messenger, None);
}
self.raw.destroy_instance(None);
}
}
}
@@ -495,9 +488,9 @@ impl crate::Instance<super::Api> for super::Instance {
flags: desc.flags,
debug_utils,
get_physical_device_properties,
entry,
}),
extensions,
entry,
})
}

View File

@@ -36,7 +36,7 @@ use std::{borrow::Borrow, ffi::CStr, sync::Arc};
use arrayvec::ArrayVec;
use ash::{
extensions::{ext, khr},
version::DeviceV1_0,
version::{DeviceV1_0, DeviceV1_2},
vk,
};
use parking_lot::Mutex;
@@ -83,12 +83,12 @@ struct InstanceShared {
flags: crate::InstanceFlags,
debug_utils: Option<DebugUtils>,
get_physical_device_properties: Option<vk::KhrGetPhysicalDeviceProperties2Fn>,
entry: ash::Entry,
}
pub struct Instance {
shared: Arc<InstanceShared>,
extensions: Vec<&'static CStr>,
entry: ash::Entry,
}
struct Swapchain {
@@ -140,6 +140,7 @@ enum ExtensionFn<T> {
struct DeviceExtensionFunctions {
draw_indirect_count: Option<ExtensionFn<khr::DrawIndirectCount>>,
timeline_semaphore: Option<ExtensionFn<khr::TimelineSemaphore>>,
}
/// Set of internal capabilities, which don't show up in the exposed
@@ -355,17 +356,23 @@ pub struct QuerySet {
}
#[derive(Debug)]
pub struct Fence {
last_completed: crate::FenceValue,
/// The pending fence values have to be ascending.
active: Vec<(crate::FenceValue, vk::Fence)>,
free: Vec<vk::Fence>,
pub enum Fence {
TimelineSemaphore(vk::Semaphore),
FencePool {
last_completed: crate::FenceValue,
/// The pending fence values have to be ascending.
active: Vec<(crate::FenceValue, vk::Fence)>,
free: Vec<vk::Fence>,
},
}
impl Fence {
fn get_latest(&self, device: &ash::Device) -> Result<crate::FenceValue, crate::DeviceError> {
let mut max_value = self.last_completed;
for &(value, raw) in self.active.iter() {
fn check_active(
device: &ash::Device,
mut max_value: crate::FenceValue,
active: &[(crate::FenceValue, vk::Fence)],
) -> Result<crate::FenceValue, crate::DeviceError> {
for &(value, raw) in active.iter() {
unsafe {
if value > max_value && device.get_fence_status(raw)? {
max_value = value;
@@ -375,21 +382,52 @@ impl Fence {
Ok(max_value)
}
fn get_latest(
&self,
device: &ash::Device,
extension: Option<&ExtensionFn<khr::TimelineSemaphore>>,
) -> Result<crate::FenceValue, crate::DeviceError> {
match *self {
Self::TimelineSemaphore(raw) => unsafe {
Ok(match *extension.unwrap() {
ExtensionFn::Extension(ref ext) => {
ext.get_semaphore_counter_value(device.handle(), raw)?
}
ExtensionFn::Promoted => device.get_semaphore_counter_value(raw)?,
})
},
Self::FencePool {
last_completed,
ref active,
free: _,
} => Self::check_active(device, last_completed, active),
}
}
fn maintain(&mut self, device: &ash::Device) -> Result<(), crate::DeviceError> {
let latest = self.get_latest(device)?;
let base_free = self.free.len();
for &(value, raw) in self.active.iter() {
if value <= latest {
self.free.push(raw);
match *self {
Self::TimelineSemaphore(_) => {}
Self::FencePool {
ref mut last_completed,
ref mut active,
ref mut free,
} => {
let latest = Self::check_active(device, *last_completed, active)?;
let base_free = free.len();
for &(value, raw) in active.iter() {
if value <= latest {
free.push(raw);
}
}
if free.len() != base_free {
active.retain(|&(value, _)| value > latest);
unsafe {
device.reset_fences(&free[base_free..])?;
}
}
*last_completed = latest;
}
}
if self.free.len() != base_free {
self.active.retain(|&(value, _)| value > latest);
unsafe {
device.reset_fences(&self.free[base_free..])?;
}
}
self.last_completed = latest;
Ok(())
}
}
@@ -400,35 +438,49 @@ impl crate::Queue<Api> for Queue {
command_buffers: &[&CommandBuffer],
signal_fence: Option<(&mut Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
let fence_raw = match signal_fence {
Some((fence, value)) => {
fence.maintain(&self.device.raw)?;
let raw = match fence.free.pop() {
Some(raw) => raw,
None => {
let vk_info = vk::FenceCreateInfo::builder().build();
self.device.raw.create_fence(&vk_info, None)?
}
};
fence.active.push((value, raw));
raw
}
None => vk::Fence::null(),
};
let vk_cmd_buffers = command_buffers
.iter()
.map(|cmd| cmd.raw)
.collect::<Vec<_>>();
//TODO: semaphores
let vk_info = vk::SubmitInfo::builder()
.command_buffers(&vk_cmd_buffers)
.build();
let mut vk_info = vk::SubmitInfo::builder().command_buffers(&vk_cmd_buffers);
let mut fence_raw = vk::Fence::null();
let mut vk_timeline_info;
let signal_values;
let signal_semaphores;
if let Some((fence, value)) = signal_fence {
fence.maintain(&self.device.raw)?;
match *fence {
Fence::TimelineSemaphore(raw) => {
signal_values = [value];
signal_semaphores = [raw];
vk_timeline_info = vk::TimelineSemaphoreSubmitInfo::builder()
.signal_semaphore_values(&signal_values);
vk_info = vk_info
.signal_semaphores(&signal_semaphores)
.push_next(&mut vk_timeline_info);
}
Fence::FencePool {
ref mut active,
ref mut free,
..
} => {
fence_raw = match free.pop() {
Some(raw) => raw,
None => {
let vk_info = vk::FenceCreateInfo::builder().build();
self.device.raw.create_fence(&vk_info, None)?
}
};
active.push((value, fence_raw));
}
}
}
self.device
.raw
.queue_submit(self.raw, &[vk_info], fence_raw)?;
.queue_submit(self.raw, &[vk_info.build()], fence_raw)?;
Ok(())
}