Skip to content

Commit 4fdea02

Browse files
superdumpSkiFire13
andauthored
Use instancing for sprites (#9597)
# Objective - Supercedes #8872 - Improve sprite rendering performance after the regression in #9236 ## Solution - Use an instance-rate vertex buffer to store per-instance data. - Store color, UV offset and scale, and a transform per instance. - Convert Sprite rect, custom_size, anchor, and flip_x/_y to an affine 3x4 matrix and store the transpose of that in the per-instance data. This is similar to how MeshUniform uses transpose affine matrices. - Use a special index buffer that has batches of 6 indices referencing 4 vertices. The lower 2 bits indicate the x and y of a quad such that the corners are: ``` 10 11 00 01 ``` UVs are implicit but get modified by UV offset and scale The remaining upper bits contain the instance index. ## Benchmarks I will compare versus `main` before #9236 because the results should be as good as or faster than that. Running `bevymark -- 10000 16` on an M1 Max with `main` at `e8b38925` in yellow, this PR in red: ![Screenshot 2023-08-27 at 18 44 10](https://github.com/bevyengine/bevy/assets/302146/bdc5c929-d547-44bb-b519-20dce676a316) Looking at the median frame times, that's a 37% reduction from before. --- ## Changelog - Changed: Improved sprite rendering performance by leveraging an instance-rate vertex buffer. --------- Co-authored-by: Giacomo Stevanato <[email protected]>
1 parent 40c6b3b commit 4fdea02

File tree

7 files changed

+277
-228
lines changed

7 files changed

+277
-228
lines changed

crates/bevy_pbr/src/render/mesh_functions.wgsl

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,7 @@
44
#import bevy_pbr::mesh_bindings mesh
55
#import bevy_pbr::mesh_types MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT
66
#import bevy_render::instance_index get_instance_index
7-
8-
fn affine_to_square(affine: mat3x4<f32>) -> mat4x4<f32> {
9-
return transpose(mat4x4<f32>(
10-
affine[0],
11-
affine[1],
12-
affine[2],
13-
vec4<f32>(0.0, 0.0, 0.0, 1.0),
14-
));
15-
}
16-
17-
fn mat2x4_f32_to_mat3x3_unpack(
18-
a: mat2x4<f32>,
19-
b: f32,
20-
) -> mat3x3<f32> {
21-
return mat3x3<f32>(
22-
a[0].xyz,
23-
vec3<f32>(a[0].w, a[1].xy),
24-
vec3<f32>(a[1].zw, b),
25-
);
26-
}
7+
#import bevy_render::maths affine_to_square, mat2x4_f32_to_mat3x3_unpack
278

289
fn get_model_matrix(instance_index: u32) -> mat4x4<f32> {
2910
return affine_to_square(mesh[get_instance_index(instance_index)].model);

crates/bevy_pbr/src/render/mesh_types.wgsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
struct Mesh {
44
// Affine 4x3 matrices transposed to 3x4
5-
// Use bevy_pbr::mesh_functions::affine_to_square to unpack
5+
// Use bevy_render::maths::affine_to_square to unpack
66
model: mat3x4<f32>,
77
previous_model: mat3x4<f32>,
88
// 3x3 matrix packed in mat2x4 and f32 as:

crates/bevy_render/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ pub struct RenderApp;
234234

235235
pub const INSTANCE_INDEX_SHADER_HANDLE: HandleUntyped =
236236
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 10313207077636615845);
237+
pub const MATHS_SHADER_HANDLE: HandleUntyped =
238+
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 10665356303104593376);
237239

238240
impl Plugin for RenderPlugin {
239241
/// Initializes the renderer, sets up the [`RenderSet`](RenderSet) and creates the rendering sub-app.
@@ -391,6 +393,7 @@ impl Plugin for RenderPlugin {
391393
"BASE_INSTANCE_WORKAROUND".into()
392394
]
393395
);
396+
load_internal_asset!(app, MATHS_SHADER_HANDLE, "maths.wgsl", Shader::from_wgsl);
394397
if let Some(future_renderer_resources) =
395398
app.world.remove_resource::<FutureRendererResources>()
396399
{

crates/bevy_render/src/maths.wgsl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#define_import_path bevy_render::maths
2+
3+
fn affine_to_square(affine: mat3x4<f32>) -> mat4x4<f32> {
4+
return transpose(mat4x4<f32>(
5+
affine[0],
6+
affine[1],
7+
affine[2],
8+
vec4<f32>(0.0, 0.0, 0.0, 1.0),
9+
));
10+
}
11+
12+
fn mat2x4_f32_to_mat3x3_unpack(
13+
a: mat2x4<f32>,
14+
b: f32,
15+
) -> mat3x3<f32> {
16+
return mat3x3<f32>(
17+
a[0].xyz,
18+
vec3<f32>(a[0].w, a[1].xy),
19+
vec3<f32>(a[1].zw, b),
20+
);
21+
}

crates/bevy_render/src/render_resource/buffer_vec.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ impl<T: Pod> BufferVec<T> {
144144
pub fn clear(&mut self) {
145145
self.values.clear();
146146
}
147+
148+
pub fn values(&self) -> &Vec<T> {
149+
&self.values
150+
}
151+
152+
pub fn values_mut(&mut self) -> &mut Vec<T> {
153+
&mut self.values
154+
}
147155
}
148156

149157
impl<T: Pod> Extend<T> for BufferVec<T> {

0 commit comments

Comments
 (0)