Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] reuse texture if size and type matches #37527

Merged
merged 3 commits into from
Nov 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 37 additions & 18 deletions impeller/typographer/backends/skia/text_render_context_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -297,34 +297,40 @@ 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__);
if (!allocator) {
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
Expand All @@ -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(
Expand Down Expand Up @@ -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;
}
Expand Down
28 changes: 28 additions & 0 deletions impeller/typographer/typographer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Expand Down