move shader defs updates to their own systems. make UniformResourceProvider::update World read-only

This commit is contained in:
Carter Anderson 2020-04-11 20:27:46 -07:00
parent 394b7ce940
commit b9f4c0a53b
6 changed files with 201 additions and 31 deletions

View file

@ -98,6 +98,7 @@ impl AppPlugin for RenderPlugin {
app.add_system(build_entity_render_resource_assignments_system())
.build_system_on_stage(stage::POST_UPDATE, camera::camera_update_system)
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_batcher_system())
.add_system_to_stage(stage::POST_UPDATE, shader::asset_handle_shader_def_system::<StandardMaterial>())
.add_stage_after(stage::POST_UPDATE, RENDER_STAGE)
.add_resource(RenderGraph::default())
.add_resource(AssetStorage::<Mesh>::new())

View file

@ -53,6 +53,15 @@ struct QueuedBufferWrite {
}
// TODO: make these queries only update changed T components
type UniformQueryRead<T> = Query<
(Read<T>, Read<Renderable>),
EntityFilterTuple<
And<(ComponentFilter<T>, ComponentFilter<Renderable>)>,
And<(Passthrough, Passthrough)>,
And<(Passthrough, Passthrough)>,
>,
>;
type UniformQuery<T> = Query<
(Read<T>, Write<Renderable>),
EntityFilterTuple<
@ -62,6 +71,15 @@ type UniformQuery<T> = Query<
>,
>;
type UniformHandleQueryRead<T> = Query<
(Read<Handle<T>>, Read<Renderable>),
EntityFilterTuple<
And<(ComponentFilter<Handle<T>>, ComponentFilter<Renderable>)>,
And<(Passthrough, Passthrough)>,
And<(Passthrough, Passthrough)>,
>,
>;
type UniformHandleQuery<T> = Query<
(Read<Handle<T>>, Write<Renderable>),
EntityFilterTuple<
@ -82,9 +100,9 @@ where
// PERF: somehow remove this HashSet
uniform_buffer_status: Vec<Option<(String, BufferArrayStatus)>>,
instance_buffer_status: Option<BufferArrayStatus>,
query: Option<UniformQuery<T>>,
query: Option<UniformQueryRead<T>>,
query_finish: Option<UniformQuery<T>>,
handle_query: Option<UniformHandleQuery<T>>,
handle_query: Option<UniformHandleQueryRead<T>>,
handle_query_finish: Option<UniformHandleQuery<T>>,
}
@ -102,14 +120,26 @@ where
use_dynamic_uniforms,
instance_buffer_status: None,
is_instanceable,
query: Some(<(Read<T>, Write<Renderable>)>::query()),
query: Some(<(Read<T>, Read<Renderable>)>::query()),
query_finish: Some(<(Read<T>, Write<Renderable>)>::query()),
handle_query: Some(<(Read<Handle<T>>, Write<Renderable>)>::query()),
handle_query: Some(<(Read<Handle<T>>, Read<Renderable>)>::query()),
handle_query_finish: Some(<(Read<Handle<T>>, Write<Renderable>)>::query()),
_marker: PhantomData,
}
}
fn update_readonly(
&mut self,
_render_context: &mut dyn RenderContext,
world: &World,
resources: &Resources,
) {
self.reset_buffer_array_status_counts();
self.update_uniforms_info(world);
self.update_uniform_handles_info(world, resources);
}
fn reset_buffer_array_status_counts(&mut self) {
for buffer_status in self.uniform_buffer_status.iter_mut() {
if let Some((_name, buffer_status)) = buffer_status {
@ -122,9 +152,9 @@ where
}
}
fn update_uniforms_info(&mut self, world: &mut World) {
fn update_uniforms_info(&mut self, world: &World) {
let query = self.query.take().unwrap();
for (uniforms, mut renderable) in query.iter_mut(world) {
for (uniforms, renderable) in query.iter(world) {
if !renderable.is_visible {
return;
}
@ -141,19 +171,17 @@ where
} else {
self.increment_uniform_counts(&uniforms);
}
Self::update_shader_defs(&uniforms, &mut renderable.render_resource_assignments);
}
self.query = Some(query);
}
fn update_uniform_handles_info(&mut self, world: &mut World, resources: &Resources) {
fn update_uniform_handles_info(&mut self, world: &World, resources: &Resources) {
let handle_query = self.handle_query.take().unwrap();
let assets = resources.get::<AssetStorage<T>>();
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
if let Some(assets) = assets {
for (entity, (handle, mut renderable)) in handle_query.iter_entities_mut(world) {
for (entity, (handle, renderable)) in handle_query.iter_entities(world) {
if !renderable.is_visible {
return;
}
@ -175,7 +203,6 @@ where
let uniforms = assets
.get(&handle)
.expect("Handle points to a non-existent resource");
Self::update_shader_defs(uniforms, &mut renderable.render_resource_assignments);
self.increment_uniform_counts(&uniforms);
}
@ -253,17 +280,6 @@ where
BIND_BUFFER_ALIGNMENT * ((data_size as f32 / BIND_BUFFER_ALIGNMENT as f32).ceil() as usize)
}
fn update_shader_defs(
uniforms: &T,
render_resource_assignments: &mut RenderResourceAssignments,
) {
if let Some(shader_defs) = uniforms.get_shader_defs() {
for shader_def in shader_defs {
render_resource_assignments.shader_defs.insert(shader_def);
}
}
}
fn setup_uniform_buffer_resources(
&mut self,
uniforms: &T,
@ -566,8 +582,6 @@ where
resources,
&mut batch.render_resource_assignments,
);
Self::update_shader_defs(&uniforms, &mut batch.render_resource_assignments);
}
}
}
@ -723,9 +737,7 @@ where
world: &mut World,
resources: &Resources,
) {
self.reset_buffer_array_status_counts();
self.update_uniforms_info(world);
self.update_uniform_handles_info(world, resources);
self.update_readonly(_render_context, world, resources);
}
fn finish_update(

View file

@ -2,10 +2,12 @@ use crate::{
color::ColorSource,
pipeline::{BindType, VertexBufferDescriptor},
texture::Texture,
Renderable,
};
use bevy_asset::Handle;
use bevy_asset::{AssetStorage, Handle};
use bevy_core::bytes::GetBytes;
use legion::prelude::*;
pub trait AsUniforms {
fn get_field_infos() -> &'static [FieldInfo];
@ -17,6 +19,44 @@ pub trait AsUniforms {
fn get_vertex_buffer_descriptor() -> Option<&'static VertexBufferDescriptor>;
}
pub fn shader_def_system<T>() -> Box<dyn Schedulable>
where
T: AsUniforms + Send + Sync + 'static,
{
SystemBuilder::new(format!(
"shader_def::{}",
std::any::type_name::<T>()
))
.with_query(<(Read<T>, Write<Renderable>)>::query())
.build(|_, world, _, query| {
for (uniforms, mut renderable) in query.iter_mut(world) {
if let Some(shader_defs) = uniforms.get_shader_defs() {
renderable.render_resource_assignments.shader_defs.extend(shader_defs)
}
}
})
}
pub fn asset_handle_shader_def_system<T>() -> Box<dyn Schedulable>
where
T: AsUniforms + Send + Sync + 'static,
{
SystemBuilder::new(format!(
"asset_handle_shader_def::{}",
std::any::type_name::<T>()
))
.read_resource::<AssetStorage<T>>()
.with_query(<(Read<Handle<T>>, Write<Renderable>)>::query())
.build(|_, world, asset_storage, query| {
for (uniform_handle, mut renderable) in query.iter_mut(world) {
let uniforms = asset_storage.get(&uniform_handle).unwrap();
if let Some(shader_defs) = uniforms.get_shader_defs() {
renderable.render_resource_assignments.shader_defs.extend(shader_defs)
}
}
})
}
pub trait ShaderDefSuffixProvider {
fn get_shader_def(&self) -> Option<&'static str>;
}

View file

@ -0,0 +1,110 @@
use bevy::{prelude::*};
fn main() {
App::build()
.add_default_plugins()
.setup(setup)
.run();
}
#[derive(Uniforms, Default)]
struct MyMaterial {
pub color: Color,
}
fn add_shader_to_render_graph(resources: &mut Resources) {
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
let mut pipelines = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let mut shaders = resources.get_mut::<AssetStorage<Shader>>().unwrap();
render_graph
.build(&mut pipelines, &mut shaders)
.add_resource_provider(UniformResourceProvider::<MyMaterial>::new(true))
.add_pipeline_to_pass(resource_name::pass::MAIN, "MyMaterial", |builder| {
builder
.with_vertex_shader(Shader::from_glsl(
ShaderStage::Vertex,
r#"
#version 450
layout(location = 0) in vec4 Vertex_Position;
layout(location = 0) out vec4 v_Position;
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Object {
mat4 Model;
};
void main() {
v_Position = Model * Vertex_Position;
gl_Position = ViewProj * v_Position;
}
"#,
))
.with_fragment_shader(Shader::from_glsl(
ShaderStage::Fragment,
r#"
#version 450
layout(location = 0) in vec4 v_Position;
layout(location = 0) out vec4 o_Target;
layout(set = 1, binding = 1) uniform MyMaterial_color {
vec4 color;
};
void main() {
o_Target = color;
}
"#,
))
.with_default_config();
});
}
fn setup(world: &mut World, resources: &mut Resources) {
// add our shader to the render graph
add_shader_to_render_graph(resources);
// create materials
let mut material_storage = AssetStorage::<MyMaterial>::new();
let material = material_storage.add(MyMaterial {
color: Color::rgb(0.0, 0.8, 0.0),
});
resources.insert(material_storage);
// batch materials to improve performance
let mut asset_batchers = resources.get_mut::<AssetBatchers>().unwrap();
asset_batchers.batch_types2::<Mesh, MyMaterial>();
// get a handle to our newly created shader pipeline
let mut pipeline_storage = resources
.get_mut::<AssetStorage<PipelineDescriptor>>()
.unwrap();
let pipeline_handle = pipeline_storage.get_named("MyMaterial").unwrap();
let mut mesh_storage = resources.get_mut::<AssetStorage<Mesh>>().unwrap();
let cube_handle = mesh_storage.add(Mesh::load(MeshType::Cube));
world
.build()
// cube
.add_entity(MeshMaterialEntity::<MyMaterial> {
mesh: cube_handle,
renderable: Renderable {
pipelines: vec![pipeline_handle],
..Default::default()
},
material,
translation: Translation::new(0.0, 0.0, 0.0),
..Default::default()
})
// camera
.add_entity(CameraEntity {
local_to_world: LocalToWorld(Mat4::look_at_rh(
Vec3::new(3.0, 8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
)),
..Default::default()
});
}

View file

@ -1,7 +1,14 @@
use bevy::prelude::*;
use bevy::{prelude::*, render::shader};
fn main() {
App::build().add_default_plugins().setup(setup).run();
App::build()
.add_default_plugins()
.setup(setup)
.add_system_to_stage(
stage::POST_UPDATE,
shader::asset_handle_shader_def_system::<MyMaterial>(),
)
.run();
}
#[derive(Uniforms, Default)]

View file

@ -1,5 +1,5 @@
pub use crate::AddDefaultPlugins;
pub use crate::app::{App, AppBuilder, AppPlugin, EntityArchetype, EventReader, Events, GetEventReader};
pub use crate::app::{App, AppBuilder, AppPlugin, EntityArchetype, EventReader, Events, GetEventReader, stage};
#[cfg(feature = "asset")]
pub use crate::asset::{Asset, AssetStorage, Handle};
#[cfg(feature = "derive")]