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 } ;
91use 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 } ;
2223use wgt:: InstanceFlags ;
2324use 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,10 @@ impl<'a> std::ops::Deref for AdapterContextLock<'a> {
101108
102109impl < ' a > Drop for AdapterContextLock < ' a > {
103110 fn drop ( & mut self ) {
104- self . inner . context . unmake_current ( ) . unwrap ( ) ;
111+ // EGL performs a .take() here but that causes issues with drop ordering
112+ if let Some ( wgl) = & self . inner . context {
113+ wgl. unmake_current ( ) . unwrap ( )
114+ }
105115 }
106116}
107117
@@ -136,7 +146,7 @@ unsafe impl Sync for WglContext {}
136146struct Inner {
137147 gl : ManuallyDrop < glow:: Context > ,
138148 device : InstanceDevice ,
139- context : WglContext ,
149+ context : Option < WglContext > ,
140150}
141151
142152impl Drop for Inner {
@@ -150,8 +160,14 @@ impl Drop for Inner {
150160
151161 // Context must be current when dropped. See safety docs on
152162 // `glow::HasContext`.
153- self . context . make_current ( self . device . dc ) . unwrap ( ) ;
154- let _guard = CurrentGuard ( & self . context ) ;
163+ //
164+ // NOTE: This is only set to `None` by `Adapter::new_external` which
165+ // requires the context to be current when anything that may be holding
166+ // the `Arc<AdapterShared>` is dropped.
167+ let _guard = self . context . as_ref ( ) . map ( |wgl| {
168+ wgl. make_current ( self . device . dc ) . unwrap ( ) ;
169+ CurrentGuard ( wgl)
170+ } ) ;
155171 // SAFETY: Field not used after this.
156172 unsafe { ManuallyDrop :: drop ( & mut self . gl ) } ;
157173 }
@@ -515,7 +531,8 @@ impl crate::Instance for Instance {
515531 unsafe { gl. debug_message_callback ( super :: gl_debug_message_callback) } ;
516532 }
517533
518- // Avoid accidental drop when the context is not current.
534+ // Wrap in ManuallyDrop to make it easier to "current" the
535+ // GL context before dropping this GLOW context.
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+
573627struct DeviceContextHandle {
574628 device : Gdi :: HDC ,
575629 window : Foundation :: HWND ,
0 commit comments