Skip to content

Commit

Permalink
Ensure glow::Context is current when dropped
Browse files Browse the repository at this point in the history
Cleanup code in glow needs the context to be current (mainly for debug
message callbacks).

See https://docs.rs/glow/0.14.0/glow/trait.HasContext.html#safety
  • Loading branch information
Imberflur committed Aug 14, 2024
1 parent 28be38c commit 8cf4091
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 11 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Bottom level categories:

#### Naga

* Support constant evaluation for `firstLeadingBit` and `firstTrailingBit` numeric built-ins in WGSL. Front-ends that translate to these built-ins also benefit from constant evaluation. By @ErichDonGubler in [#5101](https://github.com/gfx-rs/wgpu/pull/5101).
- Support constant evaluation for `firstLeadingBit` and `firstTrailingBit` numeric built-ins in WGSL. Front-ends that translate to these built-ins also benefit from constant evaluation. By @ErichDonGubler in [#5101](https://github.com/gfx-rs/wgpu/pull/5101).

### Bug Fixes

Expand All @@ -59,8 +59,13 @@ Bottom level categories:
- Fix crash when dropping the surface after the device. By @wumpf in [#6052](https://github.com/gfx-rs/wgpu/pull/6052)
- Fix error message that is thrown in create_render_pass to no longer say `compute_pass`. By @matthew-wong1 [#6041](https://github.com/gfx-rs/wgpu/pull/6041)

#### GLES / OpenGL

- Fix GL debug message callbacks not being properly cleaned up (causing UB). By @Imberflur in [#6114](https://github.com/gfx-rs/wgpu/pull/6114)

### Changes

- `wgpu_hal::gles::Adapter::new_external` now requires the context to be current when dropping the adapter and related objects. By @Imberflur in [#6114](https://github.com/gfx-rs/wgpu/pull/6114).
- Reduce the amount of debug and trace logs emitted by wgpu-core and wgpu-hal. By @nical in [#6065](https://github.com/gfx-rs/wgpu/issues/6065)

### Dependency Updates
Expand Down
46 changes: 38 additions & 8 deletions wgpu-hal/src/gles/egl.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use glow::HasContext;
use once_cell::sync::Lazy;
use parking_lot::{Mutex, MutexGuard, RwLock};
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard, RwLock};

use std::{collections::HashMap, ffi, os::raw, ptr, rc::Rc, sync::Arc, time::Duration};
use std::{
collections::HashMap, ffi, mem::ManuallyDrop, os::raw, ptr, rc::Rc, sync::Arc, time::Duration,
};

/// The amount of time to wait while trying to obtain a lock to the adapter context
const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
Expand Down Expand Up @@ -295,6 +297,7 @@ impl EglContext {
.make_current(self.display, self.pbuffer, self.pbuffer, Some(self.raw))
.unwrap();
}

fn unmake_current(&self) {
self.instance
.make_current(self.display, None, None, None)
Expand All @@ -305,7 +308,7 @@ impl EglContext {
/// A wrapper around a [`glow::Context`] and the required EGL context that uses locking to guarantee
/// exclusive access when shared with multiple threads.
pub struct AdapterContext {
glow: Mutex<glow::Context>,
glow: Mutex<ManuallyDrop<glow::Context>>,
egl: Option<EglContext>,
}

Expand Down Expand Up @@ -346,14 +349,34 @@ impl AdapterContext {
}
}

impl Drop for AdapterContext {
fn drop(&mut self) {
// Context must be current when dropped. See safety docs on
// `glow::HasContext`.
//
// NOTE: This is only set to `None` by `Adapter::new_external` which
// requires the context to be current when anything that may be holding
// the `Arc<AdapterShared>` is dropped.
self.egl.as_ref().map(|egl| {
egl.make_current();
});
let glow = self.glow.get_mut();
// SAFETY: Field not used after this.
unsafe { ManuallyDrop::drop(glow) };
self.egl.as_ref().map(|egl| {
egl.unmake_current();
});
}
}

struct EglContextLock<'a> {
instance: &'a Arc<EglInstance>,
display: khronos_egl::Display,
}

/// A guard containing a lock to an [`AdapterContext`]
pub struct AdapterContextLock<'a> {
glow: MutexGuard<'a, glow::Context>,
glow: MutexGuard<'a, ManuallyDrop<glow::Context>>,
egl: Option<EglContextLock<'a>>,
}

Expand Down Expand Up @@ -387,10 +410,12 @@ impl AdapterContext {
///
/// > **Note:** Calling this function **will** still lock the [`glow::Context`] which adds an
/// > extra safe-guard against accidental concurrent access to the context.
pub unsafe fn get_without_egl_lock(&self) -> MutexGuard<glow::Context> {
self.glow
pub unsafe fn get_without_egl_lock(&self) -> MappedMutexGuard<glow::Context> {
let guard = self
.glow
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
.expect("Could not lock adapter context. This is most-likely a deadlock.")
.expect("Could not lock adapter context. This is most-likely a deadlock.");
MutexGuard::map(guard, |glow| &mut **glow)
}

/// Obtain a lock to the EGL context and get handle to the [`glow::Context`] that can be used to
Expand Down Expand Up @@ -1052,6 +1077,8 @@ impl crate::Instance for Instance {
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
}

// Avoid accidental drop when the context is not current.
let gl = ManuallyDrop::new(gl);
inner.egl.unmake_current();

unsafe {
Expand All @@ -1073,13 +1100,16 @@ impl super::Adapter {
/// - The underlying OpenGL ES context must be current.
/// - The underlying OpenGL ES context must be current when interfacing with any objects returned by
/// wgpu-hal from this adapter.
/// - The underlying OpenGL ES context must be current when dropping this adapter and when
/// dropping any
/// objects returned from this adapter.
pub unsafe fn new_external(
fun: impl FnMut(&str) -> *const ffi::c_void,
) -> Option<crate::ExposedAdapter<super::Api>> {
let context = unsafe { glow::Context::from_loader_function(fun) };
unsafe {
Self::expose(AdapterContext {
glow: Mutex::new(context),
glow: Mutex::new(ManuallyDrop::new(context)),
egl: None,
})
}
Expand Down
17 changes: 15 additions & 2 deletions wgpu-hal/src/gles/wgl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use std::{
collections::HashSet,
ffi::{c_void, CStr, CString},
mem,
mem::{self, ManuallyDrop},
os::raw::c_int,
ptr,
sync::{
Expand Down Expand Up @@ -134,11 +134,22 @@ unsafe impl Send for WglContext {}
unsafe impl Sync for WglContext {}

struct Inner {
gl: glow::Context,
gl: ManuallyDrop<glow::Context>,
device: InstanceDevice,
context: WglContext,
}

impl Drop for Inner {
fn drop(&mut self) {
// Context must be current when dropped. See safety docs on
// `glow::HasContext`.
self.context.make_current(self.device.dc).unwrap();
// SAFETY: Field not used after this.
unsafe { ManuallyDrop::drop(&mut self.gl) };
self.context.unmake_current().unwrap();
}
}

unsafe impl Send for Inner {}
unsafe impl Sync for Inner {}

Expand Down Expand Up @@ -497,6 +508,8 @@ impl crate::Instance for Instance {
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
}

// Avoid accidental drop when the context is not current.
let gl = ManuallyDrop::new(gl);
context.unmake_current().map_err(|e| {
crate::InstanceError::with_source(
String::from("unable to unset the current WGL context"),
Expand Down

0 comments on commit 8cf4091

Please sign in to comment.