Skip to content

Commit 55184ee

Browse files
committed
[wgpu-hal] Allow importing external WGL contexts as with EGL
1 parent 5deaef3 commit 55184ee

File tree

6 files changed

+94
-30
lines changed

6 files changed

+94
-30
lines changed

CHANGELOG.md

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

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

115116
#### DX12
116117

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"] } # for "raw-gles" example
212-
glutin = { workspace = true, features = ["egl"] } # 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"] } # for "raw-gles" example
212+
glutin = { workspace = true, features = ["egl", "wgl"] } # 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: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
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

1717
use glutin::{
1818
config::GlConfig as _,
19-
context::{NotCurrentGlContext as _, PossiblyCurrentGlContext as _},
19+
context::{NotCurrentGlContext as _, PossiblyCurrentGlContext as _, Version},
2020
display::{GetGlDisplay as _, GlDisplay as _},
2121
surface::GlSurface as _,
2222
};
@@ -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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,8 @@ 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
1086+
// GL context before dropping this GLOW context.
10861087
let gl = ManuallyDrop::new(gl);
10871088
inner.egl.unmake_current();
10881089

wgpu-hal/src/gles/wgl.rs

Lines changed: 73 additions & 20 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,10 +85,11 @@ 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

@@ -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.take() {
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,8 @@ 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
534+
// GL context before dropping this GLOW context.
519535
let gl = ManuallyDrop::new(gl);
520536
context.unmake_current().map_err(|e| {
521537
crate::InstanceError::with_source(
@@ -528,7 +544,7 @@ impl crate::Instance for Instance {
528544
inner: Arc::new(Mutex::new(Inner {
529545
device,
530546
gl,
531-
context,
547+
context: Some(context),
532548
})),
533549
srgb_capable,
534550
})
@@ -570,6 +586,43 @@ impl crate::Instance for Instance {
570586
}
571587
}
572588

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

0 commit comments

Comments
 (0)