| Flutter Impeller |

Classes | Public Types | Public Member Functions | Static Public Attributes | List of all members
impeller::EntityPass Class Reference

`#include <entity_pass.h>`

## Public Types
using | Element = std::variant< Entity, std::unique_ptr< EntityPass > >
using | BackdropFilterProc = std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, const Matrix &effect_transform, Entity::RenderingMode rendering_mode)>

## Public Member Functions
| EntityPass ()
| ~EntityPass ()
void | SetDelegate (std::shared_ptr< EntityPassDelegate > delgate)
void | SetBoundsLimit (std::optional< Rect > bounds_limit, ContentBoundsPromise bounds_promise=ContentBoundsPromise::kUnknown)
| Set the bounds limit, which is provided by the user when creating a SaveLayer. This is a hint that allows the user to communicate that it's OK to not render content outside of the bounds. More...
std::optional< Rect > | GetBoundsLimit () const
| Get the bounds limit, which is provided by the user when creating a SaveLayer. More...
bool | GetBoundsLimitMightClipContent () const
| Indicates if the bounds limit set using |SetBoundsLimit()| might clip the contents of the pass. More...
bool | GetBoundsLimitIsSnug () const
| Indicates if the bounds limit set using |SetBoundsLimit()| is a reasonably tight estimate of the bounds of the contents. More...
size_t | GetSubpassesDepth () const
void | AddEntity (Entity entity)
| Add an entity to the current entity pass. More...
void | PushClip (Entity entity)
void | PopClips (size_t num_clips, uint64_t depth)
void | PopAllClips (uint64_t depth)
void | SetElements (std::vector< Element > elements)
EntityPass * | AddSubpass (std::unique_ptr< EntityPass > pass)
| Appends a given pass as a subpass. More...
void | AddSubpassInline (std::unique_ptr< EntityPass > pass)
| Merges a given pass into this pass. Useful for drawing pre-recorded pictures that don't require rendering into a separate subpass. More...
EntityPass * | GetSuperpass () const
bool | Render (ContentContext &renderer, const RenderTarget &render_target) const
void | IterateAllElements (const std::function< bool(Element &)> &iterator)
| Iterate all elements (entities and subpasses) in this pass, recursively including elements of child passes. The iteration order is depth-first. Whenever a subpass elements is encountered, it's included in the stream before its children. More...
void | IterateAllElements (const std::function< bool(const Element &)> &iterator) const
void | IterateAllEntities (const std::function< bool(Entity &)> &iterator)
| Iterate all entities in this pass, recursively including entities of child passes. The iteration order is depth-first. More...
void | IterateAllEntities (const std::function< bool(const Entity &)> &iterator) const
| Iterate all entities in this pass, recursively including entities of child passes. The iteration order is depth-first and does not allow modification of the entities. More...
bool | IterateUntilSubpass (const std::function< bool(Entity &)> &iterator)
| Iterate entities in this pass up until the first subpass is found. This is useful for limiting look-ahead optimizations. More...
size_t | GetElementCount () const
| Return the number of elements on this pass. More...
void | SetTransform (Matrix transform)
void | SetClipDepth (size_t clip_depth)
size_t | GetClipDepth () const
void | SetNewClipDepth (size_t clip_depth)
uint32_t | GetNewClipDepth () const
void | SetBlendMode (BlendMode blend_mode)
std::optional< Color > | GetClearColor (ISize size=ISize::Infinite()) const
| Return the premultiplied clear color of the pass entities, if any. More...
Color | GetClearColorOrDefault (ISize size=ISize::Infinite()) const
| Return the premultiplied clear color of the pass entities. More...
void | SetBackdropFilter (BackdropFilterProc proc)
void | SetEnableOffscreenCheckerboard (bool enabled)
int32_t | GetRequiredMipCount () const
void | SetRequiredMipCount (int32_t mip_count)
std::optional< Rect > | GetSubpassCoverage (const EntityPass &subpass, std::optional< Rect > coverage_limit) const
| Computes the coverage of a given subpass. This is used to determine the texture size of a given subpass before it's rendered to and passed through the subpass ImageFilter, if any. More...
std::optional< Rect > | GetElementsCoverage (std::optional< Rect > coverage_limit) const

## Static Public Attributes
static const std::string | kCaptureDocumentName = "EntityPass"

## Detailed Description

Definition at line 43 of file entity_pass.h.

## Member Typedef Documentation

## ◆ BackdropFilterProc

using impeller::EntityPass::BackdropFilterProc = std::function<std::shared_ptr<FilterContents>( FilterInput::Ref, const Matrix& effect_transform, Entity::RenderingMode rendering_mode)>

Definition at line 61 of file entity_pass.h.

## ◆ Element

using impeller::EntityPass::Element = std::variant<Entity, std::unique_ptr<EntityPass> >

Elements are renderable items in the `EntityPass`. Each can either be an `Entity` or a child `EntityPass`.

When the element is a child `EntityPass`, it may be rendered to an offscreen texture and converted into an `Entity` that draws the texture into the current pass, or its children may be collapsed into the current

