Skip to content

Commit a0d2102

Browse files
committed
[wgpu-hal] Allow importing external WGL contexts as with EGL
1 parent bbdbafd commit a0d2102

File tree

6 files changed

+97
-31
lines changed

6 files changed

+97
-31
lines changed

CHANGELOG.md

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

117117
- Replace `winapi` code in WGL wrapper to use the `windows` crate. By @MarijnS95 in [#6006](https://github.com/gfx-rs/wgpu/pull/6006)
118118
- 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)
119+
- 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)
119120

120121
#### DX12
121122

Cargo.lock

Lines changed: 13 additions & 2 deletions
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
@@ -207,8 +207,8 @@ env_logger.workspace = true
207207
glam.workspace = true # for ray-traced-triangle example
208208
winit.workspace = true # for "halmark" example
209209

210-
[target.'cfg(not(any(target_arch = "wasm32", windows, target_os = "ios")))'.dev-dependencies]
211-
glutin-winit = { workspace = true, features = ["egl", "wayland", "x11"] } # for "raw-gles" example
212-
glutin = { workspace = true, features = ["egl", "wayland", "x11"] } # for "raw-gles" example
210+
[target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dev-dependencies]
211+
glutin-winit = { workspace = true, features = ["egl", "wgl", "wayland", "x11"] } # for "raw-gles" example
212+
glutin = { workspace = true, features = ["egl", "wgl", "wayland", "x11"] } # for "raw-gles" example
213213
rwh_05 = { version = "0.5", package = "raw-window-handle" } # temporary compatibility for glutin-winit in "raw-gles" example
214214
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
}
@@ -515,7 +530,9 @@ impl crate::Instance for Instance {
515530
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
516531
}
517532

518-
// Avoid accidental drop when the context is not current.
533+
// Wrap in ManuallyDrop to make it easier to "current" the GL context before dropping this
534+
// GLOW context, which could also happen if a panic occurs after we uncurrent the context
535+
// below but before Inner is constructed.
519536
let gl = ManuallyDrop::new(gl);
520537
context.unmake_current().map_err(|e| {
521538
crate::InstanceError::with_source(
@@ -528,7 +545,7 @@ impl crate::Instance for Instance {
528545
inner: Arc::new(Mutex::new(Inner {
529546
device,
530547
gl,
531-
context,
548+
context: Some(context),
532549
})),
533550
srgb_capable,
534551
})
@@ -570,6 +587,43 @@ impl crate::Instance for Instance {
570587
}
571588
}
572589

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

0 commit comments

Comments
 (0)