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