`EntityPass`. Elements are converted to Entities in `GetEntityForElement()`.

Definition at line 54 of file entity_pass.h.

## Constructor & Destructor Documentation

## ◆ EntityPass()

impeller::EntityPass::EntityPass | ( |  | ) |
| default

## ◆ ~EntityPass()

impeller::EntityPass::~EntityPass | ( |  | ) |
| default

## Member Function Documentation

## ◆ AddEntity()

void impeller::EntityPass::AddEntity | ( | Entity | entity | ) |

Add an entity to the current entity pass.

Definition at line 106 of file entity_pass.cc.

106 {
107 if (entity.GetBlendMode() == BlendMode::kSourceOver &&
108 entity.GetContents()->IsOpaque()) {
109 entity.SetBlendMode(BlendMode::kSource);
110 }
111
112 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
113 advanced_blend_reads_from_pass_texture_ += 1;
114 }
115 elements_.emplace_back(std::move(entity));
116 }

References impeller::Entity::GetBlendMode(), impeller::Entity::GetContents(), impeller::Entity::kLastPipelineBlendMode, impeller::kSource, impeller::kSourceOver, and impeller::Entity::SetBlendMode().

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

## ◆ AddSubpass()

EntityPass * impeller::EntityPass::AddSubpass | ( | std::unique_ptr< EntityPass > | pass | ) |

Appends a given pass as a subpass.

Definition at line 272 of file entity_pass.cc.

272 {
273 if (!pass) {
274 return nullptr;
275 }
276 FML_DCHECK(pass->superpass_ == nullptr);
277 pass->superpass_ = this;
278
279 if (pass->backdrop_filter_proc_) {
280 backdrop_filter_reads_from_pass_texture_ += 1;
281 }
282 if (pass->blend_mode_ > Entity::kLastPipelineBlendMode) {
283 advanced_blend_reads_from_pass_texture_ += 1;
284 }
285
286 auto subpass_pointer = pass.get();
287 elements_.emplace_back(std::move(pass));
288 return subpass_pointer;
289 }

References impeller::Entity::kLastPipelineBlendMode.

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

## ◆ AddSubpassInline()

void impeller::EntityPass::AddSubpassInline | ( | std::unique_ptr< EntityPass > | pass | ) |

Merges a given pass into this pass. Useful for drawing pre-recorded pictures that don't require rendering into a separate subpass.

Definition at line 291 of file entity_pass.cc.

291 {
292 if (!pass) {
293 return;
294 }
295 FML_DCHECK(pass->superpass_ == nullptr);
296
297 std::vector<Element>& elements = pass->elements_;
298 for (auto i = 0u; i < elements.size(); i++) {
299 elements_.emplace_back(std::move(elements[i]));
300 }
301
302 backdrop_filter_reads_from_pass_texture_ +=
303 pass->backdrop_filter_reads_from_pass_texture_;
304 advanced_blend_reads_from_pass_texture_ +=
305 pass->advanced_blend_reads_from_pass_texture_;
306 }

## ◆ GetBoundsLimit()

std::optional< Rect > impeller::EntityPass::GetBoundsLimit | ( |  | ) | const

Get the bounds limit, which is provided by the user when creating a SaveLayer.

Definition at line 71 of file entity_pass.cc.

71 {
72 return bounds_limit_;
73 }

## ◆ GetBoundsLimitIsSnug()

bool impeller::EntityPass::GetBoundsLimitIsSnug | ( |  | ) | const

Indicates if the bounds limit set using |SetBoundsLimit()| is a reasonably tight estimate of the bounds of the contents.

Definition at line 94 of file entity_pass.cc.

94 {
95 switch (bounds_promise_) {
96 case ContentBoundsPromise::kUnknown:
97 return false;
98 case ContentBoundsPromise::kContainsContents:
99 case ContentBoundsPromise::kMayClipContents:
100 FML_DCHECK(bounds_limit_.has_value());
101 return true;
102 }
103 FML_UNREACHABLE();
104 }

References impeller::kContainsContents, impeller::kMayClipContents, and impeller::kUnknown.

Referenced by GetSubpassCoverage().

## ◆ GetBoundsLimitMightClipContent()

bool impeller::EntityPass::GetBoundsLimitMightClipContent | ( |  | ) | const

Indicates if the bounds limit set using |SetBoundsLimit()| might clip the contents of the pass.

Definition at line 75 of file entity_pass.cc.

75 {
76 switch (bounds_promise_) {
77 case ContentBoundsPromise::kUnknown:
78 // If the promise is unknown due to not having a bounds limit,
79 // then no clipping will occur. But if we have a bounds limit
80 // and it is unkown, then we can make no promises about whether
81 // it causes clipping of the entity pass contents and we
82 // conservatively return true.
83 return bounds_limit_.has_value();
84 case ContentBoundsPromise::kContainsContents:
85 FML_DCHECK(bounds_limit_.has_value());
86 return false;
87 case ContentBoundsPromise::kMayClipContents:
88 FML_DCHECK(bounds_limit_.has_value());
89 return true;
90 }
91 FML_UNREACHABLE();
92 }

