EntityRenderCommand and PhaseItemRenderCommand (#3111)

Adds new `EntityRenderCommand`, `EntityPhaseItem`, and `CachedPipelinePhaseItem` traits to make it possible to reuse RenderCommands across phases. This should be helpful for features like #3072 . It also makes the trait impls slightly less generic-ey in the common cases.

This also fixes the custom shader examples to account for the recent Frustum Culling and MSAA changes (the UX for these things will be improved later).
This commit is contained in:
Carter Anderson 2021-11-12 22:27:17 +00:00
parent 290b7dd9ab
commit 9a4cc42b38
8 changed files with 184 additions and 150 deletions

View File

@ -11,7 +11,7 @@ var<uniform> view: View;
struct Mesh { struct Mesh {
transform: mat4x4<f32>; transform: mat4x4<f32>;
}; };
[[group(2), binding(0)]] [[group(1), binding(0)]]
var<uniform> mesh: Mesh; var<uniform> mesh: Mesh;
struct Vertex { struct Vertex {
@ -37,7 +37,7 @@ fn vertex(vertex: Vertex) -> VertexOutput {
struct CustomMaterial { struct CustomMaterial {
color: vec4<f32>; color: vec4<f32>;
}; };
[[group(1), binding(0)]] [[group(2), binding(0)]]
var<uniform> material: CustomMaterial; var<uniform> material: CustomMaterial;
[[stage(fragment)]] [[stage(fragment)]]

View File

@ -1,5 +1,5 @@
use bevy::{ use bevy::{
core_pipeline::{SetItemPipeline, Transparent3d}, core_pipeline::Transparent3d,
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
ecs::{ ecs::{
prelude::*, prelude::*,
@ -19,11 +19,12 @@ use bevy::{
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets}, render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
render_component::ExtractComponentPlugin, render_component::ExtractComponentPlugin,
render_phase::{ render_phase::{
AddRenderCommand, DrawFunctions, RenderCommand, RenderPhase, TrackedRenderPass, AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderPhase, SetItemPipeline,
TrackedRenderPass,
}, },
render_resource::*, render_resource::*,
renderer::RenderDevice, renderer::RenderDevice,
view::ExtractedView, view::{ComputedVisibility, ExtractedView, Msaa, Visibility},
RenderApp, RenderStage, RenderApp, RenderStage,
}, },
PipelinedDefaultPlugins, PipelinedDefaultPlugins,
@ -51,6 +52,8 @@ fn setup(
meshes.add(Mesh::from(shape::Cube { size: 1.0 })), meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
Transform::from_xyz(0.0, 0.5, 0.0), Transform::from_xyz(0.0, 0.5, 0.0),
GlobalTransform::default(), GlobalTransform::default(),
Visibility::default(),
ComputedVisibility::default(),
materials.add(CustomMaterial { materials.add(CustomMaterial {
color: Color::GREEN, color: Color::GREEN,
}), }),
@ -118,21 +121,36 @@ impl Plugin for CustomMaterialPlugin {
app.sub_app(RenderApp) app.sub_app(RenderApp)
.add_render_command::<Transparent3d, DrawCustom>() .add_render_command::<Transparent3d, DrawCustom>()
.init_resource::<CustomPipeline>() .init_resource::<CustomPipeline>()
.init_resource::<SpecializedPipelines<CustomPipeline>>()
.add_system_to_stage(RenderStage::Queue, queue_custom); .add_system_to_stage(RenderStage::Queue, queue_custom);
} }
} }
pub struct CustomPipeline { pub struct CustomPipeline {
material_layout: BindGroupLayout, material_layout: BindGroupLayout,
pipeline: CachedPipelineId, shader: Handle<Shader>,
pbr_pipeline: PbrPipeline,
}
impl SpecializedPipeline for CustomPipeline {
type Key = PbrPipelineKey;
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
let mut descriptor = self.pbr_pipeline.specialize(key);
descriptor.vertex.shader = self.shader.clone();
descriptor.fragment.as_mut().unwrap().shader = self.shader.clone();
descriptor.layout = Some(vec![
self.pbr_pipeline.view_layout.clone(),
self.pbr_pipeline.mesh_layout.clone(),
self.material_layout.clone(),
]);
descriptor
}
} }
impl FromWorld for CustomPipeline { impl FromWorld for CustomPipeline {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let world = world.cell();
let asset_server = world.get_resource::<AssetServer>().unwrap(); let asset_server = world.get_resource::<AssetServer>().unwrap();
let shader = asset_server.load("shaders/custom.wgsl");
let render_device = world.get_resource::<RenderDevice>().unwrap(); let render_device = world.get_resource::<RenderDevice>().unwrap();
let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry { entries: &[BindGroupLayoutEntry {
@ -148,28 +166,22 @@ impl FromWorld for CustomPipeline {
label: None, label: None,
}); });
let pbr_pipeline = world.get_resource::<PbrPipeline>().unwrap();
let mut descriptor = pbr_pipeline.specialize(PbrPipelineKey::empty());
descriptor.vertex.shader = shader.clone();
descriptor.fragment.as_mut().unwrap().shader = shader;
descriptor.layout = Some(vec![
pbr_pipeline.view_layout.clone(),
material_layout.clone(),
pbr_pipeline.mesh_layout.clone(),
]);
let mut pipeline_cache = world.get_resource_mut::<RenderPipelineCache>().unwrap();
CustomPipeline { CustomPipeline {
pipeline: pipeline_cache.queue(descriptor), pbr_pipeline: world.get_resource::<PbrPipeline>().unwrap().clone(),
shader: asset_server.load("shaders/custom.wgsl"),
material_layout, material_layout,
} }
} }
} }
#[allow(clippy::too_many_arguments)]
pub fn queue_custom( pub fn queue_custom(
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>, transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
materials: Res<RenderAssets<CustomMaterial>>, materials: Res<RenderAssets<CustomMaterial>>,
custom_pipeline: Res<CustomPipeline>, custom_pipeline: Res<CustomPipeline>,
mut pipeline_cache: ResMut<RenderPipelineCache>,
mut specialized_pipelines: ResMut<SpecializedPipelines<CustomPipeline>>,
msaa: Res<Msaa>,
material_meshes: Query<(Entity, &Handle<CustomMaterial>, &MeshUniform), With<Handle<Mesh>>>, material_meshes: Query<(Entity, &Handle<CustomMaterial>, &MeshUniform), With<Handle<Mesh>>>,
mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>, mut views: Query<(&ExtractedView, &mut RenderPhase<Transparent3d>)>,
) { ) {
@ -177,6 +189,7 @@ pub fn queue_custom(
.read() .read()
.get_id::<DrawCustom>() .get_id::<DrawCustom>()
.unwrap(); .unwrap();
let key = PbrPipelineKey::from_msaa_samples(msaa.samples);
for (view, mut transparent_phase) in views.iter_mut() { for (view, mut transparent_phase) in views.iter_mut() {
let view_matrix = view.transform.compute_matrix(); let view_matrix = view.transform.compute_matrix();
let view_row_2 = view_matrix.row(2); let view_row_2 = view_matrix.row(2);
@ -184,7 +197,11 @@ pub fn queue_custom(
if materials.contains_key(material_handle) { if materials.contains_key(material_handle) {
transparent_phase.add(Transparent3d { transparent_phase.add(Transparent3d {
entity, entity,
pipeline: custom_pipeline.pipeline, pipeline: specialized_pipelines.specialize(
&mut pipeline_cache,
&custom_pipeline,
key,
),
draw_function: draw_custom, draw_function: draw_custom,
distance: view_row_2.dot(mesh_uniform.transform.col(3)), distance: view_row_2.dot(mesh_uniform.transform.col(3)),
}); });
@ -196,25 +213,25 @@ pub fn queue_custom(
type DrawCustom = ( type DrawCustom = (
SetItemPipeline, SetItemPipeline,
SetMeshViewBindGroup<0>, SetMeshViewBindGroup<0>,
SetTransformBindGroup<1>,
SetCustomMaterialBindGroup, SetCustomMaterialBindGroup,
SetTransformBindGroup<2>,
DrawMesh, DrawMesh,
); );
struct SetCustomMaterialBindGroup; struct SetCustomMaterialBindGroup;
impl RenderCommand<Transparent3d> for SetCustomMaterialBindGroup { impl EntityRenderCommand for SetCustomMaterialBindGroup {
type Param = ( type Param = (
SRes<RenderAssets<CustomMaterial>>, SRes<RenderAssets<CustomMaterial>>,
SQuery<Read<Handle<CustomMaterial>>>, SQuery<Read<Handle<CustomMaterial>>>,
); );
fn render<'w>( fn render<'w>(
_view: Entity, _view: Entity,
item: &Transparent3d, item: Entity,
(materials, query): SystemParamItem<'w, '_, Self::Param>, (materials, query): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) { ) {
let material_handle = query.get(item.entity).unwrap(); let material_handle = query.get(item).unwrap();
let material = materials.into_inner().get(material_handle).unwrap(); let material = materials.into_inner().get(material_handle).unwrap();
pass.set_bind_group(1, &material.bind_group, &[]); pass.set_bind_group(2, &material.bind_group, &[]);
} }
} }

View File

@ -1,5 +1,5 @@
use bevy::{ use bevy::{
core_pipeline::{SetItemPipeline, Transparent3d}, core_pipeline::Transparent3d,
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
ecs::prelude::*, ecs::prelude::*,
math::Vec3, math::Vec3,
@ -12,9 +12,9 @@ use bevy::{
camera::PerspectiveCameraBundle, camera::PerspectiveCameraBundle,
mesh::{shape, Mesh}, mesh::{shape, Mesh},
render_component::{ExtractComponent, ExtractComponentPlugin}, render_component::{ExtractComponent, ExtractComponentPlugin},
render_phase::{AddRenderCommand, DrawFunctions, RenderPhase}, render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline},
render_resource::*, render_resource::*,
view::ExtractedView, view::{ComputedVisibility, ExtractedView, Msaa, Visibility},
RenderApp, RenderStage, RenderApp, RenderStage,
}, },
PipelinedDefaultPlugins, PipelinedDefaultPlugins,
@ -64,6 +64,8 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
IsRed(true), IsRed(true),
Transform::from_xyz(-1.0, 0.5, 0.0), Transform::from_xyz(-1.0, 0.5, 0.0),
GlobalTransform::default(), GlobalTransform::default(),
Visibility::default(),
ComputedVisibility::default(),
)); ));
// blue cube // blue cube
@ -72,6 +74,8 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
IsRed(false), IsRed(false),
Transform::from_xyz(1.0, 0.5, 0.0), Transform::from_xyz(1.0, 0.5, 0.0),
GlobalTransform::default(), GlobalTransform::default(),
Visibility::default(),
ComputedVisibility::default(),
)); ));
// camera // camera
@ -99,14 +103,14 @@ impl FromWorld for IsRedPipeline {
} }
impl SpecializedPipeline for IsRedPipeline { impl SpecializedPipeline for IsRedPipeline {
type Key = IsRed; type Key = (IsRed, PbrPipelineKey);
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { fn specialize(&self, (is_red, pbr_pipeline_key): Self::Key) -> RenderPipelineDescriptor {
let mut shader_defs = Vec::new(); let mut shader_defs = Vec::new();
if key.0 { if is_red.0 {
shader_defs.push("IS_RED".to_string()); shader_defs.push("IS_RED".to_string());
} }
let mut descriptor = self.pbr_pipeline.specialize(PbrPipelineKey::empty()); let mut descriptor = self.pbr_pipeline.specialize(pbr_pipeline_key);
descriptor.vertex.shader = self.shader.clone(); descriptor.vertex.shader = self.shader.clone();
descriptor.vertex.shader_defs = shader_defs.clone(); descriptor.vertex.shader_defs = shader_defs.clone();
let fragment = descriptor.fragment.as_mut().unwrap(); let fragment = descriptor.fragment.as_mut().unwrap();
@ -130,6 +134,7 @@ type DrawIsRed = (
fn queue_custom( fn queue_custom(
transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>, transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
custom_pipeline: Res<IsRedPipeline>, custom_pipeline: Res<IsRedPipeline>,
msaa: Res<Msaa>,
mut pipelines: ResMut<SpecializedPipelines<IsRedPipeline>>, mut pipelines: ResMut<SpecializedPipelines<IsRedPipeline>>,
mut pipeline_cache: ResMut<RenderPipelineCache>, mut pipeline_cache: ResMut<RenderPipelineCache>,
material_meshes: Query<(Entity, &MeshUniform, &IsRed), With<Handle<Mesh>>>, material_meshes: Query<(Entity, &MeshUniform, &IsRed), With<Handle<Mesh>>>,
@ -139,11 +144,13 @@ fn queue_custom(
.read() .read()
.get_id::<DrawIsRed>() .get_id::<DrawIsRed>()
.unwrap(); .unwrap();
let key = PbrPipelineKey::from_msaa_samples(msaa.samples);
for (view, mut transparent_phase) in views.iter_mut() { for (view, mut transparent_phase) in views.iter_mut() {
let view_matrix = view.transform.compute_matrix(); let view_matrix = view.transform.compute_matrix();
let view_row_2 = view_matrix.row(2); let view_row_2 = view_matrix.row(2);
for (entity, mesh_uniform, is_red) in material_meshes.iter() { for (entity, mesh_uniform, is_red) in material_meshes.iter() {
let pipeline = pipelines.specialize(&mut pipeline_cache, &custom_pipeline, *is_red); let pipeline =
pipelines.specialize(&mut pipeline_cache, &custom_pipeline, (*is_red, key));
transparent_phase.add(Transparent3d { transparent_phase.add(Transparent3d {
entity, entity,
pipeline, pipeline,

View File

@ -8,17 +8,14 @@ pub use main_pass_driver::*;
use bevy_app::{App, Plugin}; use bevy_app::{App, Plugin};
use bevy_core::FloatOrd; use bevy_core::FloatOrd;
use bevy_ecs::{ use bevy_ecs::prelude::*;
prelude::*,
system::{lifetimeless::SRes, SystemParamItem},
};
use bevy_render2::{ use bevy_render2::{
camera::{ActiveCameras, CameraPlugin}, camera::{ActiveCameras, CameraPlugin},
color::Color, color::Color,
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType}, render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
render_phase::{ render_phase::{
sort_phase_system, DrawFunctionId, DrawFunctions, PhaseItem, RenderCommand, RenderPhase, sort_phase_system, CachedPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem,
TrackedRenderPass, PhaseItem, RenderPhase,
}, },
render_resource::*, render_resource::*,
renderer::RenderDevice, renderer::RenderDevice,
@ -171,38 +168,17 @@ impl PhaseItem for Transparent3d {
} }
} }
pub struct SetItemPipeline; impl EntityPhaseItem for Transparent3d {
impl RenderCommand<Transparent3d> for SetItemPipeline {
type Param = SRes<RenderPipelineCache>;
#[inline] #[inline]
fn render<'w>( fn entity(&self) -> Entity {
_view: Entity, self.entity
item: &Transparent3d,
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) {
let pipeline = pipeline_cache
.into_inner()
.get_state(item.pipeline)
.unwrap();
pass.set_render_pipeline(pipeline);
} }
} }
impl RenderCommand<Transparent2d> for SetItemPipeline { impl CachedPipelinePhaseItem for Transparent3d {
type Param = SRes<RenderPipelineCache>;
#[inline] #[inline]
fn render<'w>( fn cached_pipeline(&self) -> CachedPipelineId {
_view: Entity, self.pipeline
item: &Transparent2d,
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) {
let pipeline = pipeline_cache
.into_inner()
.get_state(item.pipeline)
.unwrap();
pass.set_render_pipeline(pipeline);
} }
} }

View File

@ -108,15 +108,10 @@ impl Plugin for PbrPlugin {
.init_resource::<SpecializedPipelines<PbrPipeline>>() .init_resource::<SpecializedPipelines<PbrPipeline>>()
.init_resource::<SpecializedPipelines<ShadowPipeline>>(); .init_resource::<SpecializedPipelines<ShadowPipeline>>();
let draw_shadow_mesh = DrawShadowMesh::new(&mut render_app.world);
let shadow_pass_node = ShadowPassNode::new(&mut render_app.world); let shadow_pass_node = ShadowPassNode::new(&mut render_app.world);
render_app.add_render_command::<Transparent3d, DrawPbr>(); render_app.add_render_command::<Transparent3d, DrawPbr>();
let render_world = render_app.world.cell(); render_app.add_render_command::<Shadow, DrawShadowMesh>();
let draw_functions = render_world let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap();
.get_resource::<DrawFunctions<Shadow>>()
.unwrap();
draw_functions.write().add(draw_shadow_mesh);
let mut graph = render_world.get_resource_mut::<RenderGraph>().unwrap();
let draw_3d_graph = graph let draw_3d_graph = graph
.get_sub_graph_mut(bevy_core_pipeline::draw_3d_graph::NAME) .get_sub_graph_mut(bevy_core_pipeline::draw_3d_graph::NAME)
.unwrap(); .unwrap();

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
AmbientLight, CubemapVisibleEntities, DirectionalLight, DirectionalLightShadowMap, MeshUniform, AmbientLight, CubemapVisibleEntities, DirectionalLight, DirectionalLightShadowMap, DrawMesh,
NotShadowCaster, PbrPipeline, PointLight, PointLightShadowMap, TransformBindGroup, NotShadowCaster, PbrPipeline, PointLight, PointLightShadowMap, SetTransformBindGroup,
SHADOW_SHADER_HANDLE, SHADOW_SHADER_HANDLE,
}; };
use bevy_asset::Handle; use bevy_asset::Handle;
@ -8,7 +8,7 @@ use bevy_core::FloatOrd;
use bevy_core_pipeline::Transparent3d; use bevy_core_pipeline::Transparent3d;
use bevy_ecs::{ use bevy_ecs::{
prelude::*, prelude::*,
system::{lifetimeless::*, SystemState}, system::{lifetimeless::*, SystemParamItem},
}; };
use bevy_math::{const_vec3, Mat4, Vec3, Vec4}; use bevy_math::{const_vec3, Mat4, Vec3, Vec4};
use bevy_render2::{ use bevy_render2::{
@ -16,10 +16,10 @@ use bevy_render2::{
color::Color, color::Color,
mesh::Mesh, mesh::Mesh,
render_asset::RenderAssets, render_asset::RenderAssets,
render_component::DynamicUniformIndex,
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
render_phase::{ render_phase::{
Draw, DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase, TrackedRenderPass, CachedPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem,
EntityRenderCommand, PhaseItem, RenderPhase, SetItemPipeline, TrackedRenderPass,
}, },
render_resource::*, render_resource::*,
renderer::{RenderContext, RenderDevice, RenderQueue}, renderer::{RenderContext, RenderDevice, RenderQueue},
@ -796,6 +796,19 @@ impl PhaseItem for Shadow {
} }
} }
impl EntityPhaseItem for Shadow {
fn entity(&self) -> Entity {
self.entity
}
}
impl CachedPipelinePhaseItem for Shadow {
#[inline]
fn cached_pipeline(&self) -> CachedPipelineId {
self.pipeline
}
}
pub struct ShadowPassNode { pub struct ShadowPassNode {
main_view_query: QueryState<&'static ViewLights>, main_view_query: QueryState<&'static ViewLights>,
view_light_query: QueryState<(&'static ViewLight, &'static RenderPhase<Shadow>)>, view_light_query: QueryState<(&'static ViewLight, &'static RenderPhase<Shadow>)>,
@ -865,63 +878,32 @@ impl Node for ShadowPassNode {
} }
} }
pub struct DrawShadowMesh { pub type DrawShadowMesh = (
params: SystemState<( SetItemPipeline,
SRes<RenderPipelineCache>, SetShadowViewBindGroup<0>,
SRes<LightMeta>, SetTransformBindGroup<1>,
SRes<TransformBindGroup>, DrawMesh,
SRes<RenderAssets<Mesh>>, );
SQuery<(Read<DynamicUniformIndex<MeshUniform>>, Read<Handle<Mesh>>)>,
SQuery<Read<ViewUniformOffset>>,
)>,
}
impl DrawShadowMesh { pub struct SetShadowViewBindGroup<const I: usize>;
pub fn new(world: &mut World) -> Self { impl<const I: usize> EntityRenderCommand for SetShadowViewBindGroup<I> {
Self { type Param = (SRes<LightMeta>, SQuery<Read<ViewUniformOffset>>);
params: SystemState::new(world), #[inline]
} fn render<'w>(
}
}
impl Draw<Shadow> for DrawShadowMesh {
fn draw<'w>(
&mut self,
world: &'w World,
pass: &mut TrackedRenderPass<'w>,
view: Entity, view: Entity,
item: &Shadow, _item: Entity,
(light_meta, view_query): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) { ) {
let (pipeline_cache, light_meta, transform_bind_group, meshes, items, views) = let view_uniform_offset = view_query.get(view).unwrap();
self.params.get(world); pass.set_bind_group(
let (transform_index, mesh_handle) = items.get(item.entity).unwrap(); I,
let view_uniform_offset = views.get(view).unwrap(); light_meta
if let Some(pipeline) = pipeline_cache.into_inner().get(item.pipeline) { .into_inner()
pass.set_render_pipeline(pipeline); .shadow_view_bind_group
pass.set_bind_group( .as_ref()
0, .unwrap(),
light_meta &[view_uniform_offset.offset],
.into_inner() );
.shadow_view_bind_group
.as_ref()
.unwrap(),
&[view_uniform_offset.offset],
);
pass.set_bind_group(
1,
&transform_bind_group.into_inner().value,
&[transform_index.index()],
);
let gpu_mesh = meshes.into_inner().get(mesh_handle).unwrap();
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
if let Some(index_info) = &gpu_mesh.index_info {
pass.set_index_buffer(index_info.buffer.slice(..), 0, index_info.index_format);
pass.draw_indexed(0..index_info.count, 0, 0..1);
} else {
panic!("non-indexed drawing not supported yet")
}
}
} }
} }

View File

@ -7,7 +7,7 @@ use crate::{
PBR_SHADER_HANDLE, PBR_SHADER_HANDLE,
}; };
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_core_pipeline::{SetItemPipeline, Transparent3d}; use bevy_core_pipeline::Transparent3d;
use bevy_ecs::{ use bevy_ecs::{
prelude::*, prelude::*,
system::{lifetimeless::*, SystemParamItem}, system::{lifetimeless::*, SystemParamItem},
@ -17,7 +17,9 @@ use bevy_render2::{
mesh::Mesh, mesh::Mesh,
render_asset::RenderAssets, render_asset::RenderAssets,
render_component::{ComponentUniforms, DynamicUniformIndex}, render_component::{ComponentUniforms, DynamicUniformIndex},
render_phase::{DrawFunctions, RenderCommand, RenderPhase, TrackedRenderPass}, render_phase::{
DrawFunctions, EntityRenderCommand, RenderPhase, SetItemPipeline, TrackedRenderPass,
},
render_resource::*, render_resource::*,
renderer::{RenderDevice, RenderQueue}, renderer::{RenderDevice, RenderQueue},
texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo}, texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo},
@ -734,7 +736,7 @@ pub type DrawPbr = (
); );
pub struct SetMeshViewBindGroup<const I: usize>; pub struct SetMeshViewBindGroup<const I: usize>;
impl<const I: usize> RenderCommand<Transparent3d> for SetMeshViewBindGroup<I> { impl<const I: usize> EntityRenderCommand for SetMeshViewBindGroup<I> {
type Param = SQuery<( type Param = SQuery<(
Read<ViewUniformOffset>, Read<ViewUniformOffset>,
Read<ViewLights>, Read<ViewLights>,
@ -743,7 +745,7 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetMeshViewBindGroup<I> {
#[inline] #[inline]
fn render<'w>( fn render<'w>(
view: Entity, view: Entity,
_item: &Transparent3d, _item: Entity,
view_query: SystemParamItem<'w, '_, Self::Param>, view_query: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) { ) {
@ -757,7 +759,7 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetMeshViewBindGroup<I> {
} }
pub struct SetTransformBindGroup<const I: usize>; pub struct SetTransformBindGroup<const I: usize>;
impl<const I: usize> RenderCommand<Transparent3d> for SetTransformBindGroup<I> { impl<const I: usize> EntityRenderCommand for SetTransformBindGroup<I> {
type Param = ( type Param = (
SRes<TransformBindGroup>, SRes<TransformBindGroup>,
SQuery<Read<DynamicUniformIndex<MeshUniform>>>, SQuery<Read<DynamicUniformIndex<MeshUniform>>>,
@ -765,11 +767,11 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetTransformBindGroup<I> {
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _view: Entity,
item: &Transparent3d, item: Entity,
(transform_bind_group, mesh_query): SystemParamItem<'w, '_, Self::Param>, (transform_bind_group, mesh_query): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) { ) {
let transform_index = mesh_query.get(item.entity).unwrap(); let transform_index = mesh_query.get(item).unwrap();
pass.set_bind_group( pass.set_bind_group(
I, I,
&transform_bind_group.into_inner().value, &transform_bind_group.into_inner().value,
@ -779,7 +781,7 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetTransformBindGroup<I> {
} }
pub struct SetStandardMaterialBindGroup<const I: usize>; pub struct SetStandardMaterialBindGroup<const I: usize>;
impl<const I: usize> RenderCommand<Transparent3d> for SetStandardMaterialBindGroup<I> { impl<const I: usize> EntityRenderCommand for SetStandardMaterialBindGroup<I> {
type Param = ( type Param = (
SRes<RenderAssets<StandardMaterial>>, SRes<RenderAssets<StandardMaterial>>,
SQuery<Read<Handle<StandardMaterial>>>, SQuery<Read<Handle<StandardMaterial>>>,
@ -787,11 +789,11 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetStandardMaterialBindGro
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _view: Entity,
item: &Transparent3d, item: Entity,
(materials, handle_query): SystemParamItem<'w, '_, Self::Param>, (materials, handle_query): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) { ) {
let handle = handle_query.get(item.entity).unwrap(); let handle = handle_query.get(item).unwrap();
let materials = materials.into_inner(); let materials = materials.into_inner();
let material = materials.get(handle).unwrap(); let material = materials.get(handle).unwrap();
@ -800,16 +802,16 @@ impl<const I: usize> RenderCommand<Transparent3d> for SetStandardMaterialBindGro
} }
pub struct DrawMesh; pub struct DrawMesh;
impl RenderCommand<Transparent3d> for DrawMesh { impl EntityRenderCommand for DrawMesh {
type Param = (SRes<RenderAssets<Mesh>>, SQuery<Read<Handle<Mesh>>>); type Param = (SRes<RenderAssets<Mesh>>, SQuery<Read<Handle<Mesh>>>);
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _view: Entity,
item: &Transparent3d, item: Entity,
(meshes, mesh_query): SystemParamItem<'w, '_, Self::Param>, (meshes, mesh_query): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) { ) {
let mesh_handle = mesh_query.get(item.entity).unwrap(); let mesh_handle = mesh_query.get(item).unwrap();
let gpu_mesh = meshes.into_inner().get(mesh_handle).unwrap(); let gpu_mesh = meshes.into_inner().get(mesh_handle).unwrap();
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..)); pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
if let Some(index_info) = &gpu_mesh.index_info { if let Some(index_info) = &gpu_mesh.index_info {

View File

@ -1,9 +1,14 @@
use crate::render_phase::TrackedRenderPass; use crate::{
render_phase::TrackedRenderPass,
render_resource::{CachedPipelineId, RenderPipelineCache},
};
use bevy_app::App; use bevy_app::App;
use bevy_ecs::{ use bevy_ecs::{
all_tuples, all_tuples,
entity::Entity, entity::Entity,
system::{ReadOnlySystemParamFetch, SystemParam, SystemParamItem, SystemState}, system::{
lifetimeless::SRes, ReadOnlySystemParamFetch, SystemParam, SystemParamItem, SystemState,
},
world::World, world::World,
}; };
use bevy_utils::HashMap; use bevy_utils::HashMap;
@ -90,6 +95,56 @@ pub trait RenderCommand<P: PhaseItem> {
); );
} }
pub trait EntityRenderCommand {
type Param: SystemParam;
fn render<'w>(
view: Entity,
item: Entity,
param: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
);
}
pub trait EntityPhaseItem: PhaseItem {
fn entity(&self) -> Entity;
}
pub trait CachedPipelinePhaseItem: PhaseItem {
fn cached_pipeline(&self) -> CachedPipelineId;
}
impl<P: EntityPhaseItem, E: EntityRenderCommand> RenderCommand<P> for E {
type Param = E::Param;
#[inline]
fn render<'w>(
view: Entity,
item: &P,
param: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) {
<E as EntityRenderCommand>::render(view, item.entity(), param, pass);
}
}
pub struct SetItemPipeline;
impl<P: CachedPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
type Param = SRes<RenderPipelineCache>;
#[inline]
fn render<'w>(
_view: Entity,
item: &P,
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) {
let pipeline = pipeline_cache
.into_inner()
.get_state(item.cached_pipeline())
.unwrap();
pass.set_render_pipeline(pipeline);
}
}
macro_rules! render_command_tuple_impl { macro_rules! render_command_tuple_impl {
($($name: ident),*) => { ($($name: ident),*) => {
impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) { impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) {