Skip to content

Commit b6103cb

Browse files
committed
Ensure glow::Context is current when dropped
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
1 parent 28be38c commit b6103cb

File tree

3 files changed

+58
-11
lines changed

3 files changed

+58
-11
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Bottom level categories:
4343

4444
#### Naga
4545

46-
* 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).
46+
- 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).
4747

4848
### Bug Fixes
4949

@@ -59,8 +59,13 @@ Bottom level categories:
5959
- Fix crash when dropping the surface after the device. By @wumpf in [#6052](https://github.com/gfx-rs/wgpu/pull/6052)
6060
- 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)
6161

62+
#### GLES / OpenGL
63+
64+
- Fix GL debug message callbacks not being properly cleaned up (causing UB). By @Imberflur in [#6114](https://github.com/gfx-rs/wgpu/pull/6114)
65+
6266
### Changes
6367

68+
- `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).
6469
- 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)
6570

6671
### Dependency Updates

wgpu-hal/src/gles/egl.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use glow::HasContext;
22
use once_cell::sync::Lazy;
3-
use parking_lot::{Mutex, MutexGuard, RwLock};
3+
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard, RwLock};
44

5-
use std::{collections::HashMap, ffi, os::raw, ptr, rc::Rc, sync::Arc, time::Duration};
5+
use std::{
6+
collections::HashMap, ffi, mem::ManuallyDrop, os::raw, ptr, rc::Rc, sync::Arc, time::Duration,
7+
};
68

79
/// The amount of time to wait while trying to obtain a lock to the adapter context
810
const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
@@ -295,6 +297,7 @@ impl EglContext {
295297
.make_current(self.display, self.pbuffer, self.pbuffer, Some(self.raw))
296298
.unwrap();
297299
}
300+
298301
fn unmake_current(&self) {
299302
self.instance
300303
.make_current(self.display, None, None, None)
@@ -305,7 +308,7 @@ impl EglContext {
305308
/// A wrapper around a [`glow::Context`] and the required EGL context that uses locking to guarantee
306309
/// exclusive access when shared with multiple threads.
307310
pub struct AdapterContext {
308-
glow: Mutex<glow::Context>,
311+
glow: Mutex<ManuallyDrop<glow::Context>>,
309312
egl: Option<EglContext>,
310313
}
311314

@@ -346,14 +349,34 @@ impl AdapterContext {
346349
}
347350
}
348351

352+
impl Drop for AdapterContext {
353+
fn drop(&mut self) {
354+
// Context must be current when dropped. See safety docs on
355+
// `glow::HasContext`.
356+
//
357+
// NOTE: This is only set to `None` by `Adapter::new_external` which
358+
// requires the context to be current when anything that may be holding
359+
// the `Arc<AdapterShared>` is dropped.
360+
if let Some(egl) = self.egl.as_ref() {
361+
egl.make_current();
362+
}
363+
let glow = self.glow.get_mut();
364+
// SAFETY: Field not used after this.
365+
unsafe { ManuallyDrop::drop(glow) };
366+
if let Some(egl) = self.egl.as_ref() {
367+
egl.unmake_current();
368+
}
369+
}
370+
}
371+
349372
struct EglContextLock<'a> {
350373
instance: &'a Arc<EglInstance>,
351374
display: khronos_egl::Display,
352375
}
353376

354377
/// A guard containing a lock to an [`AdapterContext`]
355378
pub struct AdapterContextLock<'a> {
356-
glow: MutexGuard<'a, glow::Context>,
379+
glow: MutexGuard<'a, ManuallyDrop<glow::Context>>,
357380
egl: Option<EglContextLock<'a>>,
358381
}
359382

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

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

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

10571084
unsafe {
@@ -1073,13 +1100,15 @@ impl super::Adapter {
10731100
/// - The underlying OpenGL ES context must be current.
10741101
/// - The underlying OpenGL ES context must be current when interfacing with any objects returned by
10751102
/// wgpu-hal from this adapter.
1103+
/// - The underlying OpenGL ES context must be current when dropping this adapter and when
1104+
/// dropping any objects returned from this adapter.
10761105
pub unsafe fn new_external(
10771106
fun: impl FnMut(&str) -> *const ffi::c_void,
10781107
) -> Option<crate::ExposedAdapter<super::Api>> {
10791108
let context = unsafe { glow::Context::from_loader_function(fun) };
10801109
unsafe {
10811110
Self::expose(AdapterContext {
1082-
glow: Mutex::new(context),
1111+
glow: Mutex::new(ManuallyDrop::new(context)),
10831112
egl: None,
10841113
})
10851114
}

wgpu-hal/src/gles/wgl.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
99
use std::{
1010
collections::HashSet,
1111
ffi::{c_void, CStr, CString},
12-
mem,
12+
mem::{self, ManuallyDrop},
1313
os::raw::c_int,
1414
ptr,
1515
sync::{
@@ -134,11 +134,22 @@ unsafe impl Send for WglContext {}
134134
unsafe impl Sync for WglContext {}
135135

136136
struct Inner {
137-
gl: glow::Context,
137+
gl: ManuallyDrop<glow::Context>,
138138
device: InstanceDevice,
139139
context: WglContext,
140140
}
141141

142+
impl Drop for Inner {
143+
fn drop(&mut self) {
144+
// Context must be current when dropped. See safety docs on
145+
// `glow::HasContext`.
146+
self.context.make_current(self.device.dc).unwrap();
147+
// SAFETY: Field not used after this.
148+
unsafe { ManuallyDrop::drop(&mut self.gl) };
149+
self.context.unmake_current().unwrap();
150+
}
151+
}
152+
142153
unsafe impl Send for Inner {}
143154
unsafe impl Sync for Inner {}
144155

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

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

0 commit comments

Comments
 (0)