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] - Warn instead of erroring when max_font_atlases is exceeded #6673

Closed
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions crates/bevy_text/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub enum TextError {
NoSuchFont,
#[error("failed to add glyph to newly-created atlas {0:?}")]
FailedToAddGlyph(GlyphId),
// TODO this is not used. Remove it.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it isn't used, then why not just remove it now? Is it too out of scope for the PR?

Copy link
Member

@alice-i-cecile alice-i-cecile Nov 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would introduce a breaking change, which means this can't be shipped in Bevy 0.9.1

#[error("exceeded {0:?} available TextAltases for font. This can be caused by using an excessive number of font sizes or ui scaling. If you are changing font sizes or ui scaling dynamically consider using Transform::scale to modify the size. If you need more font sizes modify TextSettings.max_font_atlases." )]
ExceedMaxTextAtlases(usize),
}
31 changes: 8 additions & 23 deletions crates/bevy_text/src/font_atlas_set.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{error::TextError, Font, FontAtlas, TextSettings};
use crate::{error::TextError, Font, FontAtlas};
use ab_glyph::{GlyphId, OutlinedGlyph, Point};
use bevy_asset::{Assets, Handle};
use bevy_math::Vec2;
Expand All @@ -14,6 +14,8 @@ type FontSizeKey = FloatOrd;
#[uuid = "73ba778b-b6b5-4f45-982d-d21b6b86ace2"]
pub struct FontAtlasSet {
font_atlases: HashMap<FontSizeKey, Vec<FontAtlas>>,
// TODO unused, remove
#[allow(dead_code)]
queue: Vec<FontSizeKey>,
}

Expand Down Expand Up @@ -52,22 +54,7 @@ impl FontAtlasSet {
texture_atlases: &mut Assets<TextureAtlas>,
textures: &mut Assets<Image>,
outlined_glyph: OutlinedGlyph,
text_settings: &TextSettings,
) -> Result<GlyphAtlasInfo, TextError> {
if !text_settings.allow_dynamic_font_size {
if self.font_atlases.len() >= text_settings.max_font_atlases.get() {
return Err(TextError::ExceedMaxTextAtlases(
text_settings.max_font_atlases.get(),
));
}
} else {
// Clear last space in queue to make room for new font size
while self.queue.len() >= text_settings.max_font_atlases.get() - 1 {
if let Some(font_size_key) = self.queue.pop() {
self.font_atlases.remove(&font_size_key);
}
}
}
let glyph = outlined_glyph.glyph();
let glyph_id = glyph.id;
let glyph_position = glyph.position;
Expand All @@ -82,7 +69,7 @@ impl FontAtlasSet {
Vec2::splat(512.0),
)]
});
self.queue.insert(0, FloatOrd(font_size));

let glyph_texture = Font::get_outlined_glyph_texture(outlined_glyph);
let add_char_to_font_atlas = |atlas: &mut FontAtlas| -> bool {
atlas.add_glyph(
Expand Down Expand Up @@ -129,12 +116,6 @@ impl FontAtlasSet {
glyph_id: GlyphId,
position: Point,
) -> Option<GlyphAtlasInfo> {
// Move to front of used queue.
let some_index = self.queue.iter().position(|x| *x == FloatOrd(font_size));
if let Some(index) = some_index {
let key = self.queue.remove(index);
self.queue.insert(0, key);
}
self.font_atlases
.get(&FloatOrd(font_size))
.and_then(|font_atlases| {
Expand All @@ -151,4 +132,8 @@ impl FontAtlasSet {
})
})
}

pub fn num_font_atlases(&self) -> usize {
self.font_atlases.len()
}
}
21 changes: 13 additions & 8 deletions crates/bevy_text/src/glyph_brush.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use bevy_asset::{Assets, Handle};
use bevy_math::Vec2;
use bevy_render::texture::Image;
use bevy_sprite::TextureAtlas;
use bevy_utils::tracing::warn;
use glyph_brush_layout::{
FontId, GlyphPositioner, Layout, SectionGeometry, SectionGlyph, SectionText, ToSectionText,
};

use crate::{
error::TextError, Font, FontAtlasSet, GlyphAtlasInfo, TextAlignment, TextSettings,
YAxisOrientation,
error::TextError, Font, FontAtlasSet, FontAtlasWarning, GlyphAtlasInfo, TextAlignment,
TextSettings, YAxisOrientation,
};

