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

Commit a569767

Browse files
author
jonahwilliams
committed
++
1 parent fbbe668 commit a569767

File tree

4 files changed

+84
-47
lines changed

4 files changed

+84
-47
lines changed

impeller/typographer/backends/skia/typographer_context_skia.cc

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "impeller/typographer/backends/skia/typographer_context_skia.h"
66

77
#include <cstddef>
8+
#include <memory>
89
#include <numeric>
910
#include <utility>
1011
#include <vector>
@@ -13,6 +14,7 @@
1314
#include "flutter/fml/trace_event.h"
1415
#include "fml/closure.h"
1516

17+
#include "impeller/base/validation.h"
1618
#include "impeller/core/allocator.h"
1719
#include "impeller/core/buffer_view.h"
1820
#include "impeller/core/formats.h"
@@ -400,11 +402,15 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
400402
// IF the current atlas size is as big as it can get, then "GC" and create an
401403
// atlas with only the required glyphs.
402404
bool blit_old_atlas = true;
405+
std::shared_ptr<GlyphAtlas> new_atlas = last_atlas;
403406
if (atlas_context->GetAtlasSize().height >= max_texture_height) {
404407
blit_old_atlas = false;
405408
first_missing_index = 0;
406409
glyph_positions.clear();
407410
height_adjustment = 0;
411+
new_atlas = std::make_shared<GlyphAtlas>(type);
412+
atlas_context->UpdateRectPacker(nullptr);
413+
atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
408414
}
409415

410416
// A new glyph atlas must be created.
@@ -415,7 +421,7 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
415421
max_texture_height //
416422
);
417423

418-
atlas_context->UpdateGlyphAtlas(last_atlas, atlas_size, height_adjustment);
424+
atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
419425
if (atlas_size.IsEmpty()) {
420426
return nullptr;
421427
}
@@ -433,89 +439,68 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
433439
}
434440
descriptor.size = atlas_size;
435441
descriptor.storage_mode = StorageMode::kDevicePrivate;
436-
descriptor.usage = TextureUsage::kShaderRead | TextureUsage::kRenderTarget;
442+
descriptor.usage = TextureUsage::kShaderRead;
437443
std::shared_ptr<Texture> new_texture =
438444
context.GetResourceAllocator()->CreateTexture(descriptor);
439-
new_texture->SetLabel("GlyphAtlas");
440-
441445
if (!new_texture) {
442446
return nullptr;
443447
}
444448

445449
new_texture->SetLabel("GlyphAtlas");
446450

447451
std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
448-
std::shared_ptr<BlitPass> blit_pass;
452+
std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
449453

450454
// The R8/A8 textures used for certain glyphs is not supported as color
451-
// attachments in most graphics drivers. To be safe, just do a CPU clear
452-
// for these.
453-
if (type == GlyphAtlas::Type::kAlphaBitmap) {
454-
size_t byte_size =
455-
new_texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
456-
BufferView buffer_view =
457-
host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
458-
459-
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
460-
byte_size);
461-
buffer_view.buffer->Flush();
462-
blit_pass = cmd_buffer->CreateBlitPass();
463-
blit_pass->AddCopy(buffer_view, new_texture);
464-
} else {
465-
// In all other cases, we can use a render pass to clear to a transparent
466-
// color.
467-
ColorAttachment attachment;
468-
attachment.clear_color = Color::BlackTransparent();
469-
attachment.load_action = LoadAction::kClear;
470-
attachment.store_action = StoreAction::kStore;
471-
attachment.texture = new_texture;
472-
473-
RenderTarget render_target;
474-
render_target.SetColorAttachment(attachment, 0u);
475-
476-
auto render_pass = cmd_buffer->CreateRenderPass(render_target);
477-
render_pass->EncodeCommands();
478-
blit_pass = cmd_buffer->CreateBlitPass();
479-
}
480-
FML_DCHECK(!!blit_pass);
455+
// attachments in most graphics drivers. For other textures, most framebuffer
456+
// attachments have a much smaller size limit than the max texture size.
457+
size_t byte_size =
458+
new_texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
459+
BufferView buffer_view =
460+
host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
461+
462+
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
463+
byte_size);
464+
buffer_view.buffer->Flush();
465+
blit_pass->AddCopy(buffer_view, new_texture);
481466

482467
fml::ScopedCleanupClosure closure([&]() {
483468
blit_pass->EncodeCommands(context.GetResourceAllocator());
484469
context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
485470
});
486471

