Skip to content

Commit

Permalink
vulkan: Replace fence with semaphore when acquiring surfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Jan 9, 2024
1 parent 4400a58 commit 372b2ac
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 59 deletions.
37 changes: 33 additions & 4 deletions wgpu-core/src/device/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
resource_log, track, FastHashMap, SubmissionIndex,
};

use hal::{CommandEncoder as _, Device as _, Queue as _};
use hal::{CommandEncoder as _, Device as _, Queue as _, RawSet as _};
use parking_lot::Mutex;

use std::{
Expand Down Expand Up @@ -1133,6 +1133,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.fetch_add(1, Ordering::Relaxed)
+ 1;
let mut active_executions = Vec::new();

// SAFETY: We're constructing this during the submission phase,
// where all resources it uses are guaranteed to outlive this
// short-lived set.
let mut submit_surface_textures = A::SubmitSurfaceTextureSet::new();

let mut used_surface_textures = track::TextureUsageScope::new();

let snatch_guard = device.snatchable_lock.read();
Expand Down Expand Up @@ -1237,8 +1243,19 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Err(QueueSubmitError::DestroyedTexture(id));
}
Some(TextureInner::Native { .. }) => false,
Some(TextureInner::Surface { ref has_work, .. }) => {
Some(TextureInner::Surface {
ref has_work,
ref raw,
..
}) => {
has_work.store(true, Ordering::Relaxed);

if let Some(raw) = raw {
unsafe {
submit_surface_textures.insert(raw);
}
}

true
}
};
Expand Down Expand Up @@ -1429,8 +1446,19 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Err(QueueSubmitError::DestroyedTexture(id));
}
Some(TextureInner::Native { .. }) => {}
Some(TextureInner::Surface { ref has_work, .. }) => {
Some(TextureInner::Surface {
ref has_work,
ref raw,
..
}) => {
has_work.store(true, Ordering::Relaxed);

if let Some(raw) = raw {
unsafe {
submit_surface_textures.insert(raw);
}
}

unsafe {
used_surface_textures
.merge_single(texture, None, hal::TextureUses::PRESENT)
Expand Down Expand Up @@ -1469,12 +1497,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.flat_map(|pool_execution| pool_execution.cmd_buffers.iter()),
)
.collect::<Vec<_>>();

unsafe {
queue
.raw
.as_ref()
.unwrap()
.submit(&refs, Some((fence, submit_index)))
.submit(&refs, &submit_surface_textures, Some((fence, submit_index)))
.map_err(DeviceError::from)?;
}

Expand Down
23 changes: 19 additions & 4 deletions wgpu-hal/examples/halmark/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
extern crate wgpu_hal as hal;

use hal::{
Adapter as _, CommandEncoder as _, Device as _, Instance as _, Queue as _, Surface as _,
Adapter as _, CommandEncoder as _, Device as _, Instance as _, Queue as _, RawSet as _,
Surface as _,
};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use winit::{
Expand Down Expand Up @@ -489,8 +490,13 @@ impl<A: hal::Api> Example<A> {
let fence = unsafe {
let mut fence = device.create_fence().unwrap();
let init_cmd = cmd_encoder.end_encoding().unwrap();
let surface_textures = A::SubmitSurfaceTextureSet::new();
queue
.submit(&[&init_cmd], Some((&mut fence, init_fence_value)))
.submit(
&[&init_cmd],
&surface_textures,
Some((&mut fence, init_fence_value)),
)
.unwrap();
device.wait(&fence, init_fence_value, !0).unwrap();
device.destroy_buffer(staging_buffer);
Expand Down Expand Up @@ -541,8 +547,13 @@ impl<A: hal::Api> Example<A> {
unsafe {
{
let ctx = &mut self.contexts[self.context_index];
let surface_textures = A::SubmitSurfaceTextureSet::new();
self.queue
.submit(&[], Some((&mut ctx.fence, ctx.fence_value)))
.submit(
&[],
&surface_textures,
Some((&mut ctx.fence, ctx.fence_value)),
)
.unwrap();
}

Expand Down Expand Up @@ -729,7 +740,11 @@ impl<A: hal::Api> Example<A> {
} else {
None
};
self.queue.submit(&[&cmd_buf], fence_param).unwrap();
let mut surface_textures = A::SubmitSurfaceTextureSet::new();
surface_textures.insert(&surface_tex);
self.queue
.submit(&[&cmd_buf], &surface_textures, fence_param)
.unwrap();
self.queue.present(&self.surface, surface_tex).unwrap();
ctx.used_cmd_bufs.push(cmd_buf);
ctx.used_views.push(surface_tex_view);
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/examples/raw-gles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,6 @@ fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height
encoder.begin_render_pass(&rp_desc);
encoder.end_render_pass();
let cmd_buf = encoder.end_encoding().unwrap();
od.queue.submit(&[&cmd_buf], None).unwrap();
od.queue.submit(&[&cmd_buf], &(), None).unwrap();
}
}
23 changes: 19 additions & 4 deletions wgpu-hal/examples/ray-traced-triangle/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
extern crate wgpu_hal as hal;

use hal::{
Adapter as _, CommandEncoder as _, Device as _, Instance as _, Queue as _, Surface as _,
Adapter as _, CommandEncoder as _, Device as _, Instance as _, Queue as _, RawSet as _,
Surface as _,
};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};

Expand Down Expand Up @@ -754,8 +755,13 @@ impl<A: hal::Api> Example<A> {
let fence = unsafe {
let mut fence = device.create_fence().unwrap();
let init_cmd = cmd_encoder.end_encoding().unwrap();
let surface_textures = A::SubmitSurfaceTextureSet::new();
queue
.submit(&[&init_cmd], Some((&mut fence, init_fence_value)))
.submit(
&[&init_cmd],
&surface_textures,
Some((&mut fence, init_fence_value)),
)
.unwrap();
device.wait(&fence, init_fence_value, !0).unwrap();
cmd_encoder.reset_all(iter::once(init_cmd));
Expand Down Expand Up @@ -960,7 +966,11 @@ impl<A: hal::Api> Example<A> {
} else {
None
};
self.queue.submit(&[&cmd_buf], fence_param).unwrap();
let mut surface_textures = A::SubmitSurfaceTextureSet::new();
surface_textures.insert(&surface_tex);
self.queue
.submit(&[&cmd_buf], &surface_textures, fence_param)
.unwrap();
self.queue.present(&self.surface, surface_tex).unwrap();
ctx.used_cmd_bufs.push(cmd_buf);
ctx.used_views.push(surface_tex_view);
Expand Down Expand Up @@ -998,8 +1008,13 @@ impl<A: hal::Api> Example<A> {
unsafe {
{
let ctx = &mut self.contexts[self.context_index];
let surface_textures = A::SubmitSurfaceTextureSet::new();
self.queue
.submit(&[], Some((&mut ctx.fence, ctx.fence_value)))
.submit(
&[],
&surface_textures,
Some((&mut ctx.fence, ctx.fence_value)),
)
.unwrap();
}

Expand Down
2 changes: 2 additions & 0 deletions wgpu-hal/src/dx12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl crate::Api for Api {
type ComputePipeline = ComputePipeline;

type AccelerationStructure = AccelerationStructure;
type SubmitSurfaceTextureSet = ();
}

// Limited by D3D12's root signature size of 64. Each element takes 1 or 2 entries.
Expand Down Expand Up @@ -877,6 +878,7 @@ impl crate::Queue<Api> for Queue {
unsafe fn submit(
&self,
command_buffers: &[&CommandBuffer],
_surface_textures: &(),
signal_fence: Option<(&mut Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
let mut temp_lists = self.temp_lists.lock();
Expand Down
2 changes: 2 additions & 0 deletions wgpu-hal/src/empty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ impl crate::Api for Api {
type ShaderModule = Resource;
type RenderPipeline = Resource;
type ComputePipeline = Resource;
type SubmitSurfaceTextureSet = ();
}

impl crate::Instance<Api> for Context {
Expand Down Expand Up @@ -104,6 +105,7 @@ impl crate::Queue<Api> for Context {
unsafe fn submit(
&self,
command_buffers: &[&Resource],
surface_textures: &(),
signal_fence: Option<(&mut Resource, crate::FenceValue)>,
) -> DeviceResult<()> {
Ok(())
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/gles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ impl crate::Api for Api {
type ShaderModule = ShaderModule;
type RenderPipeline = RenderPipeline;
type ComputePipeline = ComputePipeline;
type SubmitSurfaceTextureSet = ();
}

bitflags::bitflags! {
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/gles/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,7 @@ impl crate::Queue<super::Api> for super::Queue {
unsafe fn submit(
&self,
command_buffers: &[&super::CommandBuffer],
_surface_textures: &(),
signal_fence: Option<(&mut super::Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
let shared = Arc::clone(&self.shared);
Expand Down
23 changes: 23 additions & 0 deletions wgpu-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ pub trait Api: Clone + fmt::Debug + Sized {
type ComputePipeline: fmt::Debug + WasmNotSendSync;

type AccelerationStructure: fmt::Debug + WasmNotSendSync + 'static;
type SubmitSurfaceTextureSet: RawSet<Self::SurfaceTexture>;
}

pub trait Instance<A: Api>: Sized + WasmNotSendSync {
Expand Down Expand Up @@ -413,9 +414,12 @@ pub trait Queue<A: Api>: WasmNotSendSync {
/// - all of the command buffers were created from command pools
/// that are associated with this queue.
/// - all of the command buffers had `CommadBuffer::finish()` called.
/// - all surface textures that the command buffers write to must be
/// passed to the surface_textures argument.
unsafe fn submit(
&self,
command_buffers: &[&A::CommandBuffer],
surface_textures: &A::SubmitSurfaceTextureSet,
signal_fence: Option<(&mut A::Fence, FenceValue)>,
) -> Result<(), DeviceError>;
unsafe fn present(
Expand Down Expand Up @@ -718,6 +722,25 @@ bitflags!(
}
);

pub trait RawSet<T> {
/// Construct a new set unsafely.
fn new() -> Self;

/// Insert a value into the raw set.
///
/// The caller is responsible for ensuring that the set doesn't outlive the
/// values it contains. The exact requirements depends on which set is being
/// constructed.
unsafe fn insert(&mut self, value: &T);
}

/// Provide a default implementation for () for backends which do not need to
/// track any raw resources so they can easily be stubbed out.
impl<T> RawSet<T> for () {
fn new() -> Self {}
unsafe fn insert(&mut self, _: &T) {}
}

bitflags!(
/// Texture format capability flags.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
Expand Down
2 changes: 2 additions & 0 deletions wgpu-hal/src/metal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ impl crate::Api for Api {
type ComputePipeline = ComputePipeline;

type AccelerationStructure = AccelerationStructure;
type SubmitSurfaceTextureSet = ();
}

pub struct Instance {
Expand Down Expand Up @@ -368,6 +369,7 @@ impl crate::Queue<Api> for Queue {
unsafe fn submit(
&self,
command_buffers: &[&CommandBuffer],
_surface_textures: &(),
signal_fence: Option<(&mut Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
objc::rc::autoreleasepool(|| {
Expand Down
15 changes: 12 additions & 3 deletions wgpu-hal/src/vulkan/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,19 +627,28 @@ impl super::Device {
let images =
unsafe { functor.get_swapchain_images(raw) }.map_err(crate::DeviceError::from)?;

let vk_info = vk::FenceCreateInfo::builder().build();
let fence = unsafe { self.shared.raw.create_fence(&vk_info, None) }
// NOTE: It's important that we define at least images.len() + 1 wait
// semaphores, since we prospectively need to provide the call to
// acquire the next image with an unsignaled semaphore.
let surface_semaphores = (0..images.len() + 1)
.map(|_| unsafe {
self.shared
.raw
.create_semaphore(&vk::SemaphoreCreateInfo::builder(), None)
})
.collect::<Result<Vec<_>, _>>()
.map_err(crate::DeviceError::from)?;

Ok(super::Swapchain {
raw,
raw_flags,
functor,
device: Arc::clone(&self.shared),
fence,
images,
config: config.clone(),
view_formats: wgt_view_formats,
surface_semaphores,
next_surface_index: 0,
})
}

Expand Down
Loading

0 comments on commit 372b2ac

Please sign in to comment.