add assigned meshes render target

dynamic compiling w/ entity-specifc macros works!
This commit is contained in:
Carter Anderson 2020-02-15 22:17:24 -08:00
parent 56e5414b63
commit c208945833
13 changed files with 121 additions and 28 deletions

View file

@ -24,7 +24,7 @@ fn setup(world: &mut World) {
},
..Default::default()
})
// cube
// tan cube
.add_archetype(NewMeshEntity {
mesh: cube_handle.clone(),
material: StandardMaterial {
@ -34,6 +34,16 @@ fn setup(world: &mut World) {
translation: Translation::new(0.0, 0.0, 1.0),
..Default::default()
})
// red cube
.add_archetype(NewMeshEntity {
mesh: cube_handle.clone(),
material: StandardMaterial {
albedo: math::vec4(0.5, 0.4, 0.3, 1.0),
everything_is_red: true,
},
translation: Translation::new(3.0, 0.0, 1.0),
..Default::default()
})
// light
.add_archetype(LightEntity {
light: Light {

View file

@ -1,5 +1,4 @@
use core::marker::PhantomData;
use bevy::{prelude::*, render::render_graph_2::{Renderable, StandardMaterial}};
use bevy::{prelude::*, render::render_graph_2::StandardMaterial};
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::VecDeque;
@ -83,23 +82,17 @@ fn setup(world: &mut World) {
.add_archetype(NewMeshEntity {
mesh: cube_handle.clone(),
material: StandardMaterial {
albedo: math::vec4(1.0, 0.0, 0.0, 1.0),
everything_is_red: true,
albedo: math::vec4(1.0, 1.0, 1.0, 1.0),
everything_is_red: false,
},
translation: Translation::new(0.0, 0.0, 1.0),
renderable: Renderable {
pipelines: vec![
Handle::new(0), // Forward Pipeline Handle
],
..Default::default()
},
..Default::default()
})
.add_archetype(NewMeshEntity {
mesh: cube_handle.clone(),
material: StandardMaterial {
albedo: math::vec4(0.0, 1.0, 0.0, 1.0),
everything_is_red: false,
everything_is_red: true,
},
translation: Translation::new(-2.0, 0.0, 1.0),
..Default::default()

View file

@ -16,7 +16,7 @@ use crate::{
};
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
use render_graph_2::{CompiledShaderMap, PipelineDescriptor, resource_name, draw_targets::{ui_draw_target, meshes_draw_target}};
use render_graph_2::{CompiledShaderMap, PipelineDescriptor, resource_name, draw_targets::{ui_draw_target, meshes_draw_target, assigned_meshes_draw_target}};
use std::collections::HashMap;
pub struct AppBuilder {
@ -196,6 +196,7 @@ impl AppBuilder {
self.render_graph_builder = self
.render_graph_builder
.add_draw_target(resource_name::draw_target::MESHES, meshes_draw_target)
.add_draw_target(resource_name::draw_target::ASSIGNED_MESHES, assigned_meshes_draw_target)
.add_draw_target(resource_name::draw_target::UI, ui_draw_target)
.add_resource_provider(Box::new(CameraResourceProvider))
.add_resource_provider(Box::new(Camera2dResourceProvider))

View file

@ -1,7 +1,11 @@
use crate::render::render_graph_2::RenderPass;
use crate::{asset::Handle, render::render_graph_2::{pipeline::PipelineDescriptor, RenderPass}};
use legion::prelude::World;
// A set of draw calls. ex: get + draw meshes, get + draw instanced meshes, draw ui meshes, etc
// TODO: consider swapping out dyn RenderPass for explicit WgpuRenderPass type to avoid dynamic dispatch
pub type DrawTarget = fn(world: &World, render_pass: &mut dyn RenderPass);
pub type DrawTarget = fn(
world: &World,
render_pass: &mut dyn RenderPass,
pipeline_handle: Handle<PipelineDescriptor>,
);

View file

@ -0,0 +1,79 @@
use crate::{
asset::{AssetStorage, Handle, Mesh},
legion::prelude::*,
render::{
render_graph_2::{resource_name, RenderPass, Renderable, PipelineDescriptor, ShaderPipelineAssignments},
},
};
use zerocopy::AsBytes;
pub fn assigned_meshes_draw_target(
world: &World,
render_pass: &mut dyn RenderPass,
pipeline_handle: Handle<PipelineDescriptor>,
) {
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let shader_pipeline_assignments = world
.resources
.get_mut::<ShaderPipelineAssignments>()
.unwrap();
let mut current_mesh_id = None;
let mut current_mesh_index_length = 0;
let assigned_entities = shader_pipeline_assignments
.assignments
.get(&pipeline_handle);
if let Some(assigned_entities) = assigned_entities {
for entity in assigned_entities.iter() {
// TODO: hopefully legion has better random access apis that are more like queries?
let renderable = world.get_component::<Renderable>(*entity).unwrap();
let mesh = world.get_component::<Handle<Mesh>>(*entity).unwrap();
if !renderable.is_visible {
continue;
}
let mut should_load_mesh = current_mesh_id == None;
if let Some(current) = current_mesh_id {
should_load_mesh = current != mesh.id;
}
if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get_id(mesh.id) {
let renderer = render_pass.get_renderer();
renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
mesh_asset.vertices.as_bytes(),
wgpu::BufferUsage::VERTEX,
);
renderer.create_buffer_with_data(
resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME,
mesh_asset.indices.as_bytes(),
wgpu::BufferUsage::INDEX,
);
// TODO: Verify buffer format matches render pass
render_pass
.set_index_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME, 0);
render_pass.set_vertex_buffer(
0,
resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME,
0,
);
current_mesh_id = Some(mesh.id);
current_mesh_index_length = mesh_asset.indices.len() as u32;
};
}
// TODO: validate bind group properties against shader uniform properties at least once
render_pass.setup_bind_groups(Some(&entity));
render_pass.draw_indexed(0..current_mesh_index_length, 0, 0..1);
}
// cleanup buffers
let renderer = render_pass.get_renderer();
renderer.remove_buffer(resource_name::buffer::TEMP_MESH_VERTEX_BUFFER_NAME);
renderer.remove_buffer(resource_name::buffer::TEMP_MESH_INDEX_BUFFER_NAME);
}
}

View file

@ -2,14 +2,14 @@ use crate::{
asset::{AssetStorage, Handle, Mesh},
legion::prelude::*,
render::{
render_graph_2::{resource_name, RenderPass, Renderable, ShaderUniforms},
render_graph_2::{resource_name, RenderPass, Renderable, ShaderUniforms, PipelineDescriptor},
Instanced,
},
};
use zerocopy::AsBytes;
pub fn meshes_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
pub fn meshes_draw_target(world: &World, render_pass: &mut dyn RenderPass, _pipeline_handle: Handle<PipelineDescriptor>) {
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let mut current_mesh_id = None;
let mut current_mesh_index_length = 0;

View file

@ -1,5 +1,7 @@
mod meshes_draw_target;
mod assigned_meshes_draw_target;
mod ui_draw_target;
pub use meshes_draw_target::*;
pub use assigned_meshes_draw_target::*;
pub use ui_draw_target::*;

View file

@ -1,12 +1,12 @@
use crate::{
asset::{AssetStorage, Mesh},
asset::{AssetStorage, Mesh, Handle},
legion::prelude::*,
render::render_graph_2::{resource_name, RenderPass, ResourceInfo},
render::render_graph_2::{resource_name, RenderPass, ResourceInfo, PipelineDescriptor},
};
use zerocopy::AsBytes;
pub fn ui_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
pub fn ui_draw_target(world: &World, render_pass: &mut dyn RenderPass, _pipeline_handle: Handle<PipelineDescriptor>) {
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
// NOTE: this is ugly and borrowing is stupid
let result = {

View file

@ -1,5 +1,5 @@
use crate::{asset::{AssetStorage, Handle}, render::{
render_graph_2::{BindGroup, DrawTarget, PipelineLayout},
render_graph_2::{BindGroup, PipelineLayout},
shader::{Shader, ShaderStages},
}};

View file

@ -101,7 +101,7 @@ impl ForwardPipelineBuilder for RenderGraphBuilder {
write_mask: wgpu::ColorWrite::ALL,
})
.add_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor())
.add_draw_target(resource_name::draw_target::MESHES)
.add_draw_target(resource_name::draw_target::ASSIGNED_MESHES)
.build(),
)
}

View file

@ -1,6 +1,6 @@
use crate::{
asset::{AssetStorage, Handle},
render::{render_graph_2::RenderGraph, Shader, ShaderStages, ShaderSource},
render::{render_graph_2::RenderGraph, Shader, ShaderSource},
};
use legion::prelude::*;
use std::collections::{HashMap, HashSet};
@ -16,7 +16,9 @@ impl Default for Renderable {
fn default() -> Self {
Renderable {
is_visible: true,
pipelines: Vec::new(),
pipelines: vec![
Handle::new(0), // TODO: this could be better
],
shader_defs: HashSet::new(),
}
}
@ -98,7 +100,6 @@ pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGra
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);
@ -114,7 +115,10 @@ pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGra
macroed_pipeline.shader_stages.fragment = fragment;
}
pipeline_descriptor_storage.add(macroed_pipeline)
let macroed_pipeline_handle = pipeline_descriptor_storage.add(macroed_pipeline);
// TODO: get correct pass name
render_graph.add_pipeline("main", macroed_pipeline_handle.clone());
macroed_pipeline_handle
} else {
pipeline_handle.clone()
}
@ -125,7 +129,6 @@ pub fn update_shader_assignments(world: &mut World, render_graph: &mut RenderGra
macroed_pipeline_handle
};
// TODO: collecting assigments in a map means they won't be removed when the macro changes
// TODO: this will break down if pipeline layout changes. fix this with "autolayout"
if let None = shader_pipeline_assignments.assignments.get(&final_handle) {
shader_pipeline_assignments.assignments.insert(final_handle.clone(), Vec::new());

View file

@ -448,7 +448,7 @@ impl Renderer for WgpuRenderer {
for draw_target_name in pipeline_descriptor.draw_targets.iter() {
let draw_target = render_graph.draw_targets.get(draw_target_name).unwrap();
draw_target(world, &mut render_pass);
draw_target(world, &mut render_pass, pass_pipeline.clone());
}
}
}

View file

@ -17,5 +17,6 @@ pub mod buffer {
pub mod draw_target {
pub const MESHES: &str = "Meshes";
pub const ASSIGNED_MESHES: &str = "AssignedMeshes";
pub const UI: &str = "Ui";
}