Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ static std::unique_ptr<PipelineT> CreateDefaultPipeline(

ContentContext::ContentContext(std::shared_ptr<Context> context)
: context_(std::move(context)),
tessellator_(std::make_shared<Tessellator>()) {
tessellator_(std::make_shared<Tessellator>()),
glyph_atlas_context_(std::make_shared<GlyphAtlasContext>()) {
if (!context_ || !context_->IsValid()) {
return;
}
Expand Down Expand Up @@ -291,6 +292,11 @@ std::shared_ptr<Tessellator> ContentContext::GetTessellator() const {
return tessellator_;
}

std::shared_ptr<GlyphAtlasContext> ContentContext::GetGlyphAtlasContext()
const {
return glyph_atlas_context_;
}

std::shared_ptr<Context> ContentContext::GetContext() const {
return context_;
}
Expand Down
5 changes: 5 additions & 0 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
#include "impeller/entity/position_color.vert.h"
#include "impeller/entity/position_uv.vert.h"

#include "impeller/typographer/glyph_atlas.h"

namespace impeller {

using LinearGradientFillPipeline =
Expand Down Expand Up @@ -376,6 +378,8 @@ class ContentContext {

std::shared_ptr<Context> GetContext() const;

std::shared_ptr<GlyphAtlasContext> GetGlyphAtlasContext() const;

using SubpassCallback =
std::function<bool(const ContentContext&, RenderPass&)>;

Expand Down Expand Up @@ -465,6 +469,7 @@ class ContentContext {

bool is_valid_ = false;
std::shared_ptr<Tessellator> tessellator_;
std::shared_ptr<GlyphAtlasContext> glyph_atlas_context_;

FML_DISALLOW_COPY_AND_ASSIGN(ContentContext);
};
Expand Down
10 changes: 6 additions & 4 deletions impeller/entity/contents/text_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ void TextContents::SetGlyphAtlas(std::shared_ptr<LazyGlyphAtlas> atlas) {

std::shared_ptr<GlyphAtlas> TextContents::ResolveAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
std::shared_ptr<Context> context) const {
FML_DCHECK(lazy_atlas_);
if (lazy_atlas_) {
return lazy_atlas_->CreateOrGetGlyphAtlas(type, context);
return lazy_atlas_->CreateOrGetGlyphAtlas(type, atlas_context, context);
}

return nullptr;
Expand Down Expand Up @@ -172,8 +173,9 @@ static bool CommonRender(const ContentContext& renderer,
bool TextContents::RenderSdf(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
auto atlas = ResolveAtlas(GlyphAtlas::Type::kSignedDistanceField,
renderer.GetContext());
auto atlas =
ResolveAtlas(GlyphAtlas::Type::kSignedDistanceField,
renderer.GetGlyphAtlasContext(), renderer.GetContext());

if (!atlas || !atlas->IsValid()) {
VALIDATION_LOG << "Cannot render glyphs without prepared atlas.";
Expand Down Expand Up @@ -208,7 +210,7 @@ bool TextContents::Render(const ContentContext& renderer,
auto atlas =
ResolveAtlas(lazy_atlas_->HasColor() ? GlyphAtlas::Type::kColorBitmap
: GlyphAtlas::Type::kAlphaBitmap,
renderer.GetContext());
renderer.GetGlyphAtlasContext(), renderer.GetContext());

if (!atlas || !atlas->IsValid()) {
VALIDATION_LOG << "Cannot render glyphs without prepared atlas.";
Expand Down
1 change: 1 addition & 0 deletions impeller/entity/contents/text_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class TextContents final : public Contents {

std::shared_ptr<GlyphAtlas> ResolveAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
std::shared_ptr<Context> context) const;

FML_DISALLOW_COPY_AND_ASSIGN(TextContents);
Expand Down
30 changes: 21 additions & 9 deletions impeller/typographer/backends/skia/text_render_context_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -340,25 +340,37 @@ static std::shared_ptr<Texture> UploadGlyphTextureAtlas(

std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
FrameIterator frame_iterator) const {
TRACE_EVENT0("impeller", __FUNCTION__);
if (!IsValid()) {
return nullptr;
}

auto glyph_atlas = std::make_shared<GlyphAtlas>(type);
auto last_atlas = atlas_context->GetGlyphAtlas();

// ---------------------------------------------------------------------------
// Step 1: Collect unique font-glyph pairs in the frame.
// ---------------------------------------------------------------------------

auto font_glyph_pairs = CollectUniqueFontGlyphPairs(type, frame_iterator);
if (font_glyph_pairs.empty()) {
return glyph_atlas;
return last_atlas;
}

// ---------------------------------------------------------------------------
// Step 2: Determine if the atlas type and font glyph pairs are compatible
// with the current atlas and reuse if possible.
// ---------------------------------------------------------------------------
if (last_atlas->GetType() == type &&
last_atlas->HasSamePairs(font_glyph_pairs)) {
return last_atlas;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should file an issue to explore copying out the glyphs we still need. Or maybe just copy the whole atlas if it's small enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking something like, if you need a small number of additional glyphs and they fit on the current atlas, just append them and re-upload. Even if we resized the atlas, reusing and blitting the old atlas instead of each character would be a good idea too

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd either have to keep the rect packer around or store the taken/free area somehow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this probably deserves a doc exploring the options we have here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I explored this a bit while I was out. There are a lot of potential caching options available to us, but I think we should probably keep pulling on making the whole thing faster first before we invest too much effort into tuning this.

To that end, lets land the trivial case caching and circle back?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM

}

auto glyph_atlas = std::make_shared<GlyphAtlas>(type);
atlas_context->UpdateGlyphAtlas(glyph_atlas);

// ---------------------------------------------------------------------------
// Step 2: Get the optimum size of the texture atlas.
// Step 3: Get the optimum size of the texture atlas.
// ---------------------------------------------------------------------------
std::vector<Rect> glyph_positions;
const auto atlas_size =
Expand All @@ -368,7 +380,7 @@ std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
}

// ---------------------------------------------------------------------------
// Step 3: Find location of font-glyph pairs in the atlas. We have this from
// Step 4: Find location of font-glyph pairs in the atlas. We have this from
// the last step. So no need to do create another rect packer. But just do a
// sanity check of counts. This could also be just an assertion as only a
// construction issue would cause such a failure.
Expand All @@ -378,23 +390,23 @@ std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
}

// ---------------------------------------------------------------------------
// Step 4: Record the positions in the glyph atlas.
// Step 5: Record the positions in the glyph atlas.
// ---------------------------------------------------------------------------
for (size_t i = 0, count = glyph_positions.size(); i < count; i++) {
glyph_atlas->AddTypefaceGlyphPosition(font_glyph_pairs[i],
glyph_positions[i]);
}

// ---------------------------------------------------------------------------
// Step 5: Draw font-glyph pairs in the correct spot in the atlas.
// Step 6: Draw font-glyph pairs in the correct spot in the atlas.
// ---------------------------------------------------------------------------
auto bitmap = CreateAtlasBitmap(*glyph_atlas, atlas_size);
if (!bitmap) {
return nullptr;
}

// ---------------------------------------------------------------------------
// Step 6: Upload the atlas as a texture.
// Step 7: Upload the atlas as a texture.
// ---------------------------------------------------------------------------
PixelFormat format;
switch (type) {
Expand All @@ -416,7 +428,7 @@ std::shared_ptr<GlyphAtlas> TextRenderContextSkia::CreateGlyphAtlas(
}

// ---------------------------------------------------------------------------
// Step 7: Record the texture in the glyph atlas.
// Step 8: Record the texture in the glyph atlas.
// ---------------------------------------------------------------------------
glyph_atlas->SetTexture(std::move(texture));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class TextRenderContextSkia : public TextRenderContext {
// |TextRenderContext|
std::shared_ptr<GlyphAtlas> CreateGlyphAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
FrameIterator iterator) const override;

private:
Expand Down
22 changes: 22 additions & 0 deletions impeller/typographer/glyph_atlas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@

namespace impeller {

GlyphAtlasContext::GlyphAtlasContext()
: atlas_(std::make_shared<GlyphAtlas>(GlyphAtlas::Type::kAlphaBitmap)) {}

GlyphAtlasContext::~GlyphAtlasContext() {}

std::shared_ptr<GlyphAtlas> GlyphAtlasContext::GetGlyphAtlas() const {
return atlas_;
}

void GlyphAtlasContext::UpdateGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas) {
atlas_ = atlas;
}

GlyphAtlas::GlyphAtlas(Type type) : type_(type) {}

GlyphAtlas::~GlyphAtlas() = default;
Expand Down Expand Up @@ -61,4 +74,13 @@ size_t GlyphAtlas::IterateGlyphs(
return count;
}

bool GlyphAtlas::HasSamePairs(const FontGlyphPair::Vector& new_glyphs) {
for (const auto& pair : new_glyphs) {
if (positions_.find(pair) == positions_.end()) {
return false;
}
}
return true;
}

} // namespace impeller
33 changes: 33 additions & 0 deletions impeller/typographer/glyph_atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@ class GlyphAtlas {
///
std::optional<Rect> FindFontGlyphPosition(const FontGlyphPair& pair) const;

//----------------------------------------------------------------------------
/// @brief whether this atlas contains all of the same font-glyph pairs
/// as the vector.
///
/// @param[in] new_glyphs The full set of new glyphs
///
/// @return Whether this atlas contains all passed pairs.
///
bool HasSamePairs(const FontGlyphPair::Vector& new_glyphs);

private:
const Type type_;
std::shared_ptr<Texture> texture_;
Expand All @@ -129,4 +139,27 @@ class GlyphAtlas {
FML_DISALLOW_COPY_AND_ASSIGN(GlyphAtlas);
};

//------------------------------------------------------------------------------
/// @brief A container for caching a glyph atlas across frames.
///
class GlyphAtlasContext {
public:
GlyphAtlasContext();

~GlyphAtlasContext();

//----------------------------------------------------------------------------
/// @brief Retrieve the current glyph atlas.
std::shared_ptr<GlyphAtlas> GetGlyphAtlas() const;

//----------------------------------------------------------------------------
/// @brief Update the context with a newly constructed glyph atlas.
void UpdateGlyphAtlas(std::shared_ptr<GlyphAtlas> atlas);

private:
std::shared_ptr<GlyphAtlas> atlas_;

FML_DISALLOW_COPY_AND_ASSIGN(GlyphAtlasContext);
};

} // namespace impeller
3 changes: 2 additions & 1 deletion impeller/typographer/lazy_glyph_atlas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ bool LazyGlyphAtlas::HasColor() const {

std::shared_ptr<GlyphAtlas> LazyGlyphAtlas::CreateOrGetGlyphAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
std::shared_ptr<Context> context) const {
{
auto atlas_it = atlas_map_.find(type);
Expand All @@ -47,7 +48,7 @@ std::shared_ptr<GlyphAtlas> LazyGlyphAtlas::CreateOrGetGlyphAtlas(
i++;
return &result;
};
auto atlas = text_context->CreateGlyphAtlas(type, iterator);
auto atlas = text_context->CreateGlyphAtlas(type, atlas_context, iterator);
if (!atlas || !atlas->IsValid()) {
VALIDATION_LOG << "Could not create valid atlas.";
return nullptr;
Expand Down
1 change: 1 addition & 0 deletions impeller/typographer/lazy_glyph_atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class LazyGlyphAtlas {

std::shared_ptr<GlyphAtlas> CreateOrGetGlyphAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
std::shared_ptr<Context> context) const;

bool HasColor() const;
Expand Down
3 changes: 2 additions & 1 deletion impeller/typographer/text_render_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const std::shared_ptr<Context>& TextRenderContext::GetContext() const {

std::shared_ptr<GlyphAtlas> TextRenderContext::CreateGlyphAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
const TextFrame& frame) const {
size_t count = 0;
FrameIterator iterator = [&]() -> const TextFrame* {
Expand All @@ -43,7 +44,7 @@ std::shared_ptr<GlyphAtlas> TextRenderContext::CreateGlyphAtlas(
}
return nullptr;
};
return CreateGlyphAtlas(type, iterator);
return CreateGlyphAtlas(type, atlas_context, iterator);
}

} // namespace impeller
7 changes: 5 additions & 2 deletions impeller/typographer/text_render_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ class TextRenderContext {

virtual std::shared_ptr<GlyphAtlas> CreateGlyphAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
FrameIterator iterator) const = 0;

std::shared_ptr<GlyphAtlas> CreateGlyphAtlas(GlyphAtlas::Type type,
const TextFrame& frame) const;
std::shared_ptr<GlyphAtlas> CreateGlyphAtlas(
GlyphAtlas::Type type,
std::shared_ptr<GlyphAtlasContext> atlas_context,
const TextFrame& frame) const;

protected:
//----------------------------------------------------------------------------
Expand Down
Loading