| Flutter Impeller |

Classes | Public Types | Public Member Functions | 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...
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 | SetClipHeight (size_t clip_height)
size_t | GetClipHeight () const
void | SetClipDepth (size_t clip_depth)
uint32_t | GetClipDepth () 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)
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

## 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 59 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 100 of file entity_pass.cc.

100 {
101 if (entity.GetBlendMode() == BlendMode::kSourceOver &&
102 entity.GetContents()->IsOpaque()) {
103 entity.SetBlendMode(BlendMode::kSource);
104 }
105
106 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
107 advanced_blend_reads_from_pass_texture_ = true;
108 }
109 elements_.emplace_back(std::move(entity));
110 }

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 267 of file entity_pass.cc.

267 {
268 if (!pass) {
269 return nullptr;
270 }
271 FML_DCHECK(pass->superpass_ == nullptr);
272 pass->superpass_ = this;
273
274 if (pass->backdrop_filter_proc_) {
275 backdrop_filter_reads_from_pass_texture_ = true;
276 }
277 if (pass->blend_mode_ > Entity::kLastPipelineBlendMode) {
278 advanced_blend_reads_from_pass_texture_ = true;
279 }
280
281 auto subpass_pointer = pass.get();
282 elements_.emplace_back(std::move(pass));
283 return subpass_pointer;
284 }

References impeller::Entity::kLastPipelineBlendMode.

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

## ◆ 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 65 of file entity_pass.cc.

65 {
66 return bounds_limit_;
67 }

## ◆ 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 88 of file entity_pass.cc.

88 {
89 switch (bounds_promise_) {
90 case ContentBoundsPromise::kUnknown:
91 return false;
92 case ContentBoundsPromise::kContainsContents:
93 case ContentBoundsPromise::kMayClipContents:
94 FML_DCHECK(bounds_limit_.has_value());
95 return true;
96 }
97 FML_UNREACHABLE();
98 }

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 69 of file entity_pass.cc.

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

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

## ◆ 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 1124 of file entity_pass.cc.

1124 {
1125 if (backdrop_filter_proc_) {
1126 return std::nullopt;
1127 }
1128
1129 std::optional<Color> result = std::nullopt;
1130 for (const Element& element : elements_) {
1131 auto [entity_color, blend_mode] =
1132 ElementAsBackgroundColor(element, target_size);
1133 if (!entity_color.has_value()) {
1134 break;
1135 }
1136 result = result.value_or(Color::BlackTransparent())
1137 .Blend(entity_color.value(), blend_mode);
1138 }
1139 if (result.has_value()) {
1140 return result->Premultiply();
1141 }
1142 return result;
1143 }

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 1120 of file entity_pass.cc.

1120 {
1121 return GetClearColor(size).value_or(Color::BlackTransparent());
1122 }

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

Referenced by Render().

## ◆ GetClipDepth()

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

Definition at line 1111 of file entity_pass.cc.

1111 {
1112 return clip_depth_;
1113 }

## ◆ GetClipHeight()

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

Definition at line 1103 of file entity_pass.cc.

1103 {
1104 return clip_height_;
1105 }

## ◆ GetElementCount()

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

Return the number of elements on this pass.

Definition at line 1091 of file entity_pass.cc.

1091 {
1092 return elements_.size();
1093 }

## ◆ GetElementsCoverage()

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

Definition at line 154 of file entity_pass.cc.

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

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

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

## ◆ GetRequiredMipCount()

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

Definition at line 175 of file entity_pass.h.

175 { 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 231 of file entity_pass.cc.

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

References GetBoundsLimitIsSnug(), and GetElementsCoverage().

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

## ◆ GetSubpassesDepth()

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

Definition at line 143 of file entity_pass.cc.

143 {
144 size_t max_subpass_depth = 0u;
145 for (const auto& element : elements_) {
146 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
147 max_subpass_depth =
148 std::max(max_subpass_depth, subpass->get()->GetSubpassesDepth());
149 }
150 }
151 return max_subpass_depth + 1u;
152 }

## ◆ GetSuperpass()

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

Definition at line 263 of file entity_pass.cc.

263 {
264 return superpass_;
265 }

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 1011 of file entity_pass.cc.

1012 {
1013 /// TODO(gaaclarke): Remove duplication here between const and non-const
1014 /// versions.
1015 if (!iterator) {
1016 return;
1017 }
1018
1019 for (auto& element : elements_) {
1020 if (!iterator(element)) {
1021 return;
1022 }
1023 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1024 const EntityPass* entity_pass = subpass->get();
1025 entity_pass->IterateAllElements(iterator);
1026 }
1027 }
1028 }

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 995 of file entity_pass.cc.

996 {
997 if (!iterator) {
998 return;
999 }
1000
1001 for (auto& element : elements_) {
1002 if (!iterator(element)) {
1003 return;
1004 }
1005 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1006 subpass->get()->IterateAllElements(iterator);
1007 }
1008 }
1009 }

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 1051 of file entity_pass.cc.

