mirror of
https://github.com/bevyengine/bevy
synced 2025-02-16 14:08:32 +00:00
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:
parent
f866d72f15
commit
2d727afaf7
12 changed files with 242 additions and 217 deletions
|
@ -27,7 +27,7 @@ use bevy_render::{
|
|||
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
|
||||
render_phase::{
|
||||
batch_phase_system, sort_phase_system, BatchedPhaseItem, CachedRenderPipelinePhaseItem,
|
||||
DrawFunctionId, DrawFunctions, EntityPhaseItem, PhaseItem, RenderPhase,
|
||||
DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase,
|
||||
},
|
||||
render_resource::CachedRenderPipelineId,
|
||||
Extract, RenderApp, RenderStage,
|
||||
|
@ -115,6 +115,11 @@ pub struct Transparent2d {
|
|||
impl PhaseItem for Transparent2d {
|
||||
type SortKey = FloatOrd;
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
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 {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
|
|
|
@ -29,8 +29,8 @@ use bevy_render::{
|
|||
prelude::Msaa,
|
||||
render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType},
|
||||
render_phase::{
|
||||
sort_phase_system, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions,
|
||||
EntityPhaseItem, PhaseItem, RenderPhase,
|
||||
sort_phase_system, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, PhaseItem,
|
||||
RenderPhase,
|
||||
},
|
||||
render_resource::{
|
||||
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.
|
||||
type SortKey = Reverse<FloatOrd>;
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
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 {
|
||||
#[inline]
|
||||
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.
|
||||
type SortKey = Reverse<FloatOrd>;
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
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 {
|
||||
#[inline]
|
||||
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.
|
||||
type SortKey = FloatOrd;
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
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 {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
|
|
|
@ -10,12 +10,11 @@ use bevy_core_pipeline::{
|
|||
};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
event::EventReader,
|
||||
prelude::World,
|
||||
schedule::IntoSystemDescriptor,
|
||||
system::{
|
||||
lifetimeless::{Read, SQuery, SRes},
|
||||
lifetimeless::{Read, SRes},
|
||||
Commands, Local, Query, Res, ResMut, Resource, SystemParamItem,
|
||||
},
|
||||
world::FromWorld,
|
||||
|
@ -27,8 +26,8 @@ use bevy_render::{
|
|||
prelude::Image,
|
||||
render_asset::{PrepareAssetLabel, RenderAssets},
|
||||
render_phase::{
|
||||
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
||||
SetItemPipeline, TrackedRenderPass,
|
||||
AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
|
||||
RenderPhase, SetItemPipeline, TrackedRenderPass,
|
||||
},
|
||||
render_resource::{
|
||||
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.
|
||||
pub struct SetMaterialBindGroup<M: Material, const I: usize>(PhantomData<M>);
|
||||
impl<M: Material, const I: usize> EntityRenderCommand for SetMaterialBindGroup<M, I> {
|
||||
type Param = (SRes<RenderMaterials<M>>, SQuery<Read<Handle<M>>>);
|
||||
impl<P: PhaseItem, M: Material, const I: usize> RenderCommand<P> for SetMaterialBindGroup<M, I> {
|
||||
type Param = SRes<RenderMaterials<M>>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<Handle<M>>;
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(materials, query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
material_handle: &'_ Handle<M>,
|
||||
materials: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let material_handle = query.get(item).unwrap();
|
||||
let material = materials.into_inner().get(material_handle).unwrap();
|
||||
pass.set_bind_group(I, &material.bind_group, &[]);
|
||||
RenderCommandResult::Success
|
||||
|
|
|
@ -18,9 +18,8 @@ use bevy_render::{
|
|||
render_asset::RenderAssets,
|
||||
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
|
||||
render_phase::{
|
||||
CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem,
|
||||
EntityRenderCommand, PhaseItem, RenderCommandResult, RenderPhase, SetItemPipeline,
|
||||
TrackedRenderPass,
|
||||
CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, PhaseItem, RenderCommand,
|
||||
RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass,
|
||||
},
|
||||
render_resource::*,
|
||||
renderer::{RenderContext, RenderDevice, RenderQueue},
|
||||
|
@ -1699,6 +1698,11 @@ pub struct Shadow {
|
|||
impl PhaseItem for Shadow {
|
||||
type SortKey = FloatOrd;
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
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 {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
|
@ -1806,16 +1804,19 @@ pub type DrawShadowMesh = (
|
|||
);
|
||||
|
||||
pub struct SetShadowViewBindGroup<const I: usize>;
|
||||
impl<const I: usize> EntityRenderCommand for SetShadowViewBindGroup<I> {
|
||||
type Param = (SRes<LightMeta>, SQuery<Read<ViewUniformOffset>>);
|
||||
impl<const I: usize> RenderCommand<Shadow> for SetShadowViewBindGroup<I> {
|
||||
type Param = SRes<LightMeta>;
|
||||
type ViewWorldQuery = Read<ViewUniformOffset>;
|
||||
type ItemWorldQuery = ();
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
_item: Entity,
|
||||
(light_meta, view_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &Shadow,
|
||||
view_uniform_offset: &'_ ViewUniformOffset,
|
||||
_entity: (),
|
||||
light_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let view_uniform_offset = view_query.get(view).unwrap();
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
light_meta
|
||||
|
|
|
@ -7,6 +7,7 @@ use bevy_app::Plugin;
|
|||
use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped};
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
query::ROQueryItem,
|
||||
system::{lifetimeless::*, SystemParamItem, SystemState},
|
||||
};
|
||||
use bevy_math::{Mat3A, Mat4, Vec2};
|
||||
|
@ -19,7 +20,7 @@ use bevy_render::{
|
|||
GpuBufferInfo, Mesh, MeshVertexBufferLayout,
|
||||
},
|
||||
render_asset::RenderAssets,
|
||||
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||
render_resource::*,
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
texture::{
|
||||
|
@ -873,20 +874,23 @@ pub fn queue_mesh_view_bind_groups(
|
|||
}
|
||||
|
||||
pub struct SetMeshViewBindGroup<const I: usize>;
|
||||
impl<const I: usize> EntityRenderCommand for SetMeshViewBindGroup<I> {
|
||||
type Param = SQuery<(
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I> {
|
||||
type Param = ();
|
||||
type ViewWorldQuery = (
|
||||
Read<ViewUniformOffset>,
|
||||
Read<ViewLightsUniformOffset>,
|
||||
Read<MeshViewBindGroup>,
|
||||
)>;
|
||||
);
|
||||
type ItemWorldQuery = ();
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
_item: Entity,
|
||||
view_query: SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
(view_uniform, view_lights, mesh_view_bind_group): ROQueryItem<'w, Self::ViewWorldQuery>,
|
||||
_entity: (),
|
||||
_: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let (view_uniform, view_lights, mesh_view_bind_group) = view_query.get_inner(view).unwrap();
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
&mesh_view_bind_group.value,
|
||||
|
@ -898,22 +902,21 @@ impl<const I: usize> EntityRenderCommand for SetMeshViewBindGroup<I> {
|
|||
}
|
||||
|
||||
pub struct SetMeshBindGroup<const I: usize>;
|
||||
impl<const I: usize> EntityRenderCommand for SetMeshBindGroup<I> {
|
||||
type Param = (
|
||||
SRes<MeshBindGroup>,
|
||||
SQuery<(
|
||||
Read<DynamicUniformIndex<MeshUniform>>,
|
||||
Option<Read<SkinnedMeshJoints>>,
|
||||
)>,
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshBindGroup<I> {
|
||||
type Param = SRes<MeshBindGroup>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = (
|
||||
Read<DynamicUniformIndex<MeshUniform>>,
|
||||
Option<Read<SkinnedMeshJoints>>,
|
||||
);
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(mesh_bind_group, mesh_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
(mesh_index, skinned_mesh_joints): ROQueryItem<'_, Self::ItemWorldQuery>,
|
||||
mesh_bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let (mesh_index, skinned_mesh_joints) = mesh_query.get(item).unwrap();
|
||||
if let Some(joints) = skinned_mesh_joints {
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
|
@ -932,16 +935,18 @@ impl<const I: usize> EntityRenderCommand for SetMeshBindGroup<I> {
|
|||
}
|
||||
|
||||
pub struct DrawMesh;
|
||||
impl EntityRenderCommand for DrawMesh {
|
||||
type Param = (SRes<RenderAssets<Mesh>>, SQuery<Read<Handle<Mesh>>>);
|
||||
impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
|
||||
type Param = SRes<RenderAssets<Mesh>>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<Handle<Mesh>>;
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(meshes, mesh_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
mesh_handle: ROQueryItem<'_, Self::ItemWorldQuery>,
|
||||
meshes: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let mesh_handle = mesh_query.get(item).unwrap();
|
||||
if let Some(gpu_mesh) = meshes.into_inner().get(mesh_handle) {
|
||||
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
||||
match &gpu_mesh.buffer_info {
|
||||
|
|
|
@ -6,6 +6,7 @@ use bevy_app::App;
|
|||
use bevy_ecs::{
|
||||
all_tuples,
|
||||
entity::Entity,
|
||||
query::{QueryState, ROQueryItem, ReadOnlyWorldQuery},
|
||||
system::{
|
||||
lifetimeless::SRes, ReadOnlySystemParam, Resource, SystemParam, SystemParamItem,
|
||||
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)
|
||||
/// are more modular.
|
||||
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`].
|
||||
fn draw<'w>(
|
||||
&mut self,
|
||||
|
@ -39,6 +46,8 @@ pub trait Draw<P: PhaseItem>: Send + Sync + 'static {
|
|||
pub trait PhaseItem: Sized + Send + Sync + 'static {
|
||||
/// The type used for ordering the items. The smallest values are drawn first.
|
||||
type SortKey: Ord;
|
||||
fn entity(&self) -> Entity;
|
||||
|
||||
/// Determines the order in which the items are drawn during the corresponding [`RenderPhase`](super::RenderPhase).
|
||||
fn sort_key(&self) -> Self::SortKey;
|
||||
/// Specifies the [`Draw`] function used to render the item.
|
||||
|
@ -75,6 +84,12 @@ pub struct DrawFunctionsInternal<P: PhaseItem> {
|
|||
}
|
||||
|
||||
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.
|
||||
pub fn add<T: Draw<P>>(&mut self, draw_function: T) -> DrawFunctionId {
|
||||
self.add_with::<T, T>(draw_function)
|
||||
|
@ -168,11 +183,14 @@ pub trait RenderCommand<P: PhaseItem> {
|
|||
/// Specifies all ECS data required by [`RenderCommand::render`].
|
||||
/// All parameters have to be read only.
|
||||
type Param: SystemParam + 'static;
|
||||
type ViewWorldQuery: ReadOnlyWorldQuery;
|
||||
type ItemWorldQuery: ReadOnlyWorldQuery;
|
||||
|
||||
/// Renders the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`].
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
item: &P,
|
||||
view: ROQueryItem<'w, Self::ViewWorldQuery>,
|
||||
entity: ROQueryItem<'w, Self::ItemWorldQuery>,
|
||||
param: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult;
|
||||
|
@ -183,20 +201,6 @@ pub enum RenderCommandResult {
|
|||
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 {
|
||||
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
|
||||
/// 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
|
||||
fn batch_range(&self) -> &Option<Range<u32>>;
|
||||
|
||||
|
@ -247,30 +251,16 @@ pub enum BatchResult {
|
|||
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;
|
||||
impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
|
||||
type Param = SRes<PipelineCache>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = ();
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: &P,
|
||||
_view: (),
|
||||
_entity: (),
|
||||
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
|
@ -287,18 +277,21 @@ impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
|
|||
}
|
||||
|
||||
macro_rules! render_command_tuple_impl {
|
||||
($($name: ident),*) => {
|
||||
($(($name: ident, $view: ident, $entity: ident)),*) => {
|
||||
impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) {
|
||||
type Param = ($($name::Param,)*);
|
||||
type ViewWorldQuery = ($($name::ViewWorldQuery,)*);
|
||||
type ItemWorldQuery = ($($name::ItemWorldQuery,)*);
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
_item: &P,
|
||||
($($view,)*): ROQueryItem<'w, Self::ViewWorldQuery>,
|
||||
($($entity,)*): ROQueryItem<'w, Self::ItemWorldQuery>,
|
||||
($($name,)*): SystemParamItem<'w, '_, Self::Param>,
|
||||
_pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult{
|
||||
$(if let RenderCommandResult::Failure = $name::render(_view, _item, $name, _pass) {
|
||||
) -> RenderCommandResult {
|
||||
$(if let RenderCommandResult::Failure = $name::render(_item, $view, $entity, $name, _pass) {
|
||||
return RenderCommandResult::Failure;
|
||||
})*
|
||||
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.
|
||||
/// Therefore the [`RenderCommand::Param`] is queried from the ECS and passed to the command.
|
||||
pub struct RenderCommandState<P: PhaseItem + 'static, C: RenderCommand<P>> {
|
||||
state: SystemState<C::Param>,
|
||||
view: QueryState<C::ViewWorldQuery>,
|
||||
entity: QueryState<C::ItemWorldQuery>,
|
||||
}
|
||||
|
||||
impl<P: PhaseItem, C: RenderCommand<P>> RenderCommandState<P, C> {
|
||||
pub fn new(world: &mut World) -> Self {
|
||||
Self {
|
||||
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
|
||||
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.
|
||||
fn draw<'w>(
|
||||
&mut self,
|
||||
|
@ -336,7 +338,9 @@ where
|
|||
item: &P,
|
||||
) {
|
||||
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 mut draw_functions = draw_functions.write();
|
||||
draw_functions.prepare(world);
|
||||
|
||||
for item in &self.items {
|
||||
let draw_function = draw_functions.get_mut(item.draw_function()).unwrap();
|
||||
|
@ -107,17 +108,16 @@ mod tests {
|
|||
impl PhaseItem for TestPhaseItem {
|
||||
type SortKey = ();
|
||||
|
||||
fn entity(&self) -> bevy_ecs::entity::Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
fn sort_key(&self) -> Self::SortKey {}
|
||||
|
||||
fn draw_function(&self) -> DrawFunctionId {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
impl EntityPhaseItem for TestPhaseItem {
|
||||
fn entity(&self) -> bevy_ecs::entity::Entity {
|
||||
self.entity
|
||||
}
|
||||
}
|
||||
impl BatchedPhaseItem for TestPhaseItem {
|
||||
fn batch_range(&self) -> &Option<std::ops::Range<u32>> {
|
||||
&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_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
event::EventReader,
|
||||
prelude::{Bundle, World},
|
||||
query::ROQueryItem,
|
||||
schedule::IntoSystemDescriptor,
|
||||
system::{
|
||||
lifetimeless::{Read, SQuery, SRes},
|
||||
lifetimeless::{Read, SRes},
|
||||
Commands, Local, Query, Res, ResMut, Resource, SystemParamItem,
|
||||
},
|
||||
world::FromWorld,
|
||||
|
@ -21,8 +21,8 @@ use bevy_render::{
|
|||
prelude::Image,
|
||||
render_asset::{PrepareAssetLabel, RenderAssets},
|
||||
render_phase::{
|
||||
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
||||
SetItemPipeline, TrackedRenderPass,
|
||||
AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
|
||||
RenderPhase, SetItemPipeline, TrackedRenderPass,
|
||||
},
|
||||
render_resource::{
|
||||
AsBindGroup, AsBindGroupError, BindGroup, BindGroupLayout, OwnedBindingResource,
|
||||
|
@ -281,15 +281,21 @@ type DrawMaterial2d<M> = (
|
|||
);
|
||||
|
||||
pub struct SetMaterial2dBindGroup<M: Material2d, const I: usize>(PhantomData<M>);
|
||||
impl<M: Material2d, const I: usize> EntityRenderCommand for SetMaterial2dBindGroup<M, I> {
|
||||
type Param = (SRes<RenderMaterials2d<M>>, SQuery<Read<Handle<M>>>);
|
||||
impl<P: PhaseItem, M: Material2d, const I: usize> RenderCommand<P>
|
||||
for SetMaterial2dBindGroup<M, I>
|
||||
{
|
||||
type Param = SRes<RenderMaterials2d<M>>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<Handle<M>>;
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(materials, query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
material2d_handle: ROQueryItem<'_, Self::ItemWorldQuery>,
|
||||
materials: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let material2d_handle = query.get(item).unwrap();
|
||||
let material2d = materials.into_inner().get(material2d_handle).unwrap();
|
||||
pass.set_bind_group(I, &material2d.bind_group, &[]);
|
||||
RenderCommandResult::Success
|
||||
|
|
|
@ -2,6 +2,7 @@ use bevy_app::Plugin;
|
|||
use bevy_asset::{load_internal_asset, Handle, HandleUntyped};
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
query::ROQueryItem,
|
||||
system::{lifetimeless::*, SystemParamItem, SystemState},
|
||||
};
|
||||
use bevy_math::{Mat4, Vec2};
|
||||
|
@ -11,7 +12,7 @@ use bevy_render::{
|
|||
globals::{GlobalsBuffer, GlobalsUniform},
|
||||
mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout},
|
||||
render_asset::RenderAssets,
|
||||
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
|
||||
render_resource::*,
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
texture::{
|
||||
|
@ -495,16 +496,19 @@ pub fn queue_mesh2d_view_bind_groups(
|
|||
}
|
||||
|
||||
pub struct SetMesh2dViewBindGroup<const I: usize>;
|
||||
impl<const I: usize> EntityRenderCommand for SetMesh2dViewBindGroup<I> {
|
||||
type Param = SQuery<(Read<ViewUniformOffset>, Read<Mesh2dViewBindGroup>)>;
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMesh2dViewBindGroup<I> {
|
||||
type Param = ();
|
||||
type ViewWorldQuery = (Read<ViewUniformOffset>, Read<Mesh2dViewBindGroup>);
|
||||
type ItemWorldQuery = ();
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
_item: Entity,
|
||||
view_query: SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
(view_uniform, mesh2d_view_bind_group): ROQueryItem<'w, Self::ViewWorldQuery>,
|
||||
_view: (),
|
||||
_param: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> 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]);
|
||||
|
||||
RenderCommandResult::Success
|
||||
|
@ -512,19 +516,19 @@ impl<const I: usize> EntityRenderCommand for SetMesh2dViewBindGroup<I> {
|
|||
}
|
||||
|
||||
pub struct SetMesh2dBindGroup<const I: usize>;
|
||||
impl<const I: usize> EntityRenderCommand for SetMesh2dBindGroup<I> {
|
||||
type Param = (
|
||||
SRes<Mesh2dBindGroup>,
|
||||
SQuery<Read<DynamicUniformIndex<Mesh2dUniform>>>,
|
||||
);
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMesh2dBindGroup<I> {
|
||||
type Param = SRes<Mesh2dBindGroup>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<DynamicUniformIndex<Mesh2dUniform>>;
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(mesh2d_bind_group, mesh2d_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
mesh2d_index: &'_ DynamicUniformIndex<Mesh2dUniform>,
|
||||
mesh2d_bind_group: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let mesh2d_index = mesh2d_query.get(item).unwrap();
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
&mesh2d_bind_group.into_inner().value,
|
||||
|
@ -535,17 +539,20 @@ impl<const I: usize> EntityRenderCommand for SetMesh2dBindGroup<I> {
|
|||
}
|
||||
|
||||
pub struct DrawMesh2d;
|
||||
impl EntityRenderCommand for DrawMesh2d {
|
||||
type Param = (SRes<RenderAssets<Mesh>>, SQuery<Read<Mesh2dHandle>>);
|
||||
impl<P: PhaseItem> RenderCommand<P> for DrawMesh2d {
|
||||
type Param = SRes<RenderAssets<Mesh>>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<Mesh2dHandle>;
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(meshes, mesh2d_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
mesh_handle: ROQueryItem<'w, Self::ItemWorldQuery>,
|
||||
meshes: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let mesh_handle = &mesh2d_query.get(item).unwrap().0;
|
||||
if let Some(gpu_mesh) = meshes.into_inner().get(mesh_handle) {
|
||||
if let Some(gpu_mesh) = meshes.into_inner().get(&mesh_handle.0) {
|
||||
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
||||
match &gpu_mesh.buffer_info {
|
||||
GpuBufferInfo::Indexed {
|
||||
|
|
|
@ -16,7 +16,7 @@ use bevy_render::{
|
|||
color::Color,
|
||||
render_asset::RenderAssets,
|
||||
render_phase::{
|
||||
BatchedPhaseItem, DrawFunctions, EntityRenderCommand, RenderCommand, RenderCommandResult,
|
||||
BatchedPhaseItem, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
|
||||
RenderPhase, SetItemPipeline, TrackedRenderPass,
|
||||
},
|
||||
render_resource::*,
|
||||
|
@ -696,16 +696,18 @@ pub type DrawSprite = (
|
|||
);
|
||||
|
||||
pub struct SetSpriteViewBindGroup<const I: usize>;
|
||||
impl<const I: usize> EntityRenderCommand for SetSpriteViewBindGroup<I> {
|
||||
type Param = (SRes<SpriteMeta>, SQuery<Read<ViewUniformOffset>>);
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteViewBindGroup<I> {
|
||||
type Param = SRes<SpriteMeta>;
|
||||
type ViewWorldQuery = Read<ViewUniformOffset>;
|
||||
type ItemWorldQuery = ();
|
||||
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
_item: Entity,
|
||||
(sprite_meta, view_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
view_uniform: &'_ ViewUniformOffset,
|
||||
_entity: (),
|
||||
sprite_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let view_uniform = view_query.get(view).unwrap();
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
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>;
|
||||
impl<const I: usize> EntityRenderCommand for SetSpriteTextureBindGroup<I> {
|
||||
type Param = (SRes<ImageBindGroups>, SQuery<Read<SpriteBatch>>);
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteTextureBindGroup<I> {
|
||||
type Param = SRes<ImageBindGroups>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<SpriteBatch>;
|
||||
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(image_bind_groups, query_batch): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
sprite_batch: &'_ SpriteBatch,
|
||||
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let sprite_batch = query_batch.get(item).unwrap();
|
||||
let image_bind_groups = image_bind_groups.into_inner();
|
||||
|
||||
pass.set_bind_group(
|
||||
|
@ -741,15 +745,17 @@ impl<const I: usize> EntityRenderCommand for SetSpriteTextureBindGroup<I> {
|
|||
|
||||
pub struct 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>(
|
||||
_view: Entity,
|
||||
item: &P,
|
||||
(sprite_meta, query_batch): SystemParamItem<'w, '_, Self::Param>,
|
||||
_view: (),
|
||||
sprite_batch: &'_ SpriteBatch,
|
||||
sprite_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let sprite_batch = query_batch.get(item.entity()).unwrap();
|
||||
let sprite_meta = sprite_meta.into_inner();
|
||||
if sprite_batch.colored {
|
||||
pass.set_vertex_buffer(0, sprite_meta.colored_vertices.buffer().unwrap().slice(..));
|
||||
|
|
|
@ -106,6 +106,11 @@ pub struct TransparentUi {
|
|||
impl PhaseItem for TransparentUi {
|
||||
type SortKey = FloatOrd;
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
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 {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
|
@ -139,16 +137,18 @@ pub type DrawUi = (
|
|||
);
|
||||
|
||||
pub struct SetUiViewBindGroup<const I: usize>;
|
||||
impl<const I: usize> EntityRenderCommand for SetUiViewBindGroup<I> {
|
||||
type Param = (SRes<UiMeta>, SQuery<Read<ViewUniformOffset>>);
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {
|
||||
type Param = SRes<UiMeta>;
|
||||
type ViewWorldQuery = Read<ViewUniformOffset>;
|
||||
type ItemWorldQuery = ();
|
||||
|
||||
fn render<'w>(
|
||||
view: Entity,
|
||||
_item: Entity,
|
||||
(ui_meta, view_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
view_uniform: &'w ViewUniformOffset,
|
||||
_entity: (),
|
||||
ui_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let view_uniform = view_query.get(view).unwrap();
|
||||
pass.set_bind_group(
|
||||
I,
|
||||
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>;
|
||||
impl<const I: usize> EntityRenderCommand for SetUiTextureBindGroup<I> {
|
||||
type Param = (SRes<UiImageBindGroups>, SQuery<Read<UiBatch>>);
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I> {
|
||||
type Param = SRes<UiImageBindGroups>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<UiBatch>;
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(image_bind_groups, query_batch): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
batch: &'w UiBatch,
|
||||
image_bind_groups: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let batch = query_batch.get(item).unwrap();
|
||||
let image_bind_groups = image_bind_groups.into_inner();
|
||||
|
||||
pass.set_bind_group(I, image_bind_groups.values.get(&batch.image).unwrap(), &[]);
|
||||
RenderCommandResult::Success
|
||||
}
|
||||
}
|
||||
pub struct DrawUiNode;
|
||||
impl EntityRenderCommand for DrawUiNode {
|
||||
type Param = (SRes<UiMeta>, SQuery<Read<UiBatch>>);
|
||||
impl<P: PhaseItem> RenderCommand<P> for DrawUiNode {
|
||||
type Param = SRes<UiMeta>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = Read<UiBatch>;
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(ui_meta, query_batch): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
batch: &'w UiBatch,
|
||||
ui_meta: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let batch = query_batch.get(item).unwrap();
|
||||
|
||||
pass.set_vertex_buffer(0, ui_meta.into_inner().vertices.buffer().unwrap().slice(..));
|
||||
pass.draw(batch.range.clone(), 0..1);
|
||||
RenderCommandResult::Success
|
||||
|
|
|
@ -13,8 +13,8 @@ use bevy::{
|
|||
mesh::{GpuBufferInfo, MeshVertexBufferLayout},
|
||||
render_asset::RenderAssets,
|
||||
render_phase::{
|
||||
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
|
||||
SetItemPipeline, TrackedRenderPass,
|
||||
AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult,
|
||||
RenderPhase, SetItemPipeline, TrackedRenderPass,
|
||||
},
|
||||
render_resource::*,
|
||||
renderer::RenderDevice,
|
||||
|
@ -223,22 +223,19 @@ type DrawCustom = (
|
|||
|
||||
pub struct DrawMeshInstanced;
|
||||
|
||||
impl EntityRenderCommand for DrawMeshInstanced {
|
||||
type Param = (
|
||||
SRes<RenderAssets<Mesh>>,
|
||||
SQuery<Read<Handle<Mesh>>>,
|
||||
SQuery<Read<InstanceBuffer>>,
|
||||
);
|
||||
impl<P: PhaseItem> RenderCommand<P> for DrawMeshInstanced {
|
||||
type Param = SRes<RenderAssets<Mesh>>;
|
||||
type ViewWorldQuery = ();
|
||||
type ItemWorldQuery = (Read<Handle<Mesh>>, Read<InstanceBuffer>);
|
||||
|
||||
#[inline]
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(meshes, mesh_query, instance_buffer_query): SystemParamItem<'w, '_, Self::Param>,
|
||||
_item: &P,
|
||||
_view: (),
|
||||
(mesh_handle, instance_buffer): (&'w Handle<Mesh>, &'w InstanceBuffer),
|
||||
meshes: SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> 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) {
|
||||
Some(gpu_mesh) => gpu_mesh,
|
||||
None => return RenderCommandResult::Failure,
|
||||
|
|
Loading…
Add table
Reference in a new issue