References impeller::kContainsContents, impeller::kMayClipContents, and impeller::kUnknown.

Referenced by impeller::OpacityPeepholePassDelegate::CanCollapseIntoParentPass().

## ◆ GetClearColor()

std::optional< Color > impeller::EntityPass::GetClearColor | ( | ISize | size = `ISize::Infinite()` | ) | const

Return the premultiplied clear color of the pass entities, if any.

Definition at line 1187 of file entity_pass.cc.

1187 {
1188 if (backdrop_filter_proc_) {
1189 return std::nullopt;
1190 }
1191
1192 std::optional<Color> result = std::nullopt;
1193 for (const Element& element : elements_) {
1194 auto [entity_color, blend_mode] =
1195 ElementAsBackgroundColor(element, target_size);
1196 if (!entity_color.has_value()) {
1197 break;
1198 }
1199 result = result.value_or(Color::BlackTransparent())
1200 .Blend(entity_color.value(), blend_mode);
1201 }
1202 if (result.has_value()) {
1203 return result->Premultiply();
1204 }
1205 return result;
1206 }

References impeller::Color::BlackTransparent().

Referenced by GetClearColorOrDefault().

## ◆ GetClearColorOrDefault()

Color impeller::EntityPass::GetClearColorOrDefault | ( | ISize | size = `ISize::Infinite()` | ) | const

Return the premultiplied clear color of the pass entities.

If the entity pass has no clear color, this will return transparent black.

Definition at line 1183 of file entity_pass.cc.

1183 {
1184 return GetClearColor(size).value_or(Color::BlackTransparent());
1185 }

References impeller::Color::BlackTransparent(), and GetClearColor().

Referenced by Render().

## ◆ GetClipDepth()

size_t impeller::EntityPass::GetClipDepth | ( |  | ) | const

Definition at line 1166 of file entity_pass.cc.

1166 {
1167 return clip_depth_;
1168 }

## ◆ GetElementCount()

size_t impeller::EntityPass::GetElementCount | ( |  | ) | const

Return the number of elements on this pass.

Definition at line 1154 of file entity_pass.cc.

1154 {
1155 return elements_.size();
1156 }

Referenced by impeller::OpacityPeepholePassDelegate::CanCollapseIntoParentPass().

## ◆ GetElementsCoverage()

std::optional< Rect > impeller::EntityPass::GetElementsCoverage | ( | std::optional< Rect > | coverage_limit | ) | const

Definition at line 160 of file entity_pass.cc.

161 {
162 std::optional<Rect> accumulated_coverage;
163 for (const auto& element : elements_) {
164 std::optional<Rect> element_coverage;
165
166 if (auto entity = std::get_if<Entity>(&element)) {
167 element_coverage = entity->GetCoverage();
168
169 // When the coverage limit is std::nullopt, that means there is no limit,
170 // as opposed to empty coverage.
171 if (element_coverage.has_value() && coverage_limit.has_value()) {
172 const auto* filter = entity->GetContents()->AsFilter();
173 if (!filter || filter->IsTranslationOnly()) {
174 element_coverage =
175 element_coverage->Intersection(coverage_limit.value());
176 }
177 }
178 } else if (auto subpass_ptr =
179 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
180 auto& subpass = *subpass_ptr->get();
181
182 std::optional<Rect> unfiltered_coverage =
183 GetSubpassCoverage(subpass, std::nullopt);
184
185 // If the current pass elements have any coverage so far and there's a
186 // backdrop filter, then incorporate the backdrop filter in the
187 // pre-filtered coverage of the subpass.
188 if (accumulated_coverage.has_value() && subpass.backdrop_filter_proc_) {
189 std::shared_ptr<FilterContents> backdrop_filter =
190 subpass.backdrop_filter_proc_(
191 FilterInput::Make(accumulated_coverage.value()),
192 subpass.transform_, Entity::RenderingMode::kSubpass);
193 if (backdrop_filter) {
194 auto backdrop_coverage = backdrop_filter->GetCoverage({});
195 unfiltered_coverage =
196 Rect::Union(unfiltered_coverage, backdrop_coverage);
197 } else {
198 VALIDATION_LOG << "The EntityPass backdrop filter proc didn't return "
199 "a valid filter.";
200 }
201 }
202
203 if (!unfiltered_coverage.has_value()) {
204 continue;
205 }
206
207 // Additionally, subpass textures may be passed through filters, which may
208 // modify the coverage.
209 //
210 // Note that we currently only assume that ImageFilters (such as blurs and
211 // matrix transforms) may modify coverage, although it's technically
212 // possible ColorFilters to affect coverage as well. For example: A
213 // ColorMatrixFilter could output a completely transparent result, and
214 // we could potentially detect this case as zero coverage in the future.
215 std::shared_ptr<FilterContents> image_filter =
216 subpass.delegate_->WithImageFilter(*unfiltered_coverage,
217 subpass.transform_);
218 if (image_filter) {
219 Entity subpass_entity;
220 subpass_entity.SetTransform(subpass.transform_);
221 element_coverage = image_filter->GetCoverage(subpass_entity);
222 } else {
223 element_coverage = unfiltered_coverage;
224 }
225
226 element_coverage = Rect::Intersection(element_coverage, coverage_limit);
227 } else {
228 FML_UNREACHABLE();
229 }
230
231 accumulated_coverage = Rect::Union(accumulated_coverage, element_coverage);
232 }
233 return accumulated_coverage;
234 }

