1use std::{
2 collections::HashSet,
3 ffi::{c_void, CStr, CString},
4 mem::{self, size_of, size_of_val, ManuallyDrop},
5 os::raw::c_int,
6 ptr,
7 sync::{
8 mpsc::{sync_channel, SyncSender},
9 Arc,
10 },
11 thread,
12 time::Duration,
13};
14
15use glow::HasContext;
16use 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};
20use once_cell::sync::Lazy;
21use parking_lot::{Mutex, MutexGuard, RwLock};
22use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
23use wgt::InstanceFlags;
24use windows::{
25 core::{Error, PCSTR},
26 Win32::{
27 Foundation,
28 Graphics::{Gdi, OpenGL},
29 System::LibraryLoader,
30 UI::WindowsAndMessaging,
31 },
32};
33
34const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1;
36
37pub struct AdapterContext {
40 inner: Arc<Mutex<Inner>>,
41}
42
43unsafe impl Sync for AdapterContext {}
44unsafe impl Send for AdapterContext {}
45
46impl AdapterContext {
47 pub fn is_owned(&self) -> bool {
48 true
49 }
50
51 pub fn raw_context(&self) -> *mut c_void {
52 match self.inner.lock().context {
53 Some(ref wgl) => wgl.context.0,
54 None => ptr::null_mut(),
55 }
56 }
57
58 #[track_caller]
61 pub fn lock(&self) -> AdapterContextLock<'_> {
62 let inner = self
63 .inner
64 .try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
67 .expect("Could not lock adapter context. This is most-likely a deadlock.");
68
69 if let Some(wgl) = &inner.context {
70 wgl.make_current(inner.device.dc).unwrap()
71 };
72
73 AdapterContextLock { inner }
74 }
75
76 #[track_caller]
82 fn lock_with_dc(&self, device: Gdi::HDC) -> windows::core::Result<AdapterContextLock<'_>> {
83 let inner = self
84 .inner
85 .try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
86 .expect("Could not lock adapter context. This is most-likely a deadlock.");
87
88 if let Some(wgl) = &inner.context {
89 wgl.make_current(device)?;
90 }
91
92 Ok(AdapterContextLock { inner })
93 }
94}
95
96pub struct AdapterContextLock<'a> {
98 inner: MutexGuard<'a, Inner>,
99}
100
101impl<'a> std::ops::Deref for AdapterContextLock<'a> {
102 type Target = glow::Context;
103
104 fn deref(&self) -> &Self::Target {
105 &self.inner.gl
106 }
107}
108
109impl<'a> Drop for AdapterContextLock<'a> {
110 fn drop(&mut self) {
111 if let Some(wgl) = &self.inner.context {
112 wgl.unmake_current().unwrap()
113 }
114 }
115}
116
117struct WglContext {
118 context: OpenGL::HGLRC,
119}
120
121impl WglContext {
122 fn make_current(&self, device: Gdi::HDC) -> windows::core::Result<()> {
123 unsafe { OpenGL::wglMakeCurrent(device, self.context) }
124 }
125
126 fn unmake_current(&self) -> windows::core::Result<()> {
127 if unsafe { OpenGL::wglGetCurrentContext() }.is_invalid() {
128 return Ok(());
129 }
130 unsafe { OpenGL::wglMakeCurrent(None, None) }
131 }
132}
133
134impl Drop for WglContext {
135 fn drop(&mut self) {
136 if let Err(e) = unsafe { OpenGL::wglDeleteContext(self.context) } {
137 log::error!("failed to delete WGL context: {e}");
138 }
139 }
140}
141
142unsafe impl Send for WglContext {}
143unsafe impl Sync for WglContext {}
144
145struct Inner {
146 gl: ManuallyDrop<glow::Context>,
147 device: InstanceDevice,
148 context: Option<WglContext>,
149}
150
151impl Drop for Inner {
152 fn drop(&mut self) {
153 struct CurrentGuard<'a>(&'a WglContext);
154 impl Drop for CurrentGuard<'_> {
155 fn drop(&mut self) {
156 self.0.unmake_current().unwrap();
157 }
158 }
159
160 let _guard = self.context.as_ref().map(|wgl| {
167 wgl.make_current(self.device.dc).unwrap();
168 CurrentGuard(wgl)
169 });
170 unsafe { ManuallyDrop::drop(&mut self.gl) };
172 }
173}
174
175unsafe impl Send for Inner {}
176unsafe impl Sync for Inner {}
177
178pub struct Instance {
179 srgb_capable: bool,
180 inner: Arc<Mutex<Inner>>,
181}
182
183unsafe impl Send for Instance {}
184unsafe impl Sync for Instance {}
185
186fn load_gl_func(name: &str, module: Option<Foundation::HMODULE>) -> *const c_void {
187 let addr = CString::new(name.as_bytes()).unwrap();
188 let mut ptr = unsafe { OpenGL::wglGetProcAddress(PCSTR(addr.as_ptr().cast())) };
189 if ptr.is_none() {
190 if let Some(module) = module {
191 ptr = unsafe { LibraryLoader::GetProcAddress(module, PCSTR(addr.as_ptr().cast())) };
192 }
193 }
194 ptr.map_or_else(ptr::null_mut, |p| p as *mut c_void)
195}
196
197fn get_extensions(extra: &Wgl, dc: Gdi::HDC) -> HashSet<String> {
198 if extra.GetExtensionsStringARB.is_loaded() {
199 unsafe { CStr::from_ptr(extra.GetExtensionsStringARB(dc.0)) }
200 .to_str()
201 .unwrap_or("")
202 } else {
203 ""
204 }
205 .split(' ')
206 .map(|s| s.to_owned())
207 .collect()
208}
209
210unsafe fn setup_pixel_format(dc: Gdi::HDC) -> Result<(), crate::InstanceError> {
211 {
212 let format = OpenGL::PIXELFORMATDESCRIPTOR {
213 nVersion: 1,
214 nSize: size_of::<OpenGL::PIXELFORMATDESCRIPTOR>() as u16,
215 dwFlags: OpenGL::PFD_DRAW_TO_WINDOW
216 | OpenGL::PFD_SUPPORT_OPENGL
217 | OpenGL::PFD_DOUBLEBUFFER,
218 iPixelType: OpenGL::PFD_TYPE_RGBA,
219 cColorBits: 8,
220 ..unsafe { mem::zeroed() }
221 };
222
223 let index = unsafe { OpenGL::ChoosePixelFormat(dc, &format) };
224 if index == 0 {
225 return Err(crate::InstanceError::with_source(
226 String::from("unable to choose pixel format"),
227 Error::from_win32(),
228 ));
229 }
230
231 let current = unsafe { OpenGL::GetPixelFormat(dc) };
232
233 if index != current {
234 unsafe { OpenGL::SetPixelFormat(dc, index, &format) }.map_err(|e| {
235 crate::InstanceError::with_source(String::from("unable to set pixel format"), e)
236 })?;
237 }
238 }
239
240 {
241 let index = unsafe { OpenGL::GetPixelFormat(dc) };
242 if index == 0 {
243 return Err(crate::InstanceError::with_source(
244 String::from("unable to get pixel format index"),
245 Error::from_win32(),
246 ));
247 }
248 let mut format = Default::default();
249 if unsafe {
250 OpenGL::DescribePixelFormat(dc, index, size_of_val(&format) as u32, Some(&mut format))
251 } == 0
252 {
253 return Err(crate::InstanceError::with_source(
254 String::from("unable to read pixel format"),
255 Error::from_win32(),
256 ));
257 }
258
259 if !format.dwFlags.contains(OpenGL::PFD_SUPPORT_OPENGL)
260 || format.iPixelType != OpenGL::PFD_TYPE_RGBA
261 {
262 return Err(crate::InstanceError::new(String::from(
263 "unsuitable pixel format",
264 )));
265 }
266 }
267 Ok(())
268}
269
270fn create_global_window_class() -> Result<CString, crate::InstanceError> {
271 let instance = unsafe { LibraryLoader::GetModuleHandleA(None) }.map_err(|e| {
272 crate::InstanceError::with_source(String::from("unable to get executable instance"), e)
273 })?;
274
275 static UNIQUE: Mutex<u8> = Mutex::new(0);
278 let class_addr: *const _ = &UNIQUE;
279 let name = format!("wgpu Device Class {:x}\0", class_addr as usize);
280 let name = CString::from_vec_with_nul(name.into_bytes()).unwrap();
281
282 unsafe extern "system" fn wnd_proc(
284 window: Foundation::HWND,
285 msg: u32,
286 wparam: Foundation::WPARAM,
287 lparam: Foundation::LPARAM,
288 ) -> Foundation::LRESULT {
289 unsafe { WindowsAndMessaging::DefWindowProcA(window, msg, wparam, lparam) }
290 }
291
292 let window_class = WindowsAndMessaging::WNDCLASSEXA {
293 cbSize: size_of::<WindowsAndMessaging::WNDCLASSEXA>() as u32,
294 style: WindowsAndMessaging::CS_OWNDC,
295 lpfnWndProc: Some(wnd_proc),
296 cbClsExtra: 0,
297 cbWndExtra: 0,
298 hInstance: instance.into(),
299 hIcon: WindowsAndMessaging::HICON::default(),
300 hCursor: WindowsAndMessaging::HCURSOR::default(),
301 hbrBackground: Gdi::HBRUSH::default(),
302 lpszMenuName: PCSTR::null(),
303 lpszClassName: PCSTR(name.as_ptr().cast()),
304 hIconSm: WindowsAndMessaging::HICON::default(),
305 };
306
307 let atom = unsafe { WindowsAndMessaging::RegisterClassExA(&window_class) };
308
309 if atom == 0 {
310 return Err(crate::InstanceError::with_source(
311 String::from("unable to register window class"),
312 Error::from_win32(),
313 ));
314 }
315
316 Ok(name)
319}
320
321fn get_global_window_class() -> Result<CString, crate::InstanceError> {
322 static GLOBAL: Lazy<Result<CString, crate::InstanceError>> =
323 Lazy::new(create_global_window_class);
324 GLOBAL.clone()
325}
326
327struct InstanceDevice {
328 dc: Gdi::HDC,
329
330 _tx: SyncSender<()>,
332}
333
334fn create_instance_device() -> Result<InstanceDevice, crate::InstanceError> {
335 #[derive(Clone, Copy)]
336 struct SendDc(Gdi::HDC);
338 unsafe impl Sync for SendDc {}
339 unsafe impl Send for SendDc {}
340
341 struct Window {
342 window: Foundation::HWND,
343 }
344 impl Drop for Window {
345 fn drop(&mut self) {
346 if let Err(e) = unsafe { WindowsAndMessaging::DestroyWindow(self.window) } {
347 log::error!("failed to destroy window: {e}");
348 }
349 }
350 }
351
352 let window_class = get_global_window_class()?;
353
354 let (drop_tx, drop_rx) = sync_channel(0);
355 let (setup_tx, setup_rx) = sync_channel(0);
356
357 thread::Builder::new()
359 .stack_size(256 * 1024)
360 .name("wgpu-hal WGL Instance Thread".to_owned())
361 .spawn(move || {
362 let setup = (|| {
363 let instance = unsafe { LibraryLoader::GetModuleHandleA(None) }.map_err(|e| {
364 crate::InstanceError::with_source(
365 String::from("unable to get executable instance"),
366 e,
367 )
368 })?;
369
370 let window = unsafe {
372 WindowsAndMessaging::CreateWindowExA(
373 WindowsAndMessaging::WINDOW_EX_STYLE::default(),
374 PCSTR(window_class.as_ptr().cast()),
375 PCSTR(window_class.as_ptr().cast()),
376 WindowsAndMessaging::WINDOW_STYLE::default(),
377 0,
378 0,
379 1,
380 1,
381 None,
382 None,
383 instance,
384 None,
385 )
386 }
387 .map_err(|e| {
388 crate::InstanceError::with_source(
389 String::from("unable to create hidden instance window"),
390 e,
391 )
392 })?;
393 let window = Window { window };
394
395 let dc = unsafe { Gdi::GetDC(window.window) };
396 if dc.is_invalid() {
397 return Err(crate::InstanceError::with_source(
398 String::from("unable to create memory device"),
399 Error::from_win32(),
400 ));
401 }
402 let dc = DeviceContextHandle {
403 device: dc,
404 window: window.window,
405 };
406 unsafe { setup_pixel_format(dc.device)? };
407
408 Ok((window, dc))
409 })();
410
411 match setup {
412 Ok((_window, dc)) => {
413 setup_tx.send(Ok(SendDc(dc.device))).unwrap();
414 drop_rx.recv().ok();
416 }
417 Err(err) => {
418 setup_tx.send(Err(err)).unwrap();
419 }
420 }
421 })
422 .map_err(|e| {
423 crate::InstanceError::with_source(String::from("unable to create instance thread"), e)
424 })?;
425
426 let dc = setup_rx.recv().unwrap()?.0;
427
428 Ok(InstanceDevice { dc, _tx: drop_tx })
429}
430
431impl crate::Instance for Instance {
432 type A = super::Api;
433
434 unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
435 profiling::scope!("Init OpenGL (WGL) Backend");
436 let opengl_module =
437 unsafe { LibraryLoader::LoadLibraryA(PCSTR("opengl32.dll\0".as_ptr())) }.map_err(
438 |e| {
439 crate::InstanceError::with_source(
440 String::from("unable to load the OpenGL library"),
441 e,
442 )
443 },
444 )?;
445
446 let device = create_instance_device()?;
447 let dc = device.dc;
448
449 let context = unsafe { OpenGL::wglCreateContext(dc) }.map_err(|e| {
450 crate::InstanceError::with_source(
451 String::from("unable to create initial OpenGL context"),
452 e,
453 )
454 })?;
455 let context = WglContext { context };
456 context.make_current(dc).map_err(|e| {
457 crate::InstanceError::with_source(
458 String::from("unable to set initial OpenGL context as current"),
459 e,
460 )
461 })?;
462
463 let extra = Wgl::load_with(|name| load_gl_func(name, None));
464 let extensions = get_extensions(&extra, dc);
465
466 let can_use_profile = extensions.contains("WGL_ARB_create_context_profile")
467 && extra.CreateContextAttribsARB.is_loaded();
468
469 let context = if can_use_profile {
470 let attributes = [
471 CONTEXT_PROFILE_MASK_ARB as c_int,
472 CONTEXT_CORE_PROFILE_BIT_ARB as c_int,
473 CONTEXT_FLAGS_ARB as c_int,
474 if desc.flags.contains(InstanceFlags::DEBUG) {
475 CONTEXT_DEBUG_BIT_ARB as c_int
476 } else {
477 0
478 },
479 0, ];
481 let context =
482 unsafe { extra.CreateContextAttribsARB(dc.0, ptr::null(), attributes.as_ptr()) };
483 if context.is_null() {
484 return Err(crate::InstanceError::with_source(
485 String::from("unable to create OpenGL context"),
486 Error::from_win32(),
487 ));
488 }
489 WglContext {
490 context: OpenGL::HGLRC(context.cast_mut()),
491 }
492 } else {
493 context
494 };
495
496 context.make_current(dc).map_err(|e| {
497 crate::InstanceError::with_source(
498 String::from("unable to set OpenGL context as current"),
499 e,
500 )
501 })?;
502
503 let mut gl = unsafe {
504 glow::Context::from_loader_function(|name| load_gl_func(name, Some(opengl_module)))
505 };
506
507 let extra = Wgl::load_with(|name| load_gl_func(name, None));
508 let extensions = get_extensions(&extra, dc);
509
510 let srgb_capable = extensions.contains("WGL_EXT_framebuffer_sRGB")
511 || extensions.contains("WGL_ARB_framebuffer_sRGB")
512 || gl
513 .supported_extensions()
514 .contains("GL_ARB_framebuffer_sRGB");
515
516 if srgb_capable {
519 unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) };
520 }
521
522 if desc.flags.contains(InstanceFlags::VALIDATION) && gl.supports_debug() {
523 log::debug!("Enabling GL debug output");
524 unsafe { gl.enable(glow::DEBUG_OUTPUT) };
525 unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
526 }
527
528 let gl = ManuallyDrop::new(gl);
532 context.unmake_current().map_err(|e| {
533 crate::InstanceError::with_source(
534 String::from("unable to unset the current WGL context"),
535 e,
536 )
537 })?;
538
539 Ok(Instance {
540 inner: Arc::new(Mutex::new(Inner {
541 device,
542 gl,
543 context: Some(context),
544 })),
545 srgb_capable,
546 })
547 }
548
549 #[cfg_attr(target_os = "macos", allow(unused, unused_mut, unreachable_code))]
550 unsafe fn create_surface(
551 &self,
552 _display_handle: RawDisplayHandle,
553 window_handle: RawWindowHandle,
554 ) -> Result<Surface, crate::InstanceError> {
555 let window = if let RawWindowHandle::Win32(handle) = window_handle {
556 handle
557 } else {
558 return Err(crate::InstanceError::new(format!(
559 "unsupported window: {window_handle:?}"
560 )));
561 };
562 Ok(Surface {
563 window: Foundation::HWND(window.hwnd.get() as *mut _),
565 presentable: true,
566 swapchain: RwLock::new(None),
567 srgb_capable: self.srgb_capable,
568 })
569 }
570
571 unsafe fn enumerate_adapters(
572 &self,
573 _surface_hint: Option<&Surface>,
574 ) -> Vec<crate::ExposedAdapter<super::Api>> {
575 unsafe {
576 super::Adapter::expose(AdapterContext {
577 inner: self.inner.clone(),
578 })
579 }
580 .into_iter()
581 .collect()
582 }
583}
584
585impl super::Adapter {
586 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
615impl super::Device {
616 pub fn context(&self) -> &AdapterContext {
618 &self.shared.context
619 }
620}
621
622struct DeviceContextHandle {
623 device: Gdi::HDC,
624 window: Foundation::HWND,
625}
626
627impl Drop for DeviceContextHandle {
628 fn drop(&mut self) {
629 unsafe {
630 Gdi::ReleaseDC(self.window, self.device);
631 };
632 }
633}
634
635pub struct Swapchain {
636 framebuffer: glow::Framebuffer,
637 renderbuffer: glow::Renderbuffer,
638
639 extent: wgt::Extent3d,
641
642 format: wgt::TextureFormat,
643 format_desc: super::TextureFormatDesc,
644 #[allow(unused)]
645 sample_type: wgt::TextureSampleType,
646}
647
648pub struct Surface {
649 window: Foundation::HWND,
650 pub(super) presentable: bool,
651 swapchain: RwLock<Option<Swapchain>>,
652 srgb_capable: bool,
653}
654
655unsafe impl Send for Surface {}
656unsafe impl Sync for Surface {}
657
658impl Surface {
659 pub(super) unsafe fn present(
660 &self,
661 _suf_texture: super::Texture,
662 context: &AdapterContext,
663 ) -> Result<(), crate::SurfaceError> {
664 let swapchain = self.swapchain.read();
665 let sc = swapchain.as_ref().unwrap();
666 let dc = unsafe { Gdi::GetDC(self.window) };
667 if dc.is_invalid() {
668 log::error!(
669 "unable to get the device context from window: {}",
670 Error::from_win32()
671 );
672 return Err(crate::SurfaceError::Other(
673 "unable to get the device context from window",
674 ));
675 }
676 let dc = DeviceContextHandle {
677 device: dc,
678 window: self.window,
679 };
680
681 let gl = context.lock_with_dc(dc.device).map_err(|e| {
682 log::error!("unable to make the OpenGL context current for surface: {e}",);
683 crate::SurfaceError::Other("unable to make the OpenGL context current for surface")
684 })?;
685
686 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
687 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)) };
688
689 if self.srgb_capable {
690 unsafe { gl.disable(glow::FRAMEBUFFER_SRGB) };
693 }
694
695 unsafe {
699 gl.blit_framebuffer(
700 0,
701 sc.extent.height as i32,
702 sc.extent.width as i32,
703 0,
704 0,
705 0,
706 sc.extent.width as i32,
707 sc.extent.height as i32,
708 glow::COLOR_BUFFER_BIT,
709 glow::NEAREST,
710 )
711 };
712
713 if self.srgb_capable {
714 unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) };
715 }
716
717 unsafe { gl.bind_renderbuffer(glow::RENDERBUFFER, None) };
718 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
719
720 if let Err(e) = unsafe { OpenGL::SwapBuffers(dc.device) } {
721 log::error!("unable to swap buffers: {e}");
722 return Err(crate::SurfaceError::Other("unable to swap buffers"));
723 }
724
725 Ok(())
726 }
727
728 pub fn supports_srgb(&self) -> bool {
729 self.srgb_capable
730 }
731}
732
733impl crate::Surface for Surface {
734 type A = super::Api;
735
736 unsafe fn configure(
737 &self,
738 device: &super::Device,
739 config: &crate::SurfaceConfiguration,
740 ) -> Result<(), crate::SurfaceError> {
741 unsafe { self.unconfigure(device) };
743
744 let dc = unsafe { Gdi::GetDC(self.window) };
745 if dc.is_invalid() {
746 log::error!(
747 "unable to get the device context from window: {}",
748 Error::from_win32()
749 );
750 return Err(crate::SurfaceError::Other(
751 "unable to get the device context from window",
752 ));
753 }
754 let dc = DeviceContextHandle {
755 device: dc,
756 window: self.window,
757 };
758
759 if let Err(e) = unsafe { setup_pixel_format(dc.device) } {
760 log::error!("unable to setup surface pixel format: {e}",);
761 return Err(crate::SurfaceError::Other(
762 "unable to setup surface pixel format",
763 ));
764 }
765
766 let format_desc = device.shared.describe_texture_format(config.format);
767 let gl = &device.shared.context.lock_with_dc(dc.device).map_err(|e| {
768 log::error!("unable to make the OpenGL context current for surface: {e}",);
769 crate::SurfaceError::Other("unable to make the OpenGL context current for surface")
770 })?;
771
772 let renderbuffer = unsafe { gl.create_renderbuffer() }.map_err(|error| {
773 log::error!("Internal swapchain renderbuffer creation failed: {error}");
774 crate::DeviceError::OutOfMemory
775 })?;
776 unsafe { gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)) };
777 unsafe {
778 gl.renderbuffer_storage(
779 glow::RENDERBUFFER,
780 format_desc.internal,
781 config.extent.width as _,
782 config.extent.height as _,
783 )
784 };
785
786 let framebuffer = unsafe { gl.create_framebuffer() }.map_err(|error| {
787 log::error!("Internal swapchain framebuffer creation failed: {error}");
788 crate::DeviceError::OutOfMemory
789 })?;
790 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer)) };
791 unsafe {
792 gl.framebuffer_renderbuffer(
793 glow::READ_FRAMEBUFFER,
794 glow::COLOR_ATTACHMENT0,
795 glow::RENDERBUFFER,
796 Some(renderbuffer),
797 )
798 };
799 unsafe { gl.bind_renderbuffer(glow::RENDERBUFFER, None) };
800 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
801
802 let extra = Wgl::load_with(|name| load_gl_func(name, None));
804 let extensions = get_extensions(&extra, dc.device);
805 if !(extensions.contains("WGL_EXT_swap_control") && extra.SwapIntervalEXT.is_loaded()) {
806 log::error!("WGL_EXT_swap_control is unsupported");
807 return Err(crate::SurfaceError::Other(
808 "WGL_EXT_swap_control is unsupported",
809 ));
810 }
811
812 let vsync = match config.present_mode {
813 wgt::PresentMode::Immediate => false,
814 wgt::PresentMode::Fifo => true,
815 _ => {
816 log::error!("unsupported present mode: {:?}", config.present_mode);
817 return Err(crate::SurfaceError::Other("unsupported present mode"));
818 }
819 };
820
821 if unsafe { extra.SwapIntervalEXT(if vsync { 1 } else { 0 }) } == Foundation::FALSE.0 {
822 log::error!("unable to set swap interval: {}", Error::from_win32());
823 return Err(crate::SurfaceError::Other("unable to set swap interval"));
824 }
825
826 self.swapchain.write().replace(Swapchain {
827 renderbuffer,
828 framebuffer,
829 extent: config.extent,
830 format: config.format,
831 format_desc,
832 sample_type: wgt::TextureSampleType::Float { filterable: false },
833 });
834
835 Ok(())
836 }
837
838 unsafe fn unconfigure(&self, device: &super::Device) {
839 let gl = &device.shared.context.lock();
840 if let Some(sc) = self.swapchain.write().take() {
841 unsafe {
842 gl.delete_renderbuffer(sc.renderbuffer);
843 gl.delete_framebuffer(sc.framebuffer)
844 };
845 }
846 }
847
848 unsafe fn acquire_texture(
849 &self,
850 _timeout_ms: Option<Duration>,
851 _fence: &super::Fence,
852 ) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
853 let swapchain = self.swapchain.read();
854 let sc = swapchain.as_ref().unwrap();
855 let texture = super::Texture {
856 inner: super::TextureInner::Renderbuffer {
857 raw: sc.renderbuffer,
858 },
859 drop_guard: None,
860 array_layer_count: 1,
861 mip_level_count: 1,
862 format: sc.format,
863 format_desc: sc.format_desc.clone(),
864 copy_size: crate::CopyExtent {
865 width: sc.extent.width,
866 height: sc.extent.height,
867 depth: 1,
868 },
869 };
870 Ok(Some(crate::AcquiredSurfaceTexture {
871 texture,
872 suboptimal: false,
873 }))
874 }
875 unsafe fn discard_texture(&self, _texture: super::Texture) {}
876}