Skip to content

Commit

Permalink
delegate layout reflection to RenderResourceContext
Browse files Browse the repository at this point in the history
auto-reflect DynamicBindings
  • Loading branch information
mrk-its committed Nov 1, 2020
1 parent 9cc6368 commit ad89d22
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 232 deletions.
18 changes: 2 additions & 16 deletions crates/bevy_pbr/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bevy_ecs::Bundle;
use bevy_render::{
draw::Draw,
mesh::Mesh,
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
pipeline::{PipelineSpecialization, RenderPipeline, RenderPipelines},
render_graph::base::MainPass,
};
use bevy_transform::prelude::{GlobalTransform, Transform};
Expand All @@ -26,21 +26,7 @@ impl Default for PbrComponents {
Self {
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
FORWARD_PIPELINE_HANDLE,
PipelineSpecialization {
dynamic_bindings: vec![
// Transform
DynamicBinding {
bind_group: 2,
binding: 0,
},
// StandardMaterial_albedo
DynamicBinding {
bind_group: 3,
binding: 0,
},
],
..Default::default()
},
PipelineSpecialization::default(),
)]),
mesh: Default::default(),
material: Default::default(),
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_render/src/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ impl<'a> DrawContext<'a> {
draw: &mut Draw,
pipeline_handle: &Handle<PipelineDescriptor>,
specialization: &PipelineSpecialization,
render_resource_bindings: &mut [&mut RenderResourceBindings],
) -> Result<(), DrawError> {
let specialized_pipeline = if let Some(specialized_pipeline) = self
.pipeline_compiler
Expand All @@ -255,6 +256,7 @@ impl<'a> DrawContext<'a> {
&mut self.shaders,
pipeline_handle,
specialization,
render_resource_bindings,
)
};