References GetSubpassCoverage(), impeller::TRect< Scalar >::Intersection(), impeller::Entity::kSubpass, impeller::FilterInput::Make(), impeller::Entity::SetTransform(), impeller::TRect< Scalar >::Union(), and VALIDATION_LOG.

Referenced by GetSubpassCoverage(), and impeller::testing::TEST_P().

## ◆ GetNewClipDepth()

uint32_t impeller::EntityPass::GetNewClipDepth | ( |  | ) | const

Definition at line 1174 of file entity_pass.cc.

1174 {
1175 return new_clip_depth_;
1176 }

## ◆ GetRequiredMipCount()

int32_t impeller::EntityPass::GetRequiredMipCount | ( |  | ) | const
| inline

Definition at line 186 of file entity_pass.h.

186 { return required_mip_count_; }

Referenced by Render().

## ◆ GetSubpassCoverage()

std::optional< Rect > impeller::EntityPass::GetSubpassCoverage | ( | const EntityPass & | subpass,
|  | std::optional< Rect > | coverage_limit
| ) |  | const

Computes the coverage of a given subpass. This is used to determine the texture size of a given subpass before it's rendered to and passed through the subpass ImageFilter, if any.

Parameters

  [in] | subpass | The EntityPass for which to compute pre-filteredcoverage.
  [in] | coverage_limit | Confines coverage to a specified area. This hint is used to trim coverage to the root framebuffer area. `std::nullopt` means there is no limit.

Returns
  The screen space pixel area that the subpass contents will render into, prior to being transformed by the subpass ImageFilter, if any. `std::nullopt` means rendering the subpass will have no effect on the color attachment.

Definition at line 236 of file entity_pass.cc.

238 {
239 if (subpass.bounds_limit_.has_value() && subpass.GetBoundsLimitIsSnug()) {
240 return subpass.bounds_limit_->TransformBounds(subpass.transform_);
241 }
242
243 std::shared_ptr<FilterContents> image_filter =
244 subpass.delegate_->WithImageFilter(Rect(), subpass.transform_);
245
246 // If the subpass has an image filter, then its coverage space may deviate
247 // from the parent pass and make intersecting with the pass coverage limit
248 // unsafe.
249 if (image_filter && coverage_limit.has_value()) {
250 coverage_limit = image_filter->GetSourceCoverage(subpass.transform_,
251 coverage_limit.value());
252 }
253
254 auto entities_coverage = subpass.GetElementsCoverage(coverage_limit);
255 // The entities don't cover anything. There is nothing to do.
256 if (!entities_coverage.has_value()) {
257 return std::nullopt;
258 }
259
260 if (!subpass.bounds_limit_.has_value()) {
261 return entities_coverage;
262 }
263 auto user_bounds_coverage =
264 subpass.bounds_limit_->TransformBounds(subpass.transform_);
265 return entities_coverage->Intersection(user_bounds_coverage);
266 }

References GetBoundsLimitIsSnug(), and GetElementsCoverage().

Referenced by GetElementsCoverage(), and impeller::testing::TEST_P().

## ◆ GetSubpassesDepth()

size_t impeller::EntityPass::GetSubpassesDepth | ( |  | ) | const

Definition at line 149 of file entity_pass.cc.

149 {
150 size_t max_subpass_depth = 0u;
151 for (const auto& element : elements_) {
152 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
153 max_subpass_depth =
154 std::max(max_subpass_depth, subpass->get()->GetSubpassesDepth());
155 }
156 }
157 return max_subpass_depth + 1u;
158 }

## ◆ GetSuperpass()

EntityPass * impeller::EntityPass::GetSuperpass | ( |  | ) | const

Definition at line 268 of file entity_pass.cc.

268 {
269 return superpass_;
270 }

Referenced by impeller::Canvas::Restore().

## ◆ IterateAllElements() [1/2]

void impeller::EntityPass::IterateAllElements | ( | const std::function< bool(const Element &)> & | iterator | ) | const

TODO(gaaclarke): Remove duplication here between const and non-const versions.

Definition at line 1074 of file entity_pass.cc.

1075 {
1076 /// TODO(gaaclarke): Remove duplication here between const and non-const
1077 /// versions.
1078 if (!iterator) {
1079 return;
1080 }
1081
1082 for (auto& element : elements_) {
1083 if (!iterator(element)) {
1084 return;
1085 }
1086 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1087 const EntityPass* entity_pass = subpass->get();
1088 entity_pass->IterateAllElements(iterator);
1089 }
1090 }
1091 }

