Flutter Engine
 
Loading...
Searching...
No Matches
impeller::TypographerContextSkia Class Reference

#include <typographer_context_skia.h>

Inheritance diagram for impeller::TypographerContextSkia:
impeller::TypographerContext

Public Member Functions

 TypographerContextSkia ()
 
 ~TypographerContextSkia () override
 
std::shared_ptr< GlyphAtlasContextCreateGlyphAtlasContext (GlyphAtlas::Type type) const override
 
std::shared_ptr< GlyphAtlasCreateGlyphAtlas (Context &context, GlyphAtlas::Type type, HostBuffer &host_buffer, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::vector< std::shared_ptr< TextFrame > > &text_frames) const override
 
- Public Member Functions inherited from impeller::TypographerContext
virtual ~TypographerContext ()
 
virtual bool IsValid () const
 

Static Public Member Functions

static std::shared_ptr< TypographerContextMake ()
 

Additional Inherited Members

- Protected Member Functions inherited from impeller::TypographerContext
 TypographerContext ()
 Create a new context to render text that talks to an underlying graphics context.
 

Detailed Description

Definition at line 12 of file typographer_context_skia.h.

Constructor & Destructor Documentation

◆ TypographerContextSkia()

impeller::TypographerContextSkia::TypographerContextSkia ( )
default

◆ ~TypographerContextSkia()

impeller::TypographerContextSkia::~TypographerContextSkia ( )
overridedefault

Member Function Documentation

◆ CreateGlyphAtlas()

std::shared_ptr< GlyphAtlas > impeller::TypographerContextSkia::CreateGlyphAtlas ( Context context,
GlyphAtlas::Type  type,
HostBuffer host_buffer,
const std::shared_ptr< GlyphAtlasContext > &  atlas_context,
const std::vector< std::shared_ptr< TextFrame > > &  text_frames 
) const
overridevirtual

Implements impeller::TypographerContext.

Definition at line 503 of file typographer_context_skia.cc.

