From 5971c8cd5f7c5b6e32efbacf45bfe8594de23386 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sat, 31 May 2025 21:53:20 +0200 Subject: [PATCH] MaterialManager: first iteration --- src/core/render/material_manager.rs | 218 ++++++++++++++++++++++++++++ src/core/render/mod.rs | 1 + 2 files changed, 219 insertions(+) create mode 100644 src/core/render/material_manager.rs diff --git a/src/core/render/material_manager.rs b/src/core/render/material_manager.rs new file mode 100644 index 0000000..dd8f657 --- /dev/null +++ b/src/core/render/material_manager.rs @@ -0,0 +1,218 @@ +use std::{ + any::TypeId, + collections::HashMap, + error::Error, + sync::{Arc, RwLock}, +}; + +use vulkano::{ + device::Device, format::Format, memory::allocator::StandardMemoryAllocator, + pipeline::Pipeline as VulkanoPipeline, +}; + +pub trait Pipeline { + fn load( + &mut self, + device: &Device, + memory_allocator: &StandardMemoryAllocator, + swapchain_format: Format, + depth_format: Format, + ) -> Result<(), Box>; +} + +pub trait Material { + fn pipeline_type_id() -> TypeId + where + Self: Sized; + + fn load( + &mut self, + device: &Device, + memory_allocator: &StandardMemoryAllocator, + ) -> Result<(), Box>; +} + +pub struct MaterialManager { + device: Arc, + memory_allocator: Arc, + swapchain_format: Format, + depth_format: Format, + + // cached pipelines by Pipeline ID + loading_pipelines: Arc>>>>, + loaded_pipelines: Arc>>>>, + + // cached materials by Material ID + loading_materials: Arc>>>>, + loaded_materials: Arc>>>>, + material_pipeline_map: Arc>>, + + // Store all materials marked as renderable when pipeline and material are loaded + renderable_materials: Arc>>>>, +} + +impl MaterialManager { + pub fn new( + device: Arc, + memory_allocator: Arc, + swapchain_format: Format, + depth_format: Format, + ) -> Self { + Self { + device, + memory_allocator, + swapchain_format, + depth_format, + loading_pipelines: Arc::new(RwLock::new(HashMap::new())), + loaded_pipelines: Arc::new(RwLock::new(HashMap::new())), + loading_materials: Arc::new(RwLock::new(HashMap::new())), + loaded_materials: Arc::new(RwLock::new(HashMap::new())), + material_pipeline_map: Arc::new(RwLock::new(HashMap::new())), + renderable_materials: Arc::new(RwLock::new(HashMap::new())), + } + } + + pub fn add_pipeline(&self) { + let type_id = TypeId::of::

(); + self.loading_pipelines + .write() + .expect("Failed to get write lock to loading_pipelines") + .insert(type_id, Arc::new(RwLock::new(P::default()))); + } + + pub fn add_material(&self) { + let type_id = TypeId::of::(); + let pipeline_id = M::pipeline_type_id(); + let material = Arc::new(RwLock::new(M::default())); + + self.loading_materials + .write() + .expect("Failed to get write lock to loading_materials") + .insert(type_id, material.clone()); + + self.material_pipeline_map + .write() + .expect("Failed to get write lock to material_pipeline_map") + .insert(type_id, pipeline_id); + } + + pub fn update_swapchain_format(&mut self, swapchain_format: Format) { + if self.swapchain_format == swapchain_format { + return; + } + + self.swapchain_format = swapchain_format; + self.mark_all_pipelines_as_loading(); + } + + fn load_pipelines(&self) { + let mut loaded_pipelines = HashMap::>>::new(); + + { + let loading_pipelines = self.loading_pipelines.read().unwrap(); + + for (type_id, pipeline) in loading_pipelines.iter() { + let result = { + let mut pipeline = pipeline.write().unwrap(); + pipeline.load( + &self.device, + &self.memory_allocator, + self.swapchain_format, + self.depth_format, + ) + }; + match result { + Ok(_) => { + loaded_pipelines.insert(type_id.clone(), pipeline.clone()); + } + Err(e) => { + tracing::error!("Failed to load pipeline: {e}"); + } + } + } + } + + let loaded_pipeline_keys = loaded_pipelines.keys().collect::>(); + + { + let mut loading_pipelines = self.loading_pipelines.write().unwrap(); + let loaded_materials = self.loaded_materials.read().unwrap(); + let mut renderable_materials = self.renderable_materials.write().unwrap(); + + for type_id in loaded_pipeline_keys { + loading_pipelines.remove(type_id); + + if loaded_materials.contains_key(type_id) { + renderable_materials.insert( + type_id.clone(), + loaded_materials.get(type_id).unwrap().clone(), + ); + } + } + } + + self.loaded_pipelines + .write() + .expect("Failed to get write lock to loaded_pipelines") + .extend(loaded_pipelines); + } + + fn load_materials(&self) { + let mut loaded_materials = HashMap::>>::new(); + + { + let loading_materials = self.loading_materials.read().unwrap(); + + for (type_id, material) in loading_materials.iter() { + let result = { + let mut material = material.write().unwrap(); + material.load(&self.device, &self.memory_allocator) + }; + + match result { + Ok(_) => { + loaded_materials.insert(type_id.clone(), material.clone()); + } + Err(e) => { + tracing::error!("Failed to load material: {e}"); + } + } + } + } + + { + let mut loading_materials = self.loading_materials.write().unwrap(); + let loaded_pipelines = self.loaded_pipelines.read().unwrap(); + let material_pipeline_map = self.material_pipeline_map.read().unwrap(); + let mut renderable_materials = self.renderable_materials.write().unwrap(); + + for (type_id, material) in loaded_materials.iter() { + loading_materials.remove(type_id); + + let pipeline_id = material_pipeline_map.get(type_id).unwrap().clone(); + + if loaded_pipelines.contains_key(&pipeline_id) { + renderable_materials.insert(type_id.clone(), material.clone()); + } + } + } + + self.loaded_materials + .write() + .expect("Failed to get write lock to loaded_materials") + .extend(loaded_materials); + } + + fn mark_all_pipelines_as_loading(&self) { + let mut loading_pipelines = self.loading_pipelines.write().unwrap(); + let mut loaded_pipelines = self.loaded_pipelines.write().unwrap(); + let mut renderable_materials = self.renderable_materials.write().unwrap(); + + for (type_id, pipeline) in loaded_pipelines.iter() { + loading_pipelines.insert(type_id.clone(), pipeline.clone()); + } + + loaded_pipelines.clear(); + renderable_materials.clear(); // Mark all materials as loading + } +} diff --git a/src/core/render/mod.rs b/src/core/render/mod.rs index f56fdf4..ec7ac54 100644 --- a/src/core/render/mod.rs +++ b/src/core/render/mod.rs @@ -1,3 +1,4 @@ +pub mod material_manager; pub mod primitives; pub mod render_pass_manager; pub mod texture;