Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use BinnedRenderPhase for Opaque2d #13091

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bevy_render::{
camera::ExtractedCamera,
diagnostic::RecordDiagnostics,
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
render_phase::{TrackedRenderPass, ViewSortedRenderPhases},
render_phase::{TrackedRenderPass, ViewBinnedRenderPhases},
render_resource::{CommandEncoderDescriptor, RenderPassDescriptor, StoreOp},
renderer::RenderContext,
view::{ViewDepthTexture, ViewTarget},
Expand All @@ -13,7 +13,7 @@ use bevy_utils::tracing::error;
#[cfg(feature = "trace")]
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)]
pub struct MainOpaquePass2dNode;
impl ViewNode for MainOpaquePass2dNode {
Expand All @@ -30,7 +30,7 @@ impl ViewNode for MainOpaquePass2dNode {
(camera, target, depth): QueryItem<'w, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let Some(opaque_phases) = world.get_resource::<ViewSortedRenderPhases<Opaque2d>>() else {
let Some(opaque_phases) = world.get_resource::<ViewBinnedRenderPhases<Opaque2d>>() else {
return Ok(());
};

Expand Down Expand Up @@ -69,7 +69,7 @@ impl ViewNode for MainOpaquePass2dNode {
}

// Opaque draws
if !opaque_phase.items.is_empty() {
if !opaque_phase.is_empty() {
#[cfg(feature = "trace")]
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) {
Expand Down
91 changes: 59 additions & 32 deletions crates/bevy_core_pipeline/src/core_2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod graph {

use std::ops::Range;

use bevy_asset::UntypedAssetId;
use bevy_utils::HashMap;
pub use camera_2d::*;
pub use main_opaque_pass_2d_node::*;
Expand All @@ -45,12 +46,13 @@ use bevy_render::{
extract_component::ExtractComponentPlugin,
render_graph::{EmptyNode, RenderGraphApp, ViewNodeRunner},
render_phase::{
sort_phase_system, CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, PhaseItem,
PhaseItemExtraIndex, SortedPhaseItem, ViewSortedRenderPhases,
sort_phase_system, BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId,
DrawFunctions, PhaseItem, PhaseItemExtraIndex, SortedPhaseItem, ViewBinnedRenderPhases,
ViewSortedRenderPhases,
},
render_resource::{
CachedRenderPipelineId, Extent3d, TextureDescriptor, TextureDimension, TextureFormat,
TextureUsages,
BindGroupId, CachedRenderPipelineId, Extent3d, TextureDescriptor, TextureDimension,
TextureFormat, TextureUsages,
},
renderer::RenderDevice,
texture::TextureCache,
Expand Down Expand Up @@ -78,12 +80,11 @@ impl Plugin for Core2dPlugin {
.init_resource::<DrawFunctions<Opaque2d>>()
.init_resource::<DrawFunctions<Transparent2d>>()
.init_resource::<ViewSortedRenderPhases<Transparent2d>>()
.init_resource::<ViewSortedRenderPhases<Opaque2d>>()
.init_resource::<ViewBinnedRenderPhases<Opaque2d>>()
.add_systems(ExtractSchedule, extract_core_2d_camera_phases)
.add_systems(
Render,
(
sort_phase_system::<Opaque2d>.in_set(RenderSet::PhaseSort),
sort_phase_system::<Transparent2d>.in_set(RenderSet::PhaseSort),
prepare_core_2d_depth_textures.in_set(RenderSet::PrepareResources),
),
Expand Down Expand Up @@ -119,24 +120,47 @@ impl Plugin for Core2dPlugin {
}
}

/// Opaque 2D [`SortedPhaseItem`]s.
/// Opaque 2D [`BinnedPhaseItem`]s.
pub struct Opaque2d {
pub sort_key: FloatOrd,
pub entity: Entity,
pub pipeline: CachedRenderPipelineId,
pub draw_function: DrawFunctionId,
/// The key, which determines which can be batched.
pub key: Opaque2dBinKey,
/// An entity from which data will be fetched, including the mesh if
/// applicable.
pub representative_entity: Entity,
/// The ranges of instances.
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,
}

/// 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 {
#[inline]
fn entity(&self) -> Entity {
self.entity
self.representative_entity
}

#[inline]
fn draw_function(&self) -> DrawFunctionId {
self.draw_function
self.key.draw_function
}

#[inline]
Expand All @@ -158,25 +182,28 @@ impl PhaseItem for Opaque2d {
}
}

impl SortedPhaseItem for Opaque2d {
type SortKey = FloatOrd;

#[inline]
fn sort_key(&self) -> Self::SortKey {
self.sort_key
}

#[inline]
fn sort(items: &mut [Self]) {
// radsort is a stable radix sort that performed better than `slice::sort_by_key` or `slice::sort_unstable_by_key`.
radsort::sort_by_key(items, |item| item.sort_key().0);
impl BinnedPhaseItem for Opaque2d {
type BinKey = Opaque2dBinKey;

fn new(
key: Self::BinKey,
representative_entity: Entity,
batch_range: Range<u32>,
extra_index: PhaseItemExtraIndex,
) -> Self {
Opaque2d {
key,
representative_entity,
batch_range,
extra_index,
}
}
}

impl CachedRenderPipelinePhaseItem for Opaque2d {
#[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId {
self.pipeline
self.key.pipeline
}
}

Expand Down Expand Up @@ -246,7 +273,7 @@ impl CachedRenderPipelinePhaseItem for Transparent2d {
pub fn extract_core_2d_camera_phases(
mut commands: Commands,
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>>>,
mut live_entities: Local<EntityHashSet>,
) {
Expand All @@ -273,13 +300,13 @@ pub fn prepare_core_2d_depth_textures(
mut commands: Commands,
mut texture_cache: ResMut<TextureCache>,
render_device: Res<RenderDevice>,
transparent_2d_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
opaque_2d_phases: ResMut<ViewSortedRenderPhases<Opaque2d>>,
transparent_2d_phases: Res<ViewSortedRenderPhases<Transparent2d>>,
opaque_2d_phases: Res<ViewBinnedRenderPhases<Opaque2d>>,
views_2d: Query<(Entity, &ExtractedCamera, &Msaa), (With<Camera2d>,)>,
) {
let mut textures = HashMap::default();
for (entity, camera, msaa) in &views_2d {
if !opaque_2d_phases.contains_key(&entity) || !transparent_2d_phases.contains_key(&entity) {
for (view, camera, msaa) in &views_2d {
if !opaque_2d_phases.contains_key(&view) || !transparent_2d_phases.contains_key(&view) {
continue;
};

Expand Down Expand Up @@ -313,7 +340,7 @@ pub fn prepare_core_2d_depth_textures(
.clone();

commands
.entity(entity)
.entity(view)
.insert(ViewDepthTexture::new(cached_texture, Some(0.0)));
}
}
3 changes: 2 additions & 1 deletion crates/bevy_sprite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }

# other
bytemuck = { version = "1.5", features = ["derive"] }
bytemuck = { version = "1", features = ["derive", "must_cast"] }
fixedbitset = "0.5"
guillotiere = "0.6.0"
thiserror = "1.0"
rectangle-pack = "0.4"
bitflags = "2.3"
radsort = "0.1"
nonmax = "0.5"

[lints]
workspace = true
Expand Down
28 changes: 15 additions & 13 deletions crates/bevy_sprite/src/mesh2d/material.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy_app::{App, Plugin};
use bevy_asset::{Asset, AssetApp, AssetId, AssetServer, Handle};
use bevy_core_pipeline::{
core_2d::{Opaque2d, Transparent2d},
core_2d::{Opaque2d, Opaque2dBinKey, Transparent2d},
tonemapping::{DebandDither, Tonemapping},
};
use bevy_derive::{Deref, DerefMut};
Expand All @@ -18,8 +18,9 @@ use bevy_render::{
prepare_assets, PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets,
},
render_phase::{
AddRenderCommand, DrawFunctions, PhaseItem, PhaseItemExtraIndex, RenderCommand,
RenderCommandResult, SetItemPipeline, TrackedRenderPass, ViewSortedRenderPhases,
AddRenderCommand, BinnedRenderPhaseType, DrawFunctions, PhaseItem, PhaseItemExtraIndex,
RenderCommand, RenderCommandResult, SetItemPipeline, TrackedRenderPass,
ViewBinnedRenderPhases, ViewSortedRenderPhases,
},
render_resource::{
AsBindGroup, AsBindGroupError, BindGroup, BindGroupId, BindGroupLayout,
Expand Down Expand Up @@ -404,7 +405,7 @@ pub fn queue_material2d_meshes<M: Material2d>(
mut render_mesh_instances: ResMut<RenderMesh2dInstances>,
render_material_instances: Res<RenderMaterial2dInstances<M>>,
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
mut opaque_render_phases: ResMut<ViewSortedRenderPhases<Opaque2d>>,
mut opaque_render_phases: ResMut<ViewBinnedRenderPhases<Opaque2d>>,
mut views: Query<(
Entity,
&ExtractedView,
Expand Down Expand Up @@ -484,16 +485,17 @@ pub fn queue_material2d_meshes<M: Material2d>(

match material_2d.properties.alpha_mode {
AlphaMode2d::Opaque => {
opaque_phase.add(Opaque2d {
entity: *visible_entity,
draw_function: draw_opaque_2d,
let bin_key = Opaque2dBinKey {
pipeline: pipeline_id,
// Front-to-back ordering
sort_key: -FloatOrd(mesh_z + material_2d.properties.depth_bias),
IceSentry marked this conversation as resolved.
Show resolved Hide resolved
// Batching is done in batch_and_prepare_render_phase
batch_range: 0..1,
extra_index: PhaseItemExtraIndex::NONE,
});
draw_function: draw_opaque_2d,
asset_id: mesh_instance.mesh_asset_id.into(),
material_bind_group_id: material_2d.get_bind_group_id().0,
};
opaque_phase.add(
bin_key,
*visible_entity,
BinnedRenderPhaseType::mesh(mesh_instance.automatic_batching),
);
}
AlphaMode2d::Blend => {
transparent_phase.add(Transparent2d {
Expand Down
Loading