Flutter Impeller
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. More...
 

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 498 of file typographer_context_skia.cc.

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

References impeller::AppendToExistingAtlas(), impeller::BulkUpdateAtlasBitmap(), impeller::ComputeNextAtlasSize(), impeller::Context::CreateCommandBuffer(), impeller::Context::EnqueueCommandBuffer(), impeller::TextureDescriptor::format, impeller::Context::GetBackendType(), impeller::Context::GetCapabilities(), impeller::Context::GetResourceAllocator(), 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, 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 86 of file typographer_context_skia.cc.

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

References type.

◆ Make()

std::shared_ptr< TypographerContext > impeller::TypographerContextSkia::Make ( )
static

Definition at line 77 of file typographer_context_skia.cc.

77  {
78  return std::make_shared<TypographerContextSkia>();
79 }

Referenced by impeller::DlPlayground::OpenPlaygroundHere(), and impeller::testing::TEST_P().


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