use crate::{RenderCoreCreateInfo, prelude::*, renderbackend::RenderBackend}; use super::windowsystemintegration::WindowSystemIntegration; use crate::Result; use ecs::World; // use ui::prelude::*; use vulkan_rs::prelude::*; use std::sync::{ Arc, Mutex, RwLock, atomic::{AtomicUsize, Ordering::SeqCst}, }; use std::time::Duration; use std::u64; pub struct VulkanWindowRenderCore { device: Arc, // driver provided images swapchain: Arc, _surface: Arc, format: VkFormat, image_available_sem: RwLock>, render_finished_sem: Arc, render_fence: Arc, render_backend: RenderBackend, current_image_index: AtomicUsize, wsi: Arc, } impl VulkanWindowRenderCore { pub fn new( wsi: Arc, device: &Arc, queue: &Arc>, create_info: RenderCoreCreateInfo, ) -> Result<(Self, TargetMode<()>)> { // check swapchain extension if !device.enabled_extensions().swapchain { return Err(anyhow::Error::msg("Swapchain Extension must be enabled")); } let surface = wsi.surface(); if (surface.capabilities(device)?.supportedUsageFlagBits & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0 { return Err(anyhow::Error::msg(format!( "Surface capability not met: {:?}", VK_IMAGE_USAGE_TRANSFER_DST_BIT ))); } let usage = create_info.usage | RenderBackend::required_image_usage(); // create swapchain let swapchain = Swapchain::new( device.clone(), &surface, create_info.vsync, 2, usage, create_info.format, 1, wsi.window_size(), )?; let swapchain_images = swapchain.wrap_images(&swapchain.vk_images()?, queue, false)?; let render_sem = Semaphore::new(device.clone())?; let image_sem = Semaphore::new(device.clone())?; let fence = Fence::builder().build(device.clone())?; let images = TargetMode::Mono(swapchain_images); let render_backend = RenderBackend::new(device, queue, images)?; let window_render_core = VulkanWindowRenderCore { device: device.clone(), format: swapchain.format(), swapchain, _surface: surface, render_finished_sem: render_sem, image_available_sem: RwLock::new(image_sem), render_fence: fence, render_backend, current_image_index: AtomicUsize::new(0), wsi, }; Ok((window_render_core, TargetMode::Mono(()))) } fn aquire_next_image_index(&mut self, world: &mut World) -> Result<()> { // there was a bug that a windows never reacted after it was minimized // with this timeout, the window has 250ms delay #[cfg(target_os = "windows")] const ACQUIRE_IMAGE_TIME_OUT: u64 = 1_000_000_000 / 4; #[cfg(target_os = "linux")] const ACQUIRE_IMAGE_TIME_OUT: u64 = u64::MAX; let resize_mut = unsafe { remove_life_time_mut(self) }; let mut semaphore = self.image_available_sem.write().unwrap(); loop { match self .swapchain .acquire_next_image(ACQUIRE_IMAGE_TIME_OUT, &*semaphore)? { OutOfDate::Ok(index) => { self.current_image_index.store(index as usize, SeqCst); break; } OutOfDate::OutOfDate => { let (w, h) = self.wsi.window_size(); resize_mut.resize(world, w, h)?; *semaphore = Semaphore::new(self.device.clone())?; } OutOfDate::TimeOut => { break; } } } Ok(()) } } impl VulkanWindowRenderCore { pub fn format(&self) -> VkFormat { self.format } pub fn resize(&mut self, world: &mut World, w: u32, h: u32) -> Result<()> { self.swapchain.recreate((w, h))?; let swapchain_images = self.swapchain.wrap_images( &self.swapchain.vk_images()?, self.render_backend.queue(), false, )?; self.render_backend.resize( world, TargetMode::Mono(swapchain_images), self.swapchain.width(), self.swapchain.height(), )?; Ok(()) } pub fn next_frame(&mut self, world: &mut World) -> Result { self.aquire_next_image_index(world)?; let command_buffer = self.render_backend.render( world, TargetMode::Mono(self.current_image_index.load(SeqCst)), )?; let submits = &[SubmitInfo::default() .add_wait_semaphore( &*self.image_available_sem.read().unwrap(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, ) .add_command_buffer(command_buffer) .add_signal_semaphore(&self.render_finished_sem)]; if let OutOfDate::OutOfDate = { let queue_lock = self.render_backend.queue().lock().unwrap(); queue_lock.submit(Some(&self.render_fence), submits)?; queue_lock.present( &[&self.swapchain], &[self.current_image_index.load(SeqCst) as u32], &[&self.render_finished_sem], )? } { let (w, h) = self.wsi.window_size(); self.resize(world, w, h)?; self.render_fence.reset(); return Ok(true); } // make sure command_buffer is ready self.render_backend.device().wait_for_fences( &[&self.render_fence], true, Duration::from_secs(10), )?; self.render_fence.reset(); Ok(true) } pub fn set_clear_color(&self, color: [f32; 4]) { self.render_backend.set_clear_color(color); } // post process handling pub fn add_render_routine(&mut self, priority: u32) { self.render_backend.add_render_routine::(priority); } pub fn remove_render_routine(&mut self) { self.render_backend.remove_render_routine::(); } // getter pub fn image_count(&self) -> usize { self.render_backend.image_count() } pub fn images(&self) -> TargetMode>> { self.render_backend.images() } pub fn width(&self) -> u32 { self.swapchain.width() } pub fn height(&self) -> u32 { self.swapchain.height() } pub fn transformations(&self) -> Option<(VRTransformations, VRTransformations)> { None } } impl std::fmt::Debug for VulkanWindowRenderCore { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "VulkanWindowRenderCore {{ }}") } }