mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
hal/vk: enable timeline semaphores
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user