256 lines
7.2 KiB
Rust
256 lines
7.2 KiB
Rust
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<S: TScene + 'static> {
|
|
device: Arc<Device>,
|
|
|
|
// driver provided images
|
|
swapchain: Arc<Swapchain>,
|
|
_surface: Arc<Surface>,
|
|
|
|
format: VkFormat,
|
|
|
|
image_available_sem: RwLock<Arc<Semaphore>>,
|
|
render_finished_sem: Arc<Semaphore>,
|
|
render_fence: Arc<Fence>,
|
|
|
|
render_backend: RenderBackend<S>,
|
|
|
|
current_image_index: AtomicUsize,
|
|
|
|
wsi: Arc<WindowSystemIntegration>,
|
|
}
|
|
|
|
impl<S: TScene + 'static> VulkanWindowRenderCore<S> {
|
|
pub fn new(
|
|
wsi: Arc<WindowSystemIntegration>,
|
|
device: &Arc<Device>,
|
|
queue: &Arc<Mutex<Queue>>,
|
|
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::<S>::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<S: TScene + 'static> RenderCore for VulkanWindowRenderCore<S> {
|
|
fn format(&self) -> VkFormat {
|
|
self.format
|
|
}
|
|
|
|
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(())
|
|
}
|
|
|
|
fn next_frame(&mut self, world: &mut World) -> Result<bool> {
|
|
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)
|
|
}
|
|
|
|
fn set_clear_color(&self, color: [f32; 4]) {
|
|
self.render_backend.set_clear_color(color);
|
|
}
|
|
|
|
// post process handling
|
|
fn add_post_processing_routine(&self, post_process: Arc<dyn PostProcess>) {
|
|
self.render_backend
|
|
.add_post_processing_routine(post_process);
|
|
}
|
|
|
|
fn remove_post_processing_routine(&self, post_process: Arc<dyn PostProcess>) {
|
|
self.render_backend
|
|
.remove_post_processing_routine(post_process);
|
|
}
|
|
|
|
fn clear_post_processing_routines(&self) {
|
|
self.render_backend.clear_post_processing_routines();
|
|
}
|
|
|
|
// getter
|
|
fn image_count(&self) -> usize {
|
|
self.render_backend.image_count()
|
|
}
|
|
|
|
fn images(&self) -> TargetMode<Vec<Arc<Image>>> {
|
|
self.render_backend.images()
|
|
}
|
|
|
|
fn width(&self) -> u32 {
|
|
self.swapchain.width()
|
|
}
|
|
|
|
fn height(&self) -> u32 {
|
|
self.swapchain.height()
|
|
}
|
|
|
|
fn transformations(&self) -> Option<(VRTransformations, VRTransformations)> {
|
|
None
|
|
}
|
|
}
|
|
|
|
impl<S: TScene + 'static> std::fmt::Debug for VulkanWindowRenderCore<S> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "VulkanWindowRenderCore {{ }}")
|
|
}
|
|
}
|