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 FontGlyphMap &font_glyph_map) 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 FontGlyphMap font_glyph_map 
) const
overridevirtual

Implements impeller::TypographerContext.

Definition at line 446 of file typographer_context_skia.cc.

451  {
452  TRACE_EVENT0("impeller", __FUNCTION__);
453  if (!IsValid()) {
454  return nullptr;
455  }
456  std::shared_ptr<GlyphAtlas> last_atlas = atlas_context->GetGlyphAtlas();
457  FML_DCHECK(last_atlas->GetType() == type);
458 
459  if (font_glyph_map.empty()) {
460  return last_atlas;
461  }
462 
463  // ---------------------------------------------------------------------------
464  // Step 1: Determine if the atlas type and font glyph pairs are compatible
465  // with the current atlas and reuse if possible. For each new font and
466  // glyph pair, compute the glyph size at scale.
467  // ---------------------------------------------------------------------------
468  std::vector<FontGlyphPair> new_glyphs;
469  std::vector<Rect> glyph_sizes;
470  CollectNewGlyphs(last_atlas, font_glyph_map, new_glyphs, glyph_sizes);
471  if (new_glyphs.size() == 0) {
472  return last_atlas;
473  }
474 
475  // ---------------------------------------------------------------------------
476  // Step 2: Determine if the additional missing glyphs can be appended to the
477  // existing bitmap without recreating the atlas.
478  // ---------------------------------------------------------------------------
479  std::vector<Rect> glyph_positions;
480  glyph_positions.reserve(new_glyphs.size());
481  size_t first_missing_index = 0;
482 
483  if (last_atlas->GetTexture()) {
484  // Append all glyphs that fit into the current atlas.
485  first_missing_index = AppendToExistingAtlas(
486  last_atlas, new_glyphs, glyph_positions, glyph_sizes,
487  atlas_context->GetAtlasSize(), atlas_context->GetHeightAdjustment(),
488  atlas_context->GetRectPacker());
489 
490  // ---------------------------------------------------------------------------
491  // Step 3a: Record the positions in the glyph atlas of the newly added
492  // glyphs.
493  // ---------------------------------------------------------------------------
494  for (size_t i = 0; i < first_missing_index; i++) {
495  last_atlas->AddTypefaceGlyphPositionAndBounds(
496  new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
497  }
498 
499  std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
500  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
501 
502  fml::ScopedCleanupClosure closure([&]() {
503  blit_pass->EncodeCommands(context.GetResourceAllocator());
504  context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
505  });
506 
507  // ---------------------------------------------------------------------------
508  // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
509  // the uploads into the blit pass.
510  // ---------------------------------------------------------------------------
511  if (!UpdateAtlasBitmap(*last_atlas, blit_pass, host_buffer,
512  last_atlas->GetTexture(), new_glyphs, 0,
513  first_missing_index)) {
514  return nullptr;
515  }
516 
517  // If all glyphs fit, just return the old atlas.
518  if (first_missing_index == new_glyphs.size()) {
519  return last_atlas;
520  }
521  }
522 
523  int64_t height_adjustment = atlas_context->GetAtlasSize().height;
524  const int64_t max_texture_height =
525  context.GetResourceAllocator()->GetMaxTextureSizeSupported().height;
526 
527  // IF the current atlas size is as big as it can get, then "GC" and create an
528  // atlas with only the required glyphs. OpenGLES cannot reliably perform the
529  // blit required here, as 1) it requires attaching textures as read and write
530  // framebuffers which has substantially smaller size limits that max textures
531  // and 2) is missing a GLES 2.0 implementation and cap check.
532  bool blit_old_atlas = true;
533  std::shared_ptr<GlyphAtlas> new_atlas = last_atlas;
534  if (atlas_context->GetAtlasSize().height >= max_texture_height ||
535  context.GetBackendType() == Context::BackendType::kOpenGLES) {
536  blit_old_atlas = false;
537  new_atlas = std::make_shared<GlyphAtlas>(type);
538 
539  new_glyphs.clear();
540  glyph_sizes.clear();
541  CollectNewGlyphs(new_atlas, font_glyph_map, new_glyphs, glyph_sizes);
542  glyph_positions.clear();
543  glyph_positions.reserve(new_glyphs.size());
544  first_missing_index = 0;
545 
546  height_adjustment = 0;
547  atlas_context->UpdateRectPacker(nullptr);
548  atlas_context->UpdateGlyphAtlas(new_atlas, {0, 0}, 0);
549  }
550 
551  // A new glyph atlas must be created.
552  ISize atlas_size = ComputeNextAtlasSize(atlas_context, //
553  new_glyphs, //
554  glyph_positions, //
555  glyph_sizes, //
556  first_missing_index, //
557  max_texture_height //
558  );
559 
560  atlas_context->UpdateGlyphAtlas(new_atlas, atlas_size, height_adjustment);
561  if (atlas_size.IsEmpty()) {
562  return nullptr;
563  }
564  FML_DCHECK(new_glyphs.size() == glyph_positions.size());
565 
566  TextureDescriptor descriptor;
567  switch (type) {
569  descriptor.format =
570  context.GetCapabilities()->GetDefaultGlyphAtlasFormat();
571  break;
573  descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
574  break;
575  }
576  descriptor.size = atlas_size;
577  descriptor.storage_mode = StorageMode::kDevicePrivate;
578  descriptor.usage = TextureUsage::kShaderRead;
579  std::shared_ptr<Texture> new_texture =
580  context.GetResourceAllocator()->CreateTexture(descriptor);
581  if (!new_texture) {
582  return nullptr;
583  }
584 
585  new_texture->SetLabel("GlyphAtlas");
586 
587  std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
588  std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
589 
590  fml::ScopedCleanupClosure closure([&]() {
591  blit_pass->EncodeCommands(context.GetResourceAllocator());
592  context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
593  });
594 
595  // Now append all remaining glyphs. This should never have any missing data...
596  auto old_texture = new_atlas->GetTexture();
597  new_atlas->SetTexture(std::move(new_texture));
598 
599  // ---------------------------------------------------------------------------
600  // Step 3a: Record the positions in the glyph atlas of the newly added
601  // glyphs.
602  // ---------------------------------------------------------------------------
603  for (size_t i = first_missing_index; i < glyph_positions.size(); i++) {
604  new_atlas->AddTypefaceGlyphPositionAndBounds(
605  new_glyphs[i], glyph_positions[i], glyph_sizes[i]);
606  }
607 
608  // ---------------------------------------------------------------------------
609  // Step 4a: Draw new font-glyph pairs into the a host buffer and encode
610  // the uploads into the blit pass.
611  // ---------------------------------------------------------------------------
612  if (!BulkUpdateAtlasBitmap(*new_atlas, blit_pass, host_buffer,
613  new_atlas->GetTexture(), new_glyphs,
614  first_missing_index, new_glyphs.size())) {
615  return nullptr;
616  }
617 
618  // Blit the old texture to the top left of the new atlas.
619  if (blit_old_atlas && old_texture) {
620  blit_pass->AddCopy(old_texture, new_atlas->GetTexture(),
621  IRect::MakeSize(new_atlas->GetTexture()->GetSize()),
622  {0, 0});
623  }
624 
625  // ---------------------------------------------------------------------------
626  // Step 8b: Record the texture in the glyph atlas.
627  // ---------------------------------------------------------------------------
628 
629  return new_atlas;
630 }

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

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

References type.

◆ Make()

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

Definition at line 75 of file typographer_context_skia.cc.

75  {
76  return std::make_shared<TypographerContextSkia>();
77 }

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


The documentation for this class was generated from the following files:
impeller::ISize
ISize64 ISize
Definition: size.h:140
impeller::GlyphAtlas::Type::kColorBitmap
@ kColorBitmap
impeller::GlyphAtlas::Type::kAlphaBitmap
@ kAlphaBitmap
impeller::UpdateAtlasBitmap
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)
Definition: typographer_context_skia.cc:311
impeller::PixelFormat::kR8G8B8A8UNormInt
@ kR8G8B8A8UNormInt
impeller::CollectNewGlyphs
static void CollectNewGlyphs(const std::shared_ptr< GlyphAtlas > &atlas, const FontGlyphMap &font_glyph_map, std::vector< FontGlyphPair > &new_glyphs, std::vector< Rect > &glyph_sizes)
Definition: typographer_context_skia.cc:405
impeller::BulkUpdateAtlasBitmap
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.
Definition: typographer_context_skia.cc:253
impeller::ComputeNextAtlasSize
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)
Definition: typographer_context_skia.cc:165
impeller::Context::BackendType::kOpenGLES
@ kOpenGLES
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
type
GLenum type
Definition: blit_command_gles.cc:127
impeller::TRect::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
impeller::TextureUsage::kShaderRead
@ kShaderRead
impeller::AppendToExistingAtlas
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)
Definition: typographer_context_skia.cc:101
impeller::TypographerContext::IsValid
virtual bool IsValid() const
Definition: typographer_context.cc:17