508 {
509 TRACE_EVENT0("impeller", __FUNCTION__);
510 if (!IsValid()) {
511 return nullptr;
512 }
513 std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
514 FML_DCHECK(last_atlas->GetType() == type);
515
516 if (text_frames.empty()) {
517 return last_atlas;
518 }
519
520 // ---------------------------------------------------------------------------
521 // Step 1: Determine if the atlas type and font glyph pairs are compatible
522 // with the current atlas and reuse if possible. For each new font and
523 // glyph pair, compute the glyph size at scale.
524 // ---------------------------------------------------------------------------
525 auto [new_glyphs, glyph_sizes] = CollectNewGlyphs(last_atlas, text_frames);
526 if (new_glyphs.size() == 0) {
527 return last_atlas;
528 }
529
530 // ---------------------------------------------------------------------------
531 // Step 2: Determine if the additional missing glyphs can be appended to the
532 // existing bitmap without recreating the atlas.
533 // ---------------------------------------------------------------------------
534 std::vector<Rect> glyph_positions;
535 glyph_positions.reserve(new_glyphs.size());
536 size_t first_missing_index = 0;
537
538 if (last_atlas->GetTexture()) {
539 // Append all glyphs that fit into the current atlas.
540 first_missing_index = AppendToExistingAtlas(
541 last_atlas, new_glyphs, glyph_positions, glyph_sizes,
542 atlas_context->GetAtlasSize(), atlas_context->GetHeightAdjustment(),
543 atlas_context->GetRectPacker());
544
545 // ---------------------------------------------------------------------------
546 // Step 3a: Record the positions in the glyph atlas of the newly added
547 // glyphs.
548 // ---------------------------------------------------------------------------
549 for (size_t i = 0; i < first_missing_index; i++) {
550 last_atlas->AddTypefaceGlyphPositionAndBounds(
551 new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
552 }
553
554 std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
555 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
556
558 blit_pass->EncodeCommands();
559 if (!context.EnqueueCommandBuffer(std::move(cmd_buffer))) {
560 VALIDATION_LOG << "Failed to submit glyph atlas command buffer";
561 }
562 });
563
564 // ---------------------------------------------------------------------------
565 // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
566 // the uploads into the blit pass.
567 // ---------------------------------------------------------------------------
568 if (!UpdateAtlasBitmap(*last_atlas, blit_pass, data_host_buffer,
569 last_atlas->GetTexture(), new_glyphs, 0,
570 first_missing_index)) {
571 return nullptr;
572 }
573
574 // If all glyphs fit, just return the old atlas.
575 if (first_missing_index == new_glyphs.size()) {
576 return last_atlas;
577 }
578 }
579
580 int64_t height_adjustment = atlas_context->GetAtlasSize().height;
581 const int64_t max_texture_height =
582 context.GetResourceAllocator()->GetMaxTextureSizeSupported().height;
583
584 // IF the current atlas size is as big as it can get, then "GC" and create an
585 // atlas with only the required glyphs. OpenGLES cannot reliably perform the
586 // blit required here, as 1) it requires attaching textures as read and write
587 // framebuffers which has substantially smaller size limits that max textures
588 // and 2) is missing a GLES 2.0 implementation and cap check.
589 bool blit_old_atlas = true;
590 std::shared_ptr<GlyphAtlas> new_atlas = last_atlas;
591 if (atlas_context->GetAtlasSize().height >= max_texture_height ||
592 context.GetBackendType() == Context::BackendType::kOpenGLES) {
593 blit_old_atlas = false;
594 new_atlas = std::make_shared<GlyphAtlas>(
595 type, /*initial_generation=*/last_atlas->GetAtlasGeneration() + 1);
596
597 auto [update_glyphs, update_sizes] =
598 CollectNewGlyphs(new_atlas, text_frames);
599 new_glyphs = std::move(update_glyphs);
600 glyph_sizes = std::move(update_sizes);
601
602 glyph_positions.clear();
603 glyph_positions.reserve(new_glyphs.size());
604 first_missing_index = 0;
605
606 height_adjustment = 0;
607 atlas_context->UpdateRectPacker(nullptr);
608 atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
609 }
610
611 // A new glyph atlas must be created.
612 ISize atlas_size = ComputeNextAtlasSize(atlas_context, //
613 new_glyphs, //
614 glyph_positions, //
615 glyph_sizes, //
616 first_missing_index, //
617 max_texture_height //
618 );
619
620 atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
621 if (atlas_size.IsEmpty()) {
622 return nullptr;
623 }
624 FML_DCHECK(new_glyphs.size() == glyph_positions.size());
625
626 TextureDescriptor descriptor;
627 switch (type) {
629 descriptor.format =
630 context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
631 break;
633 descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
634 break;
635 }
636 descriptor.size = atlas_size;
637 descriptor.storage_mode = StorageMode::kDevicePrivate;
638 descriptor.usage = TextureUsage::kShaderRead;
639 std::shared_ptr<Texture> new_texture =
640 context.GetResourceAllocator()->CreateTexture(descriptor);
641 if (!new_texture) {
642 return nullptr;
643 }
644
645 new_texture->SetLabel("GlyphAtlas");
646
647 std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
648 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
649
651 blit_pass->EncodeCommands();
652 if (!context.EnqueueCommandBuffer(std::move(cmd_buffer))) {
653 VALIDATION_LOG << "Failed to submit glyph atlas command buffer";
654 }
655 });
656
657 // Now append all remaining glyphs. This should never have any missing data...
658 auto old_texture = new_atlas->GetTexture();
659 new_atlas->SetTexture(std::move(new_texture));
660
661 // ---------------------------------------------------------------------------
662 // Step 3a: Record the positions in the glyph atlas of the newly added
663 // glyphs.
664 // ---------------------------------------------------------------------------
665 for (size_t i = first_missing_index; i < glyph_positions.size(); i++) {
666 new_atlas->AddTypefaceGlyphPositionAndBounds(
667 new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
668 }
669
670 // ---------------------------------------------------------------------------
671 // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
672 // the uploads into the blit pass.
673 // ---------------------------------------------------------------------------
674 if (!BulkUpdateAtlasBitmap(*new_atlas, blit_pass, data_host_buffer,
675 new_atlas->GetTexture(), new_glyphs,
676 first_missing_index, new_glyphs.size())) {
677 return nullptr;
678 }
679
680 // Blit the old texture to the top left of the new atlas.
681 if (blit_old_atlas && old_texture) {
682 blit_pass->AddCopy(old_texture, new_atlas->GetTexture(),
683 IRect::MakeSize(new_atlas->GetTexture()->GetSize()),
684 {0, 0});
685 }
686
687 // ---------------------------------------------------------------------------
688 // Step 8b: Record the texture in the glyph atlas.
689 // ---------------------------------------------------------------------------
690
691 return new_atlas;
692}
GLenum type
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition closure.h:32
#define FML_DCHECK(condition)
Definition logging.h:122
std::function< void()> closure
Definition closure.h:14
static bool UpdateAtlasBitmap(const GlyphAtlas &atlas, std::shared_ptr< BlitPass > &blit_pass, HostBuffer &data_host_buffer, const std::shared_ptr< Texture > &texture, const std::vector< FontGlyphPair > &new_pairs, size_t start_index, size_t end_index)
static size_t AppendToExistingAtlas(const std::shared_ptr< GlyphAtlas > &atlas, const std::vector< FontGlyphPair > &extra_pairs, std::vector< Rect > &glyph_positions, const std::vector< Rect > &glyph_sizes, ISize atlas_size, int64_t height_adjustment, const std::shared_ptr< RectanglePacker > &rect_packer)
static ISize ComputeNextAtlasSize(const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::vector< FontGlyphPair > &extra_pairs, std::vector< Rect > &glyph_positions, const std::vector< Rect > &glyph_sizes, size_t glyph_index_start, int64_t max_texture_height)
static bool BulkUpdateAtlasBitmap(const GlyphAtlas &atlas, std::shared_ptr< BlitPass > &blit_pass, HostBuffer &data_host_buffer, const std::shared_ptr< Texture > &texture, const std::vector< FontGlyphPair > &new_pairs, size_t start_index, size_t end_index)
Batch render to a single surface.
ISize64 ISize
Definition size.h:162
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
#define TRACE_EVENT0(category_group, name)

