Skip to content

Commit 3f40e2e

Browse files
jonahwilliamsschwa423
authored andcommitted
[Impeller] reuse texture if size and type matches (flutter#37527)
* [Impeller] reuse texture * ++ * ++
1 parent d97271c commit 3f40e2e

File tree

2 files changed

+65
-18
lines changed

2 files changed

+65
-18
lines changed

impeller/typographer/backends/skia/text_render_context_skia.cc

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -297,34 +297,40 @@ static std::shared_ptr<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,
297297
return bitmap;
298298
}
299299

300-
static std::shared_ptr<Texture> UploadGlyphTextureAtlas(
300+
static std::shared_ptr<Texture> CreateGlyphTextureAtlas(
301301
const std::shared_ptr<Allocator>& allocator,
302-
std::shared_ptr<SkBitmap> bitmap,
303302
const ISize& atlas_size,
304303
PixelFormat format) {
305304
TRACE_EVENT0("impeller", __FUNCTION__);
306305
if (!allocator) {
307306
return nullptr;
308307
}
309308

310-
FML_DCHECK(bitmap != nullptr);
311-
const auto& pixmap = bitmap->pixmap();
312-
313309
TextureDescriptor texture_descriptor;
314310
texture_descriptor.storage_mode = StorageMode::kHostVisible;
315311
texture_descriptor.format = format;
316312
texture_descriptor.size = atlas_size;
317313

318-
if (pixmap.rowBytes() * pixmap.height() !=
319-
texture_descriptor.GetByteSizeOfBaseMipLevel()) {
320-
return nullptr;
321-
}
322-
323314
auto texture = allocator->CreateTexture(texture_descriptor);
324315
if (!texture || !texture->IsValid()) {
325316
return nullptr;
326317
}
327318
texture->SetLabel("GlyphAtlas");
319+
return texture;
320+
}
321+
322+
bool UploadGlyphTextureAtlas(const std::shared_ptr<Texture>& texture,
323+
std::shared_ptr<SkBitmap> bitmap) {
324+
TRACE_EVENT0("impeller", __FUNCTION__);
325+
326+
FML_DCHECK(bitmap != nullptr);
327+
const auto& pixmap = bitmap->pixmap();
328+
329+
auto texture_descriptor = texture->GetTextureDescriptor();
330+
if (pixmap.rowBytes() * pixmap.height() !=
331+
texture_descriptor.GetByteSizeOfBaseMipLevel()) {
332+
return false;
333+
}
328334

329335
auto mapping = std::make_shared<fml::NonOwnedMapping>(
330336
reinterpret_cast<const uint8_t*>(bitmap->getAddr(0, 0)), // data
@@ -333,9 +339,9 @@ static std::shared_ptr<Texture> UploadGlyphTextureAtlas(
333339
);
334340

335341
if (!texture->SetContents(mapping)) {
336-
return nullptr;
342+
return false;
337343
}
338-
return texture;
344+
return true;
339345
}
340346

341347
std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
@@ -421,16 +427,29 @@ std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
421427
format = PixelFormat::kR8G8B8A8UNormInt;
422428
break;
423429
}
424-
auto texture = UploadGlyphTextureAtlas(GetContext()->GetResourceAllocator(),
425-
bitmap, atlas_size, format);
426-
if (!texture) {
427-
return nullptr;
428-
}
429430

430431
// ---------------------------------------------------------------------------
431432
// Step 8: Record the texture in the glyph atlas.
433+
//
434+
// If the last_texture is the same size and type, reuse this instead of
435+
// creating a new texture.
432436
// ---------------------------------------------------------------------------
433-
glyph_atlas->SetTexture(std::move(texture));
437+
auto old_texture = last_atlas->GetTexture();
438+
if (old_texture != nullptr &&
439+
old_texture->GetTextureDescriptor().size == atlas_size &&
440+
old_texture->GetTextureDescriptor().format == format) {
441+
if (!UploadGlyphTextureAtlas(old_texture, bitmap)) {
442+
return nullptr;
443+
}
444+
glyph_atlas->SetTexture(std::move(old_texture));
445+
} else {
446+
auto texture = CreateGlyphTextureAtlas(GetContext()->GetResourceAllocator(),
447+
atlas_size, format);
448+
if (!texture || !UploadGlyphTextureAtlas(texture, bitmap)) {
449+
return nullptr;
450+
}
451+
glyph_atlas->SetTexture(std::move(texture));
452+
}
434453

435454
return glyph_atlas;
436455
}

impeller/typographer/typographer_unittests.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,34 @@ TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) {
137137
ASSERT_EQ(atlas_context->GetGlyphAtlas(), atlas);
138138
}
139139

140+
TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) {
141+
auto context = TextRenderContext::Create(GetContext());
142+
auto atlas_context = std::make_shared<GlyphAtlasContext>();
143+
ASSERT_TRUE(context && context->IsValid());
144+
SkFont sk_font;
145+
auto blob = SkTextBlob::MakeFromString("spooky skellingtons", sk_font);
146+
ASSERT_TRUE(blob);
147+
auto atlas =
148+
context->CreateGlyphAtlas(GlyphAtlas::Type::kAlphaBitmap, atlas_context,
149+
TextFrameFromTextBlob(blob));
150+
ASSERT_NE(atlas, nullptr);
151+
ASSERT_NE(atlas->GetTexture(), nullptr);
152+
ASSERT_EQ(atlas, atlas_context->GetGlyphAtlas());
153+
154+
auto* first_texture = atlas->GetTexture().get();
155+
156+
// now create a new glyph atlas with a nearly identical blob.
157+
158+
auto blob2 = SkTextBlob::MakeFromString("spooky skellington2", sk_font);
159+
auto next_atlas =
160+
context->CreateGlyphAtlas(GlyphAtlas::Type::kAlphaBitmap, atlas_context,
161+
TextFrameFromTextBlob(blob2));
162+
ASSERT_NE(atlas, next_atlas);
163+
auto* second_texture = next_atlas->GetTexture().get();
164+
165+
ASSERT_EQ(second_texture, first_texture);
166+
}
167+
140168
TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) {
141169
auto context = TextRenderContext::Create(GetContext());
142170
auto atlas_context = std::make_shared<GlyphAtlasContext>();

0 commit comments

Comments
 (0)