fix dynamic uniforms and unit tests

This commit is contained in:
Carter Anderson 2020-03-27 22:41:45 -07:00
parent 92c421b5e1
commit 78de2fe2a1
8 changed files with 67 additions and 29 deletions

View File

@ -232,8 +232,8 @@ impl AppBuilder {
.add_resource_provider(LightResourceProvider::new(10))
.add_resource_provider(UiResourceProvider::new())
.add_resource_provider(MeshResourceProvider::new())
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(false))
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(false))
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true))
.add_forward_pass()
.add_forward_pipeline();
// .add_ui_pipeline();

View File

@ -1,13 +1,13 @@
use super::BindingDescriptor;
use std::{
collections::{hash_map::DefaultHasher, BTreeSet},
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BindGroupDescriptor {
pub index: u32,
pub bindings: BTreeSet<BindingDescriptor>,
pub bindings: Vec<BindingDescriptor>,
pub id: BindGroupDescriptorId,
}
@ -18,7 +18,7 @@ impl BindGroupDescriptor {
pub fn new(index: u32, bindings: Vec<BindingDescriptor>) -> Self {
let mut descriptor = BindGroupDescriptor {
index,
bindings: bindings.iter().cloned().collect(),
bindings,
id: BindGroupDescriptorId(0),
};
@ -42,11 +42,3 @@ impl Hash for BindGroupDescriptor {
self.bindings.hash(state);
}
}
impl PartialEq for BindGroupDescriptor {
fn eq(&self, other: &BindGroupDescriptor) -> bool {
self.index == other.index && self.bindings == other.bindings
}
}
impl Eq for BindGroupDescriptor {}

View File

@ -1,10 +1,13 @@
use super::{PipelineDescriptor, PipelineLayout, PipelineLayoutType};
use super::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType};
use crate::{
asset::{AssetStorage, Handle},
prelude::{Renderable, Resources, Shader, World},
render::{
render_graph::RenderGraph,
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId},
render_resource::{
BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo,
},
renderer::Renderer,
shader::ShaderSource,
},
};
@ -31,6 +34,8 @@ impl PipelineCompiler {
shader_storage: &AssetStorage<Shader>,
render_graph: &RenderGraph,
pipeline_descriptor: &mut PipelineDescriptor,
renderer: &dyn Renderer,
render_resource_assignments: &RenderResourceAssignments,
) {
let vertex_spirv = shader_storage
.get(&pipeline_descriptor.shader_stages.vertex)
@ -49,8 +54,25 @@ impl PipelineCompiler {
let mut layout = PipelineLayout::from_shader_layouts(&mut layouts);
layout.sync_vertex_buffer_descriptors_with_render_graph(render_graph);
for mut _bind_group in layout.bind_groups.iter_mut() {
// TODO: set dynamic here
// set binding uniforms to dynamic if render resource assignments use dynamic
// TODO: this breaks down if different assignments have different "dynamic" status or if the dynamic status changes.
// the fix would be to add "dynamic bindings" to the existing shader_def sets. this would ensure new pipelines are generated
// for all permutations of dynamic/non-dynamic
for bind_group in layout.bind_groups.iter_mut() {
for binding in bind_group.bindings.iter_mut() {
if let Some(render_resource) = render_resource_assignments.get(&binding.name) {
if let Some(ResourceInfo::Buffer(BufferInfo { is_dynamic, .. })) =
renderer.get_resource_info(render_resource)
{
if let BindType::Uniform {
ref mut dynamic, ..
} = binding.bind_type
{
*dynamic = *is_dynamic
}
}
}
}
}
pipeline_descriptor.layout = PipelineLayoutType::Reflected(Some(layout));
@ -93,26 +115,35 @@ impl PipelineCompiler {
&mut self,
render_graph: &RenderGraph,
shader_storage: &mut AssetStorage<Shader>,
renderer: &dyn Renderer,
pipeline_descriptor: &PipelineDescriptor,
shader_defs: &HashSet<String>,
render_resource_assignments: &RenderResourceAssignments,
) -> PipelineDescriptor {
let mut compiled_pipeline_descriptor = pipeline_descriptor.clone();
compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader(
shader_storage,
&pipeline_descriptor.shader_stages.vertex,
&shader_defs,
&render_resource_assignments.shader_defs,
);
compiled_pipeline_descriptor.shader_stages.fragment = pipeline_descriptor
.shader_stages
.fragment
.as_ref()
.map(|fragment| self.compile_shader(shader_storage, fragment, &shader_defs));
.map(|fragment| {
self.compile_shader(
shader_storage,
fragment,
&render_resource_assignments.shader_defs,
)
});
Self::reflect_layout(
shader_storage,
render_graph,
&mut compiled_pipeline_descriptor,
renderer,
render_resource_assignments,
);
compiled_pipeline_descriptor
@ -122,6 +153,7 @@ impl PipelineCompiler {
&mut self,
render_graph: &RenderGraph,
shader_pipeline_assignments: &mut ShaderPipelineAssignments,
renderer: &dyn Renderer,
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
shader_storage: &mut AssetStorage<Shader>,
pipelines: &[Handle<PipelineDescriptor>],
@ -147,8 +179,9 @@ impl PipelineCompiler {
let compiled_pipeline = self.compile_pipeline(
render_graph,
shader_storage,
renderer,
pipeline_descriptor,
&render_resource_assignments.shader_defs,
render_resource_assignments,
);
let compiled_pipeline_handle = pipeline_storage.add(compiled_pipeline);
@ -203,7 +236,7 @@ impl ShaderPipelineAssignments {
}
// TODO: make this a system
pub fn update_shader_assignments(world: &mut World, resources: &mut Resources) {
pub fn update_shader_assignments(world: &mut World, resources: &mut Resources, renderer: &dyn Renderer) {
// 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
{
@ -229,6 +262,7 @@ pub fn update_shader_assignments(world: &mut World, resources: &mut Resources) {
pipeline_compiler.update_shader_assignments(
&mut render_graph,
&mut shader_pipeline_assignments,
renderer,
&mut pipeline_descriptor_storage,
&mut shader_storage,
&renderable.pipelines,

View File

@ -26,7 +26,7 @@ impl PipelineLayout {
panic!("Binding {} in BindGroup {} does not match across all shader types: {:?} {:?}", binding.index, bind_group.index, binding, shader_binding);
}
} else {
bind_group.bindings.insert(shader_binding.clone());
bind_group.bindings.push(shader_binding.clone());
}
}
}

View File

@ -183,7 +183,9 @@ mod tests {
..Default::default()
};
expected_batch.add_entity(entities[0]);
assert_eq!(asset_batchers.get_batch2(a1, b1).unwrap(), &expected_batch);
let actual_batch = asset_batchers.get_batch2(a1, b1).unwrap();
copy_ignored_fields(actual_batch, &mut expected_batch);
assert_eq!(actual_batch, &expected_batch);
asset_batchers.set_entity_handle(entities[0], c1);
asset_batchers.set_entity_handle(entities[1], a1);
@ -196,7 +198,9 @@ mod tests {
};
expected_batch.add_entity(entities[0]);
expected_batch.add_entity(entities[1]);
assert_eq!(asset_batchers.get_batch2(a1, b1).unwrap(), &expected_batch);
let actual_batch = asset_batchers.get_batch2(a1, b1).unwrap();
copy_ignored_fields(actual_batch, &mut expected_batch);
assert_eq!(actual_batch, &expected_batch);
// uncreated batches are empty
assert_eq!(asset_batchers.get_batch2(a1, c1), None);
@ -239,6 +243,11 @@ mod tests {
),
];
expected_batches.sort_by(|a, b| a.0.cmp(&b.0));
// copy ignored fields
batches
.iter()
.zip(expected_batches.iter_mut())
.for_each(|((_, ref actual), (_, ref mut expected))| copy_ignored_fields(actual, expected));
assert_eq!(
batches,
expected_batches
@ -247,4 +256,8 @@ mod tests {
.collect::<Vec<(&BatchKey2, &Batch)>>()
);
}
fn copy_ignored_fields(source: &Batch, destination: &mut Batch) {
destination.render_resource_assignments.id = source.render_resource_assignments.id;
}
}

View File

@ -49,7 +49,6 @@ pub trait Renderer {
}
pub trait RenderPass {
// TODO: consider using static dispatch for the renderer: Renderer<WgpuBackend>. compare compile times
fn get_renderer(&self) -> &dyn Renderer;
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor;
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64);

View File

@ -384,7 +384,7 @@ impl Renderer for WgpuRenderer {
);
self.update_resource_providers(world, resources);
update_shader_assignments(world, resources);
update_shader_assignments(world, resources, self);
self.create_queued_textures(resources);
let mut encoder = self.encoder.take().unwrap();

View File

@ -28,7 +28,7 @@ use zerocopy::AsBytes;
// println!("{:?}", structured.types);
// }
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ShaderLayout {
pub bind_groups: Vec<BindGroupDescriptor>,
pub vertex_buffer_descriptors: Vec<VertexBufferDescriptor>,