1052 {
1053 if (!iterator) {
1054 return;
1055 }
1056
1057 for (const auto& element : elements_) {
1058 if (auto entity = std::get_if<Entity>(&element)) {
1059 if (!iterator(*entity)) {
1060 return;
1061 }
1062 continue;
1063 }
1064 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1065 const EntityPass* entity_pass = subpass->get();
1066 entity_pass->IterateAllEntities(iterator);
1067 continue;
1068 }
1069 FML_UNREACHABLE();
1070 }
1071 }

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 1030 of file entity_pass.cc.

1031 {
1032 if (!iterator) {
1033 return;
1034 }
1035
1036 for (auto& element : elements_) {
1037 if (auto entity = std::get_if<Entity>(&element)) {
1038 if (!iterator(*entity)) {
1039 return;
1040 }
1041 continue;
1042 }
1043 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1044 subpass->get()->IterateAllEntities(iterator);
1045 continue;
1046 }
1047 FML_UNREACHABLE();
1048 }
1049 }

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 1073 of file entity_pass.cc.

1074 {
1075 if (!iterator) {
1076 return true;
1077 }
1078
1079 for (auto& element : elements_) {
1080 if (auto entity = std::get_if<Entity>(&element)) {
1081 if (!iterator(*entity)) {
1082 return false;
1083 }
1084 continue;
1085 }
1086 return true;
1087 }
1088 return false;
1089 }

## ◆ PopAllClips()

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

Definition at line 135 of file entity_pass.cc.

135 {
136 PopClips(active_clips_.size(), depth);
137 }

References PopClips().

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

## ◆ PopClips()

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

Definition at line 117 of file entity_pass.cc.

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

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

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

## ◆ PushClip()

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

Definition at line 112 of file entity_pass.cc.

112 {
113 elements_.emplace_back(std::move(entity));
114 active_clips_.emplace_back(elements_.size() - 1);
115 }

## ◆ Render()

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

Definition at line 354 of file entity_pass.cc.

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

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(), 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 1145 of file entity_pass.cc.

1145 {
1146 if (superpass_) {
1147 VALIDATION_LOG << "Backdrop filters cannot be set on EntityPasses that "
1148 "have already been appended to another pass.";
1149 }
1150
1151 backdrop_filter_proc_ = std::move(proc);
1152 }

References VALIDATION_LOG.

## ◆ SetBlendMode()

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

Definition at line 1115 of file entity_pass.cc.

1115 {
1116 blend_mode_ = blend_mode;
1117 flood_clip_ = Entity::IsBlendModeDestructive(blend_mode);
1118 }

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 58 of file entity_pass.cc.

59 {
60 bounds_limit_ = bounds_limit;
61 bounds_promise_ = bounds_limit.has_value() ? bounds_promise
62 : ContentBoundsPromise::kUnknown;
63 }

References impeller::kUnknown.

## ◆ SetClipDepth()

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

Definition at line 1107 of file entity_pass.cc.

1107 {
1108 clip_depth_ = clip_depth;
1109 }

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

## ◆ SetClipHeight()

void impeller::EntityPass::SetClipHeight | ( | size_t | clip_height | ) |

Definition at line 1099 of file entity_pass.cc.

1099 {
1100 clip_height_ = clip_height;
1101 }

## ◆ SetDelegate()

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

Definition at line 51 of file entity_pass.cc.

51 {
52 if (!delegate) {
53 return;
54 }
55 delegate_ = std::move(delegate);
56 }

## ◆ SetElements()

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

Definition at line 139 of file entity_pass.cc.

139 {
140 elements_ = std::move(elements);
141 }

## ◆ SetRequiredMipCount()

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

Definition at line 177 of file entity_pass.h.

177 {
178 required_mip_count_ = mip_count;
179 }

## ◆ SetTransform()

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

Definition at line 1095 of file entity_pass.cc.

1095 {
1096 transform_ = transform;
1097 }

References transform.

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:1030
impeller::Entity::kLastPipelineBlendMode
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:22
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:231
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:156
impeller::Entity::RenderingMode::kSubpassAppendSnapshotTransform
@ kSubpassAppendSnapshotTransform
impeller::TRect< Scalar >::Intersection
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition: rect.h:519
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: experimental_canvas.cc:48
impeller::Point
TPoint< Scalar > Point
Definition: point.h:322
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:231
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:175
impeller::CreateRenderTarget
static std::unique_ptr< EntityPassTarget > CreateRenderTarget(ContentContext &renderer, ISize size, int mip_count, const Color &clear_color)
Definition: experimental_canvas.cc:55
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:769
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:117
impeller::Color::BlackTransparent
static constexpr Color BlackTransparent()
Definition: color.h:272
impeller::TRect< Scalar >::Union
constexpr TRect Union(const TRect &o) const
Definition: rect.h:504
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:1124
impeller::EntityPass::GetClearColorOrDefault
Color GetClearColorOrDefault(ISize size=ISize::Infinite()) const
Return the premultiplied clear color of the pass entities.
Definition: entity_pass.cc:1120