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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic batching/instancing of draw commands #9685

Merged
merged 39 commits into from Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
5468edc
Implement batching for 2D and 3D meshes
superdump Aug 28, 2023
950abd7
HACK: Split batches for skinning or morph targets
superdump Sep 4, 2023
d3f38df
Only specify major and minor versions for nonmax
superdump Sep 6, 2023
806bd82
Drop consider_material from batching
superdump Sep 6, 2023
693c4f2
Reuse functions from bevy_render::maths shader import
superdump Sep 6, 2023
a0d2a77
Use Option<BatchMeta> instead of using Options inside BatchMeta
superdump Sep 6, 2023
e894f81
Merge branch 'main' into batching
superdump Sep 7, 2023
684d1a0
Make batching code reusable
superdump Sep 10, 2023
756b7ed
Refactor closures in prepare_and_batch_meshes
superdump Sep 10, 2023
861808e
Rename process_phase -> batch_render_phase now it is API
superdump Sep 10, 2023
c6a52f8
Remove batching dependency on GpuArrayBuffer
superdump Sep 10, 2023
739e9ad
Add ability to disable automatic batching per-entity
superdump Sep 10, 2023
fd93970
batching
robtfm Sep 13, 2023
667c70a
don't reverse, preserve render order within batch
robtfm Sep 13, 2023
a9e3585
Merge pull request #33 from robtfm/batching
superdump Sep 14, 2023
89dcd4b
Update examples/2d/mesh2d_manual.rs
superdump Sep 14, 2023
245285d
Capitalisation in comments
superdump Sep 14, 2023
d88f2d6
Consolidate conversion of Affine3 to GPU buffers
superdump Sep 14, 2023
68969ab
Use NoAutomaticBatching to split batches for skinning and morph targets
superdump Sep 15, 2023
b313921
Consolidate BatchMeta into bevy_render
superdump Sep 15, 2023
54f0b2e
Clean up outdated comments
superdump Sep 15, 2023
fe3fec8
Merge branch 'main' into batching
superdump Sep 15, 2023
7e1fad6
generic batching
robtfm Sep 16, 2023
315b271
accidentally removed AlphaMask3d
robtfm Sep 16, 2023
e359322
Merge pull request #34 from robtfm/generic-batching
superdump Sep 17, 2023
8686741
Minor cleanup
superdump Sep 17, 2023
64292a7
Use clearer system names
superdump Sep 17, 2023
892cfc4
Move prepass system scheduling to prepass plugin
superdump Sep 17, 2023
2dd8e61
Use Has<T> instead of Option<&T>.is_some()
superdump Sep 18, 2023
e76ed46
Use reduce over complex loop
nicopap Sep 19, 2023
c177c6e
In reduce, do not change start_range value
nicopap Sep 19, 2023
0bddc59
prev over old
nicopap Sep 19, 2023
5f4dd4c
Merge pull request #36 from nicopap/cleanup-batch-2
superdump Sep 19, 2023
7e08cfb
Split get_batch_data into two functions and document GetBatchData
superdump Sep 18, 2023
81b070c
Merge branch 'main' into batching
superdump Sep 21, 2023
8fccad4
Correct prepare_mesh2d_uniforms comment reference
superdump Sep 21, 2023
9ab2a95
Move nonmax to bevy_utils and reexport
superdump Sep 21, 2023
9334cc7
Remove unnecessary whitespace
superdump Sep 21, 2023
69ff8af
Make Material*BindGroupId Copy and used copied() in hot code
superdump Sep 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions assets/shaders/custom_gltf_2d.wgsl
@@ -1,8 +1,9 @@
#import bevy_sprite::mesh2d_view_bindings globals
#import bevy_sprite::mesh2d_bindings mesh
#import bevy_sprite::mesh2d_functions mesh2d_position_local_to_clip
#import bevy_sprite::mesh2d_functions get_model_matrix, mesh2d_position_local_to_clip