References impeller::AppendToExistingAtlas(), impeller::BulkUpdateAtlasBitmap(), impeller::ComputeNextAtlasSize(), impeller::Context::CreateCommandBuffer(), impeller::Context::EnqueueCommandBuffer(), FML_DCHECK, impeller::TextureDescriptor::format, impeller::Context::GetBackendType(), impeller::Context::GetCapabilities(), impeller::Context::GetResourceAllocator(), i, impeller::TSize< T >::IsEmpty(), impeller::TypographerContext::IsValid(), impeller::GlyphAtlas::kAlphaBitmap, impeller::GlyphAtlas::kColorBitmap, impeller::kDevicePrivate, impeller::Context::kOpenGLES, impeller::kR8G8B8A8UNormInt, impeller::kShaderRead, impeller::TRect< T >::MakeSize(), impeller::TextureDescriptor::size, impeller::TextureDescriptor::storage_mode, TRACE_EVENT0, type, impeller::UpdateAtlasBitmap(), and impeller::TextureDescriptor::usage.

◆ CreateGlyphAtlasContext()

std::shared_ptr< GlyphAtlasContext > impeller::TypographerContextSkia::CreateGlyphAtlasContext ( GlyphAtlas::Type  type) const
overridevirtual

Implements impeller::TypographerContext.

Definition at line 85 of file typographer_context_skia.cc.

85 {
86 return std::make_shared<GlyphAtlasContext>(type);
87}

References type.

◆ Make()


The documentation for this class was generated from the following files: