| Flutter Impeller |

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

`#include <entity_pass.h>`

## Classes
struct | ClipCoverageLayer

## 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)>
using | ClipCoverageStack = std::vector< ClipCoverageLayer >

## Public Member Functions
| EntityPass ()
| ~EntityPass ()
void | SetDelegate (std::shared_ptr< EntityPassDelegate > delgate)
void | SetBoundsLimit (std::optional< Rect > bounds_limit)
| 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...
size_t | GetSubpassesDepth () const
std::unique_ptr< EntityPass > | Clone () const
void | AddEntity (Entity entity)
| Add an entity to the current entity pass. More...
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 | 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 ()
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)
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 25 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 43 of file entity_pass.h.

## ◆ ClipCoverageStack

using impeller::EntityPass::ClipCoverageStack = std::vector<ClipCoverageLayer>

Definition at line 50 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 36 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 70 of file entity_pass.cc.

70 {
71 if (entity.GetBlendMode() == BlendMode::kSourceOver &&
72 entity.GetContents()->IsOpaque()) {
73 entity.SetBlendMode(BlendMode::kSource);
74 }
75
76 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
77 advanced_blend_reads_from_pass_texture_ += 1;
78 }
79 elements_.emplace_back(std::move(entity));
80 }

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

Referenced by impeller::Canvas::DrawAtlas(), impeller::Canvas::DrawCircle(), impeller::Canvas::DrawImageRect(), impeller::Canvas::DrawLine(), impeller::Canvas::DrawOval(), impeller::Canvas::DrawPaint(), impeller::Canvas::DrawPath(), impeller::Canvas::DrawPoints(), impeller::Canvas::DrawRect(), impeller::Canvas::DrawRRect(), impeller::Canvas::DrawTextFrame(), impeller::Canvas::DrawVertices(), and impeller::testing::TEST_P().

## ◆ AddSubpass()

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

Appends a given pass as a subpass.

Definition at line 205 of file entity_pass.cc.

205 {
206 if (!pass) {
207 return nullptr;
208 }
209 FML_DCHECK(pass->superpass_ == nullptr);
210 pass->superpass_ = this;
211
212 if (pass->backdrop_filter_proc_) {
213 backdrop_filter_reads_from_pass_texture_ += 1;
214 }
215 if (pass->blend_mode_ > Entity::kLastPipelineBlendMode) {
216 advanced_blend_reads_from_pass_texture_ += 1;
217 }
218
219 auto subpass_pointer = pass.get();
220 elements_.emplace_back(std::move(pass));
221 return subpass_pointer;
222 }

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

224 {
225 if (!pass) {
226 return;
227 }
228 FML_DCHECK(pass->superpass_ == nullptr);
229
230 std::vector<Element>& elements = pass->elements_;
231 for (auto i = 0u; i < elements.size(); i++) {
232 elements_.emplace_back(std::move(elements[i]));
233 }
234
235 backdrop_filter_reads_from_pass_texture_ +=
236 pass->backdrop_filter_reads_from_pass_texture_;
237 advanced_blend_reads_from_pass_texture_ +=
238 pass->advanced_blend_reads_from_pass_texture_;
239 }

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

## ◆ Clone()

std::unique_ptr< EntityPass > impeller::EntityPass::Clone | ( |  | ) | const

Definition at line 1080 of file entity_pass.cc.

1080 {
1081 std::vector<Element> new_elements;
1082 new_elements.reserve(elements_.size());
1083
1084 for (const auto& element : elements_) {
1085 if (auto entity = std::get_if<Entity>(&element)) {
1086 new_elements.push_back(entity->Clone());
1087 continue;
1088 }
1089 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1090 new_elements.push_back(subpass->get()->Clone());
1091 continue;
1092 }
1093 FML_UNREACHABLE();
1094 }
1095
1096 auto pass = std::make_unique<EntityPass>();
1097 pass->SetElements(std::move(new_elements));
1098 pass->backdrop_filter_reads_from_pass_texture_ =
1099 backdrop_filter_reads_from_pass_texture_;
1100 pass->advanced_blend_reads_from_pass_texture_ =
1101 advanced_blend_reads_from_pass_texture_;
1102 pass->backdrop_filter_proc_ = backdrop_filter_proc_;
1103 pass->blend_mode_ = blend_mode_;
1104 pass->delegate_ = delegate_;
1105 // Note: I tried also adding flood clip and bounds limit but one of the
1106 // two caused rendering in wonderous to break. It's 10:51 PM, and I'm
1107 // ready to move on.
1108 return pass;
1109 }

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

66 {
67 return bounds_limit_;
68 }

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

1132 {
1133 if (backdrop_filter_proc_) {
1134 return std::nullopt;
1135 }
1136
1137 std::optional<Color> result = std::nullopt;
1138 for (const Element& element : elements_) {
1139 auto [entity_color, blend_mode] =
1140 ElementAsBackgroundColor(element, target_size);
1141 if (!entity_color.has_value()) {
1142 break;
1143 }
1144 result = result.value_or(Color::BlackTransparent())
1145 .Blend(entity_color.value(), blend_mode);
1146 }
1147 if (result.has_value()) {
1148 return result->Premultiply();
1149 }
1150 return result;
1151 }

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

1128 {
1129 return GetClearColor(size).value_or(Color::BlackTransparent());
1130 }

## ◆ GetClipDepth()

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

Definition at line 1119 of file entity_pass.cc.

1119 {
1120 return clip_depth_;
1121 }

## ◆ GetElementCount()

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

Return the number of elements on this pass.

Definition at line 1076 of file entity_pass.cc.

1076 {
1077 return elements_.size();
1078 }

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

## ◆ GetElementsCoverage()

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

Definition at line 97 of file entity_pass.cc.

98 {
99 std::optional<Rect> accumulated_coverage;
100 for (const auto& element : elements_) {
101 std::optional<Rect> element_coverage;
102
103 if (auto entity = std::get_if<Entity>(&element)) {
104 element_coverage = entity->GetCoverage();
105
106 // When the coverage limit is std::nullopt, that means there is no limit,
107 // as opposed to empty coverage.
108 if (element_coverage.has_value() && coverage_limit.has_value()) {
109 const auto* filter = entity->GetContents()->AsFilter();
110 if (!filter || filter->IsTranslationOnly()) {
111 element_coverage =
112 element_coverage->Intersection(coverage_limit.value());
113 }
114 }
115 } else if (auto subpass_ptr =
116 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
117 auto& subpass = *subpass_ptr->get();
118
119 std::optional<Rect> unfiltered_coverage =
120 GetSubpassCoverage(subpass, std::nullopt);
121
122 // If the current pass elements have any coverage so far and there's a
123 // backdrop filter, then incorporate the backdrop filter in the
124 // pre-filtered coverage of the subpass.
125 if (accumulated_coverage.has_value() && subpass.backdrop_filter_proc_) {
126 std::shared_ptr<FilterContents> backdrop_filter =
127 subpass.backdrop_filter_proc_(
128 FilterInput::Make(accumulated_coverage.value()),
129 subpass.transform_, Entity::RenderingMode::kSubpass);
130 if (backdrop_filter) {
131 auto backdrop_coverage = backdrop_filter->GetCoverage({});
132 unfiltered_coverage =
133 Rect::Union(unfiltered_coverage, backdrop_coverage);
134 } else {
135 VALIDATION_LOG << "The EntityPass backdrop filter proc didn't return "
136 "a valid filter.";
137 }
138 }
139
140 if (!unfiltered_coverage.has_value()) {
141 continue;
142 }
143
144 // Additionally, subpass textures may be passed through filters, which may
145 // modify the coverage.
146 //
147 // Note that we currently only assume that ImageFilters (such as blurs and
148 // matrix transforms) may modify coverage, although it's technically
149 // possible ColorFilters to affect coverage as well. For example: A
150 // ColorMatrixFilter could output a completely transparent result, and
151 // we could potentially detect this case as zero coverage in the future.
152 std::shared_ptr<FilterContents> image_filter =
153 subpass.delegate_->WithImageFilter(*unfiltered_coverage,
154 subpass.transform_);
155 if (image_filter) {
156 Entity subpass_entity;
157 subpass_entity.SetTransform(subpass.transform_);
158 element_coverage = image_filter->GetCoverage(subpass_entity);
159 } else {
160 element_coverage = unfiltered_coverage;
161 }
162
163 element_coverage = Rect::Intersection(element_coverage, coverage_limit);
164 } else {
165 FML_UNREACHABLE();
166 }
167
168 accumulated_coverage = Rect::Union(accumulated_coverage, element_coverage);
169 }
170 return accumulated_coverage;
171 }

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().

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

175 {
176 std::shared_ptr<FilterContents> image_filter =
177 subpass.delegate_->WithImageFilter(Rect(), subpass.transform_);
178
179 // If the subpass has an image filter, then its coverage space may deviate
180 // from the parent pass and make intersecting with the pass coverage limit
181 // unsafe.
182 if (image_filter && coverage_limit.has_value()) {
183 coverage_limit = image_filter->GetSourceCoverage(subpass.transform_,
184 coverage_limit.value());
185 }
186
187 auto entities_coverage = subpass.GetElementsCoverage(coverage_limit);
188 // The entities don't cover anything. There is nothing to do.
189 if (!entities_coverage.has_value()) {
190 return std::nullopt;
191 }
192
193 if (!subpass.bounds_limit_.has_value()) {
194 return entities_coverage;
195 }
196 auto user_bounds_coverage =
197 subpass.bounds_limit_->TransformBounds(subpass.transform_);
198 return entities_coverage->Intersection(user_bounds_coverage);
199 }

References GetElementsCoverage().

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

## ◆ GetSubpassesDepth()

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

Definition at line 86 of file entity_pass.cc.

86 {
87 size_t max_subpass_depth = 0u;
88 for (const auto& element : elements_) {
89 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
90 max_subpass_depth =
91 std::max(max_subpass_depth, subpass->get()->GetSubpassesDepth());
92 }
93 }
94 return max_subpass_depth + 1u;
95 }

## ◆ GetSuperpass()

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

Definition at line 201 of file entity_pass.cc.

201 {
202 return superpass_;
203 }

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

## ◆ IterateAllElements()

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

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

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

1037 {
1038 if (!iterator) {
1039 return;
1040 }
1041
1042 for (const auto& element : elements_) {
1043 if (auto entity = std::get_if<Entity>(&element)) {
1044 if (!iterator(*entity)) {
1045 return;
1046 }
1047 continue;
1048 }
1049 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1050 const EntityPass* entity_pass = subpass->get();
1051 entity_pass->IterateAllEntities(iterator);
1052 continue;
1053 }
1054 FML_UNREACHABLE();
1055 }
1056 }

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

1016 {
1017 if (!iterator) {
1018 return;
1019 }
1020
1021 for (auto& element : elements_) {
1022 if (auto entity = std::get_if<Entity>(&element)) {
1023 if (!iterator(*entity)) {
1024 return;
1025 }
1026 continue;
1027 }
1028 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1029 subpass->get()->IterateAllEntities(iterator);
1030 continue;
1031 }
1032 FML_UNREACHABLE();
1033 }
1034 }

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

1059 {
1060 if (!iterator) {
1061 return true;
1062 }
1063
1064 for (auto& element : elements_) {
1065 if (auto entity = std::get_if<Entity>(&element)) {
1066 if (!iterator(*entity)) {
1067 return false;
1068 }
1069 continue;
1070 }
1071 return true;
1072 }
1073 return false;
1074 }

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

## ◆ Render()

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

Definition at line 304 of file entity_pass.cc.

