bevyengine / bevyengine/bevy

Text sections with the same font should be batched together

Open
#9,278 1 comment 1 reaction 0 assignees View on GitHub
A-Text A-UI C-Code-Quality C-Performance D-Trivial
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## What problem does this solve or what need does it fill?

Consider the following example:

```rust
use bevy::prelude::*;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}

fn setup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());

let sections = std::iter::repeat(
[("One", 10.), ("Two", 30.), ("Three\n", 50.)]
.into_iter()
.map(|(message, font_size)| {
TextSection::new(
message,
TextStyle {
font_size,
..Default::default()
},
)
}),
)
.take(10)
.flatten();

commands.spawn(TextBundle::from_sections(sections));
}
```

Which has output:

text_batch_example

Text glyphs are stored in `TextLayoutInfo` in the field ```glyphs: Vec```. These glyphs are stored in the natural reading order left to right, line after line from top to bottom.

In the example, the glyphs are all using the default font. But because it uses 3 different font sizes (10, 30 and 50) the text pipeline will generate three texture atlases, one for each font size. During the UI extraction schedule, the glyphs are added to the `ExtractedUiNodes` buffer in order "OneTwoThreeOneTwoThree" and so on. Then in `prepare_ui_nodes` glyphs that are adjacent in the buffer and from the same `TextureAtlas` are batched together. This generates thirty batches, ten with the glyphs for "One", ten for "Two" and ten for "Three".

Instead, we should be ordering the glyphs by `TextureAtlas` which would reduce the number of batches generated down to just three, one batch for the ten "One"s, one for the ten "Two"s and one for the ten "Three"s.

## What solution would you like?

Remove the `TextureAtlas` handle and section information from `PostionedGlyph`. Store the TextureAtlas handle in a second list (maybe in a smallvec since most text blocks don't have many text sections) per section. Then sort this second list by atlas handle.

Contributor guide

Open the contributing guide

Research direction

Start by tracing TextLayoutInfo and PositionedGlyph into the UI extraction schedule, ExtractedUiNodes, and prepare_ui_nodes. Examine how atlas handles and section information currently drive batching; done means glyphs using the same TextureAtlas are ordered together so the example produces three batches instead of thirty.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
game-dev, performance
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.