References IterateAllElements().

## ◆ IterateAllElements() [2/2]

void impeller::EntityPass::IterateAllElements | ( | const std::function< bool(Element &)> & | iterator | ) |

Iterate all elements (entities and subpasses) in this pass, recursively including elements of child passes. The iteration order is depth-first. Whenever a subpass elements is encountered, it's included in the stream before its children.

Definition at line 1058 of file entity_pass.cc.

1059 {
1060 if (!iterator) {
1061 return;
1062 }
1063
1064 for (auto& element : elements_) {
1065 if (!iterator(element)) {
1066 return;
1067 }
1068 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1069 subpass->get()->IterateAllElements(iterator);
1070 }
1071 }
1072 }

Referenced by IterateAllElements().

## ◆ IterateAllEntities() [1/2]

void impeller::EntityPass::IterateAllEntities | ( | const std::function< bool(const Entity &)> & | iterator | ) | const

Iterate all entities in this pass, recursively including entities of child passes. The iteration order is depth-first and does not allow modification of the entities.

Definition at line 1114 of file entity_pass.cc.

1115 {
1116 if (!iterator) {
1117 return;
1118 }
1119
1120 for (const auto& element : elements_) {
1121 if (auto entity = std::get_if<Entity>(&element)) {
1122 if (!iterator(*entity)) {
1123 return;
1124 }
1125 continue;
1126 }
1127 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1128 const EntityPass* entity_pass = subpass->get();
1129 entity_pass->IterateAllEntities(iterator);
1130 continue;
1131 }
1132 FML_UNREACHABLE();
1133 }
1134 }

References IterateAllEntities().

## ◆ IterateAllEntities() [2/2]

void impeller::EntityPass::IterateAllEntities | ( | const std::function< bool(Entity &)> & | iterator | ) |

Iterate all entities in this pass, recursively including entities of child passes. The iteration order is depth-first.

Definition at line 1093 of file entity_pass.cc.

1094 {
1095 if (!iterator) {
1096 return;
1097 }
1098
1099 for (auto& element : elements_) {
1100 if (auto entity = std::get_if<Entity>(&element)) {
1101 if (!iterator(*entity)) {
1102 return;
1103 }
1104 continue;
1105 }
1106 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1107 subpass->get()->IterateAllEntities(iterator);
1108 continue;
1109 }
1110 FML_UNREACHABLE();
1111 }
1112 }

Referenced by IterateAllEntities(), and Render().

## ◆ IterateUntilSubpass()

bool impeller::EntityPass::IterateUntilSubpass | ( | const std::function< bool(Entity &)> & | iterator | ) |

Iterate entities in this pass up until the first subpass is found. This is useful for limiting look-ahead optimizations.

Returns
  Returns whether a subpass was encountered.

Definition at line 1136 of file entity_pass.cc.

1137 {
1138 if (!iterator) {
1139 return true;
1140 }
1141
1142 for (auto& element : elements_) {
1143 if (auto entity = std::get_if<Entity>(&element)) {
1144 if (!iterator(*entity)) {
1145 return false;
1146 }
1147 continue;
1148 }
1149 return true;
1150 }
1151 return false;
1152 }

Referenced by impeller::OpacityPeepholePassDelegate::CanCollapseIntoParentPass().

## ◆ PopAllClips()

void impeller::EntityPass::PopAllClips | ( | uint64_t | depth | ) |

Definition at line 141 of file entity_pass.cc.

141 {
142 PopClips(active_clips_.size(), depth);
143 }

References PopClips().

Referenced by impeller::EntityPlayground::OpenPlaygroundHere().

## ◆ PopClips()

void impeller::EntityPass::PopClips | ( | size_t | num_clips,
|  | uint64_t | depth
| ) |  |

Definition at line 123 of file entity_pass.cc.

123 {
124 if (num_clips > active_clips_.size()) {
125 VALIDATION_LOG
126 << "Attempted to pop more clips than are currently active. Active: "
127 << active_clips_.size() << ", Popped: " << num_clips
128 << ", Depth: " << depth;
129 }
130
131 size_t max = std::min(num_clips, active_clips_.size());
132 for (size_t i = 0; i < max; i++) {
133 FML_DCHECK(active_clips_.back() < elements_.size());
134 Entity* element = std::get_if<Entity>(&elements_[active_clips_.back()]);
135 FML_DCHECK(element);
136 element->SetNewClipDepth(depth);
137 active_clips_.pop_back();
138 }
139 }

References impeller::Entity::SetNewClipDepth(), and VALIDATION_LOG.

Referenced by PopAllClips(), and impeller::Canvas::Restore().

## ◆ PushClip()

void impeller::EntityPass::PushClip | ( | Entity | entity | ) |

Definition at line 118 of file entity_pass.cc.

118 {
119 elements_.emplace_back(std::move(entity));
120 active_clips_.emplace_back(elements_.size() - 1);
121 }

