Skip to content

Commit

Permalink
[wgpu-hal] Allow importing external WGL contexts as with EGL
Browse files Browse the repository at this point in the history
  • Loading branch information
MarijnS95 committed Aug 27, 2024
1 parent 5deaef3 commit 55184ee
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ By @teoxoy [#6134](https://github.com/gfx-rs/wgpu/pull/6134).
#### GLES

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

#### DX12

Expand Down
15 changes: 13 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ env_logger.workspace = true
glam.workspace = true # for ray-traced-triangle example
winit.workspace = true # for "halmark" example

[target.'cfg(not(any(target_arch = "wasm32", windows, target_os = "ios")))'.dev-dependencies]
glutin-winit = { workspace = true, features = ["egl"] } # for "raw-gles" example
glutin = { workspace = true, features = ["egl"] } # for "raw-gles" example
[target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dev-dependencies]
glutin-winit = { workspace = true, features = ["egl", "wgl"] } # for "raw-gles" example
glutin = { workspace = true, features = ["egl", "wgl"] } # for "raw-gles" example
rwh_05 = { version = "0.5", package = "raw-window-handle" } # temporary compatibility for glutin-winit in "raw-gles" example
winit = { workspace = true, features = ["rwh_05"] } # for "raw-gles" example
6 changes: 2 additions & 4 deletions wgpu-hal/examples/raw-gles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@

extern crate wgpu_hal as hal;

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

use glutin::{
config::GlConfig as _,
context::{NotCurrentGlContext as _, PossiblyCurrentGlContext as _},
context::{NotCurrentGlContext as _, PossiblyCurrentGlContext as _, Version},
display::{GetGlDisplay as _, GlDisplay as _},
surface::GlSurface as _,
};
Expand Down Expand Up @@ -255,7 +255,6 @@ fn main() {
}

#[cfg(any(
windows,
all(target_arch = "wasm32", not(target_os = "emscripten")),
target_os = "ios"
))]
Expand All @@ -264,7 +263,6 @@ fn main() {
}

#[cfg(not(any(
windows,
all(target_arch = "wasm32", not(target_os = "emscripten")),
target_os = "ios"
)))]
Expand Down
3 changes: 2 additions & 1 deletion wgpu-hal/src/gles/egl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1082,7 +1082,8 @@ impl crate::Instance for Instance {
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
}

// Avoid accidental drop when the context is not current.
// Wrap in ManuallyDrop to make it easier to "current" the
// GL context before dropping this GLOW context.
let gl = ManuallyDrop::new(gl);
inner.egl.unmake_current();

Expand Down
93 changes: 73 additions & 20 deletions wgpu-hal/src/gles/wgl.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
use glow::HasContext;
use glutin_wgl_sys::wgl_extra::{
Wgl, CONTEXT_CORE_PROFILE_BIT_ARB, CONTEXT_DEBUG_BIT_ARB, CONTEXT_FLAGS_ARB,
CONTEXT_PROFILE_MASK_ARB,
};
use once_cell::sync::Lazy;
use parking_lot::{Mutex, MutexGuard, RwLock};
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use std::{
collections::HashSet,
ffi::{c_void, CStr, CString},
Expand All @@ -19,6 +11,15 @@ use std::{
thread,
time::Duration,
};

use glow::HasContext;
use glutin_wgl_sys::wgl_extra::{
Wgl, CONTEXT_CORE_PROFILE_BIT_ARB, CONTEXT_DEBUG_BIT_ARB, CONTEXT_FLAGS_ARB,
CONTEXT_PROFILE_MASK_ARB,
};
use once_cell::sync::Lazy;
use parking_lot::{Mutex, MutexGuard, RwLock};
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use wgt::InstanceFlags;
use windows::{
core::{Error, PCSTR},
Expand Down Expand Up @@ -48,7 +49,10 @@ impl AdapterContext {
}

pub fn raw_context(&self) -> *mut c_void {
self.inner.lock().context.context.0
match self.inner.lock().context {
Some(ref wgl) => wgl.context.0,
None => ptr::null_mut(),
}
}

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

inner.context.make_current(inner.device.dc).unwrap();
if let Some(wgl) = &inner.context {
wgl.make_current(inner.device.dc).unwrap()
};

AdapterContextLock { inner }
}
Expand All @@ -79,10 +85,11 @@ impl AdapterContext {
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
.expect("Could not lock adapter context. This is most-likely a deadlock.");

inner
.context
.make_current(device)
.map(|()| AdapterContextLock { inner })
if let Some(wgl) = &inner.context {
wgl.make_current(device)?;
}

Ok(AdapterContextLock { inner })
}
}

