Skip to content

Text sections with the same font should be batched together #9278

Description

@ickshonpe

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

Consider the following example:

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<PositionedGlyph>. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-TextRendering and layout for charactersA-UIGraphical user interfaces, styles, layouts, and widgetsC-Code-QualityA section of code that is hard to understand or changeC-PerformanceA change motivated by improving speed, memory usage or compile timesD-TrivialNice and easy! A great choice to get started with Bevy

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions