Skip to content

Commit 960555a

Browse files
authored
[wgpu-hal] Allow importing external WGL contexts as with EGL (#6152)
1 parent 4e78829 commit 960555a

File tree

6 files changed

+96
-30
lines changed

6 files changed

+96
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ By @teoxoy [#6134](https://github.com/gfx-rs/wgpu/pull/6134).
118118

119119
- Replace `winapi` code in WGL wrapper to use the `windows` crate. By @MarijnS95 in [#6006](https://github.com/gfx-rs/wgpu/pull/6006)
120120
- Update `glutin` to `0.31` with `glutin-winit` crate. By @MarijnS95 in [#6150](https://github.com/gfx-rs/wgpu/pull/6150) and [#6176](https://github.com/gfx-rs/wgpu/pull/6176)
121+
- Implement `Adapter::new_external()` for WGL (just like EGL) to import an external OpenGL ES context. By @MarijnS95 in [#6152](https://github.com/gfx-rs/wgpu/pull/6152)
121122

122123
#### DX12
123124

Cargo.lock

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wgpu-hal/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ env_logger.workspace = true
206206
glam.workspace = true # for ray-traced-triangle example
207207
winit.workspace = true # for "halmark" example
208208

209-
[target.'cfg(not(any(target_arch = "wasm32", windows, target_os = "ios")))'.dev-dependencies]
210-
glutin-winit = { workspace = true, features = ["egl", "wayland", "x11"] } # for "raw-gles" example
211-
glutin = { workspace = true, features = ["egl", "wayland", "x11"] } # for "raw-gles" example
209+
[target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dev-dependencies]
210+
glutin-winit = { workspace = true, features = ["egl", "wgl", "wayland", "x11"] } # for "raw-gles" example
211+
glutin = { workspace = true, features = ["egl", "wgl", "wayland", "x11"] } # for "raw-gles" example
212212
rwh_05 = { version = "0.5", package = "raw-window-handle" } # temporary compatibility for glutin-winit in "raw-gles" example
213213
winit = { workspace = true, features = ["rwh_05"] } # for "raw-gles" example

wgpu-hal/examples/raw-gles.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
1111
extern crate wgpu_hal as hal;
1212

13-
#[cfg(not(any(windows, target_arch = "wasm32", target_os = "ios")))]
13+
#[cfg(not(any(target_arch = "wasm32", target_os = "ios")))]
1414
fn main() {
1515
use std::{ffi::CString, num::NonZeroU32};
1616

@@ -255,7 +255,6 @@ fn main() {
255255
}
256256

257257
#[cfg(any(
258-
windows,
259258
all(target_arch = "wasm32", not(target_os = "emscripten")),
260259
target_os = "ios"
261260
))]
@@ -264,7 +263,6 @@ fn main() {
264263
}
265264

266265
#[cfg(not(any(
267-
windows,
268266
all(target_arch = "wasm32", not(target_os = "emscripten")),
269267
target_os = "ios"
270268
)))]

wgpu-hal/src/gles/egl.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ struct EglContextLock<'a> {
379379
display: khronos_egl::Display,
380380
}
381381

382-
/// A guard containing a lock to an [`AdapterContext`]
382+
/// A guard containing a lock to an [`AdapterContext`], while the GL context is kept current.
383383
pub struct AdapterContextLock<'a> {
384384
glow: MutexGuard<'a, ManuallyDrop<glow::Context>>,
385385
egl: Option<EglContextLock<'a>>,
@@ -1082,7 +1082,9 @@ impl crate::Instance for Instance {
10821082
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
10831083
}
10841084

1085-
// Avoid accidental drop when the context is not current.
1085+
// Wrap in ManuallyDrop to make it easier to "current" the GL context before dropping this
1086+
// GLOW context, which could also happen if a panic occurs after we uncurrent the context
1087+
// below but before AdapterContext is constructed.
10861088
let gl = ManuallyDrop::new(gl);
10871089
inner.egl.unmake_current();
10881090

wgpu-hal/src/gles/wgl.rs

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
use glow::HasContext;
2-
use glutin_wgl_sys::wgl_extra::{
3-
Wgl, CONTEXT_CORE_PROFILE_BIT_ARB, CONTEXT_DEBUG_BIT_ARB, CONTEXT_FLAGS_ARB,
4-
CONTEXT_PROFILE_MASK_ARB,
5-
};
6-
use once_cell::sync::Lazy;
7-
use parking_lot::{Mutex, MutexGuard, RwLock};
8-
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
91
use std::{
102
collections::HashSet,
113
ffi::{c_void, CStr, CString},
@@ -19,6 +11,15 @@ use std::{
1911
thread,
2012
time::Duration,
2113
};
14+
15+
use glow::HasContext;
16+
use glutin_wgl_sys::wgl_extra::{
17+
Wgl, CONTEXT_CORE_PROFILE_BIT_ARB, CONTEXT_DEBUG_BIT_ARB, CONTEXT_FLAGS_ARB,
18+
CONTEXT_PROFILE_MASK_ARB,
19+
};
20+
use once_cell::sync::Lazy;
21+
use parking_lot::{Mutex, MutexGuard, RwLock};
22+
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
2223
use wgt::InstanceFlags;
2324
use windows::{
2425
core::{Error, PCSTR},
@@ -48,7 +49,10 @@ impl AdapterContext {
4849
}
4950

5051
pub fn raw_context(&self) -> *mut c_void {
51-
self.inner.lock().context.context.0
52+
match self.inner.lock().context {
53+
Some(ref wgl) => wgl.context.0,
54+
None => ptr::null_mut(),
55+
}
5256
}
5357

5458
/// Obtain a lock to the WGL context and get handle to the [`glow::Context`] that can be used to
@@ -62,7 +66,9 @@ impl AdapterContext {
6266
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
6367
.expect("Could not lock adapter context. This is most-likely a deadlock.");
6468

65-
inner.context.make_current(inner.device.dc).unwrap();
69+
if let Some(wgl) = &inner.context {
70+
wgl.make_current(inner.device.dc).unwrap()
71+
};
6672

6773
AdapterContextLock { inner }
6874
}
@@ -79,14 +85,15 @@ impl AdapterContext {
7985
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
8086
.expect("Could not lock adapter context. This is most-likely a deadlock.");
8187

82-
inner
83-
.context
84-
.make_current(device)
85-
.map(|()| AdapterContextLock { inner })
88+
if let Some(wgl) = &inner.context {
89+
wgl.make_current(device)?;
90+
}
91+
92+
Ok(AdapterContextLock { inner })
8693
}
8794
}
8895

89-
/// A guard containing a lock to an [`AdapterContext`]
96+
/// A guard containing a lock to an [`AdapterContext`], while the GL context is kept current.
9097
pub struct AdapterContextLock<'a> {
9198
inner: MutexGuard<'a, Inner>,
9299
}
@@ -101,7 +108,9 @@ impl<'a> std::ops::Deref for AdapterContextLock<'a> {
101108

102109
impl<'a> Drop for AdapterContextLock<'a> {
103110
fn drop(&mut self) {
104-
self.inner.context.unmake_current().unwrap();
111+
if let Some(wgl) = &self.inner.context {
112+
wgl.unmake_current().unwrap()
113+
}
105114
}
106115
}
107116

@@ -136,7 +145,7 @@ unsafe impl Sync for WglContext {}
136145
struct Inner {
137146
gl: ManuallyDrop<glow::Context>,
138147
device: InstanceDevice,
139-
context: WglContext,
148+
context: Option<WglContext>,
140149
}
141150

142151
impl Drop for Inner {
@@ -150,8 +159,14 @@ impl Drop for Inner {
150159

151160
// Context must be current when dropped. See safety docs on
152161
// `glow::HasContext`.
153-
self.context.make_current(self.device.dc).unwrap();
154-
let _guard = CurrentGuard(&self.context);
162+
//
163+
// NOTE: This is only set to `None` by `Adapter::new_external` which
164+
// requires the context to be current when anything that may be holding
165+
// the `Arc<AdapterShared>` is dropped.
166+
let _guard = self.context.as_ref().map(|wgl| {
167+
wgl.make_current(self.device.dc).unwrap();
168+
CurrentGuard(wgl)
169+
});
155170
// SAFETY: Field not used after this.
156171
unsafe { ManuallyDrop::drop(&mut self.gl) };
157172
}
@@ -510,7 +525,9 @@ impl crate::Instance for Instance {
510525
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
511526
}
512527

513-
// Avoid accidental drop when the context is not current.
528+
// Wrap in ManuallyDrop to make it easier to "current" the GL context before dropping this
529+
// GLOW context, which could also happen if a panic occurs after we uncurrent the context
530+
// below but before Inner is constructed.
514531
let gl = ManuallyDrop::new(gl);
515532
context.unmake_current().map_err(|e| {
516533
crate::InstanceError::with_source(
@@ -523,7 +540,7 @@ impl crate::Instance for Instance {
523540
inner: Arc::new(Mutex::new(Inner {
524541
device,
525542
gl,
526-
context,
543+
context: Some(context),
527544
})),
528545
srgb_capable,
529546
})
@@ -565,6 +582,43 @@ impl crate::Instance for Instance {
565582
}
566583
}
567584

585+
impl super::Adapter {
586+
/// Creates a new external adapter using the specified loader function.
587+
///
588+
/// # Safety
589+
///
590+
/// - The underlying OpenGL ES context must be current.
591+
/// - The underlying OpenGL ES context must be current when interfacing with any objects returned by
592+
/// wgpu-hal from this adapter.
593+
/// - The underlying OpenGL ES context must be current when dropping this adapter and when
594+
/// dropping any objects returned from this adapter.
595+
pub unsafe fn new_external(
596+
fun: impl FnMut(&str) -> *const c_void,
597+
) -> Option<crate::ExposedAdapter<super::Api>> {
598+
let context = unsafe { glow::Context::from_loader_function(fun) };
599+
unsafe {
600+
Self::expose(AdapterContext {
601+
inner: Arc::new(Mutex::new(Inner {
602+
gl: ManuallyDrop::new(context),
603+
device: create_instance_device().ok()?,
604+
context: None,
605+
})),
606+
})
607+
}
608+
}
609+
610+
pub fn adapter_context(&self) -> &AdapterContext {
611+
&self.shared.context
612+
}
613+
}
614+
615+
impl super::Device {
616+
/// Returns the underlying WGL context.
617+
pub fn context(&self) -> &AdapterContext {
618+
&self.shared.context
619+
}
620+
}
621+
568622
struct DeviceContextHandle {
569623
device: Gdi::HDC,
570624
window: Foundation::HWND,

0 commit comments

Comments
 (0)