engine/presentation/src/renderbackend.rs

270 lines
7.7 KiB
Rust
Raw Normal View History

2024-08-23 11:22:09 +00:00
use crate::prelude::*;
use crate::Result;
use cgmath::{Matrix4, SquareMatrix};
use ui::prelude::*;
use vulkan_rs::prelude::*;
use std::ops::Deref;
use std::sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc, Mutex, RwLock,
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Eye {
Left,
Right,
}
#[derive(Debug, Clone, Copy)]
pub struct VRTransformations {
pub proj: Matrix4<f32>,
pub view: Matrix4<f32>,
}
impl VRTransformations {
pub fn invert(self) -> Result<Self> {
Ok(VRTransformations {
proj: self
.proj
.invert()
.ok_or(anyhow::Error::msg("Could not invert Matrix"))?,
view: self
.view
.invert()
.ok_or(anyhow::Error::msg("Could not invert Matrix"))?,
})
}
}
impl Default for VRTransformations {
fn default() -> Self {
VRTransformations {
proj: Matrix4::identity(),
view: Matrix4::identity(),
}
}
}
pub struct RenderBackend {
device: Arc<Device>,
queue: Arc<Mutex<Queue>>,
// driver provided images
swapchain_images: Mutex<TargetMode<Vec<Arc<Image>>>>,
image_count: AtomicUsize,
clear_color: RwLock<VkClearColorValue>,
command_buffer: Arc<CommandBuffer>,
scene: Box<dyn TScene>,
post_processes: Mutex<Vec<Arc<dyn PostProcess>>>,
}
impl RenderBackend {
pub fn new<SCENE: TScene + 'static>(
device: &Arc<Device>,
queue: &Arc<Mutex<Queue>>,
images: TargetMode<Vec<Arc<Image>>>,
scene: SCENE,
) -> Result<Self> {
let image_count = match &images {
TargetMode::Mono(images) => images.len(),
TargetMode::Stereo(left_images, right_images) => {
debug_assert!(left_images.len() == right_images.len());
left_images.len()
}
};
// create a new command buffer
let command_buffer = CommandBuffer::new_primary().build(device.clone(), queue.clone())?;
Ok(RenderBackend {
device: device.clone(),
queue: queue.clone(),
swapchain_images: Mutex::new(images),
image_count: AtomicUsize::new(image_count),
clear_color: RwLock::new(VkClearColorValue::float32([0.0, 0.0, 0.0, 1.0])),
command_buffer,
scene: Box::new(scene),
post_processes: Mutex::new(Vec::new()),
})
}
pub(crate) fn required_image_usage() -> VkImageUsageFlagBits {
VK_IMAGE_USAGE_TRANSFER_DST_BIT.into()
}
}
impl RenderBackend {
pub fn device(&self) -> &Arc<Device> {
&self.device
}
pub fn queue(&self) -> &Arc<Mutex<Queue>> {
&self.queue
}
pub fn set_clear_color(&self, clear_color: [f32; 4]) {
*self.clear_color.write().unwrap() = VkClearColorValue::float32(clear_color);
}
pub fn render(&mut self, image_indices: TargetMode<usize>) -> Result<&Arc<CommandBuffer>> {
// begin main command buffer
let mut buffer_recorder = self.command_buffer.begin(VkCommandBufferBeginInfo::new(
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
))?;
// clear the current swapchain image
{
let swapchain_images = self.swapchain_images.lock().unwrap();
let target_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
let clear_color = self.clear_color.read().unwrap().clone();
match (&image_indices, swapchain_images.deref()) {
(TargetMode::Mono(image_index), TargetMode::Mono(images)) => {
let swapchain_image = &images[*image_index];
Self::clear_image(
&mut buffer_recorder,
swapchain_image,
clear_color,
target_layout,
);
}
(
TargetMode::Stereo(left_image_index, right_image_index),
TargetMode::Stereo(left_images, right_images),
) => {
let left_image = &left_images[*left_image_index];
let right_image = &right_images[*right_image_index];
Self::clear_image(
&mut buffer_recorder,
left_image,
clear_color.clone(),
target_layout,
);
Self::clear_image(
&mut buffer_recorder,
right_image,
clear_color,
target_layout,
);
}
_ => panic!("Expected another target mode"),
}
}
// make a call to the connected scene
self.scene.process(
&mut buffer_recorder,
&*self.swapchain_images.lock().unwrap(),
&image_indices,
)?;
// post processing
for post_process in self.post_processes.lock().unwrap().iter() {
post_process.process(&mut buffer_recorder, &image_indices)?;
}
Ok(&self.command_buffer)
}
pub fn resize(
&mut self,
images: TargetMode<Vec<Arc<Image>>>,
width: u32,
height: u32,
) -> Result<()> {
self.image_count.store(
match &images {
TargetMode::Mono(images) => images.len(),
TargetMode::Stereo(left_images, right_images) => {
debug_assert!(left_images.len() == right_images.len());
left_images.len()
}
},
SeqCst,
);
self.scene.resize(width as f32, height as f32, &images)?;
*self.swapchain_images.lock().unwrap() = images;
for post_process in self.post_processes.lock().unwrap().iter() {
post_process.resize(width, height)?;
}
Ok(())
}
// scene handling
pub fn scene(&self) -> &Box<dyn TScene> {
&self.scene
}
pub fn scene_mut(&mut self) -> &mut Box<dyn TScene> {
&mut self.scene
}
pub fn add_post_processing_routine(&self, post_process: Arc<dyn PostProcess>) {
let mut post_processes = self.post_processes.lock().unwrap();
// only add if it isn't present already
if post_processes
.iter()
.find(|p| Arc::ptr_eq(p, &post_process))
.is_none()
{
post_processes.push(post_process);
post_processes.sort_by(|lhs, rhs| lhs.priority().cmp(&rhs.priority()));
}
}
pub fn remove_post_processing_routine(&self, post_process: Arc<dyn PostProcess>) {
let mut post_processes = self.post_processes.lock().unwrap();
if let Some(index) = post_processes
.iter()
.position(|p| Arc::ptr_eq(p, &post_process))
{
post_processes.remove(index);
}
}
pub fn clear_post_processing_routines(&self) {
self.post_processes.lock().unwrap().clear();
}
// getter
pub fn image_count(&self) -> usize {
self.image_count.load(SeqCst)
}
pub fn images(&self) -> TargetMode<Vec<Arc<Image>>> {
self.swapchain_images.lock().unwrap().clone()
}
}
impl RenderBackend {
#[inline]
fn clear_image(
buffer_recorder: &mut CommandBufferRecorder<'_>,
image: &Arc<Image>,
clear_color: VkClearColorValue,
target_layout: VkImageLayout,
) {
buffer_recorder.set_full_image_layout(image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
buffer_recorder.clear_color_image(image, clear_color);
buffer_recorder.set_full_image_layout(image, target_layout);
}
}