fix dynamic uniforms and unit tests
This commit is contained in:
parent
92c421b5e1
commit
78de2fe2a1
@ -232,8 +232,8 @@ impl AppBuilder {
|
|||||||
.add_resource_provider(LightResourceProvider::new(10))
|
.add_resource_provider(LightResourceProvider::new(10))
|
||||||
.add_resource_provider(UiResourceProvider::new())
|
.add_resource_provider(UiResourceProvider::new())
|
||||||
.add_resource_provider(MeshResourceProvider::new())
|
.add_resource_provider(MeshResourceProvider::new())
|
||||||
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(false))
|
.add_resource_provider(UniformResourceProvider::<StandardMaterial>::new(true))
|
||||||
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(false))
|
.add_resource_provider(UniformResourceProvider::<LocalToWorld>::new(true))
|
||||||
.add_forward_pass()
|
.add_forward_pass()
|
||||||
.add_forward_pipeline();
|
.add_forward_pipeline();
|
||||||
// .add_ui_pipeline();
|
// .add_ui_pipeline();
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
use super::BindingDescriptor;
|
use super::BindingDescriptor;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::DefaultHasher, BTreeSet},
|
collections::hash_map::DefaultHasher,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct BindGroupDescriptor {
|
pub struct BindGroupDescriptor {
|
||||||
pub index: u32,
|
pub index: u32,
|
||||||
pub bindings: BTreeSet<BindingDescriptor>,
|
pub bindings: Vec<BindingDescriptor>,
|
||||||
pub id: BindGroupDescriptorId,
|
pub id: BindGroupDescriptorId,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ impl BindGroupDescriptor {
|
|||||||
pub fn new(index: u32, bindings: Vec<BindingDescriptor>) -> Self {
|
pub fn new(index: u32, bindings: Vec<BindingDescriptor>) -> Self {
|
||||||
let mut descriptor = BindGroupDescriptor {
|
let mut descriptor = BindGroupDescriptor {
|
||||||
index,
|
index,
|
||||||
bindings: bindings.iter().cloned().collect(),
|
bindings,
|
||||||
id: BindGroupDescriptorId(0),
|
id: BindGroupDescriptorId(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,11 +42,3 @@ impl Hash for BindGroupDescriptor {
|
|||||||
self.bindings.hash(state);
|
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 {}
|
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
use super::{PipelineDescriptor, PipelineLayout, PipelineLayoutType};
|
use super::{BindType, PipelineDescriptor, PipelineLayout, PipelineLayoutType};
|
||||||
use crate::{
|
use crate::{
|
||||||
asset::{AssetStorage, Handle},
|
asset::{AssetStorage, Handle},
|
||||||
prelude::{Renderable, Resources, Shader, World},
|
prelude::{Renderable, Resources, Shader, World},
|
||||||
render::{
|
render::{
|
||||||
render_graph::RenderGraph,
|
render_graph::RenderGraph,
|
||||||
render_resource::{RenderResourceAssignments, RenderResourceAssignmentsId},
|
render_resource::{
|
||||||
|
BufferInfo, RenderResourceAssignments, RenderResourceAssignmentsId, ResourceInfo,
|
||||||
|
},
|
||||||
|
renderer::Renderer,
|
||||||
shader::ShaderSource,
|
shader::ShaderSource,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -31,6 +34,8 @@ impl PipelineCompiler {
|
|||||||
shader_storage: &AssetStorage<Shader>,
|
shader_storage: &AssetStorage<Shader>,
|
||||||
render_graph: &RenderGraph,
|
render_graph: &RenderGraph,
|
||||||
pipeline_descriptor: &mut PipelineDescriptor,
|
pipeline_descriptor: &mut PipelineDescriptor,
|
||||||
|
renderer: &dyn Renderer,
|
||||||
|
render_resource_assignments: &RenderResourceAssignments,
|
||||||
) {
|
) {
|
||||||
let vertex_spirv = shader_storage
|
let vertex_spirv = shader_storage
|
||||||
.get(&pipeline_descriptor.shader_stages.vertex)
|
.get(&pipeline_descriptor.shader_stages.vertex)
|
||||||
@ -49,8 +54,25 @@ impl PipelineCompiler {
|
|||||||
let mut layout = PipelineLayout::from_shader_layouts(&mut layouts);
|
let mut layout = PipelineLayout::from_shader_layouts(&mut layouts);
|
||||||
layout.sync_vertex_buffer_descriptors_with_render_graph(render_graph);
|
layout.sync_vertex_buffer_descriptors_with_render_graph(render_graph);
|
||||||
|
|
||||||
for mut _bind_group in layout.bind_groups.iter_mut() {
|
// set binding uniforms to dynamic if render resource assignments use dynamic
|
||||||
// TODO: set dynamic here
|
// 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));
|
pipeline_descriptor.layout = PipelineLayoutType::Reflected(Some(layout));
|
||||||
@ -93,26 +115,35 @@ impl PipelineCompiler {
|
|||||||
&mut self,
|
&mut self,
|
||||||
render_graph: &RenderGraph,
|
render_graph: &RenderGraph,
|
||||||
shader_storage: &mut AssetStorage<Shader>,
|
shader_storage: &mut AssetStorage<Shader>,
|
||||||
|
renderer: &dyn Renderer,
|
||||||
pipeline_descriptor: &PipelineDescriptor,
|
pipeline_descriptor: &PipelineDescriptor,
|
||||||
shader_defs: &HashSet<String>,
|
render_resource_assignments: &RenderResourceAssignments,
|
||||||
) -> PipelineDescriptor {
|
) -> PipelineDescriptor {
|
||||||
let mut compiled_pipeline_descriptor = pipeline_descriptor.clone();
|
let mut compiled_pipeline_descriptor = pipeline_descriptor.clone();
|
||||||
|
|
||||||
compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader(
|
compiled_pipeline_descriptor.shader_stages.vertex = self.compile_shader(
|
||||||
shader_storage,
|
shader_storage,
|
||||||
&pipeline_descriptor.shader_stages.vertex,
|
&pipeline_descriptor.shader_stages.vertex,
|
||||||
&shader_defs,
|
&render_resource_assignments.shader_defs,
|
||||||
);
|
);
|
||||||
compiled_pipeline_descriptor.shader_stages.fragment = pipeline_descriptor
|
compiled_pipeline_descriptor.shader_stages.fragment = pipeline_descriptor
|
||||||
.shader_stages
|
.shader_stages
|
||||||
.fragment
|
.fragment
|
||||||
.as_ref()
|
.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(
|
Self::reflect_layout(
|
||||||
shader_storage,
|
shader_storage,
|
||||||
render_graph,
|
render_graph,
|
||||||
&mut compiled_pipeline_descriptor,
|
&mut compiled_pipeline_descriptor,
|
||||||
|
renderer,
|
||||||
|
render_resource_assignments,
|
||||||
);
|
);
|
||||||
|
|
||||||
compiled_pipeline_descriptor
|
compiled_pipeline_descriptor
|
||||||
@ -122,6 +153,7 @@ impl PipelineCompiler {
|
|||||||
&mut self,
|
&mut self,
|
||||||
render_graph: &RenderGraph,
|
render_graph: &RenderGraph,
|
||||||
shader_pipeline_assignments: &mut ShaderPipelineAssignments,
|
shader_pipeline_assignments: &mut ShaderPipelineAssignments,
|
||||||
|
renderer: &dyn Renderer,
|
||||||
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
|
pipeline_storage: &mut AssetStorage<PipelineDescriptor>,
|
||||||
shader_storage: &mut AssetStorage<Shader>,
|
shader_storage: &mut AssetStorage<Shader>,
|
||||||
pipelines: &[Handle<PipelineDescriptor>],
|
pipelines: &[Handle<PipelineDescriptor>],
|
||||||
@ -147,8 +179,9 @@ impl PipelineCompiler {
|
|||||||
let compiled_pipeline = self.compile_pipeline(
|
let compiled_pipeline = self.compile_pipeline(
|
||||||
render_graph,
|
render_graph,
|
||||||
shader_storage,
|
shader_storage,
|
||||||
|
renderer,
|
||||||
pipeline_descriptor,
|
pipeline_descriptor,
|
||||||
&render_resource_assignments.shader_defs,
|
render_resource_assignments,
|
||||||
);
|
);
|
||||||
let compiled_pipeline_handle = pipeline_storage.add(compiled_pipeline);
|
let compiled_pipeline_handle = pipeline_storage.add(compiled_pipeline);
|
||||||
|
|
||||||
@ -203,7 +236,7 @@ impl ShaderPipelineAssignments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make this a system
|
// 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.
|
// 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
|
// 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(
|
pipeline_compiler.update_shader_assignments(
|
||||||
&mut render_graph,
|
&mut render_graph,
|
||||||
&mut shader_pipeline_assignments,
|
&mut shader_pipeline_assignments,
|
||||||
|
renderer,
|
||||||
&mut pipeline_descriptor_storage,
|
&mut pipeline_descriptor_storage,
|
||||||
&mut shader_storage,
|
&mut shader_storage,
|
||||||
&renderable.pipelines,
|
&renderable.pipelines,
|
||||||
|
|||||||
@ -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);
|
panic!("Binding {} in BindGroup {} does not match across all shader types: {:?} {:?}", binding.index, bind_group.index, binding, shader_binding);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bind_group.bindings.insert(shader_binding.clone());
|
bind_group.bindings.push(shader_binding.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -183,7 +183,9 @@ mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
expected_batch.add_entity(entities[0]);
|
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[0], c1);
|
||||||
|
|
||||||
asset_batchers.set_entity_handle(entities[1], a1);
|
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[0]);
|
||||||
expected_batch.add_entity(entities[1]);
|
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
|
// uncreated batches are empty
|
||||||
assert_eq!(asset_batchers.get_batch2(a1, c1), None);
|
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));
|
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!(
|
assert_eq!(
|
||||||
batches,
|
batches,
|
||||||
expected_batches
|
expected_batches
|
||||||
@ -247,4 +256,8 @@ mod tests {
|
|||||||
.collect::<Vec<(&BatchKey2, &Batch)>>()
|
.collect::<Vec<(&BatchKey2, &Batch)>>()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_ignored_fields(source: &Batch, destination: &mut Batch) {
|
||||||
|
destination.render_resource_assignments.id = source.render_resource_assignments.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,6 @@ pub trait Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait RenderPass {
|
pub trait RenderPass {
|
||||||
// TODO: consider using static dispatch for the renderer: Renderer<WgpuBackend>. compare compile times
|
|
||||||
fn get_renderer(&self) -> &dyn Renderer;
|
fn get_renderer(&self) -> &dyn Renderer;
|
||||||
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor;
|
fn get_pipeline_descriptor(&self) -> &PipelineDescriptor;
|
||||||
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64);
|
fn set_index_buffer(&mut self, resource: RenderResource, offset: u64);
|
||||||
|
|||||||
@ -384,7 +384,7 @@ impl Renderer for WgpuRenderer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.update_resource_providers(world, resources);
|
self.update_resource_providers(world, resources);
|
||||||
update_shader_assignments(world, resources);
|
update_shader_assignments(world, resources, self);
|
||||||
self.create_queued_textures(resources);
|
self.create_queued_textures(resources);
|
||||||
|
|
||||||
let mut encoder = self.encoder.take().unwrap();
|
let mut encoder = self.encoder.take().unwrap();
|
||||||
|
|||||||
@ -28,7 +28,7 @@ use zerocopy::AsBytes;
|
|||||||
// println!("{:?}", structured.types);
|
// println!("{:?}", structured.types);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ShaderLayout {
|
pub struct ShaderLayout {
|
||||||
pub bind_groups: Vec<BindGroupDescriptor>,
|
pub bind_groups: Vec<BindGroupDescriptor>,
|
||||||
pub vertex_buffer_descriptors: Vec<VertexBufferDescriptor>,
|
pub vertex_buffer_descriptors: Vec<VertexBufferDescriptor>,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user