487472
// Blit the old texture to the top left of the new atlas.
488-
if (last_atlas->GetTexture() && blit_old_atlas) {
489-
blit_pass->AddCopy(last_atlas->GetTexture(), new_texture,
490-
IRect::MakeSize(last_atlas->GetTexture()->GetSize()),
473+
if (new_atlas->GetTexture() && blit_old_atlas) {
474+
blit_pass->AddCopy(new_atlas->GetTexture(), new_texture,
475+
IRect::MakeSize(new_atlas->GetTexture()->GetSize()),
491476
{0, 0});
492477
}
493478

494479
// Now append all remaining glyphs. This should never have any missing data...
495-
last_atlas->SetTexture(std::move(new_texture));
480+
new_atlas->SetTexture(std::move(new_texture));
496481

497482
// ---------------------------------------------------------------------------
498483
// Step 3a: Record the positions in the glyph atlas of the newly added
499484
// glyphs.
500485
// ---------------------------------------------------------------------------
501486
for (size_t i = first_missing_index; i < glyph_positions.size(); i++) {
502-
last_atlas->AddTypefaceGlyphPosition(new_glyphs[i], glyph_positions[i]);
487+
new_atlas->AddTypefaceGlyphPosition(new_glyphs[i], glyph_positions[i]);
503488
}
504489

505490
// ---------------------------------------------------------------------------
506491
// Step 4a: Draw new font-glyph pairs into the a host buffer and encode
507492
// the uploads into the blit pass.
508493
// ---------------------------------------------------------------------------
509-
if (!UpdateAtlasBitmap(*last_atlas, blit_pass, host_buffer,
510-
last_atlas->GetTexture(), new_glyphs,
494+
if (!UpdateAtlasBitmap(*new_atlas, blit_pass, host_buffer,
495+
new_atlas->GetTexture(), new_glyphs,
511496
first_missing_index, new_glyphs.size())) {
512497
return nullptr;
513498
}
514499
// ---------------------------------------------------------------------------
515500
// Step 8b: Record the texture in the glyph atlas.
516501
// ---------------------------------------------------------------------------
517502

518-
return last_atlas;
503+
return new_atlas;
519504
}
520505

521506
} // namespace impeller

impeller/typographer/glyph_atlas.cc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,11 @@
66

77
#include <numeric>
88
#include <utility>
9-
#include "impeller/typographer/rectangle_packer.h"
109

1110
namespace impeller {
1211

1312
GlyphAtlasContext::GlyphAtlasContext(GlyphAtlas::Type type)
14-
: atlas_(std::make_shared<GlyphAtlas>(type)),
15-
atlas_size_(ISize(0, 0)),
16-
rect_packer_(RectanglePacker::Factory(4096, 512)) {}
13+
: atlas_(std::make_shared<GlyphAtlas>(type)), atlas_size_(ISize(0, 0)) {}
1714

1815
GlyphAtlasContext::~GlyphAtlasContext() {}
1916

impeller/typographer/glyph_atlas.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,14 @@ class GlyphAtlasContext {
160160
/// @brief Retrieve the previous (if any) rect packer.
161161
std::shared_ptr<RectanglePacker> GetRectPacker() const;
162162

163+
//----------------------------------------------------------------------------
164+
/// @brief A y-coordinate shift that must be applied to glyphs appended
165+
/// to
166+
/// the atlas.
167+
///
168+
/// The rectangle packer is only initialized for unfilled regions
169+
/// of the atlas. The area the rectangle packer covers is offset
170+
/// from the origin by this height adjustment.
163171
int64_t GetHeightAdjustment() const;
164172

165173
//----------------------------------------------------------------------------

impeller/typographer/typographer_unittests.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,53 @@ TEST(TypographerTest, RectanglePackerFillsRows) {
346346
EXPECT_EQ(loc.y(), 16);
347347
}
348348

349+
TEST_P(TypographerTest, GlyphAtlasTextureWillGrowTilMaxTextureSize) {
350+
auto host_buffer = HostBuffer::Create(GetContext()->GetResourceAllocator());
351+
auto context = TypographerContextSkia::Make();
352+
auto atlas_context =
353+
context->CreateGlyphAtlasContext(GlyphAtlas::Type::kAlphaBitmap);
354+
ASSERT_TRUE(context && context->IsValid());
355+
SkFont sk_font = flutter::testing::CreateTestFontOfSize(12);
356+
auto blob = SkTextBlob::MakeFromString("A", sk_font);
357+
ASSERT_TRUE(blob);
358+
auto atlas =
359+
CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
360+
GlyphAtlas::Type::kAlphaBitmap, 1.0f, atlas_context,
361+
*MakeTextFrameFromTextBlobSkia(blob));
362+
// Continually append new glyphs until the glyph size grows to the maximum.
363+
// Note that the sizes here are more or less experimentally determined, but
364+
// the important expectation is that the atlas size will shrink again after
365+
// growing to the maximum size.
366+
constexpr ISize expected_sizes[13] = {
367+
{4096, 4096}, //
368+
{4096, 4096}, //
369+
{4096, 8192}, //
370+
{4096, 8192}, //
371+
{4096, 8192}, //
372+
{4096, 8192}, //
373+
{4096, 16384}, //
374+
{4096, 16384}, //
375+
{4096, 16384}, //
376+
{4096, 16384}, //
377+
{4096, 16384}, //
378+
{4096, 16384}, //
379+
{4096, 4096} // Shrinks!
380+
};
381+
382+
for (int i = 0; i < 13; i++) {
383+
SkFont sk_font = flutter::testing::CreateTestFontOfSize(50 + i);
384+
auto blob = SkTextBlob::MakeFromString("A", sk_font);
385+
386+
atlas =
387+
CreateGlyphAtlas(*GetContext(), context.get(), *host_buffer,
388+
GlyphAtlas::Type::kAlphaBitmap, 50 + i, atlas_context,
389+
*MakeTextFrameFromTextBlobSkia(blob));
390+
ASSERT_TRUE(!!atlas);
391+
EXPECT_EQ(atlas->GetTexture()->GetTextureDescriptor().size,
392+
expected_sizes[i]);
393+
}
394+
}
395+
349396
} // namespace testing
350397
} // namespace impeller
351398

0 commit comments

Comments
 (0)