use std::marker::PhantomData;
use std::sync::{Arc};
use winit::window::Window;
use super::render_context::RenderContext;
use crate::camera::Camera;
use crate::core::{SwapchainError, VulkanError, VulkanResult};
use crate::frame_graph::FrameGraph;
use crate::resources::*;
pub struct WorldRenderer {
graph: FrameGraph,
resources: Arc<Resources>,
ctx: Arc<RenderContext>,
_marker: PhantomData<*mut ()>,
}
impl WorldRenderer {
pub fn new(window: &Window) -> VulkanResult<WorldRenderer> {
let ctx = RenderContext::new(window)?;
let resources = Resources::new(&ctx)?;
let graph = FrameGraph::new()?;
Ok(WorldRenderer {
resources,
graph,
ctx,
_marker: PhantomData,
})
}
pub fn create<T: Create>(&mut self, desc: T::Desc<'_>) -> VulkanResult<Res<T>> {
T::create(&self.ctx, &self.resources, desc)
}
pub fn get<T: Get>(&self, res: &Res<T>) -> Ref<'_, T> {
T::get(&self.resources, res)
}
pub fn get_mut<T: GetMut>(&mut self, res: &Res<T>) -> RefMut<'_, T> {
T::get_mut(&self.resources, res)
}
pub fn camera_mut(&mut self) -> RefMut<'_, Camera> {
RefMut(self.resources.camera.write())
}
pub fn camera(&self) -> Ref<'_, Camera> {
Ref(self.resources.camera.read())
}
pub fn resize(&mut self, width: u32, height: u32) -> VulkanResult<()> {
profiling::scope!("WorldRenderer::resize");
if width == 0 || height == 0 {
return Ok(());
}
self.ctx.resize(width, height)?;
Ok(())
}
pub fn draw_frame<R, F: FnOnce(&mut FrameGraph) -> R>(&mut self, setup: F) -> VulkanResult<R> {
profiling::scope!("WorldRenderer::draw_frame");
let result = setup(&mut self.graph);
self.graph.compile(&self.ctx, &self.resources)?;
if let Err(err) = self.graph.execute(&self.ctx, &self.resources) {
if let VulkanError::Swapchain(err) = err {
match err {
SwapchainError::SwapchainOutOfDateKhr => {
let extent = self.ctx.resolution();
self.resize(extent.width, extent.height)?;
},
SwapchainError::SwapchainCreationFailed(err) => {
return Err(VulkanError::Swapchain(SwapchainError::SwapchainCreationFailed(err)));
},
SwapchainError::SwapchainSubOptimal => {
},
}
} else {
return Err(err);
}
}
Ok(result)
}
}
impl Drop for WorldRenderer {
fn drop(&mut self) {
let device = &self.ctx.device;
unsafe { device.device_wait_idle().expect("Error device wait idle") };
if Arc::strong_count(&self.resources) > 1 {
panic!("Resources has another clone this is an architectural error");
}
self.graph.destroy(device);
self.resources.destroy(device);
if Arc::strong_count(&self.ctx) > 1 {
panic!("Render Context has another clone this is an architectural error");
}
}
}