## ◆ Render()

bool impeller::EntityPass::Render | ( | ContentContext & | renderer,
|  | const RenderTarget & | render_target
| ) |  | const

Definition at line 376 of file entity_pass.cc.

377 {
378 auto capture =
379 renderer.GetContext()->capture.GetDocument(kCaptureDocumentName);
380
381 renderer.GetRenderTargetCache()->Start();
382 fml::ScopedCleanupClosure reset_state([&renderer]() {
383 renderer.GetLazyGlyphAtlas()->ResetTextFrames();
384 renderer.GetRenderTargetCache()->End();
385 });
386
387 auto root_render_target = render_target;
388
389 if (root_render_target.GetColorAttachments().find(0u) ==
390 root_render_target.GetColorAttachments().end()) {
391 VALIDATION_LOG << "The root RenderTarget must have a color attachment.";
392 return false;
393 }
394 if (root_render_target.GetDepthAttachment().has_value() !=
395 root_render_target.GetStencilAttachment().has_value()) {
396 VALIDATION_LOG << "The root RenderTarget should have a stencil attachment "
397 "iff it has a depth attachment.";
398 return false;
399 }
400
401 capture.AddRect("Coverage",
402 Rect::MakeSize(root_render_target.GetRenderTargetSize()),
403 {.readonly = true});
404
405 const auto& lazy_glyph_atlas = renderer.GetLazyGlyphAtlas();
406 IterateAllEntities([&lazy_glyph_atlas](const Entity& entity) {
407 if (const auto& contents = entity.GetContents()) {
408 contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
409 }
410 return true;
411 });
412
413 EntityPassClipStack clip_stack = EntityPassClipStack(
414 Rect::MakeSize(root_render_target.GetRenderTargetSize()));
415
416 bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
417 // In this branch path, we need to render everything to an offscreen texture
418 // and then blit the results onto the onscreen texture. If using this branch,
419 // there's no need to set up a stencil attachment on the root render target.
420 if (reads_from_onscreen_backdrop) {
421 EntityPassTarget offscreen_target = CreateRenderTarget(
422 renderer, root_render_target.GetRenderTargetSize(),
423 GetRequiredMipCount(),
424 GetClearColorOrDefault(render_target.GetRenderTargetSize()));
425
426 if (!OnRender(renderer, // renderer
427 capture, // capture
428 offscreen_target.GetRenderTarget()
429 .GetRenderTargetSize(), // root_pass_size
430 offscreen_target, // pass_target
431 Point(), // global_pass_position
432 Point(), // local_pass_position
433 0, // pass_depth
434 clip_stack // clip_coverage_stack
435 )) {
436 // Validation error messages are triggered for all `OnRender()` failure
437 // cases.
438 return false;
439 }
440
441 auto command_buffer = renderer.GetContext()->CreateCommandBuffer();
442 command_buffer->SetLabel("EntityPass Root Command Buffer");
443
444 // If the context supports blitting, blit the offscreen texture to the
445 // onscreen texture. Otherwise, draw it to the parent texture using a
446 // pipeline (slower).
447 if (renderer.GetContext()
448 ->GetCapabilities()
449 ->SupportsTextureToTextureBlits()) {
450 auto blit_pass = command_buffer->CreateBlitPass();
451 blit_pass->AddCopy(
452 offscreen_target.GetRenderTarget().GetRenderTargetTexture(),
453 root_render_target.GetRenderTargetTexture());
454 if (!blit_pass->EncodeCommands(
455 renderer.GetContext()->GetResourceAllocator())) {
456 VALIDATION_LOG << "Failed to encode root pass blit command.";
457 return false;
458 }
459 if (!renderer.GetContext()
460 ->GetCommandQueue()
461 ->Submit({command_buffer})
462 .ok()) {
463 return false;
464 }
465 } else {
466 auto render_pass = command_buffer->CreateRenderPass(root_render_target);
467 render_pass->SetLabel("EntityPass Root Render Pass");
468
469 {
470 auto size_rect = Rect::MakeSize(
471 offscreen_target.GetRenderTarget().GetRenderTargetSize());
472 auto contents = TextureContents::MakeRect(size_rect);
473 contents->SetTexture(
474 offscreen_target.GetRenderTarget().GetRenderTargetTexture());
475 contents->SetSourceRect(size_rect);
476 contents->SetLabel("Root pass blit");
477
478 Entity entity;
479 entity.SetContents(contents);
480 entity.SetBlendMode(BlendMode::kSource);
481
482 if (!entity.Render(renderer, *render_pass)) {
483 VALIDATION_LOG << "Failed to render EntityPass root blit.";
484 return false;
485 }
486 }
487
488 if (!render_pass->EncodeCommands()) {
489 VALIDATION_LOG << "Failed to encode root pass command buffer.";
490 return false;
491 }
492 if (!renderer.GetContext()
493 ->GetCommandQueue()
494 ->Submit({command_buffer})
495 .ok()) {
496 return false;
497 }
498 }
499
500 return true;
501 }
502
503 // If we make it this far, that means the context is capable of rendering
504 // everything directly to the onscreen texture.
505
506 // The safety check for fetching this color attachment is at the beginning of
507 // this method.
508 auto color0 = root_render_target.GetColorAttachments().find(0u)->second;
509
510 auto stencil_attachment = root_render_target.GetStencilAttachment();
511 auto depth_attachment = root_render_target.GetDepthAttachment();
512 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
513 // Setup a new root stencil with an optimal configuration if one wasn't
514 // provided by the caller.
515 root_render_target.SetupDepthStencilAttachments(
516 *renderer.GetContext(), *renderer.GetContext()->GetResourceAllocator(),
517 color0.texture->GetSize(),
518 renderer.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
519 "ImpellerOnscreen", kDefaultStencilConfig);
520 }
521
522 // Set up the clear color of the root pass.
523 color0.clear_color =
524 GetClearColorOrDefault(render_target.GetRenderTargetSize());
525 root_render_target.SetColorAttachment(color0, 0);
526
527 EntityPassTarget pass_target(
528 root_render_target,
529 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
530 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA());
531
532 return OnRender( //
533 renderer, // renderer
534 capture, // capture
535 root_render_target.GetRenderTargetSize(), // root_pass_size
536 pass_target, // pass_target
537 Point(), // global_pass_position
538 Point(), // local_pass_position
539 0, // pass_depth
540 clip_stack); // clip_coverage_stack
541 }

