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

[Merged by Bors] - Allow unbatched render phases to use unstable sorts #5049

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 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
6 changes: 6 additions & 0 deletions crates/bevy_core_pipeline/src/core_2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use bevy_render::{
render_phase::{
batch_phase_system, sort_phase_system, BatchedPhaseItem, CachedRenderPipelinePhaseItem,
DrawFunctionId, DrawFunctions, EntityPhaseItem, PhaseItem, RenderPhase,
RenderPhaseSortMode,
},
render_resource::CachedRenderPipelineId,
RenderApp, RenderStage,
Expand Down Expand Up @@ -90,6 +91,11 @@ impl PhaseItem for Transparent2d {
fn draw_function(&self) -> DrawFunctionId {
self.draw_function
}

#[inline]
fn sort_mode() -> RenderPhaseSortMode {
james7132 marked this conversation as resolved.
Show resolved Hide resolved
RenderPhaseSortMode::Stable
}
}

impl EntityPhaseItem for Transparent2d {
Expand Down
38 changes: 38 additions & 0 deletions crates/bevy_render/src/render_phase/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ pub trait Draw<P: PhaseItem>: Send + Sync + 'static {
);
}

/// Configures how a render phase is sorted. For more information, see [`PhaseItem::sort_mode`].
pub enum RenderPhaseSortMode {
/// Requires a stable sort. Generally required for proper batching based on external criteria.
james7132 marked this conversation as resolved.
Show resolved Hide resolved
Stable,
/// The default: allows unstable sorting. Usually faster than Stable.
james7132 marked this conversation as resolved.
Show resolved Hide resolved
Unstable,
/// Unsorted. Omits sorting entirely.
Unsorted,
}

impl Default for RenderPhaseSortMode {
fn default() -> Self {
Self::Unstable
}
}

/// An item which will be drawn to the screen. A phase item should be queued up for rendering
/// during the [`RenderStage::Queue`](crate::RenderStage::Queue) stage.
/// Afterwards it will be sorted and rendered automatically in the
Expand All @@ -42,6 +58,24 @@ pub trait PhaseItem: Send + Sync + 'static {
fn sort_key(&self) -> Self::SortKey;
/// Specifies the [`Draw`] function used to render the item.
fn draw_function(&self) -> DrawFunctionId;

/// Specifies what kind of sort to apply to the phase. Generally if the same type
/// implements [`BatchedPhaseItem`], this should return [`RenderPhaseSortMode::Stable`].
/// In almost all other cases, this should not be altered from the default,
/// [`RenderPhaseSortMode::Unstable`], as this provides the best balance of CPU and GPU
/// performance.
///
/// It's generally only advised to use [`RenderPhaseSortMode::Unsorted`] if and only if
/// the renderer supports a depth prepass, which is by default not supported by the rest
/// of Bevy's first party rendering crates. Even then, this may have a negative impact
/// on GPU-side performance due to overdraw.
///
/// It's advised to always profile for performance changes when changing this to
/// a different value.
#[inline]
fn sort_mode() -> RenderPhaseSortMode {
Default::default()
}
james7132 marked this conversation as resolved.
Show resolved Hide resolved
}

// TODO: make this generic?
Expand Down Expand Up @@ -170,6 +204,10 @@ pub trait CachedRenderPipelinePhaseItem: PhaseItem {
///
/// Batching is an optimization that regroups multiple items in the same vertex buffer
/// to render them in a single draw call.
///
/// If this is implemented on a type, the implementation of [`PhaseItem::sort_mode`] should
/// be changed to return [`RenderPhaseSortMode::Stable`], or incorrect/suboptimal batching
/// may result.
pub trait BatchedPhaseItem: EntityPhaseItem {
/// Range in the vertex buffer of this item
fn batch_range(&self) -> &Option<Range<u32>>;
Expand Down
10 changes: 9 additions & 1 deletion crates/bevy_render/src/render_phase/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ impl<I: PhaseItem> RenderPhase<I> {

/// Sorts all of its [`PhaseItems`](PhaseItem).
pub fn sort(&mut self) {
self.items.sort_by_key(|d| d.sort_key());
match I::sort_mode() {
RenderPhaseSortMode::Stable => self.items.sort_by_key(|d| d.sort_key()),
RenderPhaseSortMode::Unstable => self.items.sort_unstable_by_key(|d| d.sort_key()),
RenderPhaseSortMode::Unsorted => {}
}
}
}

Expand Down Expand Up @@ -98,6 +102,10 @@ mod tests {
fn draw_function(&self) -> DrawFunctionId {
unimplemented!();
}

fn sort_mode() -> RenderPhaseSortMode {
RenderPhaseSortMode::Stable
}
}
impl EntityPhaseItem for TestPhaseItem {
fn entity(&self) -> bevy_ecs::entity::Entity {
Expand Down