Flutter Impeller
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< RectGetBoundsLimit () 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)
 
EntityPassAddSubpass (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...
 
EntityPassGetSuperpass () 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< ColorGetClearColor (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< RectGetSubpassCoverage (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< RectGetElementsCoverage (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_) {
97  return false;
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_) {
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();
85  FML_DCHECK(bounds_limit_.has_value());
86  return false;
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]subpassThe EntityPass for which to compute pre-filteredcoverage.
[in]coverage_limitConfines 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()) {
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(),
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
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::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