References impeller::CreateRenderTarget(), GetClearColorOrDefault(), impeller::Entity::GetContents(), impeller::ContentContext::GetContext(), impeller::ContentContext::GetDeviceCapabilities(), impeller::ContentContext::GetLazyGlyphAtlas(), impeller::EntityPassTarget::GetRenderTarget(), impeller::ContentContext::GetRenderTargetCache(), impeller::RenderTarget::GetRenderTargetSize(), impeller::RenderTarget::GetRenderTargetTexture(), GetRequiredMipCount(), IterateAllEntities(), kCaptureDocumentName, impeller::kDefaultStencilConfig, impeller::kSource, impeller::TextureContents::MakeRect(), impeller::TRect< Scalar >::MakeSize(), impeller::Entity::Render(), impeller::Entity::SetBlendMode(), impeller::Entity::SetContents(), impeller::Capabilities::SupportsImplicitResolvingMSAA(), impeller::Capabilities::SupportsReadFromResolve(), and VALIDATION_LOG.

Referenced by impeller::EntityPlayground::OpenPlaygroundHere().

## ◆ SetBackdropFilter()

void impeller::EntityPass::SetBackdropFilter | ( | BackdropFilterProc | proc | ) |

Definition at line 1208 of file entity_pass.cc.

1208 {
1209 if (superpass_) {
1210 VALIDATION_LOG << "Backdrop filters cannot be set on EntityPasses that "
1211 "have already been appended to another pass.";
1212 }
1213
1214 backdrop_filter_proc_ = std::move(proc);
1215 }

References VALIDATION_LOG.

## ◆ SetBlendMode()

void impeller::EntityPass::SetBlendMode | ( | BlendMode | blend_mode | ) |

Definition at line 1178 of file entity_pass.cc.

1178 {
1179 blend_mode_ = blend_mode;
1180 flood_clip_ = Entity::IsBlendModeDestructive(blend_mode);
1181 }

References impeller::Entity::IsBlendModeDestructive().

## ◆ SetBoundsLimit()

void impeller::EntityPass::SetBoundsLimit | ( | std::optional< Rect > | bounds_limit,
|  | ContentBoundsPromise | bounds_promise = `ContentBoundsPromise::kUnknown`
| ) |  |

Set the bounds limit, which is provided by the user when creating a SaveLayer. This is a hint that allows the user to communicate that it's OK to not render content outside of the bounds.

For consistency with Skia, we effectively treat this like a rectangle clip by forcing the subpass texture size to never exceed it.

The entity pass will assume that these bounds cause a clipping effect on the layer unless this call is followed up with a call to |SetBoundsClipsContent()| specifying otherwise.

Definition at line 64 of file entity_pass.cc.

65 {
66 bounds_limit_ = bounds_limit;
67 bounds_promise_ = bounds_limit.has_value() ? bounds_promise
68 : ContentBoundsPromise::kUnknown;
69 }

References impeller::kUnknown.

## ◆ SetClipDepth()

void impeller::EntityPass::SetClipDepth | ( | size_t | clip_depth | ) |

Definition at line 1162 of file entity_pass.cc.

1162 {
1163 clip_depth_ = clip_depth;
1164 }

## ◆ SetDelegate()

void impeller::EntityPass::SetDelegate | ( | std::shared_ptr< EntityPassDelegate > | delgate | ) |

Definition at line 57 of file entity_pass.cc.

57 {
58 if (!delegate) {
59 return;
60 }
61 delegate_ = std::move(delegate);
62 }

