presenting SwapchainFrames
This commit is contained in:
		
							parent
							
								
									37aaa07edc
								
							
						
					
					
						commit
						93e64e872f
					
				| 
						 | 
					@ -28,7 +28,7 @@ impl WindowState {
 | 
				
			||||||
                .with_resizable(true)
 | 
					                .with_resizable(true)
 | 
				
			||||||
                .with_inner_size(LogicalSize::new(800, 600)),
 | 
					                .with_inner_size(LogicalSize::new(800, 600)),
 | 
				
			||||||
            // TODO: pass down this error and add some kind of error handling UI or dump
 | 
					            // TODO: pass down this error and add some kind of error handling UI or dump
 | 
				
			||||||
            renderer: Renderer::new(display).expect("renderer"),
 | 
					            renderer: Renderer::new(display.as_raw()).expect("renderer"),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ impl WindowState {
 | 
				
			||||||
        _ = (window_id, new_size);
 | 
					        _ = (window_id, new_size);
 | 
				
			||||||
        info!("TODO: implement resize events");
 | 
					        info!("TODO: implement resize events");
 | 
				
			||||||
        if let Some(ctx) = self.renderer.window_contexts.get_mut(&window_id) {
 | 
					        if let Some(ctx) = self.renderer.window_contexts.get_mut(&window_id) {
 | 
				
			||||||
            ctx.recreate_swapchain(renderer::Extent2D {
 | 
					            ctx.recreate_with(renderer::Extent2D {
 | 
				
			||||||
                width: new_size.width,
 | 
					                width: new_size.width,
 | 
				
			||||||
                height: new_size.height,
 | 
					                height: new_size.height,
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,3 +21,4 @@ winit = "0.30.5"
 | 
				
			||||||
crossbeam = "0.8.4"
 | 
					crossbeam = "0.8.4"
 | 
				
			||||||
parking_lot = "0.12.3"
 | 
					parking_lot = "0.12.3"
 | 
				
			||||||
smol.workspace = true
 | 
					smol.workspace = true
 | 
				
			||||||
 | 
					tracing-test = "0.2.5"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
#![feature(c_str_module, closure_lifetime_binder, let_chains, negative_impls)]
 | 
					#![feature(c_str_module, closure_lifetime_binder, let_chains, negative_impls)]
 | 
				
			||||||
#![allow(unused)]
 | 
					#![allow(unused)]
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
 | 
					    borrow::Borrow,
 | 
				
			||||||
    collections::{BTreeMap, BTreeSet, HashMap},
 | 
					    collections::{BTreeMap, BTreeSet, HashMap},
 | 
				
			||||||
    ffi::{CStr, CString},
 | 
					    ffi::{CStr, CString},
 | 
				
			||||||
    fmt::Debug,
 | 
					    fmt::Debug,
 | 
				
			||||||
| 
						 | 
					@ -8,10 +9,12 @@ use std::{
 | 
				
			||||||
    ops::Deref,
 | 
					    ops::Deref,
 | 
				
			||||||
    sync::{
 | 
					    sync::{
 | 
				
			||||||
        atomic::{AtomicU32, AtomicU64},
 | 
					        atomic::{AtomicU32, AtomicU64},
 | 
				
			||||||
        Arc, Mutex,
 | 
					        Arc,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use parking_lot::{Mutex, MutexGuard, RwLock};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ash::{
 | 
					use ash::{
 | 
				
			||||||
    khr,
 | 
					    khr,
 | 
				
			||||||
    prelude::VkResult,
 | 
					    prelude::VkResult,
 | 
				
			||||||
| 
						 | 
					@ -22,7 +25,7 @@ use dyn_clone::DynClone;
 | 
				
			||||||
use rand::{Rng, SeedableRng};
 | 
					use rand::{Rng, SeedableRng};
 | 
				
			||||||
use tinyvec::{array_vec, ArrayVec};
 | 
					use tinyvec::{array_vec, ArrayVec};
 | 
				
			||||||
use tracing::info;
 | 
					use tracing::info;
 | 
				
			||||||
use winit::raw_window_handle::DisplayHandle;
 | 
					use winit::raw_window_handle::{DisplayHandle, RawDisplayHandle};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod commands;
 | 
					mod commands;
 | 
				
			||||||
mod images;
 | 
					mod images;
 | 
				
			||||||
| 
						 | 
					@ -111,12 +114,12 @@ impl Queue {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn with_locked<T, F: FnOnce(vk::Queue) -> T>(&self, map: F) -> T {
 | 
					    pub fn with_locked<T, F: FnOnce(vk::Queue) -> T>(&self, map: F) -> T {
 | 
				
			||||||
        let lock = self.0.lock().expect("mutex lock poison");
 | 
					        let lock = self.0.lock();
 | 
				
			||||||
        map(*lock)
 | 
					        map(*lock)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn lock(&self) -> std::sync::MutexGuard<'_, vk::Queue> {
 | 
					    pub fn lock(&self) -> MutexGuard<'_, vk::Queue> {
 | 
				
			||||||
        self.0.lock().unwrap()
 | 
					        self.0.lock()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -454,6 +457,7 @@ struct DeviceInner {
 | 
				
			||||||
    physical: PhysicalDevice,
 | 
					    physical: PhysicalDevice,
 | 
				
			||||||
    device: ash::Device,
 | 
					    device: ash::Device,
 | 
				
			||||||
    swapchain: khr::swapchain::Device,
 | 
					    swapchain: khr::swapchain::Device,
 | 
				
			||||||
 | 
					    debug_utils: ash::ext::debug_utils::Device,
 | 
				
			||||||
    main_queue: Queue,
 | 
					    main_queue: Queue,
 | 
				
			||||||
    compute_queue: Queue,
 | 
					    compute_queue: Queue,
 | 
				
			||||||
    transfer_queue: Queue,
 | 
					    transfer_queue: Queue,
 | 
				
			||||||
| 
						 | 
					@ -481,6 +485,9 @@ impl Device {
 | 
				
			||||||
    fn swapchain(&self) -> &khr::swapchain::Device {
 | 
					    fn swapchain(&self) -> &khr::swapchain::Device {
 | 
				
			||||||
        &self.0.swapchain
 | 
					        &self.0.swapchain
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fn debug_utils(&self) -> &ash::ext::debug_utils::Device {
 | 
				
			||||||
 | 
					        &self.0.debug_utils
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    fn queue_families(&self) -> &DeviceQueueFamilies {
 | 
					    fn queue_families(&self) -> &DeviceQueueFamilies {
 | 
				
			||||||
        &self.0.physical.queue_families
 | 
					        &self.0.physical.queue_families
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -540,20 +547,14 @@ struct RawSwapchain(vk::SwapchainKHR);
 | 
				
			||||||
impl !Sync for RawSwapchain {}
 | 
					impl !Sync for RawSwapchain {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
struct SwapchainHandle(parking_lot::Mutex<vk::SwapchainKHR>);
 | 
					struct SwapchainHandle(Mutex<vk::SwapchainKHR>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl SwapchainHandle {
 | 
					impl SwapchainHandle {
 | 
				
			||||||
    unsafe fn from_handle(swapchain: vk::SwapchainKHR) -> SwapchainHandle {
 | 
					    unsafe fn from_handle(swapchain: vk::SwapchainKHR) -> SwapchainHandle {
 | 
				
			||||||
        Self(parking_lot::Mutex::new(swapchain))
 | 
					        Self(Mutex::new(swapchain))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn lock(
 | 
					    fn lock(&self) -> MutexGuard<'_, vk::SwapchainKHR> {
 | 
				
			||||||
        &self,
 | 
					 | 
				
			||||||
    ) -> parking_lot::lock_api::MutexGuard<
 | 
					 | 
				
			||||||
        '_,
 | 
					 | 
				
			||||||
        parking_lot::RawMutex,
 | 
					 | 
				
			||||||
        vk::SwapchainKHR,
 | 
					 | 
				
			||||||
    > {
 | 
					 | 
				
			||||||
        self.0.lock()
 | 
					        self.0.lock()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -587,6 +588,7 @@ pub struct Swapchain {
 | 
				
			||||||
    fences: Vec<Arc<sync::Fence>>,
 | 
					    fences: Vec<Arc<sync::Fence>>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    current_frame: AtomicU32,
 | 
					    current_frame: AtomicU32,
 | 
				
			||||||
 | 
					    present_id: AtomicU64,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Drop for Swapchain {
 | 
					impl Drop for Swapchain {
 | 
				
			||||||
| 
						 | 
					@ -645,6 +647,8 @@ struct SwapchainParams {
 | 
				
			||||||
    extent: vk::Extent2D,
 | 
					    extent: vk::Extent2D,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[must_use = "This struct represents an acquired image from the swapchain and
 | 
				
			||||||
 | 
					 must be presented in order to free resources on the device."]
 | 
				
			||||||
pub struct SwapchainFrame {
 | 
					pub struct SwapchainFrame {
 | 
				
			||||||
    pub swapchain: Arc<Swapchain>,
 | 
					    pub swapchain: Arc<Swapchain>,
 | 
				
			||||||
    pub index: u32,
 | 
					    pub index: u32,
 | 
				
			||||||
| 
						 | 
					@ -654,6 +658,12 @@ pub struct SwapchainFrame {
 | 
				
			||||||
    pub release: vk::Semaphore,
 | 
					    pub release: vk::Semaphore,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SwapchainFrame {
 | 
				
			||||||
 | 
					    fn present(self) {
 | 
				
			||||||
 | 
					        self.swapchain.clone().present(self);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Swapchain {
 | 
					impl Swapchain {
 | 
				
			||||||
    const PREFERRED_IMAGES_IN_FLIGHT: u32 = 3;
 | 
					    const PREFERRED_IMAGES_IN_FLIGHT: u32 = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -794,28 +804,79 @@ impl Swapchain {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let acquire_semaphores = {
 | 
					        let acquire_semaphores = {
 | 
				
			||||||
            (0..inflight_frames)
 | 
					            (0..inflight_frames)
 | 
				
			||||||
                .map(|_| unsafe {
 | 
					                .map(|i| unsafe {
 | 
				
			||||||
                    device.dev().create_semaphore(
 | 
					                    device.dev().create_semaphore(
 | 
				
			||||||
                        &vk::SemaphoreCreateInfo::default(),
 | 
					                        &vk::SemaphoreCreateInfo::default(),
 | 
				
			||||||
                        None,
 | 
					                        None,
 | 
				
			||||||
                    )
 | 
					                    ).inspect(|r| {
 | 
				
			||||||
 | 
					                        #[cfg(debug_assertions)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            let name = CString::new(format!(
 | 
				
			||||||
 | 
					                                "semaphore-{:x}_{i}-acquire",
 | 
				
			||||||
 | 
					                                swapchain.0.lock().as_raw()
 | 
				
			||||||
 | 
					                            ))
 | 
				
			||||||
 | 
					                                .unwrap();
 | 
				
			||||||
 | 
					                            unsafe {
 | 
				
			||||||
 | 
					                                device.debug_utils().set_debug_utils_object_name(
 | 
				
			||||||
 | 
					                                    &vk::DebugUtilsObjectNameInfoEXT::default()
 | 
				
			||||||
 | 
					                                        .object_handle(*r)
 | 
				
			||||||
 | 
					                                        .object_name(&name),
 | 
				
			||||||
 | 
					                                );}
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .collect::<VkResult<Vec<_>>>()?
 | 
					                .collect::<VkResult<Vec<_>>>()?
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let release_semaphores = {
 | 
					        let release_semaphores = {
 | 
				
			||||||
            (0..inflight_frames)
 | 
					            (0..inflight_frames)
 | 
				
			||||||
                .map(|_| unsafe {
 | 
					                .map(|i| unsafe {
 | 
				
			||||||
                    device.dev().create_semaphore(
 | 
					                    device.dev().create_semaphore(
 | 
				
			||||||
                        &vk::SemaphoreCreateInfo::default(),
 | 
					                        &vk::SemaphoreCreateInfo::default(),
 | 
				
			||||||
                        None,
 | 
					                        None,
 | 
				
			||||||
                    )
 | 
					                    ).inspect(|r| {
 | 
				
			||||||
 | 
					                        #[cfg(debug_assertions)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            let name = CString::new(format!(
 | 
				
			||||||
 | 
					                                "semaphore-{:x}_{i}-release",
 | 
				
			||||||
 | 
					                                swapchain.0.lock().as_raw()
 | 
				
			||||||
 | 
					                            ))
 | 
				
			||||||
 | 
					                                .unwrap();
 | 
				
			||||||
 | 
					                            unsafe {
 | 
				
			||||||
 | 
					                                device.debug_utils().set_debug_utils_object_name(
 | 
				
			||||||
 | 
					                                    &vk::DebugUtilsObjectNameInfoEXT::default()
 | 
				
			||||||
 | 
					                                        .object_handle(*r)
 | 
				
			||||||
 | 
					                                        .object_name(&name),
 | 
				
			||||||
 | 
					                                );}
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .collect::<VkResult<Vec<_>>>()?
 | 
					                .collect::<VkResult<Vec<_>>>()?
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let fences = {
 | 
					        let fences = {
 | 
				
			||||||
            (0..inflight_frames)
 | 
					            (0..inflight_frames)
 | 
				
			||||||
                .map(|_| Ok(Arc::new(sync::Fence::create(device.clone())?)))
 | 
					                .map(|i| Ok(Arc::new(sync::Fence::create(device.clone())
 | 
				
			||||||
 | 
					                    .inspect(|r| {
 | 
				
			||||||
 | 
					                        #[cfg(debug_assertions)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            let name = CString::new(format!(
 | 
				
			||||||
 | 
					                                "fence-{:x}_{i}",
 | 
				
			||||||
 | 
					                                swapchain.0.lock().as_raw()
 | 
				
			||||||
 | 
					                            ))
 | 
				
			||||||
 | 
					                                .unwrap();
 | 
				
			||||||
 | 
					                            unsafe {
 | 
				
			||||||
 | 
					                                device.debug_utils().set_debug_utils_object_name(
 | 
				
			||||||
 | 
					                                    &vk::DebugUtilsObjectNameInfoEXT::default()
 | 
				
			||||||
 | 
					                                        .object_handle(r.fence())
 | 
				
			||||||
 | 
					                                        .object_name(&name),
 | 
				
			||||||
 | 
					                                );}
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					?)))
 | 
				
			||||||
                .collect::<VkResult<Vec<_>>>()?
 | 
					                .collect::<VkResult<Vec<_>>>()?
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -837,6 +898,7 @@ impl Swapchain {
 | 
				
			||||||
            release_semaphores,
 | 
					            release_semaphores,
 | 
				
			||||||
            fences,
 | 
					            fences,
 | 
				
			||||||
            current_frame: AtomicU32::new(0),
 | 
					            current_frame: AtomicU32::new(0),
 | 
				
			||||||
 | 
					            present_id: AtomicU64::new(1),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -919,6 +981,35 @@ impl Swapchain {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn present(&self, frame: SwapchainFrame) -> Result<()> {
 | 
				
			||||||
 | 
					        let swpchain = self.swapchain.lock();
 | 
				
			||||||
 | 
					        let queue = self.device.present_queue().lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let wait_semaphores = [frame.release];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // TODO: make this optional for devices with no support for present_wait/present_id
 | 
				
			||||||
 | 
					        let present_id = self
 | 
				
			||||||
 | 
					            .present_id
 | 
				
			||||||
 | 
					            .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
 | 
				
			||||||
 | 
					        let mut present_id = vk::PresentIdKHR::default()
 | 
				
			||||||
 | 
					            .present_ids(core::slice::from_ref(&present_id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let present_info = vk::PresentInfoKHR::default()
 | 
				
			||||||
 | 
					            .image_indices(core::slice::from_ref(&frame.index))
 | 
				
			||||||
 | 
					            .swapchains(core::slice::from_ref(&swpchain))
 | 
				
			||||||
 | 
					            .wait_semaphores(&wait_semaphores)
 | 
				
			||||||
 | 
					            .push_next(&mut present_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // call winits pre_present_notify here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            self.device
 | 
				
			||||||
 | 
					                .swapchain()
 | 
				
			||||||
 | 
					                .queue_present(*queue, &present_info)?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn create_vkswapchainkhr(
 | 
					    fn create_vkswapchainkhr(
 | 
				
			||||||
        device: &Device,
 | 
					        device: &Device,
 | 
				
			||||||
        surface: vk::SurfaceKHR,
 | 
					        surface: vk::SurfaceKHR,
 | 
				
			||||||
| 
						 | 
					@ -956,6 +1047,23 @@ impl Swapchain {
 | 
				
			||||||
        let (swapchain, images) = unsafe {
 | 
					        let (swapchain, images) = unsafe {
 | 
				
			||||||
            let swapchain =
 | 
					            let swapchain =
 | 
				
			||||||
                device.swapchain().create_swapchain(&create_info, None)?;
 | 
					                device.swapchain().create_swapchain(&create_info, None)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #[cfg(debug_assertions)]
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                let name = CString::new(format!(
 | 
				
			||||||
 | 
					                    "swapchain-{}_{}",
 | 
				
			||||||
 | 
					                    surface.as_raw(),
 | 
				
			||||||
 | 
					                    SWAPCHAIN_COUNT
 | 
				
			||||||
 | 
					                        .fetch_add(1, std::sync::atomic::Ordering::Relaxed)
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					                .unwrap();
 | 
				
			||||||
 | 
					                device.debug_utils().set_debug_utils_object_name(
 | 
				
			||||||
 | 
					                    &vk::DebugUtilsObjectNameInfoEXT::default()
 | 
				
			||||||
 | 
					                        .object_handle(swapchain)
 | 
				
			||||||
 | 
					                        .object_name(&name),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let images = device.swapchain().get_swapchain_images(swapchain)?;
 | 
					            let images = device.swapchain().get_swapchain_images(swapchain)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            (SwapchainHandle::from_handle(swapchain), images)
 | 
					            (SwapchainHandle::from_handle(swapchain), images)
 | 
				
			||||||
| 
						 | 
					@ -964,6 +1072,7 @@ impl Swapchain {
 | 
				
			||||||
        Ok((swapchain, images))
 | 
					        Ok((swapchain, images))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					static SWAPCHAIN_COUNT: AtomicU64 = AtomicU64::new(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Surface {
 | 
					struct Surface {
 | 
				
			||||||
    instance: Arc<Instance>,
 | 
					    instance: Arc<Instance>,
 | 
				
			||||||
| 
						 | 
					@ -971,9 +1080,25 @@ struct Surface {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Surface {
 | 
					impl Surface {
 | 
				
			||||||
 | 
					    fn headless(instance: Arc<Instance>) -> Result<Self> {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            let headless_instance = ash::ext::headless_surface::Instance::new(
 | 
				
			||||||
 | 
					                &instance.entry,
 | 
				
			||||||
 | 
					                &instance.instance,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let surface = headless_instance.create_headless_surface(
 | 
				
			||||||
 | 
					                &vk::HeadlessSurfaceCreateInfoEXT::default(),
 | 
				
			||||||
 | 
					                None,
 | 
				
			||||||
 | 
					            )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Ok(Self { instance, surface })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn create(
 | 
					    fn create(
 | 
				
			||||||
        instance: Arc<Instance>,
 | 
					        instance: Arc<Instance>,
 | 
				
			||||||
        display_handle: winit::raw_window_handle::RawDisplayHandle,
 | 
					        display_handle: RawDisplayHandle,
 | 
				
			||||||
        window_handle: winit::raw_window_handle::RawWindowHandle,
 | 
					        window_handle: winit::raw_window_handle::RawWindowHandle,
 | 
				
			||||||
    ) -> Result<Self> {
 | 
					    ) -> Result<Self> {
 | 
				
			||||||
        let surface = unsafe {
 | 
					        let surface = unsafe {
 | 
				
			||||||
| 
						 | 
					@ -1004,6 +1129,14 @@ pub struct Vulkan {
 | 
				
			||||||
    alloc: VkAllocator,
 | 
					    alloc: VkAllocator,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Drop for Vulkan {
 | 
				
			||||||
 | 
					    fn drop(&mut self) {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            self.device.dev().device_wait_idle();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Vulkan {
 | 
					impl Vulkan {
 | 
				
			||||||
    const VALIDATION_LAYER_NAME: &'static core::ffi::CStr =
 | 
					    const VALIDATION_LAYER_NAME: &'static core::ffi::CStr =
 | 
				
			||||||
        c"VK_LAYER_KHRONOS_validation";
 | 
					        c"VK_LAYER_KHRONOS_validation";
 | 
				
			||||||
| 
						 | 
					@ -1021,7 +1154,7 @@ impl Vulkan {
 | 
				
			||||||
        app_name: &str,
 | 
					        app_name: &str,
 | 
				
			||||||
        instance_layers: &[&CStr],
 | 
					        instance_layers: &[&CStr],
 | 
				
			||||||
        instance_extensions: &[&CStr],
 | 
					        instance_extensions: &[&CStr],
 | 
				
			||||||
        display_handle: winit::raw_window_handle::DisplayHandle,
 | 
					        display_handle: Option<RawDisplayHandle>,
 | 
				
			||||||
    ) -> Result<Self> {
 | 
					    ) -> Result<Self> {
 | 
				
			||||||
        let entry = unsafe { ash::Entry::load()? };
 | 
					        let entry = unsafe { ash::Entry::load()? };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1059,6 +1192,8 @@ impl Vulkan {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let layers =
 | 
					        let layers =
 | 
				
			||||||
            Self::get_layers(&entry, &[Self::VALIDATION_LAYER_NAME]).unwrap();
 | 
					            Self::get_layers(&entry, &[Self::VALIDATION_LAYER_NAME]).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // optional display handle
 | 
				
			||||||
        let extensions = Self::get_extensions(
 | 
					        let extensions = Self::get_extensions(
 | 
				
			||||||
            &entry,
 | 
					            &entry,
 | 
				
			||||||
            &layers,
 | 
					            &layers,
 | 
				
			||||||
| 
						 | 
					@ -1209,21 +1344,16 @@ impl Vulkan {
 | 
				
			||||||
        instance: &Instance,
 | 
					        instance: &Instance,
 | 
				
			||||||
        pdev: vk::PhysicalDevice,
 | 
					        pdev: vk::PhysicalDevice,
 | 
				
			||||||
        queue_family: u32,
 | 
					        queue_family: u32,
 | 
				
			||||||
        display_handle: winit::raw_window_handle::DisplayHandle,
 | 
					        display_handle: RawDisplayHandle,
 | 
				
			||||||
    ) -> bool {
 | 
					    ) -> bool {
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            match display_handle.as_raw() {
 | 
					            match display_handle {
 | 
				
			||||||
                winit::raw_window_handle::RawDisplayHandle::Xlib(
 | 
					                RawDisplayHandle::Xlib(_xlib_display_handle) => {
 | 
				
			||||||
                    _xlib_display_handle,
 | 
					 | 
				
			||||||
                ) => {
 | 
					 | 
				
			||||||
                    todo!()
 | 
					                    todo!()
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                winit::raw_window_handle::RawDisplayHandle::Xcb(
 | 
					                RawDisplayHandle::Xcb(_xcb_display_handle) => todo!(),
 | 
				
			||||||
                    _xcb_display_handle,
 | 
					                RawDisplayHandle::Wayland(wayland_display_handle) => {
 | 
				
			||||||
                ) => todo!(),
 | 
					                    ash::khr::wayland_surface::Instance::new(
 | 
				
			||||||
                winit::raw_window_handle::RawDisplayHandle::Wayland(
 | 
					 | 
				
			||||||
                    wayland_display_handle,
 | 
					 | 
				
			||||||
                ) => ash::khr::wayland_surface::Instance::new(
 | 
					 | 
				
			||||||
                        &instance.entry,
 | 
					                        &instance.entry,
 | 
				
			||||||
                        &instance.instance,
 | 
					                        &instance.instance,
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
| 
						 | 
					@ -1231,11 +1361,12 @@ impl Vulkan {
 | 
				
			||||||
                        pdev,
 | 
					                        pdev,
 | 
				
			||||||
                        queue_family,
 | 
					                        queue_family,
 | 
				
			||||||
                        wayland_display_handle.display.cast().as_mut(),
 | 
					                        wayland_display_handle.display.cast().as_mut(),
 | 
				
			||||||
                ),
 | 
					                    )
 | 
				
			||||||
                winit::raw_window_handle::RawDisplayHandle::Drm(_) => {
 | 
					                }
 | 
				
			||||||
 | 
					                RawDisplayHandle::Drm(_) => {
 | 
				
			||||||
                    todo!()
 | 
					                    todo!()
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                winit::raw_window_handle::RawDisplayHandle::Windows(_) => {
 | 
					                RawDisplayHandle::Windows(_) => {
 | 
				
			||||||
                    ash::khr::win32_surface::Instance::new(
 | 
					                    ash::khr::win32_surface::Instance::new(
 | 
				
			||||||
                        &instance.entry,
 | 
					                        &instance.entry,
 | 
				
			||||||
                        &instance.instance,
 | 
					                        &instance.instance,
 | 
				
			||||||
| 
						 | 
					@ -1252,7 +1383,7 @@ impl Vulkan {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn select_pdev_queue_families(
 | 
					    fn select_pdev_queue_families(
 | 
				
			||||||
        instance: &Instance,
 | 
					        instance: &Instance,
 | 
				
			||||||
        display_handle: winit::raw_window_handle::DisplayHandle,
 | 
					        display_handle: Option<RawDisplayHandle>,
 | 
				
			||||||
        pdev: vk::PhysicalDevice,
 | 
					        pdev: vk::PhysicalDevice,
 | 
				
			||||||
    ) -> DeviceQueueFamilies {
 | 
					    ) -> DeviceQueueFamilies {
 | 
				
			||||||
        let queue_families = unsafe {
 | 
					        let queue_families = unsafe {
 | 
				
			||||||
| 
						 | 
					@ -1329,12 +1460,16 @@ impl Vulkan {
 | 
				
			||||||
                        family.queue_flags.contains(vk::QueueFlags::TRANSFER)
 | 
					                        family.queue_flags.contains(vk::QueueFlags::TRANSFER)
 | 
				
			||||||
                            || is_compute
 | 
					                            || is_compute
 | 
				
			||||||
                            || is_graphics;
 | 
					                            || is_graphics;
 | 
				
			||||||
                    let is_present = Self::queue_family_supports_presentation(
 | 
					                    let is_present = display_handle
 | 
				
			||||||
 | 
					                        .map(|display_handle| {
 | 
				
			||||||
 | 
					                            Self::queue_family_supports_presentation(
 | 
				
			||||||
                                instance,
 | 
					                                instance,
 | 
				
			||||||
                                pdev,
 | 
					                                pdev,
 | 
				
			||||||
                                q,
 | 
					                                q,
 | 
				
			||||||
                                display_handle,
 | 
					                                display_handle,
 | 
				
			||||||
                    );
 | 
					                            )
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
 | 
					                        .unwrap_or(false);
 | 
				
			||||||
                    QueueFamily {
 | 
					                    QueueFamily {
 | 
				
			||||||
                        num_queues: family.queue_count,
 | 
					                        num_queues: family.queue_count,
 | 
				
			||||||
                        is_compute,
 | 
					                        is_compute,
 | 
				
			||||||
| 
						 | 
					@ -1359,12 +1494,7 @@ impl Vulkan {
 | 
				
			||||||
        // find present queue first because it is rather more important than a secondary compute queue
 | 
					        // find present queue first because it is rather more important than a secondary compute queue
 | 
				
			||||||
        let present =
 | 
					        let present =
 | 
				
			||||||
            if !queue_families.0.get(graphics as usize).unwrap().is_present {
 | 
					            if !queue_families.0.get(graphics as usize).unwrap().is_present {
 | 
				
			||||||
                // unwrap because we do need a present queue
 | 
					                queue_families.find_first(|family| family.is_present)
 | 
				
			||||||
                Some(
 | 
					 | 
				
			||||||
                    queue_families
 | 
					 | 
				
			||||||
                        .find_first(|family| family.is_present)
 | 
					 | 
				
			||||||
                        .unwrap(),
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
| 
						 | 
					@ -1379,12 +1509,13 @@ impl Vulkan {
 | 
				
			||||||
            async_compute,
 | 
					            async_compute,
 | 
				
			||||||
            transfer,
 | 
					            transfer,
 | 
				
			||||||
            present: present.or({
 | 
					            present: present.or({
 | 
				
			||||||
                if !queue_families.0.get(graphics as usize).unwrap().is_present
 | 
					                if display_handle.is_none() {
 | 
				
			||||||
                {
 | 
					                    // in this case the graphics queue will be used by default
 | 
				
			||||||
                    panic!("no present queue available");
 | 
					                    tracing::info!("no present queue available, using graphics queue as fallback for headless_surface");
 | 
				
			||||||
 | 
					                    Some(graphics)
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    None
 | 
					                    tracing::warn!("no present queue available, this is unexpected!");
 | 
				
			||||||
                }
 | 
					                    None}
 | 
				
			||||||
            }),
 | 
					            }),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1483,6 +1614,10 @@ impl Vulkan {
 | 
				
			||||||
                    &instance.instance,
 | 
					                    &instance.instance,
 | 
				
			||||||
                    &device,
 | 
					                    &device,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 | 
					                debug_utils: ash::ext::debug_utils::Device::new(
 | 
				
			||||||
 | 
					                    &instance.instance,
 | 
				
			||||||
 | 
					                    &device,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
                instance,
 | 
					                instance,
 | 
				
			||||||
                main_queue,
 | 
					                main_queue,
 | 
				
			||||||
                present_queue,
 | 
					                present_queue,
 | 
				
			||||||
| 
						 | 
					@ -1497,7 +1632,7 @@ impl Vulkan {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn choose_physical_device(
 | 
					    fn choose_physical_device(
 | 
				
			||||||
        instance: &Instance,
 | 
					        instance: &Instance,
 | 
				
			||||||
        display_handle: winit::raw_window_handle::DisplayHandle,
 | 
					        display_handle: Option<RawDisplayHandle>,
 | 
				
			||||||
        requirements: &PhysicalDeviceFeatures,
 | 
					        requirements: &PhysicalDeviceFeatures,
 | 
				
			||||||
        extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>,
 | 
					        extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>,
 | 
				
			||||||
    ) -> Result<PhysicalDevice> {
 | 
					    ) -> Result<PhysicalDevice> {
 | 
				
			||||||
| 
						 | 
					@ -1580,7 +1715,7 @@ impl Vulkan {
 | 
				
			||||||
        entry: &ash::Entry,
 | 
					        entry: &ash::Entry,
 | 
				
			||||||
        layers: &[&'a CStr],
 | 
					        layers: &[&'a CStr],
 | 
				
			||||||
        extensions: &[&'a CStr],
 | 
					        extensions: &[&'a CStr],
 | 
				
			||||||
        display_handle: winit::raw_window_handle::DisplayHandle,
 | 
					        display_handle: Option<RawDisplayHandle>,
 | 
				
			||||||
    ) -> core::result::Result<Vec<&'a CStr>, (Vec<&'a CStr>, Vec<&'a CStr>)>
 | 
					    ) -> core::result::Result<Vec<&'a CStr>, (Vec<&'a CStr>, Vec<&'a CStr>)>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
| 
						 | 
					@ -1606,10 +1741,11 @@ impl Vulkan {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let Ok(required_extension_names) =
 | 
					            let Ok(required_extension_names) = display_handle
 | 
				
			||||||
                ash_window::enumerate_required_extensions(
 | 
					                .map(|display_handle| {
 | 
				
			||||||
                    display_handle.as_raw(),
 | 
					                    ash_window::enumerate_required_extensions(display_handle)
 | 
				
			||||||
                )
 | 
					                })
 | 
				
			||||||
 | 
					                .unwrap_or(Ok(&[]))
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
                return Err((out_extensions, unsupported_extensions));
 | 
					                return Err((out_extensions, unsupported_extensions));
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
| 
						 | 
					@ -1665,9 +1801,47 @@ impl Vulkan {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use winit::raw_window_handle::RawWindowHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct WindowContext {
 | 
					pub struct WindowContext {
 | 
				
			||||||
 | 
					    window_handle: RawWindowHandle,
 | 
				
			||||||
    surface: Arc<Surface>,
 | 
					    surface: Arc<Surface>,
 | 
				
			||||||
    current_swapchain: Arc<Swapchain>,
 | 
					    // this mutex is for guarding the swapchain against being replaced
 | 
				
			||||||
 | 
					    // underneath WindowContext's functions
 | 
				
			||||||
 | 
					    current_swapchain: RwLock<Arc<Swapchain>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Drop for WindowContext {
 | 
				
			||||||
 | 
					    fn drop(&mut self) {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            self.current_swapchain
 | 
				
			||||||
 | 
					                .read()
 | 
				
			||||||
 | 
					                .device
 | 
				
			||||||
 | 
					                .dev()
 | 
				
			||||||
 | 
					                .device_wait_idle();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsafe impl Send for WindowContext {}
 | 
				
			||||||
 | 
					unsafe impl Sync for WindowContext {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Borrow<RawWindowHandle> for WindowContext {
 | 
				
			||||||
 | 
					    fn borrow(&self) -> &RawWindowHandle {
 | 
				
			||||||
 | 
					        &self.window_handle
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl PartialEq for WindowContext {
 | 
				
			||||||
 | 
					    fn eq(&self, other: &Self) -> bool {
 | 
				
			||||||
 | 
					        self.window_handle == other.window_handle
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl Eq for WindowContext {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl core::hash::Hash for WindowContext {
 | 
				
			||||||
 | 
					    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 | 
				
			||||||
 | 
					        self.window_handle.hash(state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl WindowContext {
 | 
					impl WindowContext {
 | 
				
			||||||
| 
						 | 
					@ -1675,11 +1849,14 @@ impl WindowContext {
 | 
				
			||||||
        instance: Arc<Instance>,
 | 
					        instance: Arc<Instance>,
 | 
				
			||||||
        device: Device,
 | 
					        device: Device,
 | 
				
			||||||
        extent: vk::Extent2D,
 | 
					        extent: vk::Extent2D,
 | 
				
			||||||
        window: winit::raw_window_handle::RawWindowHandle,
 | 
					        window_handle: winit::raw_window_handle::RawWindowHandle,
 | 
				
			||||||
        display: winit::raw_window_handle::RawDisplayHandle,
 | 
					        display: RawDisplayHandle,
 | 
				
			||||||
    ) -> Result<Self> {
 | 
					    ) -> Result<Self> {
 | 
				
			||||||
        let surface =
 | 
					        let surface = Arc::new(Surface::create(
 | 
				
			||||||
            Arc::new(Surface::create(instance.clone(), display, window)?);
 | 
					            instance.clone(),
 | 
				
			||||||
 | 
					            display,
 | 
				
			||||||
 | 
					            window_handle,
 | 
				
			||||||
 | 
					        )?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let swapchain = Arc::new(Swapchain::new(
 | 
					        let swapchain = Arc::new(Swapchain::new(
 | 
				
			||||||
            instance,
 | 
					            instance,
 | 
				
			||||||
| 
						 | 
					@ -1690,14 +1867,53 @@ impl WindowContext {
 | 
				
			||||||
        )?);
 | 
					        )?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            window_handle,
 | 
				
			||||||
            surface,
 | 
					            surface,
 | 
				
			||||||
            current_swapchain: swapchain,
 | 
					            current_swapchain: RwLock::new(swapchain),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn recreate_swapchain(&mut self, extent: vk::Extent2D) -> Result<()> {
 | 
					    /// spawns a task that continuously requests images from the current
 | 
				
			||||||
        self.current_swapchain =
 | 
					    /// swapchain, sending them to a channel.  returns the receiver of the
 | 
				
			||||||
            Arc::new(self.current_swapchain.recreate(extent)?);
 | 
					    /// channel, and a handle to the task, allowing for cancellation.
 | 
				
			||||||
 | 
					    fn images(
 | 
				
			||||||
 | 
					        self: Arc<Self>,
 | 
				
			||||||
 | 
					    ) -> (
 | 
				
			||||||
 | 
					        smol::channel::Receiver<SwapchainFrame>,
 | 
				
			||||||
 | 
					        smol::Task<std::result::Result<(), Error>>,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let (tx, rx) = smol::channel::bounded(8);
 | 
				
			||||||
 | 
					        let task = smol::spawn(async move {
 | 
				
			||||||
 | 
					            loop {
 | 
				
			||||||
 | 
					                let frame = self.acquire_image().await?;
 | 
				
			||||||
 | 
					                tx.send(frame)
 | 
				
			||||||
 | 
					                    .await
 | 
				
			||||||
 | 
					                    .expect("channel closed on swapchain acquiring frame");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Result::Ok(())
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        (rx, task)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn acquire_image(&self) -> Result<SwapchainFrame> {
 | 
				
			||||||
 | 
					        // clone swapchain to keep it alive
 | 
				
			||||||
 | 
					        let swapchain = self.current_swapchain.read().clone();
 | 
				
			||||||
 | 
					        let (frame, suboptimal) = swapchain.clone().acquire_image().await?;
 | 
				
			||||||
 | 
					        if suboptimal {
 | 
				
			||||||
 | 
					            let mut lock = self.current_swapchain.write();
 | 
				
			||||||
 | 
					            // only recreate our swapchain if it is still same, or else it might have already been recreated.
 | 
				
			||||||
 | 
					            if Arc::ptr_eq(&swapchain, &lock) {
 | 
				
			||||||
 | 
					                *lock = Arc::new(lock.recreate(lock.extent)?);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(frame)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn recreate_with(&self, extent: vk::Extent2D) -> Result<()> {
 | 
				
			||||||
 | 
					        let mut swapchain = self.current_swapchain.write();
 | 
				
			||||||
 | 
					        *swapchain = Arc::new(swapchain.recreate(extent)?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1705,18 +1921,18 @@ impl WindowContext {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Renderer {
 | 
					pub struct Renderer {
 | 
				
			||||||
    vulkan: Vulkan,
 | 
					    vulkan: Vulkan,
 | 
				
			||||||
    display: winit::raw_window_handle::RawDisplayHandle,
 | 
					    display: RawDisplayHandle,
 | 
				
			||||||
    pub window_contexts: HashMap<winit::window::WindowId, WindowContext>,
 | 
					    pub window_contexts: HashMap<winit::window::WindowId, WindowContext>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use vk::Extent2D;
 | 
					pub use vk::Extent2D;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Renderer {
 | 
					impl Renderer {
 | 
				
			||||||
    pub fn new(display: DisplayHandle) -> Result<Self> {
 | 
					    pub fn new(display: RawDisplayHandle) -> Result<Self> {
 | 
				
			||||||
        let vulkan = Vulkan::new("Vidya", &[], &[], display)?;
 | 
					        let vulkan = Vulkan::new("Vidya", &[], &[], Some(display))?;
 | 
				
			||||||
        Ok(Self {
 | 
					        Ok(Self {
 | 
				
			||||||
            vulkan,
 | 
					            vulkan,
 | 
				
			||||||
            display: display.as_raw(),
 | 
					            display,
 | 
				
			||||||
            window_contexts: HashMap::new(),
 | 
					            window_contexts: HashMap::new(),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1736,15 +1952,14 @@ impl Renderer {
 | 
				
			||||||
                commands::SingleUseCommand::new(dev.clone(), pool.pool())?;
 | 
					                commands::SingleUseCommand::new(dev.clone(), pool.pool())?;
 | 
				
			||||||
            let buffer = cmd.command_buffer();
 | 
					            let buffer = cmd.command_buffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let extent = ctx.current_swapchain.extent;
 | 
					            let (frame, suboptimal) = smol::block_on(
 | 
				
			||||||
 | 
					                ctx.current_swapchain.read().clone().acquire_image(),
 | 
				
			||||||
            let (frame, suboptimal) =
 | 
					            )?;
 | 
				
			||||||
                smol::block_on(ctx.current_swapchain.clone().acquire_image())?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if suboptimal {
 | 
					            if suboptimal {
 | 
				
			||||||
                tracing::warn!(
 | 
					                tracing::warn!(
 | 
				
			||||||
                    "swapchain ({:?}) is suboptimal!",
 | 
					                    "swapchain ({:?}) is suboptimal!",
 | 
				
			||||||
                    ctx.current_swapchain.swapchain
 | 
					                    ctx.current_swapchain.read().swapchain
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1826,42 +2041,11 @@ impl Renderer {
 | 
				
			||||||
                    Arc::new(sync::Fence::create(dev.clone())?),
 | 
					                    Arc::new(sync::Fence::create(dev.clone())?),
 | 
				
			||||||
                )?;
 | 
					                )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let present_id = {
 | 
					                frame.present();
 | 
				
			||||||
                    let swapchain = ctx.current_swapchain.swapchain.lock();
 | 
					 | 
				
			||||||
                    let queue = dev.present_queue().lock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    let wait_semaphores = [frame.release];
 | 
					 | 
				
			||||||
                    let swapchains = [*swapchain];
 | 
					 | 
				
			||||||
                    let indices = [frame.index];
 | 
					 | 
				
			||||||
                    static PRESENT_ID: AtomicU64 = AtomicU64::new(1);
 | 
					 | 
				
			||||||
                    let mut present_ids = [PRESENT_ID
 | 
					 | 
				
			||||||
                        .fetch_add(1, std::sync::atomic::Ordering::Release)];
 | 
					 | 
				
			||||||
                    let mut present_id =
 | 
					 | 
				
			||||||
                        vk::PresentIdKHR::default().present_ids(&present_ids);
 | 
					 | 
				
			||||||
                    let present_info = vk::PresentInfoKHR::default()
 | 
					 | 
				
			||||||
                        .image_indices(core::slice::from_ref(&frame.index))
 | 
					 | 
				
			||||||
                        .swapchains(core::slice::from_ref(&swapchain))
 | 
					 | 
				
			||||||
                        .wait_semaphores(&wait_semaphores)
 | 
					 | 
				
			||||||
                        .push_next(&mut present_id);
 | 
					 | 
				
			||||||
                    dev.swapchain().queue_present(*queue, &present_info)?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    present_ids[0]
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                future.block()?;
 | 
					                future.block()?;
 | 
				
			||||||
                ctx.current_swapchain.swapchain.with_locked(|swapchain| {
 | 
					 | 
				
			||||||
                    khr::present_wait::Device::new(
 | 
					 | 
				
			||||||
                        &self.vulkan.instance.instance,
 | 
					 | 
				
			||||||
                        self.vulkan.device.dev(),
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                    .wait_for_present(
 | 
					 | 
				
			||||||
                        swapchain,
 | 
					 | 
				
			||||||
                        present_id,
 | 
					 | 
				
			||||||
                        u64::MAX,
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                })?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                dev.dev().device_wait_idle();
 | 
					                // wait for idle here is unnecessary.
 | 
				
			||||||
 | 
					                // dev.dev().device_wait_idle();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2534,3 +2718,58 @@ pub mod utils {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test_swapchain {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn create_headless_vk() -> Result<(Vulkan, WindowContext)> {
 | 
				
			||||||
 | 
					        let vk = Vulkan::new(
 | 
				
			||||||
 | 
					            "testing",
 | 
				
			||||||
 | 
					            &[],
 | 
				
			||||||
 | 
					            &[ash::ext::headless_surface::NAME, khr::surface::NAME],
 | 
				
			||||||
 | 
					            None,
 | 
				
			||||||
 | 
					        )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let surface = Arc::new(Surface::headless(vk.instance.clone())?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let swapchain = Arc::new(Swapchain::new(
 | 
				
			||||||
 | 
					            vk.instance.clone(),
 | 
				
			||||||
 | 
					            vk.device.clone(),
 | 
				
			||||||
 | 
					            surface.clone(),
 | 
				
			||||||
 | 
					            vk.device.phy(),
 | 
				
			||||||
 | 
					            vk::Extent2D::default().width(1).height(1),
 | 
				
			||||||
 | 
					        )?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let window_ctx = WindowContext {
 | 
				
			||||||
 | 
					            window_handle: RawWindowHandle::Web(
 | 
				
			||||||
 | 
					                winit::raw_window_handle::WebWindowHandle::new(0),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            surface,
 | 
				
			||||||
 | 
					            current_swapchain: RwLock::new(swapchain),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok((vk, window_ctx))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[tracing_test::traced_test]
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn async_swapchain_acquiring() {
 | 
				
			||||||
 | 
					        let (vk, ctx) = create_headless_vk().expect("init");
 | 
				
			||||||
 | 
					        let ctx = Arc::new(ctx);
 | 
				
			||||||
 | 
					        let (rx, handle) = ctx.images();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut count = 0;
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            let mut now = std::time::Instant::now();
 | 
				
			||||||
 | 
					            let frame = rx.recv_blocking().expect("recv");
 | 
				
			||||||
 | 
					            frame.present();
 | 
				
			||||||
 | 
					            tracing::info!("mspf: {}ms", now.elapsed().as_secs_f64() / 1000.0);
 | 
				
			||||||
 | 
					            count += 1;
 | 
				
			||||||
 | 
					            if count > 1000 {
 | 
				
			||||||
 | 
					                handle.cancel();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue