mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 14:10:19 +00:00
render: move dynamic_bindings to PipelineSpecialization
This is a temporary step back in ergonomics as we are no longer automatically inferring dynamic bindings from RenderResourceBindings
This commit is contained in:
parent
0931fd0266
commit
74d0055a3d
9 changed files with 171 additions and 54 deletions
|
@ -1,14 +1,16 @@
|
|||
use crate::{light::Light, material::StandardMaterial};
|
||||
use crate::{light::Light, material::StandardMaterial, pipelines::FORWARD_PIPELINE_HANDLE};
|
||||
use bevy_asset::Handle;
|
||||
use bevy_derive::EntityArchetype;
|
||||
use bevy_render::{draw::Draw, mesh::Mesh, pipeline::RenderPipelines};
|
||||
use bevy_render::{
|
||||
draw::Draw,
|
||||
mesh::Mesh,
|
||||
pipeline::{DynamicBinding, PipelineSpecialization, RenderPipeline, RenderPipelines},
|
||||
};
|
||||
use bevy_transform::prelude::{Rotation, Scale, Transform, Translation};
|
||||
|
||||
#[derive(EntityArchetype, Default)]
|
||||
#[derive(EntityArchetype)]
|
||||
pub struct MeshEntity {
|
||||
// #[tag]
|
||||
pub mesh: Handle<Mesh>,
|
||||
// #[tag]
|
||||
pub material: Handle<StandardMaterial>,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
|
@ -18,6 +20,38 @@ pub struct MeshEntity {
|
|||
pub scale: Scale,
|
||||
}
|
||||
|
||||
impl Default for MeshEntity {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
|
||||
FORWARD_PIPELINE_HANDLE,
|
||||
PipelineSpecialization {
|
||||
dynamic_bindings: vec![
|
||||
// Transform
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 0,
|
||||
},
|
||||
// StandardMaterial_albedo
|
||||
DynamicBinding {
|
||||
bind_group: 2,
|
||||
binding: 0,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
)]),
|
||||
mesh: Default::default(),
|
||||
material: Default::default(),
|
||||
draw: Default::default(),
|
||||
transform: Default::default(),
|
||||
translation: Default::default(),
|
||||
rotation: Default::default(),
|
||||
scale: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(EntityArchetype, Default)]
|
||||
pub struct LightEntity {
|
||||
pub light: Light,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{material::StandardMaterial, nodes::LightsNode, pipelines::build_forward_pipeline};
|
||||
use crate::{material::StandardMaterial, nodes::LightsNode, pipelines::{FORWARD_PIPELINE_HANDLE, build_forward_pipeline}};
|
||||
use bevy_asset::Assets;
|
||||
use bevy_render::{
|
||||
base_render_graph,
|
||||
|
@ -36,7 +36,7 @@ impl ForwardPbrRenderGraphBuilder for RenderGraph {
|
|||
self.add_system_node(node::LIGHTS, LightsNode::new(10));
|
||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
||||
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
||||
pipelines.add_default(build_forward_pipeline(&mut shaders));
|
||||
pipelines.set(FORWARD_PIPELINE_HANDLE, build_forward_pipeline(&mut shaders));
|
||||
|
||||
// TODO: replace these with "autowire" groups
|
||||
self.add_node_edge(node::STANDARD_MATERIAL, base_render_graph::node::MAIN_PASS)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use bevy_asset::Assets;
|
||||
use bevy_asset::{Handle, Assets};
|
||||
use bevy_render::{
|
||||
pipeline::{
|
||||
state_descriptors::{
|
||||
|
@ -12,6 +12,8 @@ use bevy_render::{
|
|||
texture::TextureFormat,
|
||||
};
|
||||
|
||||
pub const FORWARD_PIPELINE_HANDLE: Handle<PipelineDescriptor> =
|
||||
Handle::from_u128(131483623140127713893804825450360211204);
|
||||
pub fn build_forward_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescriptor {
|
||||
PipelineDescriptor {
|
||||
rasterization_state: Some(RasterizationStateDescriptor {
|
||||
|
|
|
@ -4,10 +4,9 @@ use super::{
|
|||
CompareFunction, CullMode, DepthStencilStateDescriptor, FrontFace, IndexFormat,
|
||||
PrimitiveTopology, RasterizationStateDescriptor, StencilStateFaceDescriptor,
|
||||
},
|
||||
BindType, PipelineLayout, VertexBufferDescriptors,
|
||||
BindType, DynamicBinding, PipelineLayout, VertexBufferDescriptors,
|
||||
};
|
||||
use crate::{
|
||||
render_resource::{RenderResourceBinding, RenderResourceBindings},
|
||||
shader::{Shader, ShaderStages},
|
||||
texture::TextureFormat,
|
||||
};
|
||||
|
@ -119,17 +118,16 @@ impl PipelineDescriptor {
|
|||
/// 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.
|
||||
///
|
||||
/// If `render_resource_bindings` is set, shader uniforms will be set to "dynamic" if there is a matching "dynamic uniform"
|
||||
/// render resource.
|
||||
pub fn reflect_layout(
|
||||
&mut self,
|
||||
shaders: &Assets<Shader>,
|
||||
bevy_conventions: bool,
|
||||
vertex_buffer_descriptors: Option<&VertexBufferDescriptors>,
|
||||
render_resource_bindings: Option<&RenderResourceBindings>,
|
||||
dynamic_bindings: &[DynamicBinding],
|
||||
) {
|
||||
let vertex_spirv = shaders.get(&self.shader_stages.vertex).unwrap();
|
||||
let fragment_spirv = self
|
||||
|
@ -148,18 +146,16 @@ impl PipelineDescriptor {
|
|||
layout.sync_vertex_buffer_descriptors(vertex_buffer_descriptors);
|
||||
}
|
||||
|
||||
if let Some(render_resource_bindings) = render_resource_bindings {
|
||||
if !dynamic_bindings.is_empty() {
|
||||
// set binding uniforms to dynamic if render resource bindings use dynamic
|
||||
// TODO: this breaks down if different bindings 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(RenderResourceBinding::Buffer {
|
||||
dynamic_index: Some(_),
|
||||
..
|
||||
}) = render_resource_bindings.get(&binding.name)
|
||||
{
|
||||
let current = DynamicBinding {
|
||||
bind_group: bind_group.index,
|
||||
binding: binding.index,
|
||||
};
|
||||
|
||||
if dynamic_bindings.contains(¤t) {
|
||||
if let BindType::Uniform {
|
||||
ref mut dynamic, ..
|
||||
} = binding.bind_type
|
||||
|
|
|
@ -3,18 +3,19 @@ use super::{
|
|||
VertexBufferDescriptors,
|
||||
};
|
||||
use crate::{
|
||||
render_resource::RenderResourceBindings,
|
||||
renderer::RenderResourceContext,
|
||||
shader::{Shader, ShaderSource},
|
||||
};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_asset::{Assets, Handle, AssetEvent};
|
||||
use legion::prelude::*;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use bevy_app::Events;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Default)]
|
||||
pub struct PipelineSpecialization {
|
||||
pub shader_specialization: ShaderSpecialization,
|
||||
pub primitive_topology: PrimitiveTopology,
|
||||
pub dynamic_bindings: Vec<DynamicBinding>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Default)]
|
||||
|
@ -32,7 +33,12 @@ struct SpecializedPipeline {
|
|||
specialization: PipelineSpecialization,
|
||||
}
|
||||
|
||||
// TODO: consider using (Typeid, fieldinfo.index) in place of string for hashes
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Default)]
|
||||
pub struct DynamicBinding {
|
||||
pub bind_group: u32,
|
||||
pub binding: u32,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PipelineCompiler {
|
||||
specialized_shaders: HashMap<Handle<Shader>, Vec<SpecializedShader>>,
|
||||
|
@ -92,7 +98,6 @@ impl PipelineCompiler {
|
|||
source_pipeline: Handle<PipelineDescriptor>,
|
||||
vertex_buffer_descriptors: &VertexBufferDescriptors,
|
||||
pipeline_specialization: &PipelineSpecialization,
|
||||
render_resource_bindings: &RenderResourceBindings,
|
||||
) -> Handle<PipelineDescriptor> {
|
||||
let source_descriptor = pipelines.get(&source_pipeline).unwrap();
|
||||
let mut specialized_descriptor = source_descriptor.clone();
|
||||
|
@ -117,7 +122,7 @@ impl PipelineCompiler {
|
|||
shaders,
|
||||
true,
|
||||
Some(vertex_buffer_descriptors),
|
||||
Some(render_resource_bindings),
|
||||
&pipeline_specialization.dynamic_bindings,
|
||||
);
|
||||
|
||||
specialized_descriptor.primitive_topology = pipeline_specialization.primitive_topology;
|
||||
|
@ -176,7 +181,6 @@ impl PipelineCompiler {
|
|||
source_pipeline,
|
||||
vertex_buffer_descriptors,
|
||||
&render_pipeline.specialization,
|
||||
&render_pipelines.bindings,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -213,15 +217,15 @@ pub fn compile_pipelines_system(
|
|||
mut pipeline_compiler: ResMut<PipelineCompiler>,
|
||||
mut shaders: ResMut<Assets<Shader>>,
|
||||
mut pipelines: ResMut<Assets<PipelineDescriptor>>,
|
||||
// pipeline_asset_events: Res<Events<AssetEvent<PipelineDescriptor>>>,
|
||||
_pipeline_asset_events: Res<Events<AssetEvent<PipelineDescriptor>>>,
|
||||
vertex_buffer_descriptors: Res<VertexBufferDescriptors>,
|
||||
render_resource_context: Res<Box<dyn RenderResourceContext>>,
|
||||
query: &mut Query<Write<RenderPipelines>>,
|
||||
) {
|
||||
let render_resource_context = &**render_resource_context;
|
||||
// let default_specialization = PipelineSpecialization::default();
|
||||
// NOTE: this intentionally only handles events that happened prior to this system during this frame. this results in
|
||||
// "specialized pipeline" events being ignored.
|
||||
// "new specialized pipeline" events being ignored.
|
||||
// let default_specialization = PipelineSpecialization::default();
|
||||
// for event in pipeline_asset_events.iter_current_update_events() {
|
||||
// let handle_to_compile = match event {
|
||||
// AssetEvent::Created { handle } => Some(*handle),
|
||||
|
@ -229,13 +233,14 @@ pub fn compile_pipelines_system(
|
|||
// // TODO: clean up old pipelines
|
||||
// Some(*handle)
|
||||
// }
|
||||
// AssetEvent::Removed { handle } => {
|
||||
// AssetEvent::Removed { .. } => {
|
||||
// // TODO: clean up old pipelines
|
||||
// None
|
||||
// }
|
||||
// };
|
||||
|
||||
// if let Some(handle_to_compile) = handle_to_compile {
|
||||
// // TODO: try updating specialization here.
|
||||
// pipeline_compiler.compile_pipeline(
|
||||
// render_resource_context,
|
||||
// &mut pipelines,
|
||||
|
@ -243,7 +248,6 @@ pub fn compile_pipelines_system(
|
|||
// handle_to_compile,
|
||||
// &vertex_buffer_descriptors,
|
||||
// &default_specialization,
|
||||
// None,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -21,6 +21,14 @@ impl RenderPipeline {
|
|||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn specialized(pipeline: Handle<PipelineDescriptor>, specialization: PipelineSpecialization) -> Self {
|
||||
RenderPipeline {
|
||||
pipeline,
|
||||
specialization,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties)]
|
||||
|
@ -31,6 +39,13 @@ pub struct RenderPipelines {
|
|||
}
|
||||
|
||||
impl RenderPipelines {
|
||||
pub fn from_pipelines(pipelines: Vec<RenderPipeline>) -> Self {
|
||||
Self {
|
||||
pipelines,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_handles<'a, T: IntoIterator<Item = &'a Handle<PipelineDescriptor>>>(
|
||||
handles: T,
|
||||
) -> Self {
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
};
|
||||
use bevy_app::EntityArchetype;
|
||||
use bevy_asset::Handle;
|
||||
use bevy_render::{draw::Draw, mesh::Mesh, pipeline::RenderPipelines};
|
||||
use bevy_render::{draw::Draw, mesh::Mesh, pipeline::{PipelineSpecialization, RenderPipelines, RenderPipeline, DynamicBinding}};
|
||||
|
||||
#[derive(EntityArchetype)]
|
||||
pub struct SpriteEntity {
|
||||
|
@ -19,12 +19,12 @@ pub struct SpriteEntity {
|
|||
impl Default for SpriteEntity {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mesh: QUAD_HANDLE,
|
||||
render_pipelines: RenderPipelines::from_handles(&[SPRITE_PIPELINE_HANDLE]),
|
||||
sprite: Default::default(),
|
||||
quad: Default::default(),
|
||||
mesh: QUAD_HANDLE,
|
||||
material: Default::default(),
|
||||
draw: Default::default(),
|
||||
render_pipelines: RenderPipelines::from_handles(&[SPRITE_PIPELINE_HANDLE]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,11 +45,23 @@ pub struct SpriteSheetEntity {
|
|||
impl Default for SpriteSheetEntity {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
|
||||
SPRITE_SHEET_PIPELINE_HANDLE,
|
||||
PipelineSpecialization {
|
||||
dynamic_bindings: vec![
|
||||
// TextureAtlasSprite
|
||||
DynamicBinding {
|
||||
bind_group: 2,
|
||||
binding: 0,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
)]),
|
||||
mesh: QUAD_HANDLE,
|
||||
sprite: Default::default(),
|
||||
texture_atlas: Default::default(),
|
||||
draw: Default::default(),
|
||||
render_pipelines: RenderPipelines::from_handles(&[SPRITE_SHEET_PIPELINE_HANDLE]),
|
||||
mesh: QUAD_HANDLE,
|
||||
// transform: Default::default(),
|
||||
// translation: Default::default(),
|
||||
// rotation: Default::default(),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_render::base_render_graph;
|
||||
use bevy_render::{pipeline::{PipelineSpecialization, RenderPipeline, DynamicBinding}, base_render_graph};
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
|
@ -78,7 +78,25 @@ fn setup(
|
|||
// cube
|
||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||
mesh: cube_handle,
|
||||
render_pipelines: RenderPipelines::from_handles(&[pipeline_handle]),
|
||||
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
|
||||
pipeline_handle,
|
||||
// NOTE: in the future you wont need to manually declare dynamic bindings
|
||||
PipelineSpecialization {
|
||||
dynamic_bindings: vec![
|
||||
// Transform
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 0,
|
||||
},
|
||||
// MyMaterial_color
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 1,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
)]),
|
||||
material,
|
||||
translation: Translation::new(0.0, 0.0, 0.0),
|
||||
..Default::default()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::{prelude::*, render::shader};
|
||||
use bevy_render::base_render_graph;
|
||||
use bevy_render::{pipeline::{PipelineSpecialization, RenderPipeline, DynamicBinding}, base_render_graph};
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
|
@ -18,7 +18,7 @@ struct MyMaterial {
|
|||
pub color: Color,
|
||||
#[render_resources(ignore)]
|
||||
#[shader_def]
|
||||
pub always_red: bool,
|
||||
pub always_blue: bool,
|
||||
}
|
||||
|
||||
const VERTEX_SHADER: &str = r#"
|
||||
|
@ -44,8 +44,8 @@ layout(set = 1, binding = 1) uniform MyMaterial_color {
|
|||
void main() {
|
||||
o_Target = color;
|
||||
|
||||
# ifdef MYMATERIAL_ALWAYS_RED
|
||||
o_Target = vec4(0.8, 0.0, 0.0, 1.0);
|
||||
# ifdef MYMATERIAL_ALWAYS_BLUE
|
||||
o_Target = vec4(0.0, 0.0, 0.8, 1.0);
|
||||
# endif
|
||||
}
|
||||
"#;
|
||||
|
@ -78,13 +78,13 @@ fn setup(
|
|||
// Create a green material
|
||||
let green_material = materials.add(MyMaterial {
|
||||
color: Color::rgb(0.0, 0.8, 0.0),
|
||||
always_red: false,
|
||||
always_blue: false,
|
||||
});
|
||||
|
||||
// Create a red material, which uses our "always_red" shader def
|
||||
// Create a blue material, which uses our "always_blue" shader def
|
||||
let red_material = materials.add(MyMaterial {
|
||||
color: Color::rgb(0.0, 0.0, 0.0),
|
||||
always_red: true,
|
||||
always_blue: true,
|
||||
});
|
||||
|
||||
// Create a cube mesh which will use our materials
|
||||
|
@ -95,7 +95,25 @@ fn setup(
|
|||
// cube
|
||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||
mesh: cube_handle,
|
||||
render_pipelines: RenderPipelines::from_handles(&[pipeline_handle]),
|
||||
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
|
||||
pipeline_handle,
|
||||
// NOTE: in the future you wont need to manually declare dynamic bindings
|
||||
PipelineSpecialization {
|
||||
dynamic_bindings: vec![
|
||||
// Transform
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 0,
|
||||
},
|
||||
// MyMaterial_color
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 1,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
)]),
|
||||
material: green_material,
|
||||
translation: Translation::new(-2.0, 0.0, 0.0),
|
||||
..Default::default()
|
||||
|
@ -103,7 +121,25 @@ fn setup(
|
|||
// cube
|
||||
.add_entity(MeshMaterialEntity::<MyMaterial> {
|
||||
mesh: cube_handle,
|
||||
render_pipelines: RenderPipelines::from_handles(&[pipeline_handle]),
|
||||
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
|
||||
pipeline_handle,
|
||||
// NOTE: in the future you wont need to manually declare dynamic bindings
|
||||
PipelineSpecialization {
|
||||
dynamic_bindings: vec![
|
||||
// Transform
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 0,
|
||||
},
|
||||
// MyMaterial_color
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 1,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
)]),
|
||||
material: red_material,
|
||||
translation: Translation::new(2.0, 0.0, 0.0),
|
||||
..Default::default()
|
||||
|
|
Loading…
Reference in a new issue