pub struct GlyphBrush {
Expand Down Expand Up @@ -56,6 +57,7 @@ impl GlyphBrush {
texture_atlases: &mut Assets<TextureAtlas>,
textures: &mut Assets<Image>,
text_settings: &TextSettings,
font_atlas_warning: &mut FontAtlasWarning,
y_axis_orientation: YAxisOrientation,
) -> Result<Vec<PositionedGlyph>, TextError> {
if glyphs.is_empty() {
Expand Down Expand Up @@ -114,14 +116,17 @@ impl GlyphBrush {
.get_glyph_atlas_info(section_data.2, glyph_id, glyph_position)
.map(Ok)
.unwrap_or_else(|| {
font_atlas_set.add_glyph_to_atlas(
texture_atlases,
textures,
outlined_glyph,
text_settings,
)
font_atlas_set.add_glyph_to_atlas(texture_atlases, textures, outlined_glyph)
})?;

if !text_settings.allow_dynamic_font_size
&& !font_atlas_warning.warned
&& font_atlas_set.num_font_atlases() > text_settings.max_font_atlases.get()
{
warn!("warning[B0005]: Number of font atlases has exceeded the maximum of {}. Performance and memory usage may suffer.", text_settings.max_font_atlases.get());
font_atlas_warning.warned = true;
}

let texture_atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap();
let glyph_rect = texture_atlas.textures[atlas_info.glyph_index];
let size = Vec2::new(glyph_rect.width(), glyph_rect.height());
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_text/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ impl Default for TextSettings {
}
}

#[derive(Resource, Default)]
pub struct FontAtlasWarning {
warned: bool,
}

/// Text is rendered for two different view projections, normal `Text2DBundle` is rendered with a
/// `BottomToTop` y axis, and UI is rendered with a `TopToBottom` y axis. This matters for text because
/// the glyph positioning is different in either layout.
Expand All @@ -77,6 +82,7 @@ impl Plugin for TextPlugin {
.register_type::<HorizontalAlign>()
.init_asset_loader::<FontLoader>()
.init_resource::<TextSettings>()
.init_resource::<FontAtlasWarning>()
.insert_resource(TextPipeline::default())
.add_system_to_stage(
CoreStage::PostUpdate,
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_text/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use bevy_utils::HashMap;
use glyph_brush_layout::{FontId, SectionText};

use crate::{
error::TextError, glyph_brush::GlyphBrush, scale_value, Font, FontAtlasSet, PositionedGlyph,
TextAlignment, TextSection, TextSettings, YAxisOrientation,
error::TextError, glyph_brush::GlyphBrush, scale_value, Font, FontAtlasSet, FontAtlasWarning,
PositionedGlyph, TextAlignment, TextSection, TextSettings, YAxisOrientation,
};

#[derive(Default, Resource)]
Expand Down Expand Up @@ -50,6 +50,7 @@ impl TextPipeline {
texture_atlases: &mut Assets<TextureAtlas>,
textures: &mut Assets<Image>,
text_settings: &TextSettings,
font_atlas_warning: &mut FontAtlasWarning,
y_axis_orientation: YAxisOrientation,
) -> Result<TextLayoutInfo, TextError> {
let mut scaled_fonts = Vec::new();
Expand Down Expand Up @@ -106,6 +107,7 @@ impl TextPipeline {
texture_atlases,
textures,
text_settings,
font_atlas_warning,
y_axis_orientation,
)?;

Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_text/src/text2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use bevy_utils::HashSet;
use bevy_window::{WindowId, WindowScaleFactorChanged, Windows};

use crate::{
Font, FontAtlasSet, HorizontalAlign, Text, TextError, TextLayoutInfo, TextPipeline,
TextSettings, VerticalAlign, YAxisOrientation,
Font, FontAtlasSet, FontAtlasWarning, HorizontalAlign, Text, TextError, TextLayoutInfo,
TextPipeline, TextSettings, VerticalAlign, YAxisOrientation,
};

/// The calculated size of text drawn in 2D scene.
Expand Down Expand Up @@ -159,6 +159,7 @@ pub fn update_text2d_layout(
fonts: Res<Assets<Font>>,
windows: Res<Windows>,
text_settings: Res<TextSettings>,
mut font_atlas_warning: ResMut<FontAtlasWarning>,
mut scale_factor_changed: EventReader<WindowScaleFactorChanged>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
Expand Down Expand Up @@ -198,6 +199,7 @@ pub fn update_text2d_layout(
&mut texture_atlases,
&mut textures,
text_settings.as_ref(),
&mut font_atlas_warning,
YAxisOrientation::BottomToTop,
) {
Err(TextError::NoSuchFont) => {
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_ui/src/widget/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use bevy_math::Vec2;
use bevy_render::texture::Image;
use bevy_sprite::TextureAtlas;
use bevy_text::{
Font, FontAtlasSet, Text, TextError, TextLayoutInfo, TextPipeline, TextSettings,
YAxisOrientation,
Font, FontAtlasSet, FontAtlasWarning, Text, TextError, TextLayoutInfo, TextPipeline,
TextSettings, YAxisOrientation,
};
use bevy_window::Windows;

Expand Down Expand Up @@ -53,6 +53,7 @@ pub fn text_system(
fonts: Res<Assets<Font>>,
windows: Res<Windows>,
text_settings: Res<TextSettings>,
mut font_atlas_warning: ResMut<FontAtlasWarning>,
ui_scale: Res<UiScale>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
Expand Down Expand Up @@ -126,6 +127,7 @@ pub fn text_system(
&mut texture_atlases,
&mut textures,
text_settings.as_ref(),
&mut font_atlas_warning,
YAxisOrientation::TopToBottom,
) {
Err(TextError::NoSuchFont) => {
Expand Down
9 changes: 9 additions & 0 deletions errors/B0005.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# B0005

A runtime warning.

Separate font atlases are created for each font and font size. This is expensive, and the memory is never reclaimed when e.g. interpolating `TextStyle::font_size` or `UiScale::scale`.

If you need to smoothly scale font size, use `Transform::scale`.

You can disable this warning by setting `TextSettings::allow_dynamic_font_size` to `true` or raise the limit by setting `TextSettings::max_font_atlases`.