305 {
306 auto capture =
307 renderer.GetContext()->capture.GetDocument(kCaptureDocumentName);
308
309 renderer.GetRenderTargetCache()->Start();
310
311 auto root_render_target = render_target;
312
313 if (root_render_target.GetColorAttachments().find(0u) ==
314 root_render_target.GetColorAttachments().end()) {
315 VALIDATION_LOG << "The root RenderTarget must have a color attachment.";
316 return false;
317 }
318
319 capture.AddRect("Coverage",
320 Rect::MakeSize(root_render_target.GetRenderTargetSize()),
321 {.readonly = true});
322
323 fml::ScopedCleanupClosure reset_state([&renderer]() {
324 renderer.GetLazyGlyphAtlas()->ResetTextFrames();
325 renderer.GetRenderTargetCache()->End();
326 });
327
328 IterateAllEntities([lazy_glyph_atlas =
329 renderer.GetLazyGlyphAtlas()](const Entity& entity) {
330 if (const auto& contents = entity.GetContents()) {
331 contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
332 }
333 return true;
334 });
335
336 ClipCoverageStack clip_coverage_stack = {ClipCoverageLayer{
337 .coverage = Rect::MakeSize(root_render_target.GetRenderTargetSize()),
338 .clip_depth = 0}};
339
340 bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
341 // In this branch path, we need to render everything to an offscreen texture
342 // and then blit the results onto the onscreen texture. If using this branch,
343 // there's no need to set up a stencil attachment on the root render target.
344 if (reads_from_onscreen_backdrop) {
345 auto offscreen_target = CreateRenderTarget(
346 renderer, root_render_target.GetRenderTargetSize(), true,
347 GetClearColorOrDefault(render_target.GetRenderTargetSize()));
348
349 if (!OnRender(renderer, // renderer
350 capture, // capture
351 offscreen_target.GetRenderTarget()
352 .GetRenderTargetSize(), // root_pass_size
353 offscreen_target, // pass_target
354 Point(), // global_pass_position
355 Point(), // local_pass_position
356 0, // pass_depth
357 clip_coverage_stack // clip_coverage_stack
358 )) {
359 // Validation error messages are triggered for all `OnRender()` failure
360 // cases.
361 return false;
362 }
363
364 auto command_buffer = renderer.GetContext()->CreateCommandBuffer();
365 command_buffer->SetLabel("EntityPass Root Command Buffer");
366
367 // If the context supports blitting, blit the offscreen texture to the
368 // onscreen texture. Otherwise, draw it to the parent texture using a
369 // pipeline (slower).
370 if (renderer.GetContext()
371 ->GetCapabilities()
372 ->SupportsTextureToTextureBlits()) {
373 auto blit_pass = command_buffer->CreateBlitPass();
374 blit_pass->AddCopy(
375 offscreen_target.GetRenderTarget().GetRenderTargetTexture(),
376 root_render_target.GetRenderTargetTexture());
377
378 if (!command_buffer->EncodeAndSubmit(
379 blit_pass, renderer.GetContext()->GetResourceAllocator())) {
380 VALIDATION_LOG << "Failed to encode root pass blit command.";
381 return false;
382 }
383 } else {
384 auto render_pass = command_buffer->CreateRenderPass(root_render_target);
385 render_pass->SetLabel("EntityPass Root Render Pass");
386
387 {
388 auto size_rect = Rect::MakeSize(
389 offscreen_target.GetRenderTarget().GetRenderTargetSize());
390 auto contents = TextureContents::MakeRect(size_rect);
391 contents->SetTexture(
392 offscreen_target.GetRenderTarget().GetRenderTargetTexture());
393 contents->SetSourceRect(size_rect);
394 contents->SetLabel("Root pass blit");
395
396 Entity entity;
397 entity.SetContents(contents);
398 entity.SetBlendMode(BlendMode::kSource);
399
400 if (!entity.Render(renderer, *render_pass)) {
401 VALIDATION_LOG << "Failed to render EntityPass root blit.";
402 return false;
403 }
404 }
405
406 if (!command_buffer->EncodeAndSubmit(render_pass)) {
407 VALIDATION_LOG << "Failed to encode root pass command buffer.";
408 return false;
409 }
410 }
411
412 return true;
413 }
414
415 // If we make it this far, that means the context is capable of rendering
416 // everything directly to the onscreen texture.
417
418 // The safety check for fetching this color attachment is at the beginning of
419 // this method.
420 auto color0 = root_render_target.GetColorAttachments().find(0u)->second;
421
422 // If a root stencil was provided by the caller, then verify that it has a
423 // configuration which can be used to render this pass.
424 auto stencil_attachment = root_render_target.GetStencilAttachment();
425 if (stencil_attachment.has_value()) {
426 auto stencil_texture = stencil_attachment->texture;
427 if (!stencil_texture) {
428 VALIDATION_LOG << "The root RenderTarget must have a stencil texture.";
429 return false;
430 }
431
432 auto stencil_storage_mode =
433 stencil_texture->GetTextureDescriptor().storage_mode;
434 if (reads_from_onscreen_backdrop &&
435 stencil_storage_mode == StorageMode::kDeviceTransient) {
436 VALIDATION_LOG << "The given root RenderTarget stencil needs to be read, "
437 "but it's marked as transient.";
438 return false;
439 }
440 }
441 // Setup a new root stencil with an optimal configuration if one wasn't
442 // provided by the caller.
443 else {
444 root_render_target.SetupStencilAttachment(
445 *renderer.GetContext(), *renderer.GetRenderTargetCache(),
446 color0.texture->GetSize(),
447 renderer.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
448 "ImpellerOnscreen",
449 GetDefaultStencilConfig(reads_from_onscreen_backdrop));
450 }
451
452 // Set up the clear color of the root pass.
453 color0.clear_color =
454 GetClearColorOrDefault(render_target.GetRenderTargetSize());
455 root_render_target.SetColorAttachment(color0, 0);
456
457 EntityPassTarget pass_target(
458 root_render_target,
459 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
460 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA());
461
462 return OnRender( //
463 renderer, // renderer
464 capture, // capture
465 root_render_target.GetRenderTargetSize(), // root_pass_size
466 pass_target, // pass_target
467 Point(), // global_pass_position
468 Point(), // local_pass_position
469 0, // pass_depth
470 clip_coverage_stack); // clip_coverage_stack
471 }

