Made SurfaceLock a generic Lock type.

This commit is contained in:
Filipe Rodrigues 2022-02-14 15:37:03 +00:00
parent 908da8931c
commit f2f053df48
5 changed files with 69 additions and 47 deletions

View File

@ -58,6 +58,7 @@
// Modules
mod display_wrapper;
mod lock;
mod rect;
mod scan_dir;
mod side_effect;
@ -66,6 +67,7 @@ mod thread;
// Exports
pub use {
display_wrapper::DisplayWrapper,
lock::Lock,
rect::Rect,
scan_dir::dir_files_iter,
side_effect::{extse, MightBlock, MightLock, SideEffect, WithSideEffect},

41
zsw-util/src/lock.rs Normal file
View File

@ -0,0 +1,41 @@
//! Locks
// Imports
use parking_lot::MutexGuard;
/// Lock with an associated guard
// TODO: Use `lock_api` to make this cleaner
#[derive(Debug)]
pub struct Lock<'a, Data, Source> {
/// Guard
guard: MutexGuard<'a, Data>,
/// Source pointer
// Note: This is just to ensure caller only passes a
// lock that came from the same instance that locked it.
source: *const Source,
}
impl<'a, Data, Source> Lock<'a, Data, Source> {
/// Creates a new lock
pub fn new(guard: MutexGuard<'a, Data>, source: &Source) -> Self {
Self { guard, source }
}
/// Returns the inner data
pub fn get(&self, source: &Source) -> &Data {
self.assert_source(source);
&self.guard
}
/// Returns the inner data
pub fn get_mut(&mut self, source: &Source) -> &mut Data {
self.assert_source(source);
&mut self.guard
}
/// Asserts that the correct `wgpu` instance was passed
fn assert_source(&self, source: &Source) {
assert_eq!(self.source, source as *const _, "Lock had the wrong source then used");
}
}

View File

