Add pipeline loader
This commit is contained in:
parent
8b982ba089
commit
6099a3e27f
5 changed files with 179 additions and 53 deletions
|
@ -1,2 +1,3 @@
|
||||||
pub mod meshes;
|
pub mod meshes;
|
||||||
|
pub mod pipeline;
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
|
|
112
src/core/render/resources/pipeline/loader.rs
Normal file
112
src/core/render/resources/pipeline/loader.rs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
collections::HashMap,
|
||||||
|
error::Error,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
|
use vulkano::{device::Device, format::Format, pipeline::GraphicsPipeline};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub enum PipelineState {
|
||||||
|
NeedBuild,
|
||||||
|
Loaded,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type GraphicsPipelineLoadFn =
|
||||||
|
fn(&Arc<Device>, Format, Format) -> Result<Arc<GraphicsPipeline>, Box<dyn Error>>;
|
||||||
|
|
||||||
|
pub struct PipelineLoader {
|
||||||
|
device: Arc<Device>,
|
||||||
|
swapchain_image_format: Format,
|
||||||
|
depth_image_format: Format,
|
||||||
|
|
||||||
|
// Arc<GraphicsPipeline> is used in internal of vulkano. It's not possible to use Arc<RwLock<Option<GraphicsPipeline>>> directly.
|
||||||
|
pipelines_index: HashMap<TypeId, usize>,
|
||||||
|
pipelines_id: Vec<TypeId>,
|
||||||
|
pipelines_load_fn: Vec<GraphicsPipelineLoadFn>,
|
||||||
|
// Only content is protected by Arc and RwLock to avoid push in pipeline_loader in multiple threads and just allow to lock each pipeline when is needed as parallel pipelines loading.
|
||||||
|
// But only the pipeline loader is allowed to load a pipeline when it's needed.
|
||||||
|
pipelines: Vec<Arc<RwLock<Option<Arc<GraphicsPipeline>>>>>,
|
||||||
|
pipelines_state: Vec<Arc<RwLock<PipelineState>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PipelineLoader {
|
||||||
|
pub fn new(
|
||||||
|
device: Arc<Device>,
|
||||||
|
swapchain_image_format: Format,
|
||||||
|
depth_image_format: Format,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
device,
|
||||||
|
swapchain_image_format,
|
||||||
|
depth_image_format,
|
||||||
|
pipelines: Vec::new(),
|
||||||
|
pipelines_load_fn: Vec::new(),
|
||||||
|
pipelines_id: Vec::new(),
|
||||||
|
pipelines_state: Vec::new(),
|
||||||
|
pipelines_index: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register<T: 'static>(
|
||||||
|
&mut self,
|
||||||
|
load_fn: GraphicsPipelineLoadFn,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
let id = TypeId::of::<T>();
|
||||||
|
self.pipelines_index.insert(id, self.pipelines.len());
|
||||||
|
self.pipelines_id.push(id);
|
||||||
|
self.pipelines_load_fn.push(load_fn);
|
||||||
|
self.pipelines_state
|
||||||
|
.push(Arc::new(RwLock::new(PipelineState::NeedBuild)));
|
||||||
|
self.pipelines.push(Arc::new(RwLock::new(None)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_pipelines(&self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let iter = self
|
||||||
|
.pipelines_id
|
||||||
|
.iter()
|
||||||
|
.zip(self.pipelines.iter())
|
||||||
|
.zip(self.pipelines_load_fn.iter())
|
||||||
|
.zip(self.pipelines_state.iter())
|
||||||
|
.filter(|(_, state)| {
|
||||||
|
let state = state.read().unwrap();
|
||||||
|
*state == PipelineState::NeedBuild
|
||||||
|
});
|
||||||
|
|
||||||
|
for (((id, pipeline), load_fn), state) in iter {
|
||||||
|
let new_pipeline = load_fn(
|
||||||
|
&self.device,
|
||||||
|
self.swapchain_image_format,
|
||||||
|
self.depth_image_format,
|
||||||
|
)?;
|
||||||
|
let mut pipeline = pipeline.write().unwrap();
|
||||||
|
*pipeline = Some(new_pipeline);
|
||||||
|
let mut state = state.write().unwrap();
|
||||||
|
*state = PipelineState::Loaded;
|
||||||
|
tracing::trace!("Pipeline {id:?} loaded");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_pipelines_as_need_build(&mut self) {
|
||||||
|
for state in self.pipelines_state.iter() {
|
||||||
|
let mut state = state.write().unwrap();
|
||||||
|
*state = PipelineState::NeedBuild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_pipeline<T: 'static, F>(&self, f: F) -> Result<(), Box<dyn Error>>
|
||||||
|
where
|
||||||
|
F: FnOnce(&Arc<GraphicsPipeline>) -> Result<(), Box<dyn Error>>,
|
||||||
|
{
|
||||||
|
let id = TypeId::of::<T>();
|
||||||
|
let index = self.pipelines_index.get(&id).ok_or("Pipeline not found")?;
|
||||||
|
let pipeline_locker = self.pipelines[*index]
|
||||||
|
.read()
|
||||||
|
.map_err(|_| "Failed to lock pipeline")?;
|
||||||
|
let pipeline = pipeline_locker.as_ref().ok_or("Pipeline not loaded")?;
|
||||||
|
f(pipeline)
|
||||||
|
}
|
||||||
|
}
|
2
src/core/render/resources/pipeline/mod.rs
Normal file
2
src/core/render/resources/pipeline/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
mod loader;
|
||||||
|
pub use loader::{GraphicsPipelineLoadFn, PipelineLoader};
|
|
@ -1,4 +1,7 @@
|
||||||
use std::{error::Error, sync::Arc};
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer},
|
command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer},
|
||||||
|
@ -33,16 +36,14 @@ use crate::core::render::{
|
||||||
resources::texture::Texture,
|
resources::texture::Texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SimplePipeline {
|
pub struct SimplePipeline;
|
||||||
pipeline: Arc<GraphicsPipeline>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SimplePipeline {
|
impl SimplePipeline {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &Arc<Device>,
|
device: &Arc<Device>,
|
||||||
swapchain_format: Format,
|
swapchain_format: Format,
|
||||||
depth_format: Format,
|
depth_format: Format,
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> Result<Arc<GraphicsPipeline>, Box<dyn Error>> {
|
||||||
let vs = shaders::vs::load(device.clone())?
|
let vs = shaders::vs::load(device.clone())?
|
||||||
.entry_point("main")
|
.entry_point("main")
|
||||||
.ok_or("Failed find main entry point of vertex shader".to_string())?;
|
.ok_or("Failed find main entry point of vertex shader".to_string())?;
|
||||||
|
@ -111,11 +112,7 @@ impl SimplePipeline {
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Self { pipeline })
|
Ok(pipeline)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pipeline(&self) -> &Arc<GraphicsPipeline> {
|
|
||||||
&self.pipeline
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::core::render::primitives::transform::Transform;
|
||||||
use crate::core::render::primitives::{AsDescriptorSet, AsRecordable};
|
use crate::core::render::primitives::{AsDescriptorSet, AsRecordable};
|
||||||
use crate::core::render::render_pass_manager::{RenderPassConfig, RenderPassManager};
|
use crate::core::render::render_pass_manager::{RenderPassConfig, RenderPassManager};
|
||||||
use crate::core::render::resources::meshes::{ObjMesh, SquareMesh};
|
use crate::core::render::resources::meshes::{ObjMesh, SquareMesh};
|
||||||
|
use crate::core::render::resources::pipeline::PipelineLoader;
|
||||||
use crate::core::render::resources::texture::{TextureLoadInfo, TextureLoader, TextureSourceKind};
|
use crate::core::render::resources::texture::{TextureLoadInfo, TextureLoader, TextureSourceKind};
|
||||||
use crate::core::scene::Scene;
|
use crate::core::scene::Scene;
|
||||||
use crate::game::assets::pipelines::simple::SimplePipeline;
|
use crate::game::assets::pipelines::simple::SimplePipeline;
|
||||||
|
@ -28,9 +29,9 @@ use winit::window::CursorGrabMode;
|
||||||
|
|
||||||
pub struct MainSceneState {
|
pub struct MainSceneState {
|
||||||
texture_loader: TextureLoader,
|
texture_loader: TextureLoader,
|
||||||
|
pipeline_loader: PipelineLoader,
|
||||||
square: SquareMesh,
|
square: SquareMesh,
|
||||||
obj: ObjMesh,
|
obj: ObjMesh,
|
||||||
simple_pipeline: SimplePipeline,
|
|
||||||
square_instances: Vec<Transform>,
|
square_instances: Vec<Transform>,
|
||||||
obj_instances: Vec<Transform>,
|
obj_instances: Vec<Transform>,
|
||||||
camera: Camera3D,
|
camera: Camera3D,
|
||||||
|
@ -55,6 +56,14 @@ impl Scene for MainScene {
|
||||||
let swapchain_image_view =
|
let swapchain_image_view =
|
||||||
app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone());
|
app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone());
|
||||||
|
|
||||||
|
let mut pipeline_loader = PipelineLoader::new(
|
||||||
|
app_context.device.clone(),
|
||||||
|
swapchain_image_view.format(),
|
||||||
|
depth_image_view.format(),
|
||||||
|
);
|
||||||
|
pipeline_loader.register::<SimplePipeline>(SimplePipeline::new)?;
|
||||||
|
pipeline_loader.load_pipelines()?;
|
||||||
|
|
||||||
let mut texture_loader = TextureLoader::new(app_context);
|
let mut texture_loader = TextureLoader::new(app_context);
|
||||||
texture_loader.add_texture(
|
texture_loader.add_texture(
|
||||||
"wooden-crate".to_string(),
|
"wooden-crate".to_string(),
|
||||||
|
@ -90,11 +99,6 @@ impl Scene for MainScene {
|
||||||
let obj = ObjMesh::new(&app_context.memory_allocator, "res/objects/cube.obj")?;
|
let obj = ObjMesh::new(&app_context.memory_allocator, "res/objects/cube.obj")?;
|
||||||
obj.into_iter().next().unwrap()
|
obj.into_iter().next().unwrap()
|
||||||
};
|
};
|
||||||
let simple_pipeline = SimplePipeline::new(
|
|
||||||
&app_context.device,
|
|
||||||
swapchain_image_view.format(),
|
|
||||||
depth_image_view.format(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let num_instances = 100;
|
let num_instances = 100;
|
||||||
let instance_size = 10.0;
|
let instance_size = 10.0;
|
||||||
|
@ -147,7 +151,7 @@ impl Scene for MainScene {
|
||||||
self.state = Some(MainSceneState {
|
self.state = Some(MainSceneState {
|
||||||
square,
|
square,
|
||||||
obj,
|
obj,
|
||||||
simple_pipeline,
|
pipeline_loader,
|
||||||
square_instances,
|
square_instances,
|
||||||
obj_instances,
|
obj_instances,
|
||||||
camera,
|
camera,
|
||||||
|
@ -256,43 +260,53 @@ impl Scene for MainScene {
|
||||||
let obj_transform_uniform =
|
let obj_transform_uniform =
|
||||||
Transform::create_buffer(&app_context.memory_allocator, &state.obj_instances)?;
|
Transform::create_buffer(&app_context.memory_allocator, &state.obj_instances)?;
|
||||||
|
|
||||||
SimplePipeline::record_bind_commands(
|
state
|
||||||
&mut builder,
|
.pipeline_loader
|
||||||
&app_context.descriptor_set_allocator,
|
.with_pipeline::<SimplePipeline, _>(|pipeline| {
|
||||||
state.simple_pipeline.pipeline(),
|
SimplePipeline::record_bind_commands(
|
||||||
&state.square,
|
&mut builder,
|
||||||
&square_transform_uniform,
|
&app_context.descriptor_set_allocator,
|
||||||
vec![
|
pipeline,
|
||||||
camera_uniform.clone() as Arc<dyn AsDescriptorSet>,
|
&state.square,
|
||||||
state
|
&square_transform_uniform,
|
||||||
.texture_loader
|
vec![
|
||||||
.get_texture("wooden-crate")
|
camera_uniform.clone() as Arc<dyn AsDescriptorSet>,
|
||||||
.unwrap()
|
state
|
||||||
.clone(),
|
.texture_loader
|
||||||
],
|
.get_texture("wooden-crate")
|
||||||
)?;
|
.unwrap()
|
||||||
SimplePipeline::record_draw_commands(
|
.clone(),
|
||||||
&mut builder,
|
],
|
||||||
&state.square,
|
)?;
|
||||||
&square_transform_uniform,
|
SimplePipeline::record_draw_commands(
|
||||||
)?;
|
&mut builder,
|
||||||
|
&state.square,
|
||||||
|
&square_transform_uniform,
|
||||||
|
)?;
|
||||||
|
|
||||||
SimplePipeline::record_bind_commands(
|
SimplePipeline::record_bind_commands(
|
||||||
&mut builder,
|
&mut builder,
|
||||||
&app_context.descriptor_set_allocator,
|
&app_context.descriptor_set_allocator,
|
||||||
state.simple_pipeline.pipeline(),
|
pipeline,
|
||||||
&state.obj,
|
&state.obj,
|
||||||
&obj_transform_uniform,
|
&obj_transform_uniform,
|
||||||
vec![
|
vec![
|
||||||
camera_uniform.clone() as Arc<dyn AsDescriptorSet>,
|
camera_uniform.clone() as Arc<dyn AsDescriptorSet>,
|
||||||
state
|
state
|
||||||
.texture_loader
|
.texture_loader
|
||||||
.get_texture("cube-diffuse")
|
.get_texture("cube-diffuse")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone(),
|
.clone(),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
SimplePipeline::record_draw_commands(&mut builder, &state.obj, &obj_transform_uniform)?;
|
SimplePipeline::record_draw_commands(
|
||||||
|
&mut builder,
|
||||||
|
&state.obj,
|
||||||
|
&obj_transform_uniform,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
RenderPassManager::end_rendering(&mut builder)?;
|
RenderPassManager::end_rendering(&mut builder)?;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue