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< GlyphAtlasContext > CreateGlyphAtlasContext (GlyphAtlas::Type type) const override
 
std::shared_ptr< GlyphAtlas > CreateGlyphAtlas (Context &context, GlyphAtlas::Type type, HostBuffer &host_buffer, const std::shared_ptr< GlyphAtlasContext > &atlas_context, const std::vector< RenderableText > &renderable_texts) const override
 
- Public Member Functions inherited from impeller::TypographerContext
virtual ~TypographerContext ()
 
virtual bool IsValid () const
 

Static Public Member Functions

static std::shared_ptr< TypographerContext > Make ()
 
static SkImageInfo GetImageInfo (const GlyphAtlas &atlas, Size size, bool support_light_glyphs)
 

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 13 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< RenderableText > &  renderable_texts 
) const
overridevirtual

Implements impeller::TypographerContext.

Definition at line 548 of file typographer_context_skia.cc.

553  {
554  TRACE_EVENT0("impeller", __FUNCTION__);
555  if (!IsValid()) {
556  return nullptr;
557  }
558  std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
559  FML_DCHECK(last_atlas->GetType() == type);
560 
561  if (renderable_texts.empty()) {
562  return last_atlas;
563  }
564 
565  // ---------------------------------------------------------------------------
566  // Step 1: Determine if the atlas type and font glyph pairs are compatible
567  // with the current atlas and reuse if possible. For each new font and
568  // glyph pair, compute the glyph size at scale.
569  // ---------------------------------------------------------------------------
570  auto [new_glyphs, glyph_sizes] =
571  CollectNewGlyphs(last_atlas, renderable_texts);
572  if (new_glyphs.size() == 0) {
573  return last_atlas;
574  }
575 
576  // ---------------------------------------------------------------------------
577  // Step 2: Determine if the additional missing glyphs can be appended to the
578  // existing bitmap without recreating the atlas.
579  // ---------------------------------------------------------------------------
580  std::vector<Rect> glyph_positions;
581  glyph_positions.reserve(new_glyphs.size());
582  size_t first_missing_index = 0;
583 
584  if (last_atlas->GetTexture()) {
585  // Append all glyphs that fit into the current atlas.
586  first_missing_index = AppendToExistingAtlas(
587  last_atlas, new_glyphs, glyph_positions, glyph_sizes,
588  atlas_context->GetAtlasSize(), atlas_context->GetHeightAdjustment(),
589  atlas_context->GetRectPacker());
590 
591  // ---------------------------------------------------------------------------
592  // Step 3a: Record the positions in the glyph atlas of the newly added
593  // glyphs.
594  // ---------------------------------------------------------------------------
595  for (size_t i = 0; i < first_missing_index; i++) {
596  last_atlas->AddTypefaceGlyphPositionAndBounds(
597  new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
598  }
599 
600  std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
601  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
602 
603  fml::ScopedCleanupClosure closure([&]() {
604  blit_pass->EncodeCommands();
605  if (!context.EnqueueCommandBuffer(std::move(cmd_buffer))) {
606  VALIDATION_LOG << "Failed to submit glyph atlas command buffer";
607  }
608  });
609 
610  // ---------------------------------------------------------------------------
611  // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
612  // the uploads into the blit pass.
613  // ---------------------------------------------------------------------------
614  if (!UpdateAtlasBitmap(*last_atlas, blit_pass, data_host_buffer,
615  last_atlas->GetTexture(), new_glyphs, 0,
616  first_missing_index)) {
617  return nullptr;
618  }
619 
620  // If all glyphs fit, just return the old atlas.
621  if (first_missing_index == new_glyphs.size()) {
622  return last_atlas;
623  }
624  }
625 
626  int64_t height_adjustment = atlas_context->GetAtlasSize().height;
627  const int64_t max_texture_height =
628  context.GetResourceAllocator()->GetMaxTextureSizeSupported().height;
629 
630  // IF the current atlas size is as big as it can get, then "GC" and create an
631  // atlas with only the required glyphs. OpenGLES cannot reliably perform the
632  // blit required here, as 1) it requires attaching textures as read and write
633  // framebuffers which has substantially smaller size limits that max textures
634  // and 2) is missing a GLES 2.0 implementation and cap check.
635  bool blit_old_atlas = true;
636  std::shared_ptr<GlyphAtlas> new_atlas = last_atlas;
637  if (atlas_context->GetAtlasSize().height >= max_texture_height ||
638  context.GetBackendType() == Context::BackendType::kOpenGLES) {
639  blit_old_atlas = false;
640  new_atlas = std::make_shared<GlyphAtlas>(
641  type, /*initial_generation=*/last_atlas->GetAtlasGeneration() + 1);
642 
643  auto [update_glyphs, update_sizes] =
644  CollectNewGlyphs(new_atlas, renderable_texts);
645  new_glyphs = std::move(update_glyphs);
646  glyph_sizes = std::move(update_sizes);
647 
648  glyph_positions.clear();
649  glyph_positions.reserve(new_glyphs.size());
650  first_missing_index = 0;
651 
652  height_adjustment = 0;
653  atlas_context->UpdateRectPacker(nullptr);
654  atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
655  }
656 
657  // A new glyph atlas must be created.
658  ISize atlas_size = ComputeNextAtlasSize(atlas_context, //
659  new_glyphs, //
660  glyph_positions, //
661  glyph_sizes, //
662  first_missing_index, //
663  max_texture_height //
664  );
665 
666  atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
667  if (atlas_size.IsEmpty()) {
668  return nullptr;
669  }
670  FML_DCHECK(new_glyphs.size() == glyph_positions.size());
671 
672  TextureDescriptor descriptor;
673  switch (type) {
675  descriptor.format =
676  context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
677  break;
679  descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
680  break;
681  }
682  descriptor.size = atlas_size;
683  descriptor.storage_mode = StorageMode::kDevicePrivate;
684  descriptor.usage = TextureUsage::kShaderRead;
685  std::shared_ptr<Texture> new_texture =
686  context.GetResourceAllocator()->CreateTexture(descriptor);
687  if (!new_texture) {
688  return nullptr;
689  }
690 
691  new_texture->SetLabel("GlyphAtlas");
692 
693  std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
694  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
695 
696  fml::ScopedCleanupClosure closure([&]() {
697  blit_pass->EncodeCommands();
698  if (!context.EnqueueCommandBuffer(std::move(cmd_buffer))) {
699  VALIDATION_LOG << "Failed to submit glyph atlas command buffer";
700  }
701  });
702 
703  // Now append all remaining glyphs. This should never have any missing data...
704  auto old_texture = new_atlas->GetTexture();
705  new_atlas->SetTexture(std::move(new_texture));
706 
707  // ---------------------------------------------------------------------------
708  // Step 3a: Record the positions in the glyph atlas of the newly added
709  // glyphs.
710  // ---------------------------------------------------------------------------
711  for (size_t i = first_missing_index; i < glyph_positions.size(); i++) {
712  new_atlas->AddTypefaceGlyphPositionAndBounds(
713  new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
714  }
715 
716  // ---------------------------------------------------------------------------
717  // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
718  // the uploads into the blit pass.
719  // ---------------------------------------------------------------------------
720  if (!BulkUpdateAtlasBitmap(*new_atlas, blit_pass, data_host_buffer,
721  new_atlas->GetTexture(), new_glyphs,
722  first_missing_index, new_glyphs.size())) {
723  return nullptr;
724  }
725 
726  // Blit the old texture to the top left of the new atlas.
727  if (blit_old_atlas && old_texture) {
728  blit_pass->AddCopy(old_texture, new_atlas->GetTexture(),
729  IRect::MakeSize(new_atlas->GetTexture()->GetSize()),
730  {0, 0});
731  }
732 
733  // ---------------------------------------------------------------------------
734  // Step 8b: Record the texture in the glyph atlas.
735  // ---------------------------------------------------------------------------
736 
737  return new_atlas;
738 }
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
std::shared_ptr< ContextGLES > context
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150

References impeller::AppendToExistingAtlas(), impeller::BulkUpdateAtlasBitmap(), impeller::ComputeNextAtlasSize(), context, impeller::TextureDescriptor::format, 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, 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 119 of file typographer_context_skia.cc.

119  {
120  return std::make_shared<GlyphAtlasContext>(type);
121 }

◆ GetImageInfo()

SkImageInfo impeller::TypographerContextSkia::GetImageInfo ( const GlyphAtlas &  atlas,
Size  size,
bool  support_light_glyphs 
)
static

Definition at line 123 of file typographer_context_skia.cc.

125  {
126  SkISize skia_size = {static_cast<int32_t>(size.width),
127  static_cast<int32_t>(size.height)};
128 
129  switch (atlas.GetType()) {
131  return support_light_glyphs
132  ? SkImageInfo::Make(skia_size, kRGBA_8888_SkColorType,
133  kPremul_SkAlphaType)
134  : SkImageInfo::MakeA8(skia_size);
136  return SkImageInfo::Make(skia_size, kRGBA_8888_SkColorType,
137  kPremul_SkAlphaType);
138  }
139  FML_UNREACHABLE();
140 }

References impeller::GlyphAtlas::GetType(), impeller::TSize< T >::height, impeller::GlyphAtlas::kAlphaBitmap, impeller::GlyphAtlas::kColorBitmap, and impeller::TSize< T >::width.

Referenced by impeller::BulkUpdateAtlasBitmap(), impeller::testing::TEST_P(), and impeller::UpdateAtlasBitmap().

◆ Make()

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

Definition at line 110 of file typographer_context_skia.cc.

110  {
111  return std::make_shared<TypographerContextSkia>();
112 }

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


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