From 362d0cb3ab27f730847ad4f467b114e449457f63 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 11 Dec 2023 16:08:51 -0800 Subject: [PATCH] [Impeller] recycle glyph atlas texture more aggressively. (#48888) If we need to remake the glyph atlas texture but the size is the same, then reuse the old texture. For more context, see https://github.com/flutter/flutter/issues/138798 which is much slower in Impeller. This change does not fix the problem by itself. --- .../backends/skia/typographer_context_skia.cc | 14 +++++++ impeller/typographer/typographer_unittests.cc | 37 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/impeller/typographer/backends/skia/typographer_context_skia.cc b/impeller/typographer/backends/skia/typographer_context_skia.cc index e3082678d541a..b5a9decf15b43 100644 --- a/impeller/typographer/backends/skia/typographer_context_skia.cc +++ b/impeller/typographer/backends/skia/typographer_context_skia.cc @@ -446,6 +446,20 @@ std::shared_ptr TypographerContextSkia::CreateGlyphAtlas( } atlas_context_skia.UpdateBitmap(bitmap); + // If the new atlas size is the same size as the previous texture, reuse the + // texture and treat this as an updated that replaces all glyphs. + if (last_atlas && last_atlas->GetTexture()) { + std::shared_ptr last_texture = last_atlas->GetTexture(); + if (atlas_size == last_texture->GetSize()) { + if (!UpdateGlyphTextureAtlas(bitmap, last_texture)) { + return nullptr; + } + + glyph_atlas->SetTexture(last_texture); + return glyph_atlas; + } + } + // --------------------------------------------------------------------------- // Step 7b: Upload the atlas as a texture. // --------------------------------------------------------------------------- diff --git a/impeller/typographer/typographer_unittests.cc b/impeller/typographer/typographer_unittests.cc index 343c172b4121f..38ac599e6b95f 100644 --- a/impeller/typographer/typographer_unittests.cc +++ b/impeller/typographer/typographer_unittests.cc @@ -9,7 +9,6 @@ #include "impeller/typographer/backends/skia/typographer_context_skia.h" #include "impeller/typographer/lazy_glyph_atlas.h" #include "impeller/typographer/rectangle_packer.h" -#include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkFont.h" #include "third_party/skia/include/core/SkFontMgr.h" #include "third_party/skia/include/core/SkRect.h" @@ -339,6 +338,42 @@ TEST_P(TypographerTest, RectanglePackerAddsNonoverlapingRectangles) { ASSERT_EQ(packer->percentFull(), 0); } +TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledWhenContentsAreRecreated) { + auto context = TypographerContextSkia::Make(); + auto atlas_context = context->CreateGlyphAtlasContext(); + ASSERT_TRUE(context && context->IsValid()); + SkFont sk_font = flutter::testing::CreateTestFontOfSize(12); + auto blob = SkTextBlob::MakeFromString("ABCDEFGHIJKLMNOPQRSTUVQXYZ123456789", + sk_font); + ASSERT_TRUE(blob); + auto atlas = CreateGlyphAtlas( + *GetContext(), context.get(), GlyphAtlas::Type::kColorBitmap, 32.0f, + atlas_context, *MakeTextFrameFromTextBlobSkia(blob)); + auto old_packer = atlas_context->GetRectPacker(); + + ASSERT_NE(atlas, nullptr); + ASSERT_NE(atlas->GetTexture(), nullptr); + ASSERT_EQ(atlas, atlas_context->GetGlyphAtlas()); + + auto* first_texture = atlas->GetTexture().get(); + + // Now create a new glyph atlas with a completely different textblob. + // everything should be different except for the underlying atlas texture. + + auto blob2 = SkTextBlob::MakeFromString("abcdefghijklmnopqrstuvwxyz123456789", + sk_font); + auto next_atlas = CreateGlyphAtlas( + *GetContext(), context.get(), GlyphAtlas::Type::kColorBitmap, 32.0f, + atlas_context, *MakeTextFrameFromTextBlobSkia(blob2)); + ASSERT_NE(atlas, next_atlas); + auto* second_texture = next_atlas->GetTexture().get(); + + auto new_packer = atlas_context->GetRectPacker(); + + ASSERT_EQ(second_texture, first_texture); + ASSERT_NE(old_packer, new_packer); +} + } // namespace testing } // namespace impeller