## ◆ SetElements()

void impeller::EntityPass::SetElements | ( | std::vector< Element > | elements | ) |

Definition at line 145 of file entity_pass.cc.

145 {
146 elements_ = std::move(elements);
147 }

## ◆ SetEnableOffscreenCheckerboard()

void impeller::EntityPass::SetEnableOffscreenCheckerboard | ( | bool | enabled | ) |

Definition at line 1217 of file entity_pass.cc.

1217 {
1218 enable_offscreen_debug_checkerboard_ = enabled;
1219 }

## ◆ SetNewClipDepth()

void impeller::EntityPass::SetNewClipDepth | ( | size_t | clip_depth | ) |

Definition at line 1170 of file entity_pass.cc.

1170 {
1171 new_clip_depth_ = clip_depth;
1172 }

Referenced by impeller::Canvas::Restore().

## ◆ SetRequiredMipCount()

void impeller::EntityPass::SetRequiredMipCount | ( | int32_t | mip_count | ) |
| inline

Definition at line 188 of file entity_pass.h.

188 {
189 required_mip_count_ = mip_count;
190 }

## ◆ SetTransform()

void impeller::EntityPass::SetTransform | ( | Matrix | transform | ) |

Definition at line 1158 of file entity_pass.cc.

1158 {
1159 transform_ = transform;
1160 }

## Member Data Documentation

## ◆ kCaptureDocumentName

const std::string impeller::EntityPass::kCaptureDocumentName = "EntityPass"
| static

Definition at line 56 of file entity_pass.h.

Referenced by Render().

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

- impeller/entity/entity_pass.h
- impeller/entity/entity_pass.cc

impeller::EntityPass::IterateAllEntities
void IterateAllEntities(const std::function< bool(Entity &)> &iterator)
Iterate all entities in this pass, recursively including entities of child passes....
Definition: entity_pass.cc:1093
impeller::Entity::kLastPipelineBlendMode
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:23
impeller::EntityPass::GetSubpassCoverage
std::optional< Rect > GetSubpassCoverage(const EntityPass &subpass, std::optional< Rect > coverage_limit) const
Computes the coverage of a given subpass. This is used to determine the texture size of a given subpa...
Definition: entity_pass.cc:236
impeller::ContentBoundsPromise::kMayClipContents
@ kMayClipContents
The caller claims the bounds are a subset of an estimate of the reasonably tight bounds but likely cl...
impeller::EntityPass::EntityPass
EntityPass()
impeller::FilterInput::Make
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
Definition: filter_input.cc:19
impeller::BlendMode::kSource
@ kSource
impeller::Entity::IsBlendModeDestructive
static bool IsBlendModeDestructive(BlendMode blend_mode)
Returns true if the blend mode is "destructive", meaning that even fully transparent source colors wo...
Definition: entity.cc:171
impeller::TRect< Scalar >::Intersection
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition: rect.h:461
impeller::ContentBoundsPromise::kUnknown
@ kUnknown
The caller makes no claims related to the size of the bounds.
impeller::kDefaultStencilConfig
static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig
Definition: entity_pass.cc:308
impeller::Point
TPoint< Scalar > Point
Definition: point.h:316
impeller::EntityPass::Element
std::variant< Entity, std::unique_ptr< EntityPass > > Element
Definition: entity_pass.h:54
impeller::EntityPass::GetRequiredMipCount
int32_t GetRequiredMipCount() const
Definition: entity_pass.h:186
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:661
impeller::Entity::RenderingMode::kSubpass
@ kSubpass
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
impeller::EntityPass::PopClips
void PopClips(size_t num_clips, uint64_t depth)
Definition: entity_pass.cc:123
impeller::Color::BlackTransparent
static constexpr Color BlackTransparent()
Definition: color.h:262
impeller::CreateRenderTarget
static EntityPassTarget CreateRenderTarget(ContentContext &renderer, ISize size, int mip_count, const Color &clear_color)
Definition: entity_pass.cc:315
impeller::TRect< Scalar >::Union
constexpr TRect Union(const TRect &o) const
Definition: rect.h:446
impeller::EntityPass::kCaptureDocumentName
static const std::string kCaptureDocumentName
Definition: entity_pass.h:56
impeller::TextureContents::MakeRect
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
A common case factory that marks the texture contents as having a destination rectangle....
Definition: texture_contents.cc:27
impeller::ContentBoundsPromise::kContainsContents
@ kContainsContents
The caller claims the bounds are a reasonably tight estimate of the coverage of the contents and shou...
impeller::BlendMode::kSourceOver
@ kSourceOver
impeller::EntityPass::GetClearColor
std::optional< Color > GetClearColor(ISize size=ISize::Infinite()) const
Return the premultiplied clear color of the pass entities, if any.
Definition: entity_pass.cc:1187
impeller::EntityPass::GetClearColorOrDefault
Color GetClearColorOrDefault(ISize size=ISize::Infinite()) const
Return the premultiplied clear color of the pass entities.
Definition: entity_pass.cc:1183