| Flutter Impeller |

Classes | Public Member Functions | List of all members
impeller::TextShadowCache Class Reference

A cache for blurred text that re-uses these across frames. More...

`#include <text_shadow_cache.h>`

## Classes
struct | TextShadowCacheKey
| A key to look up cached glyph textures. More...

## Public Member Functions
| TextShadowCache ()=default
| ~TextShadowCache ()=default
void | MarkFrameStart ()
| Mark all glyph textures as unused this frame. More...
void | MarkFrameEnd ()
| Remove all glyph textures that were not referenced at least once. More...
std::optional< Entity > | Lookup (const ContentContext &renderer, const Entity &entity, const std::shared_ptr< FilterContents > &contents, const TextShadowCacheKey &)
| Lookup the entity in the cache with the given filter/text contents, returning the new entity to render. More...
size_t | GetCacheSizeForTesting () const

## Detailed Description

A cache for blurred text that re-uses these across frames.

Text shadows are generally stable, but expensive to compute as we use a full gaussian blur. This class caches these shadows by text blob identifier and holds them for at least one frame.

Additionally, there is an optimization for a single glyph (generally an Icon) that uses the content itself as a key.

If there was a cheaper method of text frame identity, or a per-glyph caching system this could be more efficient. As it exists, this mostly ameliorate severe performance degradation for glyph shadows but does not provide substantially better performance than Skia.

Definition at line 31 of file text_shadow_cache.h.

## Constructor & Destructor Documentation

## ◆ TextShadowCache()

impeller::TextShadowCache::TextShadowCache | ( |  | ) |
| default

## ◆ ~TextShadowCache()

impeller::TextShadowCache::~TextShadowCache | ( |  | ) |
| default

## Member Function Documentation

## ◆ GetCacheSizeForTesting()

size_t impeller::TextShadowCache::GetCacheSizeForTesting | ( |  | ) | const
| inline

Definition at line 90 of file text_shadow_cache.h.

90 { return entries_.size(); }

Referenced by impeller::testing::TEST_P().

## ◆ Lookup()

std::optional< Entity > impeller::TextShadowCache::Lookup | ( | const ContentContext & | renderer,
|  | const Entity & | entity,
|  | const std::shared_ptr< FilterContents > & | contents,
|  | const TextShadowCacheKey & | text_key
| ) |  |

Lookup the entity in the cache with the given filter/text contents, returning the new entity to render.

If the entity is not present, render and place in the cache.

Definition at line 43 of file text_shadow_cache.cc.

47 {
48 auto it = entries_.find(text_key);
49
50 if (it != entries_.end()) {
51 it->second.used_this_frame = true;
52 Entity cache_entity = it->second.entity.Clone();
53 cache_entity.SetClipDepth(entity.GetClipDepth());
54 cache_entity.SetTransform(entity.GetTransform() * it->second.key_matrix);
55 return cache_entity;
56 }
57
58 std::optional<Rect> filter_coverage = contents->GetCoverage(entity);
59 if (!filter_coverage.has_value()) {
60 return std::nullopt;
61 }
62
63 // Execute the filter to produce a snapshot that can be resued on subsequent
64 // frames. To prevent this texture from being re-used by the render target
65 // cache, we temporarily disable any RT caching.
66 renderer.GetRenderTargetCache()->DisableCache();
67 fml::ScopedCleanupClosure closure(
68 [&] { renderer.GetRenderTargetCache()->EnableCache(); });
69 std::optional<Entity> maybe_entity =
70 contents->GetEntity(renderer, entity, contents->GetCoverageHint());
71 if (!maybe_entity.has_value()) {
72 return std::nullopt;
73 }
74
75 // The original entity has a transform matrix A. The snapshot entity has a
76 // transform matrix B. We need a function that converts A to B, so that if we
77 // render an entity with a slightly different transform matrix A', it appears
78 // in the correct position.
79 // A * K = B
80 // A-1 * A * K = A-1 * B
81 // K = A-1 * B
82 //
83 // The transform matrix K can be computed by inverse A times B. Multiplying
84 // any subsequent entity transforms by this matrix will correctly position
85 // them.
86 Matrix key_matrix =
87 entity.GetTransform().Invert() * maybe_entity->GetTransform();
88 entries_[text_key] =
89 TextShadowCacheData{.entity = maybe_entity.value().Clone(),
90 .used_this_frame = true,
91 .key_matrix = key_matrix};
92
93 maybe_entity->SetClipDepth(entity.GetClipDepth());
94 return maybe_entity;
95 }

References impeller::Entity::Clone(), impeller::Entity::GetClipDepth(), impeller::Entity::GetCoverage(), impeller::ContentContext::GetRenderTargetCache(), impeller::Entity::GetTransform(), impeller::Matrix::Invert(), impeller::Entity::SetClipDepth(), and impeller::Entity::SetTransform().

## ◆ MarkFrameEnd()

void impeller::TextShadowCache::MarkFrameEnd | ( |  | ) |

Remove all glyph textures that were not referenced at least once.

Definition at line 38 of file text_shadow_cache.cc.

38 {
39 absl::erase_if(entries_,
40 [](const auto& pair) { return !pair.second.used_this_frame; });
41 }

## ◆ MarkFrameStart()

void impeller::TextShadowCache::MarkFrameStart | ( |  | ) |

Mark all glyph textures as unused this frame.

Definition at line 32 of file text_shadow_cache.cc.

32 {
33 for (auto& entry : entries_) {
34 entry.second.used_this_frame = false;
35 }
36 }

Referenced by impeller::DisplayListToTexture(), and impeller::RenderToTarget().

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

- impeller/entity/contents/text_shadow_cache.h
- impeller/entity/contents/text_shadow_cache.cc