mirror of
https://github.com/bevyengine/bevy
synced 2025-02-16 14:08:32 +00:00
Warn instead of erroring when max_font_atlases is exceeded (#6673)
# Objective Fixes #6642 In a way that doesn't create any breaking changes, as a possible way to fix the above in a patch release. ## Solution Don't actually remove font atlases when `max_font_atlases` is exceeded. Add a warning instead. Keep `TextError::ExceedMaxTextAtlases` and `TextSettings` as-is so we don't break anything. This is a bit of a cop-out, but the problems revealed by #6642 seem very challenging to fix properly. Maybe follow up later with something more like https://github.com/rparrett/bevy/commits/remove-max-font-atlases later, if this is the direction we want to go. ## Note See previous attempt at a "simple fix" that only solved some of the issues: #6666
This commit is contained in:
parent
fb5c17ab29
commit
6733102093
8 changed files with 49 additions and 37 deletions
|
@ -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.
|
||||
#[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),
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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>,
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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| {
|
||||
|
@ -151,4 +132,8 @@ impl FontAtlasSet {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn num_font_atlases(&self) -> usize {
|
||||
self.font_atlases.len()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
@ -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();
|
||||
|
@ -106,6 +107,7 @@ impl TextPipeline {
|
|||
texture_atlases,
|
||||
textures,
|
||||
text_settings,
|
||||
font_atlas_warning,
|
||||
y_axis_orientation,
|
||||
)?;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -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>>,
|
||||
|
@ -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) => {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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>>,
|
||||
|
@ -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) => {
|
||||
|
|
9
errors/B0005.md
Normal file
9
errors/B0005.md
Normal file
|
@ -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`.
|
Loading…
Add table
Reference in a new issue