mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Use BinnedRenderPhase for Opaque2d (#13091)
Based on top of #12982 and #13069 # Objective - Opaque2d was implemented with SortedRenderPhase but BinnedRenderPhase should be much faster ## Solution - Implement BinnedRenderPhase for Opaque2d ## Notes While testing this PR, before the change I had ~14 fps in bevymark with 100k entities. After this change I get ~71 fps, compared to using sprites where I only get ~63 fps. This means that after this PR mesh2d with opaque meshes will be faster than the sprite path. This is not a 1 to 1 comparison since sprites do alpha blending.
This commit is contained in:
parent
7f658cabf7
commit
9d6a4fbc85
5 changed files with 167 additions and 53 deletions
|
@ -4,7 +4,7 @@ use bevy_render::{
|
||||||
camera::ExtractedCamera,
|
camera::ExtractedCamera,
|
||||||
diagnostic::RecordDiagnostics,
|
diagnostic::RecordDiagnostics,
|
||||||
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
|
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
|
||||||
render_phase::{TrackedRenderPass, ViewSortedRenderPhases},
|
render_phase::{TrackedRenderPass, ViewBinnedRenderPhases},
|
||||||
render_resource::{CommandEncoderDescriptor, RenderPassDescriptor, StoreOp},
|
render_resource::{CommandEncoderDescriptor, RenderPassDescriptor, StoreOp},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{ViewDepthTexture, ViewTarget},
|
view::{ViewDepthTexture, ViewTarget},
|
||||||
|
@ -13,7 +13,7 @@ use bevy_utils::tracing::error;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::info_span;
|
use bevy_utils::tracing::info_span;
|
||||||
|
|
||||||
/// A [`bevy_render::render_graph::Node`] that runs the [`Opaque2d`] [`ViewSortedRenderPhases`]
|
/// A [`bevy_render::render_graph::Node`] that runs the [`Opaque2d`] [`ViewBinnedRenderPhases`]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct MainOpaquePass2dNode;
|
pub struct MainOpaquePass2dNode;
|
||||||
impl ViewNode for MainOpaquePass2dNode {
|
impl ViewNode for MainOpaquePass2dNode {
|
||||||
|
@ -30,7 +30,7 @@ impl ViewNode for MainOpaquePass2dNode {
|
||||||
(camera, target, depth): QueryItem<'w, Self::ViewQuery>,
|
(camera, target, depth): QueryItem<'w, Self::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
let Some(opaque_phases) = world.get_resource::<ViewSortedRenderPhases<Opaque2d>>() else {
|
let Some(opaque_phases) = world.get_resource::<ViewBinnedRenderPhases<Opaque2d>>() else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ impl ViewNode for MainOpaquePass2dNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opaque draws
|
// Opaque draws
|
||||||
if !opaque_phase.items.is_empty() {
|
if !opaque_phase.is_empty() {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _opaque_main_pass_2d_span = info_span!("opaque_main_pass_2d").entered();
|
let _opaque_main_pass_2d_span = info_span!("opaque_main_pass_2d").entered();
|
||||||
if let Err(err) = opaque_phase.render(&mut render_pass, world, view_entity) {
|
if let Err(err) = opaque_phase.render(&mut render_pass, world, view_entity) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub mod graph {
|
||||||
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use bevy_asset::UntypedAssetId;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
pub use camera_2d::*;
|
pub use camera_2d::*;
|
||||||
pub use main_opaque_pass_2d_node::*;
|
pub use main_opaque_pass_2d_node::*;
|
||||||
|
@ -45,12 +46,13 @@ use bevy_render::{
|
||||||
extract_component::ExtractComponentPlugin,
|
extract_component::ExtractComponentPlugin,
|
||||||
render_graph::{EmptyNode, RenderGraphApp, ViewNodeRunner},
|
render_graph::{EmptyNode, RenderGraphApp, ViewNodeRunner},
|
||||||
render_phase::{
|
render_phase::{
|
||||||
sort_phase_system, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, PhaseItem,
|
sort_phase_system, BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId,
|
||||||
PhaseItemExtraIndex, SortedPhaseItem, ViewSortedRenderPhases,
|
DrawFunctions, PhaseItem, PhaseItemExtraIndex, SortedPhaseItem, ViewBinnedRenderPhases,
|
||||||
|
ViewSortedRenderPhases,
|
||||||
},
|
},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
CachedRenderPipelineId, Extent3d, TextureDescriptor, TextureDimension, TextureFormat,
|
BindGroupId, CachedRenderPipelineId, Extent3d, TextureDescriptor, TextureDimension,
|
||||||
TextureUsages,
|
TextureFormat, TextureUsages,
|
||||||
},
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::TextureCache,
|
texture::TextureCache,
|
||||||
|
@ -78,12 +80,11 @@ impl Plugin for Core2dPlugin {
|
||||||
.init_resource::<DrawFunctions<Opaque2d>>()
|
.init_resource::<DrawFunctions<Opaque2d>>()
|
||||||
.init_resource::<DrawFunctions<Transparent2d>>()
|
.init_resource::<DrawFunctions<Transparent2d>>()
|
||||||
.init_resource::<ViewSortedRenderPhases<Transparent2d>>()
|
.init_resource::<ViewSortedRenderPhases<Transparent2d>>()
|
||||||
.init_resource::<ViewSortedRenderPhases<Opaque2d>>()
|
.init_resource::<ViewBinnedRenderPhases<Opaque2d>>()
|
||||||
.add_systems(ExtractSchedule, extract_core_2d_camera_phases)
|
.add_systems(ExtractSchedule, extract_core_2d_camera_phases)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
(
|
(
|
||||||
sort_phase_system::<Opaque2d>.in_set(RenderSet::PhaseSort),
|
|
||||||
sort_phase_system::<Transparent2d>.in_set(RenderSet::PhaseSort),
|
sort_phase_system::<Transparent2d>.in_set(RenderSet::PhaseSort),
|
||||||
prepare_core_2d_depth_textures.in_set(RenderSet::PrepareResources),
|
prepare_core_2d_depth_textures.in_set(RenderSet::PrepareResources),
|
||||||
),
|
),
|
||||||
|
@ -119,24 +120,47 @@ impl Plugin for Core2dPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opaque 2D [`SortedPhaseItem`]s.
|
/// Opaque 2D [`BinnedPhaseItem`]s.
|
||||||
pub struct Opaque2d {
|
pub struct Opaque2d {
|
||||||
pub sort_key: FloatOrd,
|
/// The key, which determines which can be batched.
|
||||||
pub entity: Entity,
|
pub key: Opaque2dBinKey,
|
||||||
pub pipeline: CachedRenderPipelineId,
|
/// An entity from which data will be fetched, including the mesh if
|
||||||
pub draw_function: DrawFunctionId,
|
/// applicable.
|
||||||
|
pub representative_entity: Entity,
|
||||||
|
/// The ranges of instances.
|
||||||
pub batch_range: Range<u32>,
|
pub batch_range: Range<u32>,
|
||||||
|
/// An extra index, which is either a dynamic offset or an index in the
|
||||||
|
/// indirect parameters list.
|
||||||
pub extra_index: PhaseItemExtraIndex,
|
pub extra_index: PhaseItemExtraIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Data that must be identical in order to batch phase items together.
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Opaque2dBinKey {
|
||||||
|
/// The identifier of the render pipeline.
|
||||||
|
pub pipeline: CachedRenderPipelineId,
|
||||||
|
/// The function used to draw.
|
||||||
|
pub draw_function: DrawFunctionId,
|
||||||
|
/// The asset that this phase item is associated with.
|
||||||
|
///
|
||||||
|
/// Normally, this is the ID of the mesh, but for non-mesh items it might be
|
||||||
|
/// the ID of another type of asset.
|
||||||
|
pub asset_id: UntypedAssetId,
|
||||||
|
/// The ID of a bind group specific to the material.
|
||||||
|
///
|
||||||
|
/// In the case of PBR, this is the `MaterialBindGroupId`.
|
||||||
|
pub material_bind_group_id: Option<BindGroupId>,
|
||||||
|
}
|
||||||
|
|
||||||
impl PhaseItem for Opaque2d {
|
impl PhaseItem for Opaque2d {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn entity(&self) -> Entity {
|
fn entity(&self) -> Entity {
|
||||||
self.entity
|
self.representative_entity
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn draw_function(&self) -> DrawFunctionId {
|
fn draw_function(&self) -> DrawFunctionId {
|
||||||
self.draw_function
|
self.key.draw_function
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -158,25 +182,28 @@ impl PhaseItem for Opaque2d {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SortedPhaseItem for Opaque2d {
|
impl BinnedPhaseItem for Opaque2d {
|
||||||
type SortKey = FloatOrd;
|
type BinKey = Opaque2dBinKey;
|
||||||
|
|
||||||
#[inline]
|
fn new(
|
||||||
fn sort_key(&self) -> Self::SortKey {
|
key: Self::BinKey,
|
||||||
self.sort_key
|
representative_entity: Entity,
|
||||||
}
|
batch_range: Range<u32>,
|
||||||
|
extra_index: PhaseItemExtraIndex,
|
||||||
#[inline]
|
) -> Self {
|
||||||
fn sort(items: &mut [Self]) {
|
Opaque2d {
|
||||||
// radsort is a stable radix sort that performed better than `slice::sort_by_key` or `slice::sort_unstable_by_key`.
|
key,
|
||||||
radsort::sort_by_key(items, |item| item.sort_key().0);
|
representative_entity,
|
||||||
|
batch_range,
|
||||||
|
extra_index,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CachedRenderPipelinePhaseItem for Opaque2d {
|
impl CachedRenderPipelinePhaseItem for Opaque2d {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||||
self.pipeline
|
self.key.pipeline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +273,7 @@ impl CachedRenderPipelinePhaseItem for Transparent2d {
|
||||||
pub fn extract_core_2d_camera_phases(
|
pub fn extract_core_2d_camera_phases(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut transparent_2d_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
|
mut transparent_2d_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
|
||||||
mut opaque_2d_phases: ResMut<ViewSortedRenderPhases<Opaque2d>>,
|
mut opaque_2d_phases: ResMut<ViewBinnedRenderPhases<Opaque2d>>,
|
||||||
cameras_2d: Extract<Query<(Entity, &Camera), With<Camera2d>>>,
|
cameras_2d: Extract<Query<(Entity, &Camera), With<Camera2d>>>,
|
||||||
mut live_entities: Local<EntityHashSet>,
|
mut live_entities: Local<EntityHashSet>,
|
||||||
) {
|
) {
|
||||||
|
@ -273,13 +300,13 @@ pub fn prepare_core_2d_depth_textures(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut texture_cache: ResMut<TextureCache>,
|
mut texture_cache: ResMut<TextureCache>,
|
||||||
render_device: Res<RenderDevice>,
|
render_device: Res<RenderDevice>,
|
||||||
transparent_2d_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
|
transparent_2d_phases: Res<ViewSortedRenderPhases<Transparent2d>>,
|
||||||
opaque_2d_phases: ResMut<ViewSortedRenderPhases<Opaque2d>>,
|
opaque_2d_phases: Res<ViewBinnedRenderPhases<Opaque2d>>,
|
||||||
views_2d: Query<(Entity, &ExtractedCamera, &Msaa), (With<Camera2d>,)>,
|
views_2d: Query<(Entity, &ExtractedCamera, &Msaa), (With<Camera2d>,)>,
|
||||||
) {
|
) {
|
||||||
let mut textures = HashMap::default();
|
let mut textures = HashMap::default();
|
||||||
for (entity, camera, msaa) in &views_2d {
|
for (view, camera, msaa) in &views_2d {
|
||||||
if !opaque_2d_phases.contains_key(&entity) || !transparent_2d_phases.contains_key(&entity) {
|
if !opaque_2d_phases.contains_key(&view) || !transparent_2d_phases.contains_key(&view) {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -313,7 +340,7 @@ pub fn prepare_core_2d_depth_textures(
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
commands
|
commands
|
||||||
.entity(entity)
|
.entity(view)
|
||||||
.insert(ViewDepthTexture::new(cached_texture, Some(0.0)));
|
.insert(ViewDepthTexture::new(cached_texture, Some(0.0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,14 @@ bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||||
|
|
||||||
# other
|
# other
|
||||||
bytemuck = { version = "1.5", features = ["derive"] }
|
bytemuck = { version = "1", features = ["derive", "must_cast"] }
|
||||||
fixedbitset = "0.5"
|
fixedbitset = "0.5"
|
||||||
guillotiere = "0.6.0"
|
guillotiere = "0.6.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
rectangle-pack = "0.4"
|
rectangle-pack = "0.4"
|
||||||
bitflags = "2.3"
|
bitflags = "2.3"
|
||||||
radsort = "0.1"
|
radsort = "0.1"
|
||||||
|
nonmax = "0.5"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{Asset, AssetApp, AssetId, AssetServer, Handle};
|
use bevy_asset::{Asset, AssetApp, AssetId, AssetServer, Handle};
|
||||||
use bevy_core_pipeline::{
|
use bevy_core_pipeline::{
|
||||||
core_2d::{Opaque2d, Transparent2d},
|
core_2d::{Opaque2d, Opaque2dBinKey, Transparent2d},
|
||||||
tonemapping::{DebandDither, Tonemapping},
|
tonemapping::{DebandDither, Tonemapping},
|
||||||
};
|
};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
@ -18,8 +18,9 @@ use bevy_render::{
|
||||||
prepare_assets, PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets,
|
prepare_assets, PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets,
|
||||||
},
|
},
|
||||||
render_phase::{
|
render_phase::{
|
||||||
AddRenderCommand, DrawFunctions, PhaseItem, PhaseItemExtraIndex, RenderCommand,
|
AddRenderCommand, BinnedRenderPhaseType, DrawFunctions, PhaseItem, PhaseItemExtraIndex,
|
||||||
RenderCommandResult, SetItemPipeline, TrackedRenderPass, ViewSortedRenderPhases,
|
RenderCommand, RenderCommandResult, SetItemPipeline, TrackedRenderPass,
|
||||||
|
ViewBinnedRenderPhases, ViewSortedRenderPhases,
|
||||||
},
|
},
|
||||||
render_resource::{
|
render_resource::{
|
||||||
AsBindGroup, AsBindGroupError, BindGroup, BindGroupId, BindGroupLayout,
|
AsBindGroup, AsBindGroupError, BindGroup, BindGroupId, BindGroupLayout,
|
||||||
|
@ -404,7 +405,7 @@ pub fn queue_material2d_meshes<M: Material2d>(
|
||||||
mut render_mesh_instances: ResMut<RenderMesh2dInstances>,
|
mut render_mesh_instances: ResMut<RenderMesh2dInstances>,
|
||||||
render_material_instances: Res<RenderMaterial2dInstances<M>>,
|
render_material_instances: Res<RenderMaterial2dInstances<M>>,
|
||||||
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
|
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
|
||||||
mut opaque_render_phases: ResMut<ViewSortedRenderPhases<Opaque2d>>,
|
mut opaque_render_phases: ResMut<ViewBinnedRenderPhases<Opaque2d>>,
|
||||||
mut views: Query<(
|
mut views: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&ExtractedView,
|
&ExtractedView,
|
||||||
|
@ -484,16 +485,17 @@ pub fn queue_material2d_meshes<M: Material2d>(
|
||||||
|
|
||||||
match material_2d.properties.alpha_mode {
|
match material_2d.properties.alpha_mode {
|
||||||
AlphaMode2d::Opaque => {
|
AlphaMode2d::Opaque => {
|
||||||
opaque_phase.add(Opaque2d {
|
let bin_key = Opaque2dBinKey {
|
||||||
entity: *visible_entity,
|
|
||||||
draw_function: draw_opaque_2d,
|
|
||||||
pipeline: pipeline_id,
|
pipeline: pipeline_id,
|
||||||
// Front-to-back ordering
|
draw_function: draw_opaque_2d,
|
||||||
sort_key: -FloatOrd(mesh_z + material_2d.properties.depth_bias),
|
asset_id: mesh_instance.mesh_asset_id.into(),
|
||||||
// Batching is done in batch_and_prepare_render_phase
|
material_bind_group_id: material_2d.get_bind_group_id().0,
|
||||||
batch_range: 0..1,
|
};
|
||||||
extra_index: PhaseItemExtraIndex::NONE,
|
opaque_phase.add(
|
||||||
});
|
bin_key,
|
||||||
|
*visible_entity,
|
||||||
|
BinnedRenderPhaseType::mesh(mesh_instance.automatic_batching),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
AlphaMode2d::Blend => {
|
AlphaMode2d::Blend => {
|
||||||
transparent_phase.add(Transparent2d {
|
transparent_phase.add(Transparent2d {
|
||||||
|
|
|
@ -14,10 +14,13 @@ use bevy_ecs::{
|
||||||
};
|
};
|
||||||
use bevy_math::{Affine3, Vec4};
|
use bevy_math::{Affine3, Vec4};
|
||||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||||
|
use bevy_render::batching::gpu_preprocessing::IndirectParameters;
|
||||||
|
use bevy_render::batching::no_gpu_preprocessing::batch_and_prepare_binned_render_phase;
|
||||||
use bevy_render::batching::no_gpu_preprocessing::{
|
use bevy_render::batching::no_gpu_preprocessing::{
|
||||||
self, batch_and_prepare_sorted_render_phase, write_batched_instance_buffer,
|
self, batch_and_prepare_sorted_render_phase, write_batched_instance_buffer,
|
||||||
BatchedInstanceBuffer,
|
BatchedInstanceBuffer,
|
||||||
};
|
};
|
||||||
|
use bevy_render::batching::GetFullBatchData;
|
||||||
use bevy_render::mesh::allocator::MeshAllocator;
|
use bevy_render::mesh::allocator::MeshAllocator;
|
||||||
use bevy_render::mesh::{MeshVertexBufferLayoutRef, RenderMesh};
|
use bevy_render::mesh::{MeshVertexBufferLayoutRef, RenderMesh};
|
||||||
use bevy_render::texture::FallbackImage;
|
use bevy_render::texture::FallbackImage;
|
||||||
|
@ -38,6 +41,8 @@ use bevy_render::{
|
||||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
|
use bevy_utils::tracing::error;
|
||||||
|
use nonmax::NonMaxU32;
|
||||||
|
|
||||||
use crate::Material2dBindGroupId;
|
use crate::Material2dBindGroupId;
|
||||||
|
|
||||||
|
@ -107,7 +112,7 @@ impl Plugin for Mesh2dRenderPlugin {
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
(
|
(
|
||||||
batch_and_prepare_sorted_render_phase::<Opaque2d, Mesh2dPipeline>
|
batch_and_prepare_binned_render_phase::<Opaque2d, Mesh2dPipeline>
|
||||||
.in_set(RenderSet::PrepareResources),
|
.in_set(RenderSet::PrepareResources),
|
||||||
batch_and_prepare_sorted_render_phase::<Transparent2d, Mesh2dPipeline>
|
batch_and_prepare_sorted_render_phase::<Transparent2d, Mesh2dPipeline>
|
||||||
.in_set(RenderSet::PrepareResources),
|
.in_set(RenderSet::PrepareResources),
|
||||||
|
@ -163,7 +168,7 @@ pub struct Mesh2dTransforms {
|
||||||
pub flags: u32,
|
pub flags: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ShaderType, Clone)]
|
#[derive(ShaderType, Clone, Copy)]
|
||||||
pub struct Mesh2dUniform {
|
pub struct Mesh2dUniform {
|
||||||
// Affine 4x3 matrix transposed to 3x4
|
// Affine 4x3 matrix transposed to 3x4
|
||||||
pub world_from_local: [Vec4; 3],
|
pub world_from_local: [Vec4; 3],
|
||||||
|
@ -360,12 +365,16 @@ impl Mesh2dPipeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetBatchData for Mesh2dPipeline {
|
impl GetBatchData for Mesh2dPipeline {
|
||||||
type Param = SRes<RenderMesh2dInstances>;
|
type Param = (
|
||||||
|
SRes<RenderMesh2dInstances>,
|
||||||
|
SRes<RenderAssets<RenderMesh>>,
|
||||||
|
SRes<MeshAllocator>,
|
||||||
|
);
|
||||||
type CompareData = (Material2dBindGroupId, AssetId<Mesh>);
|
type CompareData = (Material2dBindGroupId, AssetId<Mesh>);
|
||||||
type BufferData = Mesh2dUniform;
|
type BufferData = Mesh2dUniform;
|
||||||
|
|
||||||
fn get_batch_data(
|
fn get_batch_data(
|
||||||
mesh_instances: &SystemParamItem<Self::Param>,
|
(mesh_instances, _, _): &SystemParamItem<Self::Param>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
|
) -> Option<(Self::BufferData, Option<Self::CompareData>)> {
|
||||||
let mesh_instance = mesh_instances.get(&entity)?;
|
let mesh_instance = mesh_instances.get(&entity)?;
|
||||||
|
@ -379,6 +388,81 @@ impl GetBatchData for Mesh2dPipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GetFullBatchData for Mesh2dPipeline {
|
||||||
|
type BufferInputData = ();
|
||||||
|
|
||||||
|
fn get_binned_batch_data(
|
||||||
|
(mesh_instances, _, _): &SystemParamItem<Self::Param>,
|
||||||
|
entity: Entity,
|
||||||
|
) -> Option<Self::BufferData> {
|
||||||
|
let mesh_instance = mesh_instances.get(&entity)?;
|
||||||
|
Some((&mesh_instance.transforms).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_index_and_compare_data(
|
||||||
|
_: &SystemParamItem<Self::Param>,
|
||||||
|
_query_item: Entity,
|
||||||
|
) -> Option<(NonMaxU32, Option<Self::CompareData>)> {
|
||||||
|
error!(
|
||||||
|
"`get_index_and_compare_data` is only intended for GPU mesh uniform building, \
|
||||||
|
but this is not yet implemented for 2d meshes"
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_binned_index(
|
||||||
|
_: &SystemParamItem<Self::Param>,
|
||||||
|
_query_item: Entity,
|
||||||
|
) -> Option<NonMaxU32> {
|
||||||
|
error!(
|
||||||
|
"`get_binned_index` is only intended for GPU mesh uniform building, \
|
||||||
|
but this is not yet implemented for 2d meshes"
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_batch_indirect_parameters_index(
|
||||||
|
(mesh_instances, meshes, mesh_allocator): &SystemParamItem<Self::Param>,
|
||||||
|
indirect_parameters_buffer: &mut bevy_render::batching::gpu_preprocessing::IndirectParametersBuffer,
|
||||||
|
entity: Entity,
|
||||||
|
instance_index: u32,
|
||||||
|
) -> Option<NonMaxU32> {
|
||||||
|
let mesh_instance = mesh_instances.get(&entity)?;
|
||||||
|
let mesh = meshes.get(mesh_instance.mesh_asset_id)?;
|
||||||
|
let vertex_buffer_slice = mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id)?;
|
||||||
|
|
||||||
|
// Note that `IndirectParameters` covers both of these structures, even
|
||||||
|
// though they actually have distinct layouts. See the comment above that
|
||||||
|
// type for more information.
|
||||||
|
let indirect_parameters = match mesh.buffer_info {
|
||||||
|
RenderMeshBufferInfo::Indexed {
|
||||||
|
count: index_count, ..
|
||||||
|
} => {
|
||||||
|
let index_buffer_slice =
|
||||||
|
mesh_allocator.mesh_index_slice(&mesh_instance.mesh_asset_id)?;
|
||||||
|
IndirectParameters {
|
||||||
|
vertex_or_index_count: index_count,
|
||||||
|
instance_count: 0,
|
||||||
|
first_vertex_or_first_index: index_buffer_slice.range.start,
|
||||||
|
base_vertex_or_first_instance: vertex_buffer_slice.range.start,
|
||||||
|
first_instance: instance_index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RenderMeshBufferInfo::NonIndexed => IndirectParameters {
|
||||||
|
vertex_or_index_count: mesh.vertex_count,
|
||||||
|
instance_count: 0,
|
||||||
|
first_vertex_or_first_index: vertex_buffer_slice.range.start,
|
||||||
|
base_vertex_or_first_instance: instance_index,
|
||||||
|
first_instance: instance_index,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(indirect_parameters_buffer.push(indirect_parameters) as u32)
|
||||||
|
.try_into()
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
Loading…
Reference in a new issue