Expand All @@ -101,7 +108,9 @@ impl<'a> std::ops::Deref for AdapterContextLock<'a> {

impl<'a> Drop for AdapterContextLock<'a> {
fn drop(&mut self) {
self.inner.context.unmake_current().unwrap();
if let Some(wgl) = self.inner.context.take() {
wgl.unmake_current().unwrap()
}
}
}

Expand Down Expand Up @@ -136,7 +145,7 @@ unsafe impl Sync for WglContext {}
struct Inner {
gl: ManuallyDrop<glow::Context>,
device: InstanceDevice,
context: WglContext,
context: Option<WglContext>,
}

impl Drop for Inner {
Expand All @@ -150,8 +159,14 @@ impl Drop for Inner {

// Context must be current when dropped. See safety docs on
// `glow::HasContext`.
self.context.make_current(self.device.dc).unwrap();
let _guard = CurrentGuard(&self.context);
//
// NOTE: This is only set to `None` by `Adapter::new_external` which
// requires the context to be current when anything that may be holding
// the `Arc<AdapterShared>` is dropped.
let _guard = self.context.as_ref().map(|wgl| {
wgl.make_current(self.device.dc).unwrap();
CurrentGuard(wgl)
});
// SAFETY: Field not used after this.
unsafe { ManuallyDrop::drop(&mut self.gl) };
}
Expand Down Expand Up @@ -515,7 +530,8 @@ impl crate::Instance for Instance {
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
}

// Avoid accidental drop when the context is not current.
// Wrap in ManuallyDrop to make it easier to "current" the
// GL context before dropping this GLOW context.
let gl = ManuallyDrop::new(gl);
context.unmake_current().map_err(|e| {
crate::InstanceError::with_source(
Expand All @@ -528,7 +544,7 @@ impl crate::Instance for Instance {
inner: Arc::new(Mutex::new(Inner {
device,
gl,
context,
context: Some(context),
})),
srgb_capable,
})
Expand Down Expand Up @@ -570,6 +586,43 @@ impl crate::Instance for Instance {
}
}

impl super::Adapter {
/// Creates a new external adapter using the specified loader function.
///
/// # Safety
///
/// - The underlying OpenGL ES context must be current.
/// - The underlying OpenGL ES context must be current when interfacing with any objects returned by
/// wgpu-hal from this adapter.
/// - The underlying OpenGL ES context must be current when dropping this adapter and when
/// dropping any objects returned from this adapter.
pub unsafe fn new_external(
fun: impl FnMut(&str) -> *const c_void,
) -> Option<crate::ExposedAdapter<super::Api>> {
let context = unsafe { glow::Context::from_loader_function(fun) };
unsafe {
Self::expose(AdapterContext {
inner: Arc::new(Mutex::new(Inner {
gl: ManuallyDrop::new(context),
device: create_instance_device().ok()?,
context: None,
})),
})
}
}

pub fn adapter_context(&self) -> &AdapterContext {
&self.shared.context
}
}

impl super::Device {
/// Returns the underlying WGL context.
pub fn context(&self) -> &AdapterContext {
&self.shared.context
}
}

struct DeviceContextHandle {
device: Gdi::HDC,
window: Foundation::HWND,
Expand Down

0 comments on commit 55184ee

Please sign in to comment.