only update pipelines when macros change. better handle debug print
This commit is contained in:
parent
26588d0c41
commit
56e5414b63
@ -1,4 +1,5 @@
|
|||||||
use bevy::{prelude::*, render::render_graph_2::StandardMaterial};
|
use core::marker::PhantomData;
|
||||||
|
use bevy::{prelude::*, render::render_graph_2::{Renderable, StandardMaterial}};
|
||||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
@ -83,9 +84,15 @@ fn setup(world: &mut World) {
|
|||||||
mesh: cube_handle.clone(),
|
mesh: cube_handle.clone(),
|
||||||
material: StandardMaterial {
|
material: StandardMaterial {
|
||||||
albedo: math::vec4(1.0, 0.0, 0.0, 1.0),
|
albedo: math::vec4(1.0, 0.0, 0.0, 1.0),
|
||||||
everything_is_red: false,
|
everything_is_red: true,
|
||||||
},
|
},
|
||||||
translation: Translation::new(0.0, 0.0, 1.0),
|
translation: Translation::new(0.0, 0.0, 1.0),
|
||||||
|
renderable: Renderable {
|
||||||
|
pipelines: vec![
|
||||||
|
Handle::new(0), // Forward Pipeline Handle
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.add_archetype(NewMeshEntity {
|
.add_archetype(NewMeshEntity {
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
passes::*,
|
passes::*,
|
||||||
render_graph_2::{
|
render_graph_2::{
|
||||||
passes::*, pipelines::*, renderers::wgpu_renderer::WgpuRenderer, resource_providers::*,
|
passes::*, pipelines::*, renderers::wgpu_renderer::WgpuRenderer, resource_providers::*,
|
||||||
ShaderAssignments, StandardMaterial,
|
ShaderPipelineAssignments, StandardMaterial,
|
||||||
},
|
},
|
||||||
*,
|
*,
|
||||||
},
|
},
|
||||||
@ -16,7 +16,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
|
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
|
||||||
use render_graph_2::{CompiledShaderMap, PipelineDescriptor, resource_name, draw_targets::{ui_draw_target, mesh_draw_target}};
|
use render_graph_2::{CompiledShaderMap, PipelineDescriptor, resource_name, draw_targets::{ui_draw_target, meshes_draw_target}};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct AppBuilder {
|
pub struct AppBuilder {
|
||||||
@ -167,7 +167,7 @@ impl AppBuilder {
|
|||||||
resources.insert(AssetStorage::<Texture>::new());
|
resources.insert(AssetStorage::<Texture>::new());
|
||||||
resources.insert(AssetStorage::<Shader>::new());
|
resources.insert(AssetStorage::<Shader>::new());
|
||||||
resources.insert(AssetStorage::<PipelineDescriptor>::new());
|
resources.insert(AssetStorage::<PipelineDescriptor>::new());
|
||||||
resources.insert(ShaderAssignments::new());
|
resources.insert(ShaderPipelineAssignments::new());
|
||||||
resources.insert(CompiledShaderMap::new());
|
resources.insert(CompiledShaderMap::new());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ impl AppBuilder {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
self.render_graph_builder = self
|
self.render_graph_builder = self
|
||||||
.render_graph_builder
|
.render_graph_builder
|
||||||
.add_draw_target(resource_name::draw_target::MESHES, mesh_draw_target)
|
.add_draw_target(resource_name::draw_target::MESHES, meshes_draw_target)
|
||||||
.add_draw_target(resource_name::draw_target::UI, ui_draw_target)
|
.add_draw_target(resource_name::draw_target::UI, ui_draw_target)
|
||||||
.add_resource_provider(Box::new(CameraResourceProvider))
|
.add_resource_provider(Box::new(CameraResourceProvider))
|
||||||
.add_resource_provider(Box::new(Camera2dResourceProvider))
|
.add_resource_provider(Box::new(Camera2dResourceProvider))
|
||||||
|
@ -3,18 +3,29 @@ mod mesh;
|
|||||||
mod texture;
|
mod texture;
|
||||||
|
|
||||||
pub use self::gltf::load_gltf;
|
pub use self::gltf::load_gltf;
|
||||||
use std::hash::{Hash, Hasher};
|
|
||||||
pub use mesh::*;
|
pub use mesh::*;
|
||||||
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
};
|
||||||
pub use texture::*;
|
pub use texture::*;
|
||||||
|
|
||||||
use std::{collections::HashMap, marker::PhantomData};
|
use std::{collections::HashMap, marker::PhantomData};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Handle<T> {
|
pub struct Handle<T> {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
marker: PhantomData<T>,
|
marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Handle<T> {
|
||||||
|
pub fn new(id: usize) -> Self {
|
||||||
|
Handle {
|
||||||
|
id,
|
||||||
|
marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Hash for Handle<T> {
|
impl<T> Hash for Handle<T> {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.id.hash(state);
|
self.id.hash(state);
|
||||||
@ -29,6 +40,13 @@ impl<T> PartialEq for Handle<T> {
|
|||||||
|
|
||||||
impl<T> Eq for Handle<T> {}
|
impl<T> Eq for Handle<T> {}
|
||||||
|
|
||||||
|
impl<T> Debug for Handle<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||||
|
let name = std::any::type_name::<T>().split("::").last().unwrap();
|
||||||
|
write!(f, "Handle<{}>({})", name, self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: somehow handle this gracefully in asset managers. or alternatively remove Default
|
// TODO: somehow handle this gracefully in asset managers. or alternatively remove Default
|
||||||
impl<T> Default for Handle<T> {
|
impl<T> Default for Handle<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
|
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
|
|
||||||
pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
|
pub fn meshes_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
|
||||||
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||||
let mut current_mesh_id = None;
|
let mut current_mesh_id = None;
|
||||||
let mut current_mesh_index_length = 0;
|
let mut current_mesh_index_length = 0;
|
@ -1,5 +1,5 @@
|
|||||||
mod mesh_draw_target;
|
mod meshes_draw_target;
|
||||||
mod ui_draw_target;
|
mod ui_draw_target;
|
||||||
|
|
||||||
pub use mesh_draw_target::*;
|
pub use meshes_draw_target::*;
|
||||||
pub use ui_draw_target::*;
|
pub use ui_draw_target::*;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
asset::{AssetStorage, Handle},
|
asset::{AssetStorage, Handle},
|
||||||
render::{render_graph_2::RenderGraph, Shader, ShaderStages},
|
render::{render_graph_2::RenderGraph, Shader, ShaderStages, ShaderSource},
|
||||||
};
|
};
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@ -25,40 +25,31 @@ impl Default for Renderable {
|
|||||||
pub struct CompiledShaderMap {
|
pub struct CompiledShaderMap {
|
||||||
// TODO: need macro hash lookup
|
// TODO: need macro hash lookup
|
||||||
pub source_to_compiled: HashMap<Handle<Shader>, Vec<(HashSet<String>, Handle<Shader>)>>,
|
pub source_to_compiled: HashMap<Handle<Shader>, Vec<(HashSet<String>, Handle<Shader>)>>,
|
||||||
|
pub pipeline_to_macro_pipelines: HashMap<Handle<PipelineDescriptor>, Vec<(HashSet<String>, Handle<PipelineDescriptor>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompiledShaderMap {
|
impl CompiledShaderMap {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
CompiledShaderMap {
|
CompiledShaderMap {
|
||||||
source_to_compiled: HashMap::new(),
|
source_to_compiled: HashMap::new(),
|
||||||
|
pipeline_to_macro_pipelines: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ShaderAssignments {
|
pub struct ShaderPipelineAssignments {
|
||||||
pub assignments: HashMap<usize, Vec<Entity>>,
|
pub assignments: HashMap<Handle<PipelineDescriptor>, Vec<Entity>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShaderAssignments {
|
impl ShaderPipelineAssignments {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ShaderAssignments {
|
ShaderPipelineAssignments {
|
||||||
assignments: HashMap::new(),
|
assignments: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGraph) {
|
fn try_compiling_shader_with_macros(compiled_shader_map: &mut CompiledShaderMap, shader_storage: &mut AssetStorage<Shader>, renderable: &Renderable, shader_handle: &Handle<Shader>) -> Option<Handle<Shader>> {
|
||||||
// PERF: this seems like a lot of work for things that don't change that often.
|
|
||||||
// lots of string + hashset allocations. sees uniform_resource_provider for more context
|
|
||||||
{
|
|
||||||
let shader_assignments = world.resources.get_mut::<ShaderAssignments>().unwrap();
|
|
||||||
let mut compiled_shader_map = world.resources.get_mut::<CompiledShaderMap>().unwrap();
|
|
||||||
let mut shader_storage = world.resources.get_mut::<AssetStorage<Shader>>().unwrap();
|
|
||||||
let pipeline_descriptor_storage = world.resources.get_mut::<AssetStorage<PipelineDescriptor>>().unwrap();
|
|
||||||
for (entity, renderable) in <Read<Renderable>>::query().iter_entities(world) {
|
|
||||||
for pipeline_handle in renderable.pipelines.iter() {
|
|
||||||
let pipeline_descriptor = pipeline_descriptor_storage.get(pipeline_handle).unwrap();
|
|
||||||
for shader_handle in pipeline_descriptor.shader_stages.iter() {
|
|
||||||
if let None = compiled_shader_map.source_to_compiled.get(shader_handle) {
|
if let None = compiled_shader_map.source_to_compiled.get(shader_handle) {
|
||||||
compiled_shader_map
|
compiled_shader_map
|
||||||
.source_to_compiled
|
.source_to_compiled
|
||||||
@ -66,17 +57,82 @@ pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGra
|
|||||||
}
|
}
|
||||||
|
|
||||||
let compiled_shaders = compiled_shader_map.source_to_compiled.get_mut(shader_handle).unwrap();
|
let compiled_shaders = compiled_shader_map.source_to_compiled.get_mut(shader_handle).unwrap();
|
||||||
if let None = compiled_shaders.iter().find(|(shader_defs, _shader)| *shader_defs == renderable.shader_defs) {
|
let shader = shader_storage.get(shader_handle).unwrap();
|
||||||
let shader_resource = shader_storage.get(shader_handle).unwrap();
|
|
||||||
|
// don't produce new shader if the input source is already spriv
|
||||||
|
if let ShaderSource::Spirv(_) = shader.source {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_shader_defs, compiled_shader)) = compiled_shaders.iter().find(|(shader_defs, _shader)| *shader_defs == renderable.shader_defs) {
|
||||||
|
Some(compiled_shader.clone())
|
||||||
|
} else {
|
||||||
let shader_def_vec = renderable.shader_defs.iter().cloned().collect::<Vec<String>>();
|
let shader_def_vec = renderable.shader_defs.iter().cloned().collect::<Vec<String>>();
|
||||||
let compiled_shader = shader_resource.get_spirv_shader(Some(&shader_def_vec));
|
let compiled_shader = shader.get_spirv_shader(Some(&shader_def_vec));
|
||||||
compiled_shaders.push((renderable.shader_defs.clone(), shader_handle.clone()));
|
compiled_shaders.push((renderable.shader_defs.clone(), shader_handle.clone()));
|
||||||
let compiled_shader_handle = shader_storage.add(compiled_shader);
|
let compiled_shader_handle = shader_storage.add(compiled_shader);
|
||||||
|
Some(compiled_shader_handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGraph) {
|
||||||
|
// PERF: this seems like a lot of work for things that don't change that often.
|
||||||
|
// lots of string + hashset allocations. sees uniform_resource_provider for more context
|
||||||
|
{
|
||||||
|
let mut shader_pipeline_assignments = world.resources.get_mut::<ShaderPipelineAssignments>().unwrap();
|
||||||
|
let mut compiled_shader_map = world.resources.get_mut::<CompiledShaderMap>().unwrap();
|
||||||
|
let mut shader_storage = world.resources.get_mut::<AssetStorage<Shader>>().unwrap();
|
||||||
|
let mut pipeline_descriptor_storage = world.resources.get_mut::<AssetStorage<PipelineDescriptor>>().unwrap();
|
||||||
|
|
||||||
|
// reset assignments so they are updated every frame
|
||||||
|
shader_pipeline_assignments.assignments = HashMap::new();
|
||||||
|
|
||||||
|
for (entity, renderable) in <Read<Renderable>>::query().iter_entities(world) {
|
||||||
|
for pipeline_handle in renderable.pipelines.iter() {
|
||||||
|
if let None = compiled_shader_map.pipeline_to_macro_pipelines.get(pipeline_handle) {
|
||||||
|
compiled_shader_map
|
||||||
|
.pipeline_to_macro_pipelines
|
||||||
|
.insert(pipeline_handle.clone(), Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let final_handle = if let Some((_shader_defs, macroed_pipeline_handle)) = compiled_shader_map.pipeline_to_macro_pipelines.get_mut(pipeline_handle).unwrap().iter().find(|(shader_defs, _macroed_pipeline_handle)| *shader_defs == renderable.shader_defs) {
|
||||||
|
macroed_pipeline_handle.clone()
|
||||||
|
} else {
|
||||||
|
println!("Create pipeline {:?} {:?}", pipeline_handle, renderable.shader_defs);
|
||||||
|
let pipeline_descriptor = pipeline_descriptor_storage.get(pipeline_handle).unwrap();
|
||||||
|
let macroed_pipeline_handle = {
|
||||||
|
let mut macroed_vertex_handle = try_compiling_shader_with_macros(&mut compiled_shader_map, &mut shader_storage, &renderable, &pipeline_descriptor.shader_stages.vertex);
|
||||||
|
let mut macroed_fragment_handle = pipeline_descriptor.shader_stages.fragment.as_ref().map(|fragment| try_compiling_shader_with_macros(&mut compiled_shader_map, &mut shader_storage, &renderable, fragment));
|
||||||
|
|
||||||
|
if macroed_vertex_handle.is_some() || macroed_fragment_handle.is_some() {
|
||||||
|
let mut macroed_pipeline = pipeline_descriptor.clone();
|
||||||
|
if let Some(vertex) = macroed_vertex_handle.take() {
|
||||||
|
macroed_pipeline.shader_stages.vertex = vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(fragment) = macroed_fragment_handle.take() {
|
||||||
|
macroed_pipeline.shader_stages.fragment = fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline_descriptor_storage.add(macroed_pipeline)
|
||||||
|
} else {
|
||||||
|
pipeline_handle.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let macro_pipelines = compiled_shader_map.pipeline_to_macro_pipelines.get_mut(pipeline_handle).unwrap();
|
||||||
|
macro_pipelines.push((renderable.shader_defs.clone(), macroed_pipeline_handle.clone()));
|
||||||
|
macroed_pipeline_handle
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: collecting assigments in a map means they won't be removed when the macro changes
|
// TODO: collecting assigments in a map means they won't be removed when the macro changes
|
||||||
// TODO: need to somehow grab base shader's pipeline, then copy it
|
// TODO: this will break down if pipeline layout changes. fix this with "autolayout"
|
||||||
// shader_assignments.assignments.insert()
|
if let None = shader_pipeline_assignments.assignments.get(&final_handle) {
|
||||||
}
|
shader_pipeline_assignments.assignments.insert(final_handle.clone(), Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let assignments = shader_pipeline_assignments.assignments.get_mut(&final_handle).unwrap();
|
||||||
|
assignments.push(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ impl GetBytes for Vec4 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: add ability to specify specific pipeline for uniforms
|
||||||
pub trait AsUniforms {
|
pub trait AsUniforms {
|
||||||
fn get_uniform_infos(&self) -> &[UniformInfo];
|
fn get_uniform_infos(&self) -> &[UniformInfo];
|
||||||
fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo>;
|
fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo>;
|
||||||
|
@ -96,33 +96,4 @@ impl ShaderStages {
|
|||||||
fragment: None,
|
fragment: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> ShaderStagesIter {
|
|
||||||
ShaderStagesIter {
|
|
||||||
shader_stages: self,
|
|
||||||
index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ShaderStagesIter<'a> {
|
|
||||||
pub shader_stages: &'a ShaderStages,
|
|
||||||
pub index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for ShaderStagesIter<'a> {
|
|
||||||
type Item = &'a Handle<Shader>;
|
|
||||||
fn next(&mut self) -> Option<&'a Handle<Shader>> {
|
|
||||||
match self.index {
|
|
||||||
0 => Some(&self.shader_stages.vertex),
|
|
||||||
1 => {
|
|
||||||
if let Some(ref fragment) = self.shader_stages.fragment {
|
|
||||||
Some(fragment)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user