gfx_backend_vulkan/
window.rs

1use std::{borrow::Borrow, fmt, os::raw::c_void, sync::Arc, time::Instant};
2
3use ash::{extensions::khr, version::DeviceV1_0 as _, vk};
4use hal::{format::Format, window as w};
5
6use crate::{
7    conv, info, native, Backend, Device, Instance, PhysicalDevice, QueueFamily, RawDevice,
8    RawInstance,
9};
10
11#[derive(Debug)]
12struct SurfaceFrame {
13    image: vk::Image,
14    view: vk::ImageView,
15}
16
17#[derive(Debug)]
18pub struct SurfaceSwapchain {
19    pub(crate) swapchain: Swapchain,
20    device: Arc<RawDevice>,
21    fence: native::Fence,
22    pub(crate) semaphore: native::Semaphore,
23    frames: Vec<SurfaceFrame>,
24}
25
26impl SurfaceSwapchain {
27    unsafe fn release_resources(self, device: &ash::Device) -> Swapchain {
28        let _ = device.device_wait_idle();
29        device.destroy_fence(self.fence.0, None);
30        device.destroy_semaphore(self.semaphore.0, None);
31        for frame in self.frames {
32            device.destroy_image_view(frame.view, None);
33        }
34        self.swapchain
35    }
36}
37
38pub struct Surface {
39    // Vk (EXT) specs [29.2.7 Platform-Independent Information]
40    // For vkDestroySurfaceKHR: Host access to surface must be externally synchronized
41    pub(crate) raw: Arc<RawSurface>,
42    pub(crate) swapchain: Option<SurfaceSwapchain>,
43}
44
45impl fmt::Debug for Surface {
46    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
47        fmt.write_str("Surface")
48    }
49}
50
51pub struct RawSurface {
52    pub(crate) handle: vk::SurfaceKHR,
53    pub(crate) functor: khr::Surface,
54    pub(crate) instance: Arc<RawInstance>,
55}
56
57impl Instance {
58    #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
59    pub fn create_surface_from_xlib(&self, dpy: *mut vk::Display, window: vk::Window) -> Surface {
60        if !self.extensions.contains(&khr::XlibSurface::name()) {
61            panic!("Vulkan driver does not support VK_KHR_XLIB_SURFACE");
62        }
63
64        let surface = {
65            let xlib_loader = khr::XlibSurface::new(&self.entry, &self.raw.inner);
66            let info = vk::XlibSurfaceCreateInfoKHR::builder()
67                .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
68                .window(window)
69                .dpy(dpy);
70
71            unsafe { xlib_loader.create_xlib_surface(&info, None) }
72                .expect("XlibSurface::create_xlib_surface() failed")
73        };
74
75        self.create_surface_from_vk_surface_khr(surface)
76    }
77
78    #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
79    pub fn create_surface_from_xcb(
80        &self,
81        connection: *mut vk::xcb_connection_t,
82        window: vk::xcb_window_t,
83    ) -> Surface {
84        if !self.extensions.contains(&khr::XcbSurface::name()) {
85            panic!("Vulkan driver does not support VK_KHR_XCB_SURFACE");
86        }
87
88        let surface = {
89            let xcb_loader = khr::XcbSurface::new(&self.entry, &self.raw.inner);
90            let info = vk::XcbSurfaceCreateInfoKHR::builder()
91                .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
92                .window(window)
93                .connection(connection);
94
95            unsafe { xcb_loader.create_xcb_surface(&info, None) }
96                .expect("XcbSurface::create_xcb_surface() failed")
97        };
98
99        self.create_surface_from_vk_surface_khr(surface)
100    }
101
102    #[cfg(all(unix, not(target_os = "android")))]
103    pub fn create_surface_from_wayland(
104        &self,
105        display: *mut c_void,
106        surface: *mut c_void,
107    ) -> Surface {
108        if !self.extensions.contains(&khr::WaylandSurface::name()) {
109            panic!("Vulkan driver does not support VK_KHR_WAYLAND_SURFACE");
110        }
111
112        let surface = {
113            let w_loader = khr::WaylandSurface::new(&self.entry, &self.raw.inner);
114            let info = vk::WaylandSurfaceCreateInfoKHR::builder()
115                .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
116                .display(display)
117                .surface(surface);
118
119            unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed")
120        };
121
122        self.create_surface_from_vk_surface_khr(surface)
123    }
124
125    #[cfg(target_os = "android")]
126    pub fn create_surface_android(&self, window: *const c_void) -> Surface {
127        let surface = {
128            let a_loader = khr::AndroidSurface::new(&self.entry, &self.raw.inner);
129            let info = vk::AndroidSurfaceCreateInfoKHR::builder()
130                .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
131                .window(window as *mut _);
132
133            unsafe { a_loader.create_android_surface(&info, None) }.expect("AndroidSurface failed")
134        };
135
136        self.create_surface_from_vk_surface_khr(surface)
137    }
138
139    #[cfg(windows)]
140    pub fn create_surface_from_hwnd(&self, hinstance: *mut c_void, hwnd: *mut c_void) -> Surface {
141        if !self.extensions.contains(&khr::Win32Surface::name()) {
142            panic!("Vulkan driver does not support VK_KHR_WIN32_SURFACE");
143        }
144
145        let surface = {
146            let info = vk::Win32SurfaceCreateInfoKHR::builder()
147                .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
148                .hinstance(hinstance)
149                .hwnd(hwnd);
150            let win32_loader = khr::Win32Surface::new(&self.entry, &self.raw.inner);
151            unsafe {
152                win32_loader
153                    .create_win32_surface(&info, None)
154                    .expect("Unable to create Win32 surface")
155            }
156        };
157
158        self.create_surface_from_vk_surface_khr(surface)
159    }
160
161    #[cfg(target_os = "macos")]
162    pub fn create_surface_from_ns_view(&self, view: *mut c_void) -> Surface {
163        use ash::extensions::mvk;
164        use core_graphics_types::{base::CGFloat, geometry::CGRect};
165        use objc::runtime::{Object, BOOL, YES};
166
167        // TODO: this logic is duplicated from gfx-backend-metal, refactor?
168        unsafe {
169            let view = view as *mut Object;
170            let existing: *mut Object = msg_send![view, layer];
171            let class = class!(CAMetalLayer);
172
173            let use_current = if existing.is_null() {
174                false
175            } else {
176                let result: BOOL = msg_send![existing, isKindOfClass: class];
177                result == YES
178            };
179
180            if !use_current {
181                let layer: *mut Object = msg_send![class, new];
182                let () = msg_send![view, setLayer: layer];
183                let bounds: CGRect = msg_send![view, bounds];
184                let () = msg_send![layer, setBounds: bounds];
185
186                let window: *mut Object = msg_send![view, window];
187                if !window.is_null() {
188                    let scale_factor: CGFloat = msg_send![window, backingScaleFactor];
189                    let () = msg_send![layer, setContentsScale: scale_factor];
190                }
191            }
192        }
193
194        if !self.extensions.contains(&mvk::MacOSSurface::name()) {
195            panic!("Vulkan driver does not support VK_MVK_MACOS_SURFACE");
196        }
197
198        let surface = {
199            let mac_os_loader = mvk::MacOSSurface::new(&self.entry, &self.raw.inner);
200            let mut info = vk::MacOSSurfaceCreateInfoMVK::builder()
201                .flags(vk::MacOSSurfaceCreateFlagsMVK::empty());
202            if let Some(view) = unsafe { view.as_ref() } {
203                info = info.view(view);
204            }
205
206            unsafe {
207                mac_os_loader
208                    .create_mac_os_surface_mvk(&info, None)
209                    .expect("Unable to create macOS surface")
210            }
211        };
212
213        self.create_surface_from_vk_surface_khr(surface)
214    }
215
216    pub fn create_surface_from_vk_surface_khr(&self, surface: vk::SurfaceKHR) -> Surface {
217        let functor = khr::Surface::new(&self.entry, &self.raw.inner);
218
219        let raw = Arc::new(RawSurface {
220            handle: surface,
221            functor,
222            instance: self.raw.clone(),
223        });
224
225        Surface {
226            raw,
227            swapchain: None,
228        }
229    }
230}
231
232impl w::Surface<Backend> for Surface {
233    fn supports_queue_family(&self, queue_family: &QueueFamily) -> bool {
234        match unsafe {
235            self.raw.functor.get_physical_device_surface_support(
236                queue_family.device,
237                queue_family.index,
238                self.raw.handle,
239            )
240        } {
241            Ok(ok) => ok,
242            Err(e) => {
243                error!("get_physical_device_surface_support error {:?}", e);
244                false
245            }
246        }
247    }
248
249    fn capabilities(&self, physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
250        // Capabilities
251        let caps = unsafe {
252            match self
253                .raw
254                .functor
255                .get_physical_device_surface_capabilities(physical_device.handle, self.raw.handle)
256            {
257                Ok(caps) => caps,
258                Err(vk::Result::ERROR_SURFACE_LOST_KHR) => {
259                    error!(
260                        "get_physical_device_surface_capabilities error {:?}",
261                        vk::Result::ERROR_SURFACE_LOST_KHR
262                    );
263                    vk::SurfaceCapabilitiesKHR::default()
264                }
265                Err(e) => panic!("Unable to query surface capabilities {:?}", e),
266            }
267        };
268
269        // If image count is 0, the support number of images is unlimited.
270        let max_images = if caps.max_image_count == 0 {
271            !0
272        } else {
273            caps.max_image_count
274        };
275
276        // `0xFFFFFFFF` indicates that the extent depends on the created swapchain.
277        let current_extent = if caps.current_extent.width != !0 && caps.current_extent.height != !0
278        {
279            Some(w::Extent2D {
280                width: caps.current_extent.width,
281                height: caps.current_extent.height,
282            })
283        } else {
284            None
285        };
286
287        let min_extent = w::Extent2D {
288            width: caps.min_image_extent.width,
289            height: caps.min_image_extent.height,
290        };
291
292        let max_extent = w::Extent2D {
293            width: caps.max_image_extent.width,
294            height: caps.max_image_extent.height,
295        };
296
297        let raw_present_modes = unsafe {
298            match self
299                .raw
300                .functor
301                .get_physical_device_surface_present_modes(physical_device.handle, self.raw.handle)
302            {
303                Ok(present_modes) => present_modes,
304                Err(vk::Result::ERROR_SURFACE_LOST_KHR) => {
305                    error!(
306                        "get_physical_device_surface_present_modes error {:?}",
307                        vk::Result::ERROR_SURFACE_LOST_KHR
308                    );
309                    Vec::new()
310                }
311                Err(e) => panic!("Unable to query present modes {:?}", e),
312            }
313        };
314
315        w::SurfaceCapabilities {
316            present_modes: raw_present_modes
317                .into_iter()
318                .fold(w::PresentMode::empty(), |u, m| {
319                    u | conv::map_vk_present_mode(m)
320                }),
321            composite_alpha_modes: conv::map_vk_composite_alpha(caps.supported_composite_alpha),
322            image_count: caps.min_image_count..=max_images,
323            current_extent,
324            extents: min_extent..=max_extent,
325            max_image_layers: caps.max_image_array_layers as _,
326            usage: conv::map_vk_image_usage(caps.supported_usage_flags),
327        }
328    }
329
330    fn supported_formats(&self, physical_device: &PhysicalDevice) -> Option<Vec<Format>> {
331        // Swapchain formats
332        let raw_formats = unsafe {
333            match self
334                .raw
335                .functor
336                .get_physical_device_surface_formats(physical_device.handle, self.raw.handle)
337            {
338                Ok(formats) => formats,
339                Err(vk::Result::ERROR_SURFACE_LOST_KHR) => {
340                    error!(
341                        "get_physical_device_surface_formats error {:?}",
342                        vk::Result::ERROR_SURFACE_LOST_KHR
343                    );
344                    return Some(Vec::new());
345                }
346                Err(e) => panic!("Unable to query surface formats {:?}", e),
347            }
348        };
349
350        match raw_formats[0].format {
351            // If pSurfaceFormats includes just one entry, whose value for format is
352            // VK_FORMAT_UNDEFINED, surface has no preferred format. In this case, the application
353            // can use any valid VkFormat value.
354            vk::Format::UNDEFINED => None,
355            _ => Some(
356                raw_formats
357                    .into_iter()
358                    .filter_map(|sf| conv::map_vk_format(sf.format))
359                    .collect(),
360            ),
361        }
362    }
363}
364
365#[derive(Debug)]
366pub struct SurfaceImage {
367    pub(crate) index: w::SwapImageIndex,
368    image: native::Image,
369    view: native::ImageView,
370}
371
372impl Borrow<native::Image> for SurfaceImage {
373    fn borrow(&self) -> &native::Image {
374        &self.image
375    }
376}
377
378impl Borrow<native::ImageView> for SurfaceImage {
379    fn borrow(&self) -> &native::ImageView {
380        &self.view
381    }
382}
383
384impl w::PresentationSurface<Backend> for Surface {
385    type SwapchainImage = SurfaceImage;
386
387    unsafe fn configure_swapchain(
388        &mut self,
389        device: &Device,
390        config: w::SwapchainConfig,
391    ) -> Result<(), w::SwapchainError> {
392        use hal::device::Device as _;
393
394        let usage = config.image_usage;
395        let format = config.format;
396        let old = self
397            .swapchain
398            .take()
399            .map(|ssc| ssc.release_resources(&device.shared.raw));
400
401        let (swapchain, images) = device.create_swapchain(self, config, old)?;
402
403        self.swapchain = Some(SurfaceSwapchain {
404            swapchain,
405            device: Arc::clone(&device.shared),
406            fence: device.create_fence(false).unwrap(),
407            semaphore: device.create_semaphore().unwrap(),
408            frames: images
409                .iter()
410                .map(|image| {
411                    let view = device
412                        .create_image_view(
413                            image,
414                            hal::image::ViewKind::D2,
415                            format,
416                            hal::format::Swizzle::NO,
417                            usage,
418                            hal::image::SubresourceRange {
419                                aspects: hal::format::Aspects::COLOR,
420                                ..Default::default()
421                            },
422                        )
423                        .unwrap();
424                    SurfaceFrame {
425                        image: view.image,
426                        view: view.raw,
427                    }
428                })
429                .collect(),
430        });
431
432        Ok(())
433    }
434
435    unsafe fn unconfigure_swapchain(&mut self, device: &Device) {
436        if let Some(ssc) = self.swapchain.take() {
437            let swapchain = ssc.release_resources(&device.shared.raw);
438            swapchain.functor.destroy_swapchain(swapchain.raw, None);
439        }
440    }
441
442    unsafe fn acquire_image(
443        &mut self,
444        mut timeout_ns: u64,
445    ) -> Result<(Self::SwapchainImage, Option<w::Suboptimal>), w::AcquireError> {
446        let ssc = self.swapchain.as_mut().unwrap();
447        let moment = Instant::now();
448        let (index, suboptimal) =
449            ssc.swapchain
450                .acquire_image(timeout_ns, None, Some(&ssc.fence))?;
451        timeout_ns = timeout_ns.saturating_sub(moment.elapsed().as_nanos() as u64);
452        let fences = &[ssc.fence.0];
453
454        match ssc.device.raw.wait_for_fences(fences, true, timeout_ns) {
455            Ok(()) => {
456                ssc.device.raw.reset_fences(fences).unwrap();
457                let frame = &ssc.frames[index as usize];
458                let image = Self::SwapchainImage {
459                    index,
460                    image: native::Image {
461                        raw: frame.image,
462                        ty: vk::ImageType::TYPE_2D,
463                        flags: vk::ImageCreateFlags::empty(),
464                        extent: ssc.swapchain.extent,
465                    },
466                    view: native::ImageView {
467                        image: frame.image,
468                        raw: frame.view,
469                        range: hal::image::SubresourceRange {
470                            aspects: hal::format::Aspects::COLOR,
471                            ..Default::default()
472                        },
473                    },
474                };
475                Ok((image, suboptimal))
476            }
477            Err(vk::Result::NOT_READY) => Err(w::AcquireError::NotReady { timeout: false }),
478            Err(vk::Result::TIMEOUT) => Err(w::AcquireError::NotReady { timeout: true }),
479            Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => Err(w::OutOfDate.into()),
480            Err(vk::Result::ERROR_SURFACE_LOST_KHR) => Err(w::SurfaceLost.into()),
481            Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => Err(hal::device::OutOfMemory::Host.into()),
482            Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => {
483                Err(hal::device::OutOfMemory::Device.into())
484            }
485            Err(vk::Result::ERROR_DEVICE_LOST) => Err(hal::device::DeviceLost.into()),
486            _ => unreachable!(),
487        }
488    }
489}
490
491pub struct Swapchain {
492    pub(crate) raw: vk::SwapchainKHR,
493    pub(crate) functor: khr::Swapchain,
494    pub(crate) vendor_id: u32,
495    pub(crate) extent: vk::Extent3D,
496}
497
498impl fmt::Debug for Swapchain {
499    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
500        fmt.write_str("Swapchain")
501    }
502}
503
504impl Swapchain {
505    unsafe fn acquire_image(
506        &mut self,
507        timeout_ns: u64,
508        semaphore: Option<&native::Semaphore>,
509        fence: Option<&native::Fence>,
510    ) -> Result<(w::SwapImageIndex, Option<w::Suboptimal>), w::AcquireError> {
511        let semaphore = semaphore.map_or(vk::Semaphore::null(), |s| s.0);
512        let fence = fence.map_or(vk::Fence::null(), |f| f.0);
513
514        // will block if no image is available
515        let index = self
516            .functor
517            .acquire_next_image(self.raw, timeout_ns, semaphore, fence);
518
519        match index {
520            // special case for Intel Vulkan returning bizzare values (ugh)
521            Ok((i, _)) if self.vendor_id == info::intel::VENDOR && i > 0x100 => {
522                Err(w::OutOfDate.into())
523            }
524            Ok((i, true)) => Ok((i, Some(w::Suboptimal))),
525            Ok((i, false)) => Ok((i, None)),
526            Err(vk::Result::NOT_READY) => Err(w::AcquireError::NotReady { timeout: false }),
527            Err(vk::Result::TIMEOUT) => Err(w::AcquireError::NotReady { timeout: true }),
528            Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => Err(w::OutOfDate.into()),
529            Err(vk::Result::ERROR_SURFACE_LOST_KHR) => Err(w::SurfaceLost.into()),
530            Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => Err(hal::device::OutOfMemory::Host.into()),
531            Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => {
532                Err(hal::device::OutOfMemory::Device.into())
533            }
534            Err(vk::Result::ERROR_DEVICE_LOST) => Err(hal::device::DeviceLost.into()),
535            _ => panic!("Failed to acquire image."),
536        }
537    }
538}