References impeller::ContentContext::GetContext(), impeller::ContentContext::GetLazyGlyphAtlas(), impeller::ContentContext::GetRenderTargetCache(), IterateAllEntities(), kCaptureDocumentName, impeller::TRect< Scalar >::MakeSize(), and VALIDATION_LOG.

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

## ◆ SetBackdropFilter()

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

Definition at line 1153 of file entity_pass.cc.

1153 {
1154 if (superpass_) {
1155 VALIDATION_LOG << "Backdrop filters cannot be set on EntityPasses that "
1156 "have already been appended to another pass.";
1157 }
1158
1159 backdrop_filter_proc_ = std::move(proc);
1160 }

References VALIDATION_LOG.

## ◆ SetBlendMode()

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

Definition at line 1123 of file entity_pass.cc.

1123 {
1124 blend_mode_ = blend_mode;
1125 flood_clip_ = Entity::IsBlendModeDestructive(blend_mode);
1126 }

## ◆ SetBoundsLimit()

void impeller::EntityPass::SetBoundsLimit | ( | std::optional< Rect > | bounds_limit | ) |

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.

Definition at line 62 of file entity_pass.cc.

62 {
63 bounds_limit_ = bounds_limit;
64 }

## ◆ SetClipDepth()

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

Definition at line 1115 of file entity_pass.cc.

1115 {
1116 clip_depth_ = clip_depth;
1117 }

## ◆ SetDelegate()

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

Definition at line 55 of file entity_pass.cc.

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

## ◆ SetElements()

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

Definition at line 82 of file entity_pass.cc.

82 {
83 elements_ = std::move(elements);
84 }

## ◆ SetEnableOffscreenCheckerboard()

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

Definition at line 1162 of file entity_pass.cc.

1162 {
1163 enable_offscreen_debug_checkerboard_ = enabled;
1164 }

## ◆ SetTransform()

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

Definition at line 1111 of file entity_pass.cc.

1111 {
1112 transform_ = transform;
1113 }

## Member Data Documentation

## ◆ kCaptureDocumentName

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

Definition at line 38 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:1015
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:173
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:142
impeller::EntityPass::ClipCoverageStack
std::vector< ClipCoverageLayer > ClipCoverageStack
Definition: entity_pass.h:50
impeller::CreateRenderTarget
static EntityPassTarget CreateRenderTarget(ContentContext &renderer, ISize size, bool readable, const Color &clear_color)
Definition: entity_pass.cc:250
impeller::StorageMode::kDeviceTransient
@ kDeviceTransient
impeller::Point
TPoint< Scalar > Point
Definition: point.h:308
impeller::TRect< Scalar >::Intersection
constexpr std::optional< TRect< Scalar > > Intersection(const TRect &o) const
Definition: rect.h:312
impeller::EntityPass::Element
std::variant< Entity, std::unique_ptr< EntityPass > > Element
Definition: entity_pass.h:36
impeller::GetDefaultStencilConfig
static RenderTarget::AttachmentConfig GetDefaultStencilConfig(bool readable)
Definition: entity_pass.cc:241
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:488
impeller::Entity::RenderingMode::kSubpass
@ kSubpass
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:67
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:44
impeller::Color::BlackTransparent
static constexpr Color BlackTransparent()
Definition: color.h:262
impeller::TRect< Scalar >::Union
constexpr TRect Union(const TRect &o) const
Definition: rect.h:302
impeller::EntityPass::kCaptureDocumentName
static const std::string kCaptureDocumentName
Definition: entity_pass.h:38
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::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:1132
impeller::EntityPass::GetClearColorOrDefault
Color GetClearColorOrDefault(ISize size=ISize::Infinite()) const
Return the premultiplied clear color of the pass entities.
Definition: entity_pass.cc:1128