From 04c5d0b972c41155a9a90a54c9a5df6daac1250b Mon Sep 17 00:00:00 2001 From: Rob Parrett Date: Thu, 17 Nov 2022 16:58:29 -0700 Subject: [PATCH 1/4] Only warn when max_font_atlases is exceeded --- crates/bevy_text/src/error.rs | 1 + crates/bevy_text/src/font_atlas_set.rs | 27 +++++--------------------- crates/bevy_text/src/glyph_brush.rs | 21 ++++++++++++-------- crates/bevy_text/src/lib.rs | 6 ++++++ crates/bevy_text/src/pipeline.rs | 6 ++++-- crates/bevy_text/src/text2d.rs | 6 ++++-- crates/bevy_ui/src/widget/text.rs | 6 ++++-- errors/B0005.md | 9 +++++++++ 8 files changed, 46 insertions(+), 36 deletions(-) create mode 100644 errors/B0005.md diff --git a/crates/bevy_text/src/error.rs b/crates/bevy_text/src/error.rs index bf45a1129ed9c..40fe1bca11ab7 100644 --- a/crates/bevy_text/src/error.rs +++ b/crates/bevy_text/src/error.rs @@ -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), } diff --git a/crates/bevy_text/src/font_atlas_set.rs b/crates/bevy_text/src/font_atlas_set.rs index 2649e37243391..3c8c9e4429c7b 100644 --- a/crates/bevy_text/src/font_atlas_set.rs +++ b/crates/bevy_text/src/font_atlas_set.rs @@ -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; @@ -52,22 +52,7 @@ impl FontAtlasSet { texture_atlases: &mut Assets, textures: &mut Assets, outlined_glyph: OutlinedGlyph, - text_settings: &TextSettings, ) -> Result { - 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; @@ -129,12 +114,6 @@ impl FontAtlasSet { glyph_id: GlyphId, position: Point, ) -> Option { - // 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 +130,8 @@ impl FontAtlasSet { }) }) } + + pub fn num_font_atlases(&self) -> usize { + self.font_atlases.len() + } } diff --git a/crates/bevy_text/src/glyph_brush.rs b/crates/bevy_text/src/glyph_brush.rs index 476b8064608d0..b3b8e3d79f018 100644 --- a/crates/bevy_text/src/glyph_brush.rs +++ b/crates/bevy_text/src/glyph_brush.rs @@ -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, textures: &mut Assets, text_settings: &TextSettings, + font_atlas_warning: &mut FontAtlasWarning, y_axis_orientation: YAxisOrientation, ) -> Result, 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()); diff --git a/crates/bevy_text/src/lib.rs b/crates/bevy_text/src/lib.rs index 7c71aa815530e..79f6909289a5e 100644 --- a/crates/bevy_text/src/lib.rs +++ b/crates/bevy_text/src/lib.rs @@ -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::() .init_asset_loader::() .init_resource::() + .init_resource::() .insert_resource(TextPipeline::default()) .add_system_to_stage( CoreStage::PostUpdate, diff --git a/crates/bevy_text/src/pipeline.rs b/crates/bevy_text/src/pipeline.rs index 4f252e8e13dd2..3726f57fd4038 100644 --- a/crates/bevy_text/src/pipeline.rs +++ b/crates/bevy_text/src/pipeline.rs @@ -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, textures: &mut Assets, text_settings: &TextSettings, + font_atlas_warning: &mut FontAtlasWarning, y_axis_orientation: YAxisOrientation, ) -> Result { let mut scaled_fonts = Vec::new(); @@ -106,6 +107,7 @@ impl TextPipeline { texture_atlases, textures, text_settings, + font_atlas_warning, y_axis_orientation, )?; diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 43cafbffe8923..3f6ac64012cb1 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -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>, windows: Res, text_settings: Res, + mut font_atlas_warning: ResMut, mut scale_factor_changed: EventReader, mut texture_atlases: ResMut>, mut font_atlas_set_storage: ResMut>, @@ -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) => { diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 267a00cb56a31..48e7b5a9246ce 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -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>, windows: Res, text_settings: Res, + mut font_atlas_warning: ResMut, ui_scale: Res, mut texture_atlases: ResMut>, mut font_atlas_set_storage: ResMut>, @@ -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) => { diff --git a/errors/B0005.md b/errors/B0005.md new file mode 100644 index 0000000000000..440816b3d40a4 --- /dev/null +++ b/errors/B0005.md @@ -0,0 +1,9 @@ +# B0004 + +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 `TextPlugin::max_font_sizes` to `None` or `Some(larger_value)`. From 52d84aabd8a7928ee385aa92c04dfddb532fd84d Mon Sep 17 00:00:00 2001 From: Rob Parrett Date: Thu, 17 Nov 2022 17:31:43 -0700 Subject: [PATCH 2/4] Fix error title --- errors/B0005.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/errors/B0005.md b/errors/B0005.md index 440816b3d40a4..11c69acfc51da 100644 --- a/errors/B0005.md +++ b/errors/B0005.md @@ -1,4 +1,4 @@ -# B0004 +# B0005 A runtime warning. From 1a369dcfaeac76f8db05355d6b799a3ffe661257 Mon Sep 17 00:00:00 2001 From: Rob Parrett Date: Thu, 17 Nov 2022 17:34:04 -0700 Subject: [PATCH 3/4] Fix error text referring to wrong changeset --- errors/B0005.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/errors/B0005.md b/errors/B0005.md index 11c69acfc51da..16b198f5e2cd6 100644 --- a/errors/B0005.md +++ b/errors/B0005.md @@ -6,4 +6,4 @@ Separate font atlases are created for each font and font size. This is expensive If you need to smoothly scale font size, use `Transform::scale`. -You can disable this warning by setting `TextPlugin::max_font_sizes` to `None` or `Some(larger_value)`. +You can disable this warning by setting `TextSettings::allow_dynamic_font_size` to `true` or raise the limit by setting `TextSettings::max_font_atlases`. From ea6b796deb4165bf351d8c1d9bc67b60872a889a Mon Sep 17 00:00:00 2001 From: Rob Parrett Date: Thu, 17 Nov 2022 18:33:10 -0700 Subject: [PATCH 4/4] Cleanup --- crates/bevy_text/src/font_atlas_set.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_text/src/font_atlas_set.rs b/crates/bevy_text/src/font_atlas_set.rs index 3c8c9e4429c7b..9468a5405fcfb 100644 --- a/crates/bevy_text/src/font_atlas_set.rs +++ b/crates/bevy_text/src/font_atlas_set.rs @@ -14,6 +14,8 @@ type FontSizeKey = FloatOrd; #[uuid = "73ba778b-b6b5-4f45-982d-d21b6b86ace2"] pub struct FontAtlasSet { font_atlases: HashMap>, + // TODO unused, remove + #[allow(dead_code)] queue: Vec, } @@ -67,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(