@ -60,7 +60,7 @@
use {
anyhow::Context,
crossbeam::atomic::AtomicCell,
parking_lot::{Mutex, MutexGuard},
parking_lot::Mutex,
pollster::FutureExt,
std::marker::PhantomData,
wgpu::TextureFormat,
@ -136,6 +136,9 @@ pub struct Wgpu<'window> {
/// Window lifetime
// Note: Our surface must outlive the window, so we make sure of it using the `'window` lifetime
window_phantom: PhantomData<&'window Window>,
/// Lock source
lock_source: LockSource,
}
impl<'window> Wgpu<'window> {
@ -163,6 +166,7 @@ impl<'window> Wgpu<'window> {
surface_texture_format,
queued_resize: AtomicCell::new(None),
window_phantom: PhantomData,
lock_source: LockSource,
})
}
@ -181,13 +185,11 @@ impl<'window> Wgpu<'window> {
/// # Blocking
/// Will block until any existing surface locks are dropped
#[side_effect(MightLock<SurfaceLock>)]
pub fn lock_surface(&self) -> SurfaceLock<'window, '_> {
pub fn lock_surface(&self) -> SurfaceLock {
// DEADLOCK: Caller is responsible to ensure we don't deadlock
// We don't lock it outside of this method
SurfaceLock {
guard: self.surface.lock_se().allow::<MightBlock>(),
wgpu: self as *const _,
}
let guard = self.surface.lock_se().allow::<MightBlock>();
SurfaceLock::new(guard, &self.lock_source)
}
/// Returns the current surface's size
@ -197,7 +199,7 @@ impl<'window> Wgpu<'window> {
/// use it on `wgpu` operations that might panic on wrong surface
/// sizes.
pub fn surface_size(&self, surface_lock: &SurfaceLock) -> PhysicalSize<u32> {
surface_lock.get(self).size
surface_lock.get(&self.lock_source).size
}
/// Returns the surface texture format
@ -230,10 +232,10 @@ impl<'window> Wgpu<'window> {
// TODO: Remove size from passed parameters
pub fn render(
&self,
surface_lock: &mut SurfaceLock<'window, '_>,
surface_lock: &mut SurfaceLock,
f: impl FnOnce(&mut wgpu::CommandEncoder, &wgpu::TextureView, PhysicalSize<u32>) -> Result<(), anyhow::Error>,
) -> Result<(), anyhow::Error> {
let surface = surface_lock.get_mut(self);
let surface = surface_lock.get_mut(&self.lock_source);
// Check for resizes
if let Some(size) = self.queued_resize.take() {
@ -274,37 +276,14 @@ impl<'window> Wgpu<'window> {
}
}
/// Source for all locks
// Note: This is to ensure user can't create the locks themselves
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub struct LockSource;
/// Surface lock
#[derive(Debug)]
pub struct SurfaceLock<'window, 'a> {
/// Guard
guard: MutexGuard<'a, Surface>,
/// `Wgpu` pointer
// Note: This is just to ensure caller only passes a
// lock that came from the same instance
wgpu: *const Wgpu<'window>,
}
impl<'window, 'a> SurfaceLock<'window, 'a> {
/// Returns the guard after ensuring the correct `wgpu` instance was passed
pub fn get(&self, wgpu: &Wgpu<'window>) -> &Surface {
self.assert_source(wgpu);
&self.guard
}
/// Returns the guard mutable after ensuring the correct `wgpu` instance was passed
pub fn get_mut(&mut self, wgpu: &Wgpu<'window>) -> &mut Surface {
self.assert_source(wgpu);
&mut self.guard
}
/// Asserts that the correct `wgpu` instance was passed
fn assert_source(&self, wgpu: &Wgpu<'window>) {
assert_eq!(self.wgpu, wgpu, "Wrong `wgpu` instance was passed to method");
}
}
pub type SurfaceLock<'a> = zsw_util::Lock<'a, Surface, LockSource>;
/// Configures the window surface and returns the preferred surface texture format
fn configure_window_surface(

View File

@ -30,7 +30,7 @@ impl Renderer {
///
/// # Locking
/// Locks the `zsw_wgpu::SurfaceLock` lock on `wgpu`
#[side_effect(MightLock<zsw_wgpu::SurfaceLock<'window, 'wgpu>>)]
#[side_effect(MightLock<zsw_wgpu::SurfaceLock<'wgpu>>)]
pub async fn run<'window, 'wgpu>(
&self,
window: &Window,
@ -81,7 +81,7 @@ impl Renderer {
///
/// # Locking
/// Locks the `zsw_wgpu::SurfaceLock` lock on `wgpu`
#[side_effect(MightLock<zsw_wgpu::SurfaceLock<'window, 'wgpu>>)]
#[side_effect(MightLock<zsw_wgpu::SurfaceLock<'wgpu>>)]
async fn render<'window, 'wgpu>(
window: &Window,
wgpu: &'wgpu Wgpu<'window>,
@ -93,7 +93,7 @@ impl Renderer {
// DEADLOCK: We don't hold the `wgpu::SurfaceLock` lock from `wgpu`.
// Caller ensures we can lock it.
let paint_jobs = settings_window
.paint_jobs()
.paint_jobs(wgpu)
.await
.allow::<MightLock<zsw_wgpu::SurfaceLock>>();

View File

@ -72,10 +72,10 @@ impl SettingsWindow {
///
/// # Locking
/// Locks the `zsw_wgpu::SurfaceLock` lock on `wgpu`
#[side_effect(MightLock<zsw_wgpu::SurfaceLock<'_, '_>>)]
pub async fn run(
#[side_effect(MightLock<zsw_wgpu::SurfaceLock<'wgpu>>)]
pub async fn run<'wgpu>(
&self,
wgpu: &Wgpu<'_>,
wgpu: &'wgpu Wgpu<'_>,
egui: &Egui,
window: &Window,
panels: &Panels,
@ -126,8 +126,8 @@ impl SettingsWindow {
/// Locks the `zsw_wgpu::SurfaceLock` lock on `wgpu`
// Note: Doesn't literally lock it, but the other side of the channel
// needs to lock it in order to progress, so it's equivalent
#[side_effect(MightLock<zsw_wgpu::SurfaceLock<'_, '_>>)]
pub async fn paint_jobs(&self) -> Vec<egui::epaint::ClippedMesh> {
#[side_effect(MightLock<zsw_wgpu::SurfaceLock<'wgpu>>)]
pub async fn paint_jobs<'wgpu>(&self, _wgpu: &'wgpu Wgpu<'_>) -> Vec<egui::epaint::ClippedMesh> {
// Note: This can't return an `Err` because `self` owns a sender
self.paint_jobs_rx.recv().await.expect("Paint jobs sender was closed")
}