[Impeller] reuse texture if size and type matches (flutter/engine#37527)

* [Impeller] reuse texture

* ++

* ++
This commit is contained in:
Jonah Williams 2022-11-12 09:16:14 -08:00 committed by GitHub
parent 37cb87a053
commit 59db03fb47
2 changed files with 65 additions and 18 deletions

View File

@ -297,9 +297,8 @@ static std::shared_ptr<SkBitmap> CreateAtlasBitmap(const GlyphAtlas& atlas,
return bitmap;
}
static std::shared_ptr<Texture> UploadGlyphTextureAtlas(
static std::shared_ptr<Texture> CreateGlyphTextureAtlas(
const std::shared_ptr<Allocator>& allocator,
std::shared_ptr<SkBitmap> bitmap,
const ISize& atlas_size,
PixelFormat format) {
TRACE_EVENT0("impeller", __FUNCTION__);
@ -307,24 +306,31 @@ static std::shared_ptr<Texture> UploadGlyphTextureAtlas(
return nullptr;
}
FML_DCHECK(bitmap != nullptr);
const auto& pixmap = bitmap->pixmap();
TextureDescriptor texture_descriptor;
texture_descriptor.storage_mode = StorageMode::kHostVisible;
texture_descriptor.format = format;
texture_descriptor.size = atlas_size;
if (pixmap.rowBytes() * pixmap.height() !=
texture_descriptor.GetByteSizeOfBaseMipLevel()) {
return nullptr;
}
auto texture = allocator->CreateTexture(texture_descriptor);
if (!texture || !texture->IsValid()) {
return nullptr;
}
texture->SetLabel("GlyphAtlas");
return texture;
}
bool UploadGlyphTextureAtlas(const std::shared_ptr<Texture>& texture,
std::shared_ptr<SkBitmap> bitmap) {
TRACE_EVENT0("impeller", __FUNCTION__);
FML_DCHECK(bitmap != nullptr);
const auto& pixmap = bitmap->pixmap();
auto texture_descriptor = texture->GetTextureDescriptor();
if (pixmap.rowBytes() * pixmap.height() !=
texture_descriptor.GetByteSizeOfBaseMipLevel()) {
return false;
}
auto mapping = std::make_shared<fml::NonOwnedMapping>(
reinterpret_cast<const uint8_t*>(bitmap->getAddr(0, 0)), // data
@ -333,9 +339,9 @@ static std::shared_ptr<Texture> UploadGlyphTextureAtlas(
);
if (!texture->SetContents(mapping)) {
return nullptr;
return false;
}
return texture;
return true;
}
std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
@ -421,16 +427,29 @@ std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
format = PixelFormat::kR8G8B8A8UNormInt;
break;
}
auto texture = UploadGlyphTextureAtlas(GetContext()->GetResourceAllocator(),
bitmap, atlas_size, format);
if (!texture) {
return nullptr;
}
// ---------------------------------------------------------------------------
// Step 8: Record the texture in the glyph atlas.
//
// If the last_texture is the same size and type, reuse this instead of
// creating a new texture.
// ---------------------------------------------------------------------------
glyph_atlas->SetTexture(std::move(texture));
auto old_texture = last_atlas->GetTexture();
if (old_texture != nullptr &&
old_texture->GetTextureDescriptor().size == atlas_size &&
old_texture->GetTextureDescriptor().format == format) {
if (!UploadGlyphTextureAtlas(old_texture, bitmap)) {
return nullptr;
}
glyph_atlas->SetTexture(std::move(old_texture));
} else {
auto texture = CreateGlyphTextureAtlas(GetContext()->GetResourceAllocator(),
atlas_size, format);
if (!texture || !UploadGlyphTextureAtlas(texture, bitmap)) {
return nullptr;
}
glyph_atlas->SetTexture(std::move(texture));
}
return glyph_atlas;
}

View File

@ -137,6 +137,34 @@ TEST_P(TypographerTest, GlyphAtlasIsRecycledIfUnchanged) {
ASSERT_EQ(atlas_context->GetGlyphAtlas(), atlas);
}
TEST_P(TypographerTest, GlyphAtlasTextureIsRecycledIfUnchanged) {
auto context = TextRenderContext::Create(GetContext());
auto atlas_context = std::make_shared<GlyphAtlasContext>();
ASSERT_TRUE(context && context->IsValid());
SkFont sk_font;
auto blob = SkTextBlob::MakeFromString("spooky skellingtons", sk_font);
ASSERT_TRUE(blob);
auto atlas =
context->CreateGlyphAtlas(GlyphAtlas::Type::kAlphaBitmap, atlas_context,
TextFrameFromTextBlob(blob));
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 nearly identical blob.
auto blob2 = SkTextBlob::MakeFromString("spooky skellington2", sk_font);
auto next_atlas =
context->CreateGlyphAtlas(GlyphAtlas::Type::kAlphaBitmap, atlas_context,
TextFrameFromTextBlob(blob2));
ASSERT_NE(atlas, next_atlas);
auto* second_texture = next_atlas->GetTexture().get();
ASSERT_EQ(second_texture, first_texture);
}
TEST_P(TypographerTest, GlyphAtlasWithLotsOfdUniqueGlyphSize) {
auto context = TextRenderContext::Create(GetContext());
auto atlas_context = std::make_shared<GlyphAtlasContext>();