struct Vertex {
@builtin(instance_index) instance_index: u32,
@location(0) position: vec3<f32>,
@location(1) color: vec4<f32>,
@location(2) barycentric: vec3<f32>,
Expand All @@ -17,7 +18,8 @@ struct VertexOutput {
@vertex
fn vertex(vertex: Vertex) -> VertexOutput {
var out: VertexOutput;
out.clip_position = mesh2d_position_local_to_clip(mesh.model, vec4<f32>(vertex.position, 1.0));
let model = get_model_matrix(vertex.instance_index);
out.clip_position = mesh2d_position_local_to_clip(model, vec4<f32>(vertex.position, 1.0));
out.color = vertex.color;
out.barycentric = vertex.barycentric;
return out;
Expand Down
26 changes: 22 additions & 4 deletions crates/bevy_core_pipeline/src/core_2d/mod.rs
Expand Up @@ -19,6 +19,8 @@ pub mod graph {
}
pub const CORE_2D: &str = graph::NAME;

use std::ops::Range;

pub use camera_2d::*;
pub use main_pass_2d_node::*;

Expand All @@ -35,7 +37,7 @@ use bevy_render::{
render_resource::CachedRenderPipelineId,
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
};
use bevy_utils::FloatOrd;
use bevy_utils::{nonmax::NonMaxU32, FloatOrd};

use crate::{tonemapping::TonemappingNode, upscaling::UpscalingNode};

Expand Down Expand Up @@ -83,7 +85,8 @@ pub struct Transparent2d {
pub entity: Entity,
pub pipeline: CachedRenderPipelineId,
pub draw_function: DrawFunctionId,
pub batch_size: usize,
pub batch_range: Range<u32>,
pub dynamic_offset: Option<NonMaxU32>,
}

impl PhaseItem for Transparent2d {
Expand Down Expand Up @@ -111,8 +114,23 @@ impl PhaseItem for Transparent2d {
}

#[inline]
fn batch_size(&self) -> usize {
self.batch_size
fn batch_range(&self) -> &Range<u32> {
superdump marked this conversation as resolved.
Show resolved Hide resolved
&self.batch_range
}

#[inline]
fn batch_range_mut(&mut self) -> &mut Range<u32> {
&mut self.batch_range
}

#[inline]
fn dynamic_offset(&self) -> Option<NonMaxU32> {
self.dynamic_offset
}

#[inline]
fn dynamic_offset_mut(&mut self) -> &mut Option<NonMaxU32> {
&mut self.dynamic_offset
}
}

Expand Down
70 changes: 59 additions & 11 deletions crates/bevy_core_pipeline/src/core_3d/mod.rs
Expand Up @@ -24,7 +24,7 @@ pub mod graph {
}
pub const CORE_3D: &str = graph::NAME;

use std::cmp::Reverse;
use std::{cmp::Reverse, ops::Range};

pub use camera_3d::*;
pub use main_opaque_pass_3d_node::*;
Expand All @@ -50,7 +50,7 @@ use bevy_render::{
view::ViewDepthTexture,
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
};
use bevy_utils::{FloatOrd, HashMap};
use bevy_utils::{nonmax::NonMaxU32, FloatOrd, HashMap};

use crate::{
prepass::{
Expand Down Expand Up @@ -135,7 +135,8 @@ pub struct Opaque3d {
pub pipeline: CachedRenderPipelineId,
pub entity: Entity,
pub draw_function: DrawFunctionId,
pub batch_size: usize,
pub batch_range: Range<u32>,
pub dynamic_offset: Option<NonMaxU32>,
}

impl PhaseItem for Opaque3d {
Expand Down Expand Up @@ -164,8 +165,23 @@ impl PhaseItem for Opaque3d {
}

#[inline]
fn batch_size(&self) -> usize {
self.batch_size
fn batch_range(&self) -> &Range<u32> {
&self.batch_range
}

#[inline]
fn batch_range_mut(&mut self) -> &mut Range<u32> {
&mut self.batch_range
}

#[inline]
fn dynamic_offset(&self) -> Option<NonMaxU32> {
self.dynamic_offset
}

#[inline]
fn dynamic_offset_mut(&mut self) -> &mut Option<NonMaxU32> {
&mut self.dynamic_offset
}
}

Expand All @@ -181,7 +197,8 @@ pub struct AlphaMask3d {
pub pipeline: CachedRenderPipelineId,
pub entity: Entity,
pub draw_function: DrawFunctionId,
pub batch_size: usize,
pub batch_range: Range<u32>,
pub dynamic_offset: Option<NonMaxU32>,
}

impl PhaseItem for AlphaMask3d {
Expand Down Expand Up @@ -210,8 +227,23 @@ impl PhaseItem for AlphaMask3d {
}

#[inline]
fn batch_size(&self) -> usize {
self.batch_size
fn batch_range(&self) -> &Range<u32> {
&self.batch_range
}

#[inline]
fn batch_range_mut(&mut self) -> &mut Range<u32> {
&mut self.batch_range
}

#[inline]
fn dynamic_offset(&self) -> Option<NonMaxU32> {
self.dynamic_offset
}

#[inline]
fn dynamic_offset_mut(&mut self) -> &mut Option<NonMaxU32> {
&mut self.dynamic_offset
}
}

Expand All @@ -227,7 +259,8 @@ pub struct Transparent3d {
pub pipeline: CachedRenderPipelineId,
pub entity: Entity,
pub draw_function: DrawFunctionId,
pub batch_size: usize,
pub batch_range: Range<u32>,
pub dynamic_offset: Option<NonMaxU32>,
}

impl PhaseItem for Transparent3d {
Expand Down Expand Up @@ -255,8 +288,23 @@ impl PhaseItem for Transparent3d {
}

#[inline]
fn batch_size(&self) -> usize {
self.batch_size
fn batch_range(&self) -> &Range<u32> {
&self.batch_range
}

#[inline]
fn batch_range_mut(&mut self) -> &mut Range<u32> {
&mut self.batch_range
}

#[inline]
fn dynamic_offset(&self) -> Option<NonMaxU32> {
self.dynamic_offset
}

#[inline]
fn dynamic_offset_mut(&mut self) -> &mut Option<NonMaxU32> {
&mut self.dynamic_offset
}
}

Expand Down
48 changes: 46 additions & 2 deletions crates/bevy_core_pipeline/src/prepass/mod.rs
Expand Up @@ -27,7 +27,7 @@

pub mod node;

use std::cmp::Reverse;
use std::{cmp::Reverse, ops::Range};

use bevy_ecs::prelude::*;
use bevy_reflect::Reflect;
Expand All @@ -36,7 +36,7 @@ use bevy_render::{
render_resource::{CachedRenderPipelineId, Extent3d, TextureFormat},
texture::CachedTexture,
};
use bevy_utils::FloatOrd;
use bevy_utils::{nonmax::NonMaxU32, FloatOrd};

pub const DEPTH_PREPASS_FORMAT: TextureFormat = TextureFormat::Depth32Float;
pub const NORMAL_PREPASS_FORMAT: TextureFormat = TextureFormat::Rgb10a2Unorm;
Expand Down Expand Up @@ -83,6 +83,8 @@ pub struct Opaque3dPrepass {
pub entity: Entity,
pub pipeline_id: CachedRenderPipelineId,
pub draw_function: DrawFunctionId,
pub batch_range: Range<u32>,
pub dynamic_offset: Option<NonMaxU32>,
}

impl PhaseItem for Opaque3dPrepass {
Expand All @@ -109,6 +111,26 @@ impl PhaseItem for Opaque3dPrepass {
// Key negated to match reversed SortKey ordering
radsort::sort_by_key(items, |item| -item.distance);
}

#[inline]
fn batch_range(&self) -> &Range<u32> {
&self.batch_range
}

#[inline]
fn batch_range_mut(&mut self) -> &mut Range<u32> {
&mut self.batch_range
}

#[inline]
fn dynamic_offset(&self) -> Option<NonMaxU32> {
self.dynamic_offset
}

#[inline]
fn dynamic_offset_mut(&mut self) -> &mut Option<NonMaxU32> {
&mut self.dynamic_offset
}
}

impl CachedRenderPipelinePhaseItem for Opaque3dPrepass {
Expand All @@ -128,6 +150,8 @@ pub struct AlphaMask3dPrepass {
pub entity: Entity,
pub pipeline_id: CachedRenderPipelineId,
pub draw_function: DrawFunctionId,
pub batch_range: Range<u32>,
pub dynamic_offset: Option<NonMaxU32>,
}

impl PhaseItem for AlphaMask3dPrepass {
Expand All @@ -154,6 +178,26 @@ impl PhaseItem for AlphaMask3dPrepass {
// Key negated to match reversed SortKey ordering
radsort::sort_by_key(items, |item| -item.distance);
}

#[inline]
fn batch_range(&self) -> &Range<u32> {
&self.batch_range
}

#[inline]
fn batch_range_mut(&mut self) -> &mut Range<u32> {
&mut self.batch_range
}

#[inline]
fn dynamic_offset(&self) -> Option<NonMaxU32> {
self.dynamic_offset
}

#[inline]
fn dynamic_offset_mut(&mut self) -> &mut Option<NonMaxU32> {
&mut self.dynamic_offset
}
}

impl CachedRenderPipelinePhaseItem for AlphaMask3dPrepass {
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_gizmos/src/pipeline_2d.rs
Expand Up @@ -178,7 +178,8 @@ fn queue_line_gizmos_2d(
draw_function,
pipeline,
sort_key: FloatOrd(f32::INFINITY),
batch_size: 1,
batch_range: 0..1,
dynamic_offset: None,
});
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_gizmos/src/pipeline_3d.rs
Expand Up @@ -192,7 +192,8 @@ fn queue_line_gizmos_3d(
draw_function,
pipeline,
distance: 0.,
batch_size: 1,
batch_range: 0..1,
dynamic_offset: None,
});
}
}
Expand Down
32 changes: 31 additions & 1 deletion crates/bevy_math/src/affine3.rs
@@ -1,4 +1,4 @@
use glam::{Affine3A, Mat3, Vec3};
use glam::{Affine3A, Mat3, Vec3, Vec3Swizzles, Vec4};

/// Reduced-size version of `glam::Affine3A` for use when storage has
/// significant performance impact. Convert to `glam::Affine3A` to do
Expand All @@ -10,6 +10,36 @@ pub struct Affine3 {
pub translation: Vec3,
}

impl Affine3 {
/// Calculates the transpose of the affine 4x3 matrix to a 3x4 and formats it for packing into GPU buffers
#[inline]
pub fn to_transpose(&self) -> [Vec4; 3] {
let transpose_3x3 = self.matrix3.transpose();
[
transpose_3x3.x_axis.extend(self.translation.x),
transpose_3x3.y_axis.extend(self.translation.y),
transpose_3x3.z_axis.extend(self.translation.z),
]
}

/// Calculates the inverse transpose of the 3x3 matrix and formats it for packing into GPU buffers
#[inline]
pub fn inverse_transpose_3x3(&self) -> ([Vec4; 2], f32) {
let inverse_transpose_3x3 = Affine3A::from(self).inverse().matrix3.transpose();
(
[
(inverse_transpose_3x3.x_axis, inverse_transpose_3x3.y_axis.x).into(),
(
inverse_transpose_3x3.y_axis.yz(),
inverse_transpose_3x3.z_axis.xy(),
)
.into(),
],
inverse_transpose_3x3.z_axis.z,
)
}
}

impl From<&Affine3A> for Affine3 {
fn from(affine: &Affine3A) -> Self {
Self {
Expand Down