Flatten render commands (#6885)

# Objective
Speed up the render phase of rendering. Simplify the trait structure for render commands.

## Solution

 - Merge `EntityPhaseItem` into `PhaseItem` (`EntityPhaseItem::entity` -> `PhaseItem::entity`)
 - Merge `EntityRenderCommand` into `RenderCommand`.
 - Add two associated types to `RenderCommand`: `RenderCommand::ViewWorldQuery` and `RenderCommand::WorldQuery`.
 - Use the new associated types to construct two `QueryStates`s for `RenderCommandState`.
 - Hoist any `SQuery<T>` fetches in `EntityRenderCommand`s into the aformentioned two queries. Batch fetch them all at once.

## Performance
`main_opaque_pass_3d` is slightly faster on `many_foxes` (427.52us -> 401.15us)

![image](https://user-images.githubusercontent.com/3137680/206359804-9928b20a-7d92-41f8-bf7d-6e8c5cc802f0.png)

The shadow pass node is also slightly faster (344.52 -> 338.24us)

![image](https://user-images.githubusercontent.com/3137680/206359977-1212198d-f933-49a0-80f1-62ff88eb5727.png)

## Future Work

 - Can we hoist the view level queries out of the core loop?

---

## Changelog
Added: `PhaseItem::entity`
Added: `RenderCommand::ViewWorldQuery` associated type.
Added: `RenderCommand::ItemorldQuery` associated type.
Added: `Draw<T>::prepare` optional trait function.
Removed: `EntityPhaseItem` trait

## Migration Guide
TODO
This commit is contained in:
James Liu 2023-01-04 01:13:30 +00:00
parent f866d72f15
commit 2d727afaf7
12 changed files with 242 additions and 217 deletions

View File

@ -27,7 +27,7 @@ use bevy_render::{
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType}, render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
render_phase::{ render_phase::{
batch_phase_system, sort_phase_system, BatchedPhaseItem, CachedRenderPipelinePhaseItem, batch_phase_system, sort_phase_system, BatchedPhaseItem, CachedRenderPipelinePhaseItem,
DrawFunctionId, DrawFunctions, EntityPhaseItem, PhaseItem, RenderPhase, DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase,
}, },
render_resource::CachedRenderPipelineId, render_resource::CachedRenderPipelineId,
Extract, RenderApp, RenderStage, Extract, RenderApp, RenderStage,
@ -115,6 +115,11 @@ pub struct Transparent2d {
impl PhaseItem for Transparent2d { impl PhaseItem for Transparent2d {
type SortKey = FloatOrd; type SortKey = FloatOrd;
#[inline]
fn entity(&self) -> Entity {
self.entity
}
#[inline] #[inline]
fn sort_key(&self) -> Self::SortKey { fn sort_key(&self) -> Self::SortKey {
self.sort_key self.sort_key
@ -131,13 +136,6 @@ impl PhaseItem for Transparent2d {
} }
} }
impl EntityPhaseItem for Transparent2d {
#[inline]
fn entity(&self) -> Entity {
self.entity
}
}
impl CachedRenderPipelinePhaseItem for Transparent2d { impl CachedRenderPipelinePhaseItem for Transparent2d {
#[inline] #[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId { fn cached_pipeline(&self) -> CachedRenderPipelineId {

View File

@ -29,8 +29,8 @@ use bevy_render::{
prelude::Msaa, prelude::Msaa,
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType}, render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
render_phase::{ render_phase::{
sort_phase_system, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, sort_phase_system, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, PhaseItem,
EntityPhaseItem, PhaseItem, RenderPhase, RenderPhase,
}, },
render_resource::{ render_resource::{
CachedRenderPipelineId, Extent3d, TextureDescriptor, TextureDimension, TextureFormat, CachedRenderPipelineId, Extent3d, TextureDescriptor, TextureDimension, TextureFormat,
@ -124,6 +124,11 @@ impl PhaseItem for Opaque3d {
// NOTE: Values increase towards the camera. Front-to-back ordering for opaque means we need a descending sort. // NOTE: Values increase towards the camera. Front-to-back ordering for opaque means we need a descending sort.
type SortKey = Reverse<FloatOrd>; type SortKey = Reverse<FloatOrd>;
#[inline]
fn entity(&self) -> Entity {
self.entity
}
#[inline] #[inline]
fn sort_key(&self) -> Self::SortKey { fn sort_key(&self) -> Self::SortKey {
Reverse(FloatOrd(self.distance)) Reverse(FloatOrd(self.distance))
@ -141,13 +146,6 @@ impl PhaseItem for Opaque3d {
} }
} }
impl EntityPhaseItem for Opaque3d {
#[inline]
fn entity(&self) -> Entity {
self.entity
}
}
impl CachedRenderPipelinePhaseItem for Opaque3d { impl CachedRenderPipelinePhaseItem for Opaque3d {
#[inline] #[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId { fn cached_pipeline(&self) -> CachedRenderPipelineId {
@ -166,6 +164,11 @@ impl PhaseItem for AlphaMask3d {
// NOTE: Values increase towards the camera. Front-to-back ordering for alpha mask means we need a descending sort. // NOTE: Values increase towards the camera. Front-to-back ordering for alpha mask means we need a descending sort.
type SortKey = Reverse<FloatOrd>; type SortKey = Reverse<FloatOrd>;
#[inline]
fn entity(&self) -> Entity {
self.entity
}
#[inline] #[inline]
fn sort_key(&self) -> Self::SortKey { fn sort_key(&self) -> Self::SortKey {
Reverse(FloatOrd(self.distance)) Reverse(FloatOrd(self.distance))
@ -183,13 +186,6 @@ impl PhaseItem for AlphaMask3d {
} }
} }
impl EntityPhaseItem for AlphaMask3d {
#[inline]
fn entity(&self) -> Entity {
self.entity
}
}
impl CachedRenderPipelinePhaseItem for AlphaMask3d { impl CachedRenderPipelinePhaseItem for AlphaMask3d {
#[inline] #[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId { fn cached_pipeline(&self) -> CachedRenderPipelineId {
@ -208,6 +204,11 @@ impl PhaseItem for Transparent3d {
// NOTE: Values increase towards the camera. Back-to-front ordering for transparent means we need an ascending sort. // NOTE: Values increase towards the camera. Back-to-front ordering for transparent means we need an ascending sort.
type SortKey = FloatOrd; type SortKey = FloatOrd;
#[inline]
fn entity(&self) -> Entity {
self.entity
}
#[inline] #[inline]
fn sort_key(&self) -> Self::SortKey { fn sort_key(&self) -> Self::SortKey {
FloatOrd(self.distance) FloatOrd(self.distance)
@ -224,13 +225,6 @@ impl PhaseItem for Transparent3d {
} }
} }
impl EntityPhaseItem for Transparent3d {
#[inline]
fn entity(&self) -> Entity {
self.entity
}
}
impl CachedRenderPipelinePhaseItem for Transparent3d { impl CachedRenderPipelinePhaseItem for Transparent3d {
#[inline] #[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId { fn cached_pipeline(&self) -> CachedRenderPipelineId {

View File

@ -10,12 +10,11 @@ use bevy_core_pipeline::{
}; };
use bevy_derive::{Deref, DerefMut}; use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{ use bevy_ecs::{
entity::Entity,
event::EventReader, event::EventReader,
prelude::World, prelude::World,
schedule::IntoSystemDescriptor, schedule::IntoSystemDescriptor,
system::{ system::{
lifetimeless::{Read, SQuery, SRes}, lifetimeless::{Read, SRes},
Commands, Local, Query, Res, ResMut, Resource, SystemParamItem, Commands, Local, Query, Res, ResMut, Resource, SystemParamItem,
}, },
world::FromWorld, world::FromWorld,
@ -27,8 +26,8 @@ use bevy_render::{
prelude::Image, prelude::Image,
render_asset::{PrepareAssetLabel, RenderAssets}, render_asset::{PrepareAssetLabel, RenderAssets},
render_phase::{ render_phase::{
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase, AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
SetItemPipeline, TrackedRenderPass, RenderPhase, SetItemPipeline, TrackedRenderPass,
}, },
render_resource::{ render_resource::{
AsBindGroup, AsBindGroupError, BindGroup, BindGroupLayout, OwnedBindingResource, AsBindGroup, AsBindGroupError, BindGroup, BindGroupLayout, OwnedBindingResource,
@ -296,15 +295,19 @@ type DrawMaterial<M> = (
/// Sets the bind group for a given [`Material`] at the configured `I` index. /// Sets the bind group for a given [`Material`] at the configured `I` index.
pub struct SetMaterialBindGroup<M: Material, const I: usize>(PhantomData<M>); pub struct SetMaterialBindGroup<M: Material, const I: usize>(PhantomData<M>);
impl<M: Material, const I: usize> EntityRenderCommand for SetMaterialBindGroup<M, I> { impl<P: PhaseItem, M: Material, const I: usize> RenderCommand<P> for SetMaterialBindGroup<M, I> {
type Param = (SRes<RenderMaterials<M>>, SQuery<Read<Handle<M>>>); type Param = SRes<RenderMaterials<M>>;
type ViewWorldQuery = ();
type ItemWorldQuery = Read<Handle<M>>;
#[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(materials, query): SystemParamItem<'w, '_, Self::Param>, material_handle: &'_ Handle<M>,
materials: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
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(I, &material.bind_group, &[]); pass.set_bind_group(I, &material.bind_group, &[]);
RenderCommandResult::Success RenderCommandResult::Success

View File

@ -18,9 +18,8 @@ use bevy_render::{
render_asset::RenderAssets, render_asset::RenderAssets,
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
render_phase::{ render_phase::{
CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, PhaseItem, RenderCommand,
EntityRenderCommand, PhaseItem, RenderCommandResult, RenderPhase, SetItemPipeline, RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass,
TrackedRenderPass,
}, },
render_resource::*, render_resource::*,
renderer::{RenderContext, RenderDevice, RenderQueue}, renderer::{RenderContext, RenderDevice, RenderQueue},
@ -1699,6 +1698,11 @@ pub struct Shadow {
impl PhaseItem for Shadow { impl PhaseItem for Shadow {
type SortKey = FloatOrd; type SortKey = FloatOrd;
#[inline]
fn entity(&self) -> Entity {
self.entity
}
#[inline] #[inline]
fn sort_key(&self) -> Self::SortKey { fn sort_key(&self) -> Self::SortKey {
FloatOrd(self.distance) FloatOrd(self.distance)
@ -1715,12 +1719,6 @@ impl PhaseItem for Shadow {
} }
} }
impl EntityPhaseItem for Shadow {
fn entity(&self) -> Entity {
self.entity
}
}
impl CachedRenderPipelinePhaseItem for Shadow { impl CachedRenderPipelinePhaseItem for Shadow {
#[inline] #[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId { fn cached_pipeline(&self) -> CachedRenderPipelineId {
@ -1806,16 +1804,19 @@ pub type DrawShadowMesh = (
); );
pub struct SetShadowViewBindGroup<const I: usize>; pub struct SetShadowViewBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetShadowViewBindGroup<I> { impl<const I: usize> RenderCommand<Shadow> for SetShadowViewBindGroup<I> {
type Param = (SRes<LightMeta>, SQuery<Read<ViewUniformOffset>>); type Param = SRes<LightMeta>;
type ViewWorldQuery = Read<ViewUniformOffset>;
type ItemWorldQuery = ();
#[inline] #[inline]
fn render<'w>( fn render<'w>(
view: Entity, _item: &Shadow,
_item: Entity, view_uniform_offset: &'_ ViewUniformOffset,
(light_meta, view_query): SystemParamItem<'w, '_, Self::Param>, _entity: (),
light_meta: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let view_uniform_offset = view_query.get(view).unwrap();
pass.set_bind_group( pass.set_bind_group(
I, I,
light_meta light_meta

View File

@ -7,6 +7,7 @@ use bevy_app::Plugin;
use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped}; use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped};
use bevy_ecs::{ use bevy_ecs::{
prelude::*, prelude::*,
query::ROQueryItem,
system::{lifetimeless::*, SystemParamItem, SystemState}, system::{lifetimeless::*, SystemParamItem, SystemState},
}; };
use bevy_math::{Mat3A, Mat4, Vec2}; use bevy_math::{Mat3A, Mat4, Vec2};
@ -19,7 +20,7 @@ use bevy_render::{
GpuBufferInfo, Mesh, MeshVertexBufferLayout, GpuBufferInfo, Mesh, MeshVertexBufferLayout,
}, },
render_asset::RenderAssets, render_asset::RenderAssets,
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass}, render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
render_resource::*, render_resource::*,
renderer::{RenderDevice, RenderQueue}, renderer::{RenderDevice, RenderQueue},
texture::{ texture::{
@ -873,20 +874,23 @@ pub fn queue_mesh_view_bind_groups(
} }
pub struct SetMeshViewBindGroup<const I: usize>; pub struct SetMeshViewBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetMeshViewBindGroup<I> { impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I> {
type Param = SQuery<( type Param = ();
type ViewWorldQuery = (
Read<ViewUniformOffset>, Read<ViewUniformOffset>,
Read<ViewLightsUniformOffset>, Read<ViewLightsUniformOffset>,
Read<MeshViewBindGroup>, Read<MeshViewBindGroup>,
)>; );
type ItemWorldQuery = ();
#[inline] #[inline]
fn render<'w>( fn render<'w>(
view: Entity, _item: &P,
_item: Entity, (view_uniform, view_lights, mesh_view_bind_group): ROQueryItem<'w, Self::ViewWorldQuery>,
view_query: SystemParamItem<'w, '_, Self::Param>, _entity: (),
_: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let (view_uniform, view_lights, mesh_view_bind_group) = view_query.get_inner(view).unwrap();
pass.set_bind_group( pass.set_bind_group(
I, I,
&mesh_view_bind_group.value, &mesh_view_bind_group.value,
@ -898,22 +902,21 @@ impl<const I: usize> EntityRenderCommand for SetMeshViewBindGroup<I> {
} }
pub struct SetMeshBindGroup<const I: usize>; pub struct SetMeshBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetMeshBindGroup<I> { impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshBindGroup<I> {
type Param = ( type Param = SRes<MeshBindGroup>;
SRes<MeshBindGroup>, type ViewWorldQuery = ();
SQuery<( type ItemWorldQuery = (
Read<DynamicUniformIndex<MeshUniform>>, Read<DynamicUniformIndex<MeshUniform>>,
Option<Read<SkinnedMeshJoints>>, Option<Read<SkinnedMeshJoints>>,
)>,
); );
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(mesh_bind_group, mesh_query): SystemParamItem<'w, '_, Self::Param>, (mesh_index, skinned_mesh_joints): ROQueryItem<'_, Self::ItemWorldQuery>,
mesh_bind_group: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let (mesh_index, skinned_mesh_joints) = mesh_query.get(item).unwrap();
if let Some(joints) = skinned_mesh_joints { if let Some(joints) = skinned_mesh_joints {
pass.set_bind_group( pass.set_bind_group(
I, I,
@ -932,16 +935,18 @@ impl<const I: usize> EntityRenderCommand for SetMeshBindGroup<I> {
} }
pub struct DrawMesh; pub struct DrawMesh;
impl EntityRenderCommand for DrawMesh { impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
type Param = (SRes<RenderAssets<Mesh>>, SQuery<Read<Handle<Mesh>>>); type Param = SRes<RenderAssets<Mesh>>;
type ViewWorldQuery = ();
type ItemWorldQuery = Read<Handle<Mesh>>;
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(meshes, mesh_query): SystemParamItem<'w, '_, Self::Param>, mesh_handle: ROQueryItem<'_, Self::ItemWorldQuery>,
meshes: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let mesh_handle = mesh_query.get(item).unwrap();
if let Some(gpu_mesh) = meshes.into_inner().get(mesh_handle) { if let Some(gpu_mesh) = meshes.into_inner().get(mesh_handle) {
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..)); pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
match &gpu_mesh.buffer_info { match &gpu_mesh.buffer_info {

View File

@ -6,6 +6,7 @@ use bevy_app::App;
use bevy_ecs::{ use bevy_ecs::{
all_tuples, all_tuples,
entity::Entity, entity::Entity,
query::{QueryState, ROQueryItem, ReadOnlyWorldQuery},
system::{ system::{
lifetimeless::SRes, ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, lifetimeless::SRes, ReadOnlySystemParam, Resource, SystemParam, SystemParamItem,
SystemState, SystemState,
@ -21,6 +22,12 @@ use std::{any::TypeId, fmt::Debug, hash::Hash, ops::Range};
/// They are the general form of drawing items, whereas [`RenderCommands`](RenderCommand) /// They are the general form of drawing items, whereas [`RenderCommands`](RenderCommand)
/// are more modular. /// are more modular.
pub trait Draw<P: PhaseItem>: Send + Sync + 'static { pub trait Draw<P: PhaseItem>: Send + Sync + 'static {
/// Prepares the draw function to be used. This is called once and only once before the phase
/// begins. There may be zero or more `draw` calls following a call to this function..
/// Implementing this is optional.
#[allow(unused_variables)]
fn prepare(&mut self, world: &'_ World) {}
/// Draws the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`]. /// Draws the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`].
fn draw<'w>( fn draw<'w>(
&mut self, &mut self,
@ -39,6 +46,8 @@ pub trait Draw<P: PhaseItem>: Send + Sync + 'static {
pub trait PhaseItem: Sized + Send + Sync + 'static { pub trait PhaseItem: Sized + Send + Sync + 'static {
/// The type used for ordering the items. The smallest values are drawn first. /// The type used for ordering the items. The smallest values are drawn first.
type SortKey: Ord; type SortKey: Ord;
fn entity(&self) -> Entity;
/// Determines the order in which the items are drawn during the corresponding [`RenderPhase`](super::RenderPhase). /// Determines the order in which the items are drawn during the corresponding [`RenderPhase`](super::RenderPhase).
fn sort_key(&self) -> Self::SortKey; fn sort_key(&self) -> Self::SortKey;
/// Specifies the [`Draw`] function used to render the item. /// Specifies the [`Draw`] function used to render the item.
@ -75,6 +84,12 @@ pub struct DrawFunctionsInternal<P: PhaseItem> {
} }
impl<P: PhaseItem> DrawFunctionsInternal<P> { impl<P: PhaseItem> DrawFunctionsInternal<P> {
pub fn prepare(&mut self, world: &World) {
for function in &mut self.draw_functions {
function.prepare(world);
}
}
/// Adds the [`Draw`] function and associates it to its own type. /// Adds the [`Draw`] function and associates it to its own type.
pub fn add<T: Draw<P>>(&mut self, draw_function: T) -> DrawFunctionId { pub fn add<T: Draw<P>>(&mut self, draw_function: T) -> DrawFunctionId {
self.add_with::<T, T>(draw_function) self.add_with::<T, T>(draw_function)
@ -168,11 +183,14 @@ pub trait RenderCommand<P: PhaseItem> {
/// Specifies all ECS data required by [`RenderCommand::render`]. /// Specifies all ECS data required by [`RenderCommand::render`].
/// All parameters have to be read only. /// All parameters have to be read only.
type Param: SystemParam + 'static; type Param: SystemParam + 'static;
type ViewWorldQuery: ReadOnlyWorldQuery;
type ItemWorldQuery: ReadOnlyWorldQuery;
/// Renders the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`]. /// Renders the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`].
fn render<'w>( fn render<'w>(
view: Entity,
item: &P, item: &P,
view: ROQueryItem<'w, Self::ViewWorldQuery>,
entity: ROQueryItem<'w, Self::ItemWorldQuery>,
param: SystemParamItem<'w, '_, Self::Param>, param: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult; ) -> RenderCommandResult;
@ -183,20 +201,6 @@ pub enum RenderCommandResult {
Failure, Failure,
} }
pub trait EntityRenderCommand {
type Param: SystemParam + 'static;
fn render<'w>(
view: Entity,
item: Entity,
param: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult;
}
pub trait EntityPhaseItem: PhaseItem {
fn entity(&self) -> Entity;
}
pub trait CachedRenderPipelinePhaseItem: PhaseItem { pub trait CachedRenderPipelinePhaseItem: PhaseItem {
fn cached_pipeline(&self) -> CachedRenderPipelineId; fn cached_pipeline(&self) -> CachedRenderPipelineId;
} }
@ -208,7 +212,7 @@ pub trait CachedRenderPipelinePhaseItem: PhaseItem {
/// ///
/// If this is implemented on a type, the implementation of [`PhaseItem::sort`] should /// If this is implemented on a type, the implementation of [`PhaseItem::sort`] should
/// be changed to implement a stable sort, or incorrect/suboptimal batching may result. /// be changed to implement a stable sort, or incorrect/suboptimal batching may result.
pub trait BatchedPhaseItem: EntityPhaseItem { pub trait BatchedPhaseItem: PhaseItem {
/// Range in the vertex buffer of this item /// Range in the vertex buffer of this item
fn batch_range(&self) -> &Option<Range<u32>>; fn batch_range(&self) -> &Option<Range<u32>>;
@ -247,30 +251,16 @@ pub enum BatchResult {
IncompatibleItems, IncompatibleItems,
} }
impl<P: EntityPhaseItem, E: EntityRenderCommand> RenderCommand<P> for E
where
E::Param: 'static,
{
type Param = E::Param;
#[inline]
fn render<'w>(
view: Entity,
item: &P,
param: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
<E as EntityRenderCommand>::render(view, item.entity(), param, pass)
}
}
pub struct SetItemPipeline; pub struct SetItemPipeline;
impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline { impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
type Param = SRes<PipelineCache>; type Param = SRes<PipelineCache>;
type ViewWorldQuery = ();
type ItemWorldQuery = ();
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity,
item: &P, item: &P,
_view: (),
_entity: (),
pipeline_cache: SystemParamItem<'w, '_, Self::Param>, pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
@ -287,18 +277,21 @@ impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
} }
macro_rules! render_command_tuple_impl { macro_rules! render_command_tuple_impl {
($($name: ident),*) => { ($(($name: ident, $view: ident, $entity: ident)),*) => {
impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) { impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) {
type Param = ($($name::Param,)*); type Param = ($($name::Param,)*);
type ViewWorldQuery = ($($name::ViewWorldQuery,)*);
type ItemWorldQuery = ($($name::ItemWorldQuery,)*);
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn render<'w>( fn render<'w>(
_view: Entity,
_item: &P, _item: &P,
($($view,)*): ROQueryItem<'w, Self::ViewWorldQuery>,
($($entity,)*): ROQueryItem<'w, Self::ItemWorldQuery>,
($($name,)*): SystemParamItem<'w, '_, Self::Param>, ($($name,)*): SystemParamItem<'w, '_, Self::Param>,
_pass: &mut TrackedRenderPass<'w>, _pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult{ ) -> RenderCommandResult {
$(if let RenderCommandResult::Failure = $name::render(_view, _item, $name, _pass) { $(if let RenderCommandResult::Failure = $name::render(_item, $view, $entity, $name, _pass) {
return RenderCommandResult::Failure; return RenderCommandResult::Failure;
})* })*
RenderCommandResult::Success RenderCommandResult::Success
@ -307,18 +300,22 @@ macro_rules! render_command_tuple_impl {
}; };
} }
all_tuples!(render_command_tuple_impl, 0, 15, C); all_tuples!(render_command_tuple_impl, 0, 15, C, V, E);
/// Wraps a [`RenderCommand`] into a state so that it can be used as a [`Draw`] function. /// Wraps a [`RenderCommand`] into a state so that it can be used as a [`Draw`] function.
/// Therefore the [`RenderCommand::Param`] is queried from the ECS and passed to the command. /// Therefore the [`RenderCommand::Param`] is queried from the ECS and passed to the command.
pub struct RenderCommandState<P: PhaseItem + 'static, C: RenderCommand<P>> { pub struct RenderCommandState<P: PhaseItem + 'static, C: RenderCommand<P>> {
state: SystemState<C::Param>, state: SystemState<C::Param>,
view: QueryState<C::ViewWorldQuery>,
entity: QueryState<C::ItemWorldQuery>,
} }
impl<P: PhaseItem, C: RenderCommand<P>> RenderCommandState<P, C> { impl<P: PhaseItem, C: RenderCommand<P>> RenderCommandState<P, C> {
pub fn new(world: &mut World) -> Self { pub fn new(world: &mut World) -> Self {
Self { Self {
state: SystemState::new(world), state: SystemState::new(world),
view: world.query(),
entity: world.query(),
} }
} }
} }
@ -327,6 +324,11 @@ impl<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static> Draw<P> for Rend
where where
C::Param: ReadOnlySystemParam, C::Param: ReadOnlySystemParam,
{ {
fn prepare(&mut self, world: &'_ World) {
self.view.update_archetypes(world);
self.entity.update_archetypes(world);
}
/// Prepares the ECS parameters for the wrapped [`RenderCommand`] and then renders it. /// Prepares the ECS parameters for the wrapped [`RenderCommand`] and then renders it.
fn draw<'w>( fn draw<'w>(
&mut self, &mut self,
@ -336,7 +338,9 @@ where
item: &P, item: &P,
) { ) {
let param = self.state.get(world); let param = self.state.get(world);
C::render(view, item, param, pass); let view = self.view.get_manual(world, view).unwrap();
let entity = self.entity.get_manual(world, item.entity()).unwrap();
C::render(item, view, entity, param, pass);
} }
} }

View File

@ -40,6 +40,7 @@ impl<I: PhaseItem> RenderPhase<I> {
) { ) {
let draw_functions = world.resource::<DrawFunctions<I>>(); let draw_functions = world.resource::<DrawFunctions<I>>();
let mut draw_functions = draw_functions.write(); let mut draw_functions = draw_functions.write();
draw_functions.prepare(world);
for item in &self.items { for item in &self.items {
let draw_function = draw_functions.get_mut(item.draw_function()).unwrap(); let draw_function = draw_functions.get_mut(item.draw_function()).unwrap();
@ -107,17 +108,16 @@ mod tests {
impl PhaseItem for TestPhaseItem { impl PhaseItem for TestPhaseItem {
type SortKey = (); type SortKey = ();
fn entity(&self) -> bevy_ecs::entity::Entity {
self.entity
}
fn sort_key(&self) -> Self::SortKey {} fn sort_key(&self) -> Self::SortKey {}
fn draw_function(&self) -> DrawFunctionId { fn draw_function(&self) -> DrawFunctionId {
unimplemented!(); unimplemented!();
} }
} }
impl EntityPhaseItem for TestPhaseItem {
fn entity(&self) -> bevy_ecs::entity::Entity {
self.entity
}
}
impl BatchedPhaseItem for TestPhaseItem { impl BatchedPhaseItem for TestPhaseItem {
fn batch_range(&self) -> &Option<std::ops::Range<u32>> { fn batch_range(&self) -> &Option<std::ops::Range<u32>> {
&self.batch_range &self.batch_range

View File

@ -3,12 +3,12 @@ use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
use bevy_core_pipeline::{core_2d::Transparent2d, tonemapping::Tonemapping}; use bevy_core_pipeline::{core_2d::Transparent2d, tonemapping::Tonemapping};
use bevy_derive::{Deref, DerefMut}; use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{ use bevy_ecs::{
entity::Entity,
event::EventReader, event::EventReader,
prelude::{Bundle, World}, prelude::{Bundle, World},
query::ROQueryItem,
schedule::IntoSystemDescriptor, schedule::IntoSystemDescriptor,
system::{ system::{
lifetimeless::{Read, SQuery, SRes}, lifetimeless::{Read, SRes},
Commands, Local, Query, Res, ResMut, Resource, SystemParamItem, Commands, Local, Query, Res, ResMut, Resource, SystemParamItem,
}, },
world::FromWorld, world::FromWorld,
@ -21,8 +21,8 @@ use bevy_render::{
prelude::Image, prelude::Image,
render_asset::{PrepareAssetLabel, RenderAssets}, render_asset::{PrepareAssetLabel, RenderAssets},
render_phase::{ render_phase::{
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase, AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
SetItemPipeline, TrackedRenderPass, RenderPhase, SetItemPipeline, TrackedRenderPass,
}, },
render_resource::{ render_resource::{
AsBindGroup, AsBindGroupError, BindGroup, BindGroupLayout, OwnedBindingResource, AsBindGroup, AsBindGroupError, BindGroup, BindGroupLayout, OwnedBindingResource,
@ -281,15 +281,21 @@ type DrawMaterial2d<M> = (
); );
pub struct SetMaterial2dBindGroup<M: Material2d, const I: usize>(PhantomData<M>); pub struct SetMaterial2dBindGroup<M: Material2d, const I: usize>(PhantomData<M>);
impl<M: Material2d, const I: usize> EntityRenderCommand for SetMaterial2dBindGroup<M, I> { impl<P: PhaseItem, M: Material2d, const I: usize> RenderCommand<P>
type Param = (SRes<RenderMaterials2d<M>>, SQuery<Read<Handle<M>>>); for SetMaterial2dBindGroup<M, I>
{
type Param = SRes<RenderMaterials2d<M>>;
type ViewWorldQuery = ();
type ItemWorldQuery = Read<Handle<M>>;
#[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(materials, query): SystemParamItem<'w, '_, Self::Param>, material2d_handle: ROQueryItem<'_, Self::ItemWorldQuery>,
materials: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let material2d_handle = query.get(item).unwrap();
let material2d = materials.into_inner().get(material2d_handle).unwrap(); let material2d = materials.into_inner().get(material2d_handle).unwrap();
pass.set_bind_group(I, &material2d.bind_group, &[]); pass.set_bind_group(I, &material2d.bind_group, &[]);
RenderCommandResult::Success RenderCommandResult::Success

View File

@ -2,6 +2,7 @@ use bevy_app::Plugin;
use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; use bevy_asset::{load_internal_asset, Handle, HandleUntyped};
use bevy_ecs::{ use bevy_ecs::{
prelude::*, prelude::*,
query::ROQueryItem,
system::{lifetimeless::*, SystemParamItem, SystemState}, system::{lifetimeless::*, SystemParamItem, SystemState},
}; };
use bevy_math::{Mat4, Vec2}; use bevy_math::{Mat4, Vec2};
@ -11,7 +12,7 @@ use bevy_render::{
globals::{GlobalsBuffer, GlobalsUniform}, globals::{GlobalsBuffer, GlobalsUniform},
mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout}, mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout},
render_asset::RenderAssets, render_asset::RenderAssets,
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass}, render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
render_resource::*, render_resource::*,
renderer::{RenderDevice, RenderQueue}, renderer::{RenderDevice, RenderQueue},
texture::{ texture::{
@ -495,16 +496,19 @@ pub fn queue_mesh2d_view_bind_groups(
} }
pub struct SetMesh2dViewBindGroup<const I: usize>; pub struct SetMesh2dViewBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetMesh2dViewBindGroup<I> { impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMesh2dViewBindGroup<I> {
type Param = SQuery<(Read<ViewUniformOffset>, Read<Mesh2dViewBindGroup>)>; type Param = ();
type ViewWorldQuery = (Read<ViewUniformOffset>, Read<Mesh2dViewBindGroup>);
type ItemWorldQuery = ();
#[inline] #[inline]
fn render<'w>( fn render<'w>(
view: Entity, _item: &P,
_item: Entity, (view_uniform, mesh2d_view_bind_group): ROQueryItem<'w, Self::ViewWorldQuery>,
view_query: SystemParamItem<'w, '_, Self::Param>, _view: (),
_param: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let (view_uniform, mesh2d_view_bind_group) = view_query.get_inner(view).unwrap();
pass.set_bind_group(I, &mesh2d_view_bind_group.value, &[view_uniform.offset]); pass.set_bind_group(I, &mesh2d_view_bind_group.value, &[view_uniform.offset]);
RenderCommandResult::Success RenderCommandResult::Success
@ -512,19 +516,19 @@ impl<const I: usize> EntityRenderCommand for SetMesh2dViewBindGroup<I> {
} }
pub struct SetMesh2dBindGroup<const I: usize>; pub struct SetMesh2dBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetMesh2dBindGroup<I> { impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMesh2dBindGroup<I> {
type Param = ( type Param = SRes<Mesh2dBindGroup>;
SRes<Mesh2dBindGroup>, type ViewWorldQuery = ();
SQuery<Read<DynamicUniformIndex<Mesh2dUniform>>>, type ItemWorldQuery = Read<DynamicUniformIndex<Mesh2dUniform>>;
);
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(mesh2d_bind_group, mesh2d_query): SystemParamItem<'w, '_, Self::Param>, mesh2d_index: &'_ DynamicUniformIndex<Mesh2dUniform>,
mesh2d_bind_group: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let mesh2d_index = mesh2d_query.get(item).unwrap();
pass.set_bind_group( pass.set_bind_group(
I, I,
&mesh2d_bind_group.into_inner().value, &mesh2d_bind_group.into_inner().value,
@ -535,17 +539,20 @@ impl<const I: usize> EntityRenderCommand for SetMesh2dBindGroup<I> {
} }
pub struct DrawMesh2d; pub struct DrawMesh2d;
impl EntityRenderCommand for DrawMesh2d { impl<P: PhaseItem> RenderCommand<P> for DrawMesh2d {
type Param = (SRes<RenderAssets<Mesh>>, SQuery<Read<Mesh2dHandle>>); type Param = SRes<RenderAssets<Mesh>>;
type ViewWorldQuery = ();
type ItemWorldQuery = Read<Mesh2dHandle>;
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(meshes, mesh2d_query): SystemParamItem<'w, '_, Self::Param>, mesh_handle: ROQueryItem<'w, Self::ItemWorldQuery>,
meshes: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let mesh_handle = &mesh2d_query.get(item).unwrap().0; if let Some(gpu_mesh) = meshes.into_inner().get(&mesh_handle.0) {
if let Some(gpu_mesh) = meshes.into_inner().get(mesh_handle) {
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..)); pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
match &gpu_mesh.buffer_info { match &gpu_mesh.buffer_info {
GpuBufferInfo::Indexed { GpuBufferInfo::Indexed {

View File

@ -16,7 +16,7 @@ use bevy_render::{
color::Color, color::Color,
render_asset::RenderAssets, render_asset::RenderAssets,
render_phase::{ render_phase::{
BatchedPhaseItem, DrawFunctions, EntityRenderCommand, RenderCommand, RenderCommandResult, BatchedPhaseItem, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
RenderPhase, SetItemPipeline, TrackedRenderPass, RenderPhase, SetItemPipeline, TrackedRenderPass,
}, },
render_resource::*, render_resource::*,
@ -696,16 +696,18 @@ pub type DrawSprite = (
); );
pub struct SetSpriteViewBindGroup<const I: usize>; pub struct SetSpriteViewBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetSpriteViewBindGroup<I> { impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteViewBindGroup<I> {
type Param = (SRes<SpriteMeta>, SQuery<Read<ViewUniformOffset>>); type Param = SRes<SpriteMeta>;
type ViewWorldQuery = Read<ViewUniformOffset>;
type ItemWorldQuery = ();
fn render<'w>( fn render<'w>(
view: Entity, _item: &P,
_item: Entity, view_uniform: &'_ ViewUniformOffset,
(sprite_meta, view_query): SystemParamItem<'w, '_, Self::Param>, _entity: (),
sprite_meta: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let view_uniform = view_query.get(view).unwrap();
pass.set_bind_group( pass.set_bind_group(
I, I,
sprite_meta.into_inner().view_bind_group.as_ref().unwrap(), sprite_meta.into_inner().view_bind_group.as_ref().unwrap(),
@ -715,16 +717,18 @@ impl<const I: usize> EntityRenderCommand for SetSpriteViewBindGroup<I> {
} }
} }
pub struct SetSpriteTextureBindGroup<const I: usize>; pub struct SetSpriteTextureBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetSpriteTextureBindGroup<I> { impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteTextureBindGroup<I> {
type Param = (SRes<ImageBindGroups>, SQuery<Read<SpriteBatch>>); type Param = SRes<ImageBindGroups>;
type ViewWorldQuery = ();
type ItemWorldQuery = Read<SpriteBatch>;
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(image_bind_groups, query_batch): SystemParamItem<'w, '_, Self::Param>, sprite_batch: &'_ SpriteBatch,
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let sprite_batch = query_batch.get(item).unwrap();
let image_bind_groups = image_bind_groups.into_inner(); let image_bind_groups = image_bind_groups.into_inner();
pass.set_bind_group( pass.set_bind_group(
@ -741,15 +745,17 @@ impl<const I: usize> EntityRenderCommand for SetSpriteTextureBindGroup<I> {
pub struct DrawSpriteBatch; pub struct DrawSpriteBatch;
impl<P: BatchedPhaseItem> RenderCommand<P> for DrawSpriteBatch { impl<P: BatchedPhaseItem> RenderCommand<P> for DrawSpriteBatch {
type Param = (SRes<SpriteMeta>, SQuery<Read<SpriteBatch>>); type Param = SRes<SpriteMeta>;
type ViewWorldQuery = ();
type ItemWorldQuery = Read<SpriteBatch>;
fn render<'w>( fn render<'w>(
_view: Entity,
item: &P, item: &P,
(sprite_meta, query_batch): SystemParamItem<'w, '_, Self::Param>, _view: (),
sprite_batch: &'_ SpriteBatch,
sprite_meta: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let sprite_batch = query_batch.get(item.entity()).unwrap();
let sprite_meta = sprite_meta.into_inner(); let sprite_meta = sprite_meta.into_inner();
if sprite_batch.colored { if sprite_batch.colored {
pass.set_vertex_buffer(0, sprite_meta.colored_vertices.buffer().unwrap().slice(..)); pass.set_vertex_buffer(0, sprite_meta.colored_vertices.buffer().unwrap().slice(..));

View File

@ -106,6 +106,11 @@ pub struct TransparentUi {
impl PhaseItem for TransparentUi { impl PhaseItem for TransparentUi {
type SortKey = FloatOrd; type SortKey = FloatOrd;
#[inline]
fn entity(&self) -> Entity {
self.entity
}
#[inline] #[inline]
fn sort_key(&self) -> Self::SortKey { fn sort_key(&self) -> Self::SortKey {
self.sort_key self.sort_key
@ -117,13 +122,6 @@ impl PhaseItem for TransparentUi {
} }
} }
impl EntityPhaseItem for TransparentUi {
#[inline]
fn entity(&self) -> Entity {
self.entity
}
}
impl CachedRenderPipelinePhaseItem for TransparentUi { impl CachedRenderPipelinePhaseItem for TransparentUi {
#[inline] #[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId { fn cached_pipeline(&self) -> CachedRenderPipelineId {
@ -139,16 +137,18 @@ pub type DrawUi = (
); );
pub struct SetUiViewBindGroup<const I: usize>; pub struct SetUiViewBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetUiViewBindGroup<I> { impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {
type Param = (SRes<UiMeta>, SQuery<Read<ViewUniformOffset>>); type Param = SRes<UiMeta>;
type ViewWorldQuery = Read<ViewUniformOffset>;
type ItemWorldQuery = ();
fn render<'w>( fn render<'w>(
view: Entity, _item: &P,
_item: Entity, view_uniform: &'w ViewUniformOffset,
(ui_meta, view_query): SystemParamItem<'w, '_, Self::Param>, _entity: (),
ui_meta: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let view_uniform = view_query.get(view).unwrap();
pass.set_bind_group( pass.set_bind_group(
I, I,
ui_meta.into_inner().view_bind_group.as_ref().unwrap(), ui_meta.into_inner().view_bind_group.as_ref().unwrap(),
@ -158,34 +158,38 @@ impl<const I: usize> EntityRenderCommand for SetUiViewBindGroup<I> {
} }
} }
pub struct SetUiTextureBindGroup<const I: usize>; pub struct SetUiTextureBindGroup<const I: usize>;
impl<const I: usize> EntityRenderCommand for SetUiTextureBindGroup<I> { impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I> {
type Param = (SRes<UiImageBindGroups>, SQuery<Read<UiBatch>>); type Param = SRes<UiImageBindGroups>;
type ViewWorldQuery = ();
type ItemWorldQuery = Read<UiBatch>;
#[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(image_bind_groups, query_batch): SystemParamItem<'w, '_, Self::Param>, batch: &'w UiBatch,
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let batch = query_batch.get(item).unwrap();
let image_bind_groups = image_bind_groups.into_inner(); let image_bind_groups = image_bind_groups.into_inner();
pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]); pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);
RenderCommandResult::Success RenderCommandResult::Success
} }
} }
pub struct DrawUiNode; pub struct DrawUiNode;
impl EntityRenderCommand for DrawUiNode { impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {
type Param = (SRes<UiMeta>, SQuery<Read<UiBatch>>); type Param = SRes<UiMeta>;
type ViewWorldQuery = ();
type ItemWorldQuery = Read<UiBatch>;
#[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(ui_meta, query_batch): SystemParamItem<'w, '_, Self::Param>, batch: &'w UiBatch,
ui_meta: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let batch = query_batch.get(item).unwrap();
pass.set_vertex_buffer(0, ui_meta.into_inner().vertices.buffer().unwrap().slice(..)); pass.set_vertex_buffer(0, ui_meta.into_inner().vertices.buffer().unwrap().slice(..));
pass.draw(batch.range.clone(), 0..1); pass.draw(batch.range.clone(), 0..1);
RenderCommandResult::Success RenderCommandResult::Success

View File

@ -13,8 +13,8 @@ use bevy::{
mesh::{GpuBufferInfo, MeshVertexBufferLayout}, mesh::{GpuBufferInfo, MeshVertexBufferLayout},
render_asset::RenderAssets, render_asset::RenderAssets,
render_phase::{ render_phase::{
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase, AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
SetItemPipeline, TrackedRenderPass, RenderPhase, SetItemPipeline, TrackedRenderPass,
}, },
render_resource::*, render_resource::*,
renderer::RenderDevice, renderer::RenderDevice,
@ -223,22 +223,19 @@ type DrawCustom = (
pub struct DrawMeshInstanced; pub struct DrawMeshInstanced;
impl EntityRenderCommand for DrawMeshInstanced { impl<P: PhaseItem> RenderCommand<P> for DrawMeshInstanced {
type Param = ( type Param = SRes<RenderAssets<Mesh>>;
SRes<RenderAssets<Mesh>>, type ViewWorldQuery = ();
SQuery<Read<Handle<Mesh>>>, type ItemWorldQuery = (Read<Handle<Mesh>>, Read<InstanceBuffer>);
SQuery<Read<InstanceBuffer>>,
);
#[inline] #[inline]
fn render<'w>( fn render<'w>(
_view: Entity, _item: &P,
item: Entity, _view: (),
(meshes, mesh_query, instance_buffer_query): SystemParamItem<'w, '_, Self::Param>, (mesh_handle, instance_buffer): (&'w Handle<Mesh>, &'w InstanceBuffer),
meshes: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
let mesh_handle = mesh_query.get(item).unwrap();
let instance_buffer = instance_buffer_query.get_inner(item).unwrap();
let gpu_mesh = match meshes.into_inner().get(mesh_handle) { let gpu_mesh = match meshes.into_inner().get(mesh_handle) {
Some(gpu_mesh) => gpu_mesh, Some(gpu_mesh) => gpu_mesh,
None => return RenderCommandResult::Failure, None => return RenderCommandResult::Failure,