Expand Down
7 changes: 3 additions & 4 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ use camera::{
ActiveCameras, Camera, OrthographicProjection, PerspectiveProjection, VisibleEntities,
};
use pipeline::{
DynamicBinding, IndexFormat, PipelineCompiler, PipelineDescriptor, PipelineSpecialization,
PrimitiveTopology, ShaderSpecialization,
IndexFormat, PipelineCompiler, PipelineDescriptor, PipelineSpecialization, PrimitiveTopology,
ShaderSpecialization,
};
use render_graph::{
base::{self, BaseRenderGraphBuilder, BaseRenderGraphConfig},
Expand Down Expand Up @@ -66,7 +66,7 @@ pub mod stage {

/// Adds core render types and systems to an App
pub struct RenderPlugin {
/// configures the "base render graph". If this is not `None`, the "base render graph" will be added
/// configures the "base render graph". If this is not `None`, the "base render graph" will be added
pub base_render_graph_config: Option<BaseRenderGraphConfig>,
}

Expand Down Expand Up @@ -112,7 +112,6 @@ impl Plugin for RenderPlugin {
.register_property::<Color>()
.register_property::<Range<f32>>()
.register_property::<ShaderSpecialization>()
.register_property::<DynamicBinding>()
.register_property::<PrimitiveTopology>()
.register_property::<IndexFormat>()
.register_properties::<PipelineSpecialization>()
Expand Down
67 changes: 2 additions & 65 deletions crates/bevy_render/src/pipeline/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@ use super::{
CompareFunction, CullMode, DepthStencilStateDescriptor, FrontFace, IndexFormat,
PrimitiveTopology, RasterizationStateDescriptor, StencilStateFaceDescriptor,
},
BindType, DynamicBinding, PipelineLayout, StencilStateDescriptor,
PipelineLayout, StencilStateDescriptor,
};
use crate::{
shader::{Shader, ShaderStages},
texture::TextureFormat,
};
use bevy_asset::Assets;
use crate::{shader::ShaderStages, texture::TextureFormat};
use bevy_type_registry::TypeUuid;

#[derive(Clone, Debug, TypeUuid)]
Expand Down Expand Up @@ -117,63 +113,4 @@ impl PipelineDescriptor {
pub fn get_layout_mut(&mut self) -> Option<&mut PipelineLayout> {
self.layout.as_mut()
}

/// Reflects the pipeline layout from its shaders.
///
/// If `bevy_conventions` is true, it will be assumed that the shader follows "bevy shader conventions". These allow
/// richer reflection, such as inferred Vertex Buffer names and inferred instancing.
///
/// If `dynamic_bindings` has values, shader uniforms will be set to "dynamic" if there is a matching binding in the list
///
/// If `vertex_buffer_descriptors` is set, the pipeline's vertex buffers
/// will inherit their layouts from global descriptors, otherwise the layout will be assumed to be complete / local.
pub fn reflect_layout(
&mut self,
shaders: &Assets<Shader>,
bevy_conventions: bool,
dynamic_bindings: &[DynamicBinding],
) {
let vertex_spirv = shaders.get(&self.shader_stages.vertex).unwrap();
let fragment_spirv = self
.shader_stages
.fragment
.as_ref()
.map(|handle| shaders.get(handle).unwrap());

let mut layouts = vec![vertex_spirv.reflect_layout(bevy_conventions).unwrap()];
if let Some(ref fragment_spirv) = fragment_spirv {
layouts.push(fragment_spirv.reflect_layout(bevy_conventions).unwrap());
}

let mut layout = PipelineLayout::from_shader_layouts(&mut layouts);

if !dynamic_bindings.is_empty() {
// set binding uniforms to dynamic if render resource bindings use dynamic
for bind_group in layout.bind_groups.iter_mut() {
let mut binding_changed = false;
for binding in bind_group.bindings.iter_mut() {
let current = DynamicBinding {
bind_group: bind_group.index,
binding: binding.index,
};

if dynamic_bindings.contains(&current) {
if let BindType::Uniform {
ref mut dynamic, ..
} = binding.bind_type
{
*dynamic = true;
binding_changed = true;
}
}
}

if binding_changed {
bind_group.update_id();
}
}
}

self.layout = Some(layout);
}
}
68 changes: 55 additions & 13 deletions crates/bevy_render/src/pipeline/pipeline_compiler.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::{state_descriptors::PrimitiveTopology, IndexFormat, PipelineDescriptor};
use crate::{
pipeline::{
InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
BindType, InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
VERTEX_FALLBACK_LAYOUT_NAME,
},
renderer::RenderResourceContext,
renderer::{RenderResourceBinding, RenderResourceBindings, RenderResourceContext},
shader::{Shader, ShaderSource},
};
use bevy_asset::{Assets, Handle};
Expand All @@ -18,7 +18,6 @@ use std::borrow::Cow;
pub struct PipelineSpecialization {
pub shader_specialization: ShaderSpecialization,
pub primitive_topology: PrimitiveTopology,
pub dynamic_bindings: Vec<DynamicBinding>,
pub index_format: IndexFormat,
pub mesh_attribute_layout: VertexBufferDescriptor,
pub sample_count: u32,
Expand All @@ -30,7 +29,6 @@ impl Default for PipelineSpecialization {
sample_count: 1,
shader_specialization: Default::default(),
primitive_topology: Default::default(),
dynamic_bindings: Default::default(),
index_format: IndexFormat::Uint32,
mesh_attribute_layout: Default::default(),
}
Expand Down Expand Up @@ -61,12 +59,6 @@ struct SpecializedPipeline {
specialization: PipelineSpecialization,
}

#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize, Property)]
pub struct DynamicBinding {
pub bind_group: u32,
pub binding: u32,
}

#[derive(Debug, Default)]
pub struct PipelineCompiler {
specialized_shaders: HashMap<Handle<Shader>, Vec<SpecializedShader>>,
Expand Down Expand Up @@ -143,6 +135,7 @@ impl PipelineCompiler {
shaders: &mut Assets<Shader>,
source_pipeline: &Handle<PipelineDescriptor>,
pipeline_specialization: &PipelineSpecialization,
render_resource_bindings: &mut [&mut RenderResourceBindings],
) -> Handle<PipelineDescriptor> {
let source_descriptor = pipelines.get(source_pipeline).unwrap();
let mut specialized_descriptor = source_descriptor.clone();
Expand All @@ -163,12 +156,38 @@ impl PipelineCompiler {
)
});

specialized_descriptor.reflect_layout(
shaders,
let mut layout = render_resource_context.reflect_pipeline_layout(
&shaders,
&specialized_descriptor.shader_stages,
true,
&pipeline_specialization.dynamic_bindings,
);

let dynamic_bindings = self.get_dynamic_bindings(render_resource_bindings);

if !dynamic_bindings.is_empty() {
// set binding uniforms to dynamic if render resource bindings use dynamic
for bind_group in layout.bind_groups.iter_mut() {
let mut binding_changed = false;
for binding in bind_group.bindings.iter_mut() {
if dynamic_bindings.iter().any(|b| b == &binding.name) {
if let BindType::Uniform {
ref mut dynamic, ..
} = binding.bind_type
{
*dynamic = true;
binding_changed = true;
}
}
}

if binding_changed {
bind_group.update_id();
}
}
}

specialized_descriptor.layout = Some(layout);

// create a vertex layout that provides all attributes from either the specialized vertex buffers or a zero buffer
let mut pipeline_layout = specialized_descriptor.layout.as_mut().unwrap();
// the vertex buffer descriptor of the mesh
Expand Down Expand Up @@ -246,6 +265,29 @@ impl PipelineCompiler {
weak_specialized_pipeline_handle
}

fn get_dynamic_bindings(
&self,
render_resource_bindings: &mut [&mut RenderResourceBindings],
) -> Vec<String> {
render_resource_bindings
.iter()
.flat_map(|bindings| {
bindings
.bindings
.iter()
.filter(|(_, binding)| match binding {
RenderResourceBinding::Buffer {
dynamic_index: Some(_),
..
} => true,
_ => false,
})
.map(|(name, _)| name)
})
.cloned()
.collect()
}

pub fn iter_compiled_pipelines(
&self,
pipeline_handle: Handle<PipelineDescriptor>,
Expand Down
13 changes: 6 additions & 7 deletions crates/bevy_render/src/pipeline/render_pipelines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,20 @@ pub fn draw_render_pipelines_system(
}

for render_pipeline in render_pipelines.pipelines.iter() {
let render_resource_bindings = &mut [
&mut render_pipelines.bindings,
&mut render_resource_bindings,
];
draw_context
.set_pipeline(
&mut draw,
&render_pipeline.pipeline,
&render_pipeline.specialization,
render_resource_bindings,
)
.unwrap();
draw_context
.set_bind_groups_from_bindings(
&mut draw,
&mut [
&mut render_pipelines.bindings,
&mut render_resource_bindings,
],
)
.set_bind_groups_from_bindings(&mut draw, render_resource_bindings)
.unwrap();
draw_context
.set_vertex_buffers_from_bindings(&mut draw, &[&render_pipelines.bindings])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub enum BindGroupStatus {
// PERF: if the bindings are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost
#[derive(Eq, PartialEq, Debug, Default, Clone)]
pub struct RenderResourceBindings {
bindings: HashMap<String, RenderResourceBinding>,
pub bindings: HashMap<String, RenderResourceBinding>,
/// A Buffer that contains all attributes a mesh has defined
pub vertex_attribute_buffer: Option<BufferId>,
/// A Buffer that is filled with zeros that will be used for attributes required by the shader, but undefined by the mesh.
Expand Down
32 changes: 30 additions & 2 deletions crates/bevy_render/src/renderer/render_resource_context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
pipeline::{BindGroupDescriptorId, PipelineDescriptor, PipelineLayout},
renderer::{BindGroup, BufferId, BufferInfo, RenderResourceId, SamplerId, TextureId},
shader::Shader,
shader::{Shader, ShaderLayout, ShaderStages},
texture::{SamplerDescriptor, TextureDescriptor},
};
use bevy_asset::{Asset, Assets, Handle, HandleUntyped};
Expand Down Expand Up @@ -60,6 +60,34 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static {
bind_group: &BindGroup,
);
fn clear_bind_groups(&self);
/// Reflects the pipeline layout from its shaders.
///
/// If `bevy_conventions` is true, it will be assumed that the shader follows "bevy shader conventions". These allow
/// richer reflection, such as inferred Vertex Buffer names and inferred instancing.
///
/// If `dynamic_bindings` has values, shader uniforms will be set to "dynamic" if there is a matching binding in the list
///
/// If `vertex_buffer_descriptors` is set, the pipeline's vertex buffers
/// will inherit their layouts from global descriptors, otherwise the layout will be assumed to be complete / local.
fn reflect_pipeline_layout(
&self,
shaders: &Assets<Shader>,
shader_stages: &ShaderStages,
enforce_bevy_conventions: bool,
) -> PipelineLayout {
// TODO: maybe move this default implementation to PipelineLayout?
let mut shader_layouts: Vec<ShaderLayout> = shader_stages
.iter()
.map(|handle| {
shaders
.get(&handle)
.unwrap()
.reflect_layout(enforce_bevy_conventions)
.unwrap()
})
.collect();
PipelineLayout::from_shader_layouts(&mut shader_layouts)
}
}

impl dyn RenderResourceContext {
Expand Down
Loading

0 comments on commit ad89d22

Please sign in to comment.