MaterialManager: first iteration
This commit is contained in:
parent
9d2a4410f0
commit
5971c8cd5f
2 changed files with 219 additions and 0 deletions
218
src/core/render/material_manager.rs
Normal file
218
src/core/render/material_manager.rs
Normal file
|
@ -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<dyn Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Material {
|
||||||
|
fn pipeline_type_id() -> TypeId
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&mut self,
|
||||||
|
device: &Device,
|
||||||
|
memory_allocator: &StandardMemoryAllocator,
|
||||||
|
) -> Result<(), Box<dyn Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MaterialManager {
|
||||||
|
device: Arc<Device>,
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
|
swapchain_format: Format,
|
||||||
|
depth_format: Format,
|
||||||
|
|
||||||
|
// cached pipelines by Pipeline ID
|
||||||
|
loading_pipelines: Arc<RwLock<HashMap<TypeId, Arc<RwLock<dyn Pipeline>>>>>,
|
||||||
|
loaded_pipelines: Arc<RwLock<HashMap<TypeId, Arc<RwLock<dyn Pipeline>>>>>,
|
||||||
|
|
||||||
|
// cached materials by Material ID
|
||||||
|
loading_materials: Arc<RwLock<HashMap<TypeId, Arc<RwLock<dyn Material>>>>>,
|
||||||
|
loaded_materials: Arc<RwLock<HashMap<TypeId, Arc<RwLock<dyn Material>>>>>,
|
||||||
|
material_pipeline_map: Arc<RwLock<HashMap<TypeId, TypeId>>>,
|
||||||
|
|
||||||
|
// Store all materials marked as renderable when pipeline and material are loaded
|
||||||
|
renderable_materials: Arc<RwLock<HashMap<TypeId, Arc<RwLock<dyn Material>>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaterialManager {
|
||||||
|
pub fn new(
|
||||||
|
device: Arc<Device>,
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
|
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<P: Pipeline + Default + 'static>(&self) {
|
||||||
|
let type_id = TypeId::of::<P>();
|
||||||
|
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<M: Material + Default + 'static>(&self) {
|
||||||
|
let type_id = TypeId::of::<M>();
|
||||||
|
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::<TypeId, Arc<RwLock<dyn Pipeline>>>::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::<Vec<_>>();
|
||||||
|
|
||||||
|
{
|
||||||
|
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::<TypeId, Arc<RwLock<dyn Material>>>::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
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod material_manager;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
pub mod render_pass_manager;
|
pub mod render_pass_manager;
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue