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)  The shadow pass node is also slightly faster (344.52 -> 338.24us)  ## 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:
parent
f866d72f15
commit
2d727afaf7
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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(..));
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user