Skip to content

Commit fccd298

Browse files
authored
Ensure glow::Context is current when dropped (#6114)
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 685c213 commit fccd298

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ By @teoxoy [#6134](https://github.com/gfx-rs/wgpu/pull/6134).
6969

7070
#### Naga
7171

72-
* 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).
72+
- 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).
7373

7474
#### Vulkan
7575

@@ -91,8 +91,13 @@ By @teoxoy [#6134](https://github.com/gfx-rs/wgpu/pull/6134).
9191
- Fix crash when dropping the surface after the device. By @wumpf in [#6052](https://github.com/gfx-rs/wgpu/pull/6052)
9292
- 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)
9393

94+
#### GLES / OpenGL
95+
96+
- Fix GL debug message callbacks not being properly cleaned up (causing UB). By @Imberflur in [#6114](https://github.com/gfx-rs/wgpu/pull/6114)
97+
9498
### Changes
9599

100+
- `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).
96101
- 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)
97102
- `Rg11b10Float` is renamed to `Rg11b10UFloat`. By @sagudev in [#6108](https://github.com/gfx-rs/wgpu/pull/6108)
98103

wgpu-hal/src/gles/egl.rs

Lines changed: 42 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,39 @@ impl AdapterContext {
346349
}
347350
}
348351

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

354382
/// A guard containing a lock to an [`AdapterContext`]
355383
pub struct AdapterContextLock<'a> {
356-
glow: MutexGuard<'a, glow::Context>,
384+
glow: MutexGuard<'a, ManuallyDrop<glow::Context>>,
357385
egl: Option<EglContextLock<'a>>,
358386
}
359387

@@ -387,10 +415,12 @@ impl AdapterContext {
387415
///
388416
/// > **Note:** Calling this function **will** still lock the [`glow::Context`] which adds an
389417
/// > 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
418+
pub unsafe fn get_without_egl_lock(&self) -> MappedMutexGuard<glow::Context> {
419+
let guard = self
420+
.glow
392421
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
393-
.expect("Could not lock adapter context. This is most-likely a deadlock.")
422+
.expect("Could not lock adapter context. This is most-likely a deadlock.");
423+
MutexGuard::map(guard, |glow| &mut **glow)
394424
}
395425

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

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

10571089
unsafe {
@@ -1073,13 +1105,15 @@ impl super::Adapter {
10731105
/// - The underlying OpenGL ES context must be current.
10741106
/// - The underlying OpenGL ES context must be current when interfacing with any objects returned by
10751107
/// wgpu-hal from this adapter.
1108+
/// - The underlying OpenGL ES context must be current when dropping this adapter and when
1109+
/// dropping any objects returned from this adapter.
10761110
pub unsafe fn new_external(
10771111
fun: impl FnMut(&str) -> *const ffi::c_void,
10781112
) -> Option<crate::ExposedAdapter<super::Api>> {
10791113
let context = unsafe { glow::Context::from_loader_function(fun) };
10801114
unsafe {
10811115
Self::expose(AdapterContext {
1082-
glow: Mutex::new(context),
1116+
glow: Mutex::new(ManuallyDrop::new(context)),
10831117
egl: None,
10841118
})
10851119
}

wgpu-hal/src/gles/wgl.rs

Lines changed: 22 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,29 @@ 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+
struct CurrentGuard<'a>(&'a WglContext);
145+
impl Drop for CurrentGuard<'_> {
146+
fn drop(&mut self) {
147+
self.0.unmake_current().unwrap();
148+
}
149+
}
150+
151+
// Context must be current when dropped. See safety docs on
152+
// `glow::HasContext`.
153+
self.context.make_current(self.device.dc).unwrap();
154+
let _guard = CurrentGuard(&self.context);
155+
// SAFETY: Field not used after this.
156+
unsafe { ManuallyDrop::drop(&mut self.gl) };
157+
}
158+
}
159+
142160
unsafe impl Send for Inner {}
143161
unsafe impl Sync for Inner {}
144162

@@ -497,6 +515,8 @@ impl crate::Instance for Instance {
497515
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
498516
}
499517

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

0 commit comments

Comments
 (0)