Flutter Impeller
entity_pass.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <limits>
8 #include <memory>
9 #include <utility>
10 #include <variant>
11 
12 #include "flutter/fml/closure.h"
13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/trace_event.h"
15 #include "impeller/base/strings.h"
17 #include "impeller/core/formats.h"
23 #include "impeller/entity/entity.h"
27 #include "impeller/geometry/rect.h"
28 #include "impeller/geometry/size.h"
30 
31 namespace impeller {
32 
33 namespace {
34 std::tuple<std::optional<Color>, BlendMode> ElementAsBackgroundColor(
35  const EntityPass::Element& element,
36  ISize target_size) {
37  if (const Entity* entity = std::get_if<Entity>(&element)) {
38  std::optional<Color> entity_color = entity->AsBackgroundColor(target_size);
39  if (entity_color.has_value()) {
40  return {entity_color.value(), entity->GetBlendMode()};
41  }
42  }
43  return {};
44 }
45 } // namespace
46 
47 EntityPass::EntityPass() = default;
48 
49 EntityPass::~EntityPass() = default;
50 
51 void EntityPass::SetDelegate(std::shared_ptr<EntityPassDelegate> delegate) {
52  if (!delegate) {
53  return;
54  }
55  delegate_ = std::move(delegate);
56 }
57 
58 void EntityPass::SetBoundsLimit(std::optional<Rect> bounds_limit,
59  ContentBoundsPromise bounds_promise) {
60  bounds_limit_ = bounds_limit;
61  bounds_promise_ = bounds_limit.has_value() ? bounds_promise
63 }
64 
65 std::optional<Rect> EntityPass::GetBoundsLimit() const {
66  return bounds_limit_;
67 }
68 
70  switch (bounds_promise_) {
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();
79  FML_DCHECK(bounds_limit_.has_value());
80  return false;
82  FML_DCHECK(bounds_limit_.has_value());
83  return true;
84  }
85  FML_UNREACHABLE();
86 }
87 
89  switch (bounds_promise_) {
91  return false;
94  FML_DCHECK(bounds_limit_.has_value());
95  return true;
96  }
97  FML_UNREACHABLE();
98 }
99 
101  if (entity.GetBlendMode() == BlendMode::kSourceOver &&
102  entity.GetContents()->IsOpaque()) {
104  }
105 
107  advanced_blend_reads_from_pass_texture_ = true;
108  }
109  elements_.emplace_back(std::move(entity));
110 }
111 
113  elements_.emplace_back(std::move(entity));
114  active_clips_.emplace_back(elements_.size() - 1);
115 }
116 
117 void EntityPass::PopClips(size_t num_clips, uint64_t depth) {
118  if (num_clips > active_clips_.size()) {
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 }
134 
135 void EntityPass::PopAllClips(uint64_t depth) {
136  PopClips(active_clips_.size(), depth);
137 }
138 
139 void EntityPass::SetElements(std::vector<Element> elements) {
140  elements_ = std::move(elements);
141 }
142 
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 }
153 
155  std::optional<Rect> coverage_limit) const {
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_,
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 }
230 
231 std::optional<Rect> EntityPass::GetSubpassCoverage(
232  const EntityPass& subpass,
233  std::optional<Rect> coverage_limit) const {
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 }
262 
264  return superpass_;
265 }
266 
267 EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
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 }
285 
289  .load_action = LoadAction::kDontCare,
290  .store_action = StoreAction::kDontCare,
291  };
292 
294  ISize size,
295  int mip_count,
296  const Color& clear_color) {
297  const std::shared_ptr<Context>& context = renderer.GetContext();
298 
299  /// All of the load/store actions are managed by `InlinePassContext` when
300  /// `RenderPasses` are created, so we just set them to `kDontCare` here.
301  /// What's important is the `StorageMode` of the textures, which cannot be
302  /// changed for the lifetime of the textures.
303 
304  if (context->GetBackendType() == Context::BackendType::kOpenGLES) {
305  // TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map
306  // generation on opengles.
307  mip_count = 1;
308  }
309 
310  RenderTarget target;
311  if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
312  target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
313  /*context=*/*context,
314  /*size=*/size,
315  /*mip_count=*/mip_count,
316  /*label=*/"EntityPass",
317  /*color_attachment_config=*/
320  .resolve_storage_mode = StorageMode::kDevicePrivate,
321  .load_action = LoadAction::kDontCare,
322  .store_action = StoreAction::kMultisampleResolve,
323  .clear_color = clear_color},
324  /*stencil_attachment_config=*/
326  } else {
327  target = renderer.GetRenderTargetCache()->CreateOffscreen(
328  *context, // context
329  size, // size
330  /*mip_count=*/mip_count,
331  "EntityPass", // label
334  .load_action = LoadAction::kDontCare,
335  .store_action = StoreAction::kDontCare,
336  .clear_color = clear_color,
337  }, // color_attachment_config
338  kDefaultStencilConfig // stencil_attachment_config
339  );
340  }
341 
342  return EntityPassTarget(
343  target, renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
345 }
346 
347 bool EntityPass::DoesBackdropGetRead(ContentContext& renderer) const {
348  return renderer.GetDeviceCapabilities().SupportsFramebufferFetch()
349  ? backdrop_filter_reads_from_pass_texture_
350  : backdrop_filter_reads_from_pass_texture_ ||
351  advanced_blend_reads_from_pass_texture_;
352 }
353 
355  const RenderTarget& render_target) const {
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 
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(),
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);
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 =
494  root_render_target.SetColorAttachment(color0, 0);
495 
496  EntityPassTarget pass_target(
497  root_render_target,
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 }
510 
511 EntityPass::EntityResult EntityPass::GetEntityForElement(
512  const EntityPass::Element& element,
513  ContentContext& renderer,
514  InlinePassContext& pass_context,
515  ISize root_pass_size,
516  Point global_pass_position,
517  uint32_t pass_depth,
518  EntityPassClipStack& clip_coverage_stack,
519  size_t clip_height_floor) const {
520  //--------------------------------------------------------------------------
521  /// Setup entity element.
522  ///
523  if (const auto& entity = std::get_if<Entity>(&element)) {
524  Entity element_entity = entity->Clone();
525 
526  if (!global_pass_position.IsZero()) {
527  // If the pass image is going to be rendered with a non-zero position,
528  // apply the negative translation to entity copies before rendering them
529  // so that they'll end up rendering to the correct on-screen position.
530  element_entity.SetTransform(
531  Matrix::MakeTranslation(Vector3(-global_pass_position)) *
532  element_entity.GetTransform());
533  }
534  return EntityPass::EntityResult::Success(std::move(element_entity));
535  }
536 
537  //--------------------------------------------------------------------------
538  /// Setup subpass element.
539  ///
540  if (const auto& subpass_ptr =
541  std::get_if<std::unique_ptr<EntityPass>>(&element)) {
542  auto subpass = subpass_ptr->get();
543  if (subpass->delegate_->CanElide()) {
544  return EntityPass::EntityResult::Skip();
545  }
546 
547  if (!subpass->backdrop_filter_proc_ &&
548  subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
549  // Directly render into the parent target and move on.
550  if (!subpass->OnRender(
551  renderer, // renderer
552  root_pass_size, // root_pass_size
553  pass_context.GetPassTarget(), // pass_target
554  global_pass_position, // global_pass_position
555  Point(), // local_pass_position
556  pass_depth, // pass_depth
557  clip_coverage_stack, // clip_coverage_stack
558  clip_height_, // clip_height_floor
559  nullptr, // backdrop_filter_contents
560  pass_context.GetRenderPass(pass_depth) // collapsed_parent_pass
561  )) {
562  // Validation error messages are triggered for all `OnRender()` failure
563  // cases.
564  return EntityPass::EntityResult::Failure();
565  }
566  return EntityPass::EntityResult::Skip();
567  }
568 
569  std::shared_ptr<Contents> subpass_backdrop_filter_contents = nullptr;
570  if (subpass->backdrop_filter_proc_) {
571  auto texture = pass_context.GetTexture();
572  // Render the backdrop texture before any of the pass elements.
573  const auto& proc = subpass->backdrop_filter_proc_;
574 
575  subpass_backdrop_filter_contents = proc(
576  FilterInput::Make(std::move(texture)), subpass->transform_.Basis(),
577  // When the subpass has a translation that means the math with
578  // the snapshot has to be different.
579  subpass->transform_.HasTranslation()
582 
583  // If the very first thing we render in this EntityPass is a subpass that
584  // happens to have a backdrop filter, than that backdrop filter will end
585  // may wind up sampling from the raw, uncleared texture that came straight
586  // out of the texture cache. By calling `pass_context.GetRenderPass` here,
587  // we force the texture to pass through at least one RenderPass with the
588  // correct clear configuration before any sampling occurs.
589  pass_context.GetRenderPass(pass_depth);
590 
591  // The subpass will need to read from the current pass texture when
592  // rendering the backdrop, so if there's an active pass, end it prior to
593  // rendering the subpass.
594  pass_context.EndPass();
595  }
596 
597  if (!clip_coverage_stack.HasCoverage()) {
598  // The current clip is empty. This means the pass texture won't be
599  // visible, so skip it.
600  return EntityPass::EntityResult::Skip();
601  }
602  auto clip_coverage_back = clip_coverage_stack.CurrentClipCoverage();
603  if (!clip_coverage_back.has_value()) {
604  return EntityPass::EntityResult::Skip();
605  }
606 
607  // The maximum coverage of the subpass. Subpasses textures should never
608  // extend outside the parent pass texture or the current clip coverage.
609  auto coverage_limit = Rect::MakeOriginSize(global_pass_position,
610  Size(pass_context.GetPassTarget()
611  .GetRenderTarget()
613  .Intersection(clip_coverage_back.value());
614  if (!coverage_limit.has_value()) {
615  return EntityPass::EntityResult::Skip();
616  }
617 
618  coverage_limit =
619  coverage_limit->Intersection(Rect::MakeSize(root_pass_size));
620  if (!coverage_limit.has_value()) {
621  return EntityPass::EntityResult::Skip();
622  }
623 
624  auto subpass_coverage =
625  (subpass->flood_clip_ || subpass_backdrop_filter_contents)
626  ? coverage_limit
627  : GetSubpassCoverage(*subpass, coverage_limit);
628  if (!subpass_coverage.has_value()) {
629  return EntityPass::EntityResult::Skip();
630  }
631 
632  auto subpass_size = ISize(subpass_coverage->GetSize());
633  if (subpass_size.IsEmpty()) {
634  return EntityPass::EntityResult::Skip();
635  }
636 
637  auto subpass_target = CreateRenderTarget(
638  renderer, // renderer
639  subpass_size, // size
640  subpass->GetRequiredMipCount(),
641  subpass->GetClearColorOrDefault(subpass_size)); // clear_color
642 
643  if (!subpass_target.IsValid()) {
644  VALIDATION_LOG << "Subpass render target is invalid.";
645  return EntityPass::EntityResult::Failure();
646  }
647 
648  // Start non-collapsed subpasses with a fresh clip coverage stack limited by
649  // the subpass coverage. This is important because image filters applied to
650  // save layers may transform the subpass texture after it's rendered,
651  // causing parent clip coverage to get misaligned with the actual area that
652  // the subpass will affect in the parent pass.
653  clip_coverage_stack.PushSubpass(subpass_coverage, subpass->clip_height_);
654 
655  // Stencil textures aren't shared between EntityPasses (as much of the
656  // time they are transient).
657  if (!subpass->OnRender(
658  renderer, // renderer
659  root_pass_size, // root_pass_size
660  subpass_target, // pass_target
661  subpass_coverage->GetOrigin(), // global_pass_position
662  subpass_coverage->GetOrigin() -
663  global_pass_position, // local_pass_position
664  ++pass_depth, // pass_depth
665  clip_coverage_stack, // clip_coverage_stack
666  subpass->clip_height_, // clip_height_floor
667  subpass_backdrop_filter_contents // backdrop_filter_contents
668  )) {
669  // Validation error messages are triggered for all `OnRender()` failure
670  // cases.
671  return EntityPass::EntityResult::Failure();
672  }
673 
674  clip_coverage_stack.PopSubpass();
675 
676  // The subpass target's texture may have changed during OnRender.
677  auto subpass_texture =
678  subpass_target.GetRenderTarget().GetRenderTargetTexture();
679 
680  auto offscreen_texture_contents =
681  subpass->delegate_->CreateContentsForSubpassTarget(
682  subpass_texture,
683  Matrix::MakeTranslation(Vector3{-global_pass_position}) *
684  subpass->transform_);
685 
686  if (!offscreen_texture_contents) {
687  // This is an error because the subpass delegate said the pass couldn't
688  // be collapsed into its parent. Yet, when asked how it want's to
689  // postprocess the offscreen texture, it couldn't give us an answer.
690  //
691  // Theoretically, we could collapse the pass now. But that would be
692  // wasteful as we already have the offscreen texture and we don't want
693  // to discard it without ever using it. Just make the delegate do the
694  // right thing.
695  return EntityPass::EntityResult::Failure();
696  }
697 
698  // Round the subpass texture position for pixel alignment with the parent
699  // pass render target. By default, we draw subpass textures with nearest
700  // sampling, so aligning here is important for avoiding visual nearest
701  // sampling errors caused by limited floating point precision when
702  // straddling a half pixel boundary.
703  //
704  // We do this in lieu of expanding/rounding out the subpass coverage in
705  // order to keep the bounds wrapping consistently tight around subpass
706  // elements. Which is necessary to avoid intense flickering in cases
707  // where a subpass texture has a large blur filter with clamp sampling.
708  //
709  // See also this bug: https://github.com/flutter/flutter/issues/144213
710  Point subpass_texture_position =
711  (subpass_coverage->GetOrigin() - global_pass_position).Round();
712 
713  Entity element_entity;
714  element_entity.SetClipDepth(subpass->clip_depth_);
715  element_entity.SetContents(std::move(offscreen_texture_contents));
716  element_entity.SetBlendMode(subpass->blend_mode_);
717  element_entity.SetTransform(
718  Matrix::MakeTranslation(Vector3(subpass_texture_position)));
719 
720  return EntityPass::EntityResult::Success(std::move(element_entity));
721  }
722  FML_UNREACHABLE();
723 }
724 
725 static void SetClipScissor(std::optional<Rect> clip_coverage,
726  RenderPass& pass,
727  Point global_pass_position) {
728  // Set the scissor to the clip coverage area. We do this prior to rendering
729  // the clip itself and all its contents.
730  IRect scissor;
731  if (clip_coverage.has_value()) {
732  clip_coverage = clip_coverage->Shift(-global_pass_position);
733  scissor = IRect::RoundOut(clip_coverage.value());
734  // The scissor rect must not exceed the size of the render target.
735  scissor = scissor.Intersection(IRect::MakeSize(pass.GetRenderTargetSize()))
736  .value_or(IRect());
737  }
738  pass.SetScissor(scissor);
739 }
740 
741 bool EntityPass::RenderElement(Entity& element_entity,
742  size_t clip_height_floor,
743  InlinePassContext& pass_context,
744  int32_t pass_depth,
745  ContentContext& renderer,
746  EntityPassClipStack& clip_coverage_stack,
747  Point global_pass_position) const {
748  auto result = pass_context.GetRenderPass(pass_depth);
749  if (!result.pass) {
750  // Failure to produce a render pass should be explained by specific errors
751  // in `InlinePassContext::GetRenderPass()`, so avoid log spam and don't
752  // append a validation log here.
753  return false;
754  }
755 
756  // If the pass context returns a backdrop texture, we need to draw it to the
757  // current pass. We do this because it's faster and takes significantly less
758  // memory than storing/loading large MSAA textures. Also, it's not possible to
759  // blit the non-MSAA resolve texture of the previous pass to MSAA textures
760  // (let alone a transient one).
761  if (result.backdrop_texture) {
762  auto size_rect = Rect::MakeSize(result.pass->GetRenderTargetSize());
763  auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
764  msaa_backdrop_contents->SetStencilEnabled(false);
765  msaa_backdrop_contents->SetLabel("MSAA backdrop");
766  msaa_backdrop_contents->SetSourceRect(size_rect);
767  msaa_backdrop_contents->SetTexture(result.backdrop_texture);
768 
769  Entity msaa_backdrop_entity;
770  msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
771  msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
772  msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
773  if (!msaa_backdrop_entity.Render(renderer, *result.pass)) {
774  VALIDATION_LOG << "Failed to render MSAA backdrop filter entity.";
775  return false;
776  }
777  }
778 
779  if (result.just_created) {
780  // Restore any clips that were recorded before the backdrop filter was
781  // applied.
782  auto& replay_entities = clip_coverage_stack.GetReplayEntities();
783  for (const auto& replay : replay_entities) {
784  SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
785  global_pass_position);
786  if (!replay.entity.Render(renderer, *result.pass)) {
787  VALIDATION_LOG << "Failed to render entity for clip restore.";
788  }
789  }
790  }
791 
792  auto current_clip_coverage = clip_coverage_stack.CurrentClipCoverage();
793  if (current_clip_coverage.has_value()) {
794  // Entity transforms are relative to the current pass position, so we need
795  // to check clip coverage in the same space.
796  current_clip_coverage = current_clip_coverage->Shift(-global_pass_position);
797  }
798 
799  if (!element_entity.ShouldRender(current_clip_coverage)) {
800  return true; // Nothing to render.
801  }
802 
803  auto clip_coverage = element_entity.GetClipCoverage(current_clip_coverage);
804  if (clip_coverage.coverage.has_value()) {
805  clip_coverage.coverage =
806  clip_coverage.coverage->Shift(global_pass_position);
807  }
808 
809  // The coverage hint tells the rendered Contents which portion of the
810  // rendered output will actually be used, and so we set this to the current
811  // clip coverage (which is the max clip bounds). The contents may
812  // optionally use this hint to avoid unnecessary rendering work.
813  auto element_coverage_hint = element_entity.GetContents()->GetCoverageHint();
814  element_entity.GetContents()->SetCoverageHint(
815  Rect::Intersection(element_coverage_hint, current_clip_coverage));
816 
817  EntityPassClipStack::ClipStateResult clip_state_result =
818  clip_coverage_stack.ApplyClipState(clip_coverage, element_entity,
819  clip_height_floor,
820  global_pass_position);
821 
822  if (clip_state_result.clip_did_change) {
823  // We only need to update the pass scissor if the clip state has changed.
824  SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
825  global_pass_position);
826  }
827 
828  if (!clip_state_result.should_render) {
829  return true;
830  }
831 
832  if (!element_entity.Render(renderer, *result.pass)) {
833  VALIDATION_LOG << "Failed to render entity.";
834  return false;
835  }
836  return true;
837 }
838 
839 bool EntityPass::OnRender(
840  ContentContext& renderer,
841  ISize root_pass_size,
842  EntityPassTarget& pass_target,
843  Point global_pass_position,
844  Point local_pass_position,
845  uint32_t pass_depth,
846  EntityPassClipStack& clip_coverage_stack,
847  size_t clip_height_floor,
848  std::shared_ptr<Contents> backdrop_filter_contents,
849  const std::optional<InlinePassContext::RenderPassResult>&
850  collapsed_parent_pass) const {
851  TRACE_EVENT0("impeller", "EntityPass::OnRender");
852 
853  if (!active_clips_.empty()) {
855  "EntityPass (Depth=%d) contains one or more clips with an unresolved "
856  "depth value.",
857  pass_depth);
858  }
859 
860  InlinePassContext pass_context(renderer, pass_target, GetElementCount(),
861  collapsed_parent_pass);
862  if (!pass_context.IsValid()) {
863  VALIDATION_LOG << SPrintF("Pass context invalid (Depth=%d)", pass_depth);
864  return false;
865  }
866  auto clear_color_size = pass_target.GetRenderTarget().GetRenderTargetSize();
867 
868  if (!collapsed_parent_pass) {
869  // Always force the pass to construct the render pass object, even if there
870  // is not a clear color. This ensures that the attachment textures are
871  // cleared/transitioned to the right state.
872  pass_context.GetRenderPass(pass_depth);
873  }
874 
875  if (backdrop_filter_proc_) {
876  if (!backdrop_filter_contents) {
878  << "EntityPass contains a backdrop filter, but no backdrop filter "
879  "contents was supplied by the parent pass at render time. This is "
880  "a bug in EntityPass. Parent passes are responsible for setting "
881  "up backdrop filters for their children.";
882  return false;
883  }
884 
885  Entity backdrop_entity;
886  backdrop_entity.SetContents(std::move(backdrop_filter_contents));
887  backdrop_entity.SetTransform(
888  Matrix::MakeTranslation(Vector3(-local_pass_position)));
889  backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
890 
891  RenderElement(backdrop_entity, clip_height_floor, pass_context, pass_depth,
892  renderer, clip_coverage_stack, global_pass_position);
893  }
894 
895  bool is_collapsing_clear_colors = !collapsed_parent_pass &&
896  // Backdrop filters act as a entity before
897  // everything and disrupt the optimization.
898  !backdrop_filter_proc_;
899  for (const auto& element : elements_) {
900  // Skip elements that are incorporated into the clear color.
901  if (is_collapsing_clear_colors) {
902  auto [entity_color, _] =
903  ElementAsBackgroundColor(element, clear_color_size);
904  if (entity_color.has_value()) {
905  continue;
906  }
907  is_collapsing_clear_colors = false;
908  }
909 
910  EntityResult result =
911  GetEntityForElement(element, // element
912  renderer, // renderer
913  pass_context, // pass_context
914  root_pass_size, // root_pass_size
915  global_pass_position, // global_pass_position
916  pass_depth, // pass_depth
917  clip_coverage_stack, // clip_coverage_stack
918  clip_height_floor); // clip_height_floor
919 
920  switch (result.status) {
921  case EntityResult::kSuccess:
922  break;
923  case EntityResult::kFailure:
924  // All failure cases should be covered by specific validation messages
925  // in `GetEntityForElement()`.
926  return false;
927  case EntityResult::kSkip:
928  continue;
929  };
930 
931  //--------------------------------------------------------------------------
932  /// Setup advanced blends.
933  ///
934 
935  if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
936  if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
937  auto src_contents = result.entity.GetContents();
938  auto contents = std::make_shared<FramebufferBlendContents>();
939  contents->SetChildContents(src_contents);
940  contents->SetBlendMode(result.entity.GetBlendMode());
941  result.entity.SetContents(std::move(contents));
942  result.entity.SetBlendMode(BlendMode::kSource);
943  } else {
944  // End the active pass and flush the buffer before rendering "advanced"
945  // blends. Advanced blends work by binding the current render target
946  // texture as an input ("destination"), blending with a second texture
947  // input ("source"), writing the result to an intermediate texture, and
948  // finally copying the data from the intermediate texture back to the
949  // render target texture. And so all of the commands that have written
950  // to the render target texture so far need to execute before it's bound
951  // for blending (otherwise the blend pass will end up executing before
952  // all the previous commands in the active pass).
953 
954  if (!pass_context.EndPass()) {
956  << "Failed to end the current render pass in order to read from "
957  "the backdrop texture and apply an advanced blend.";
958  return false;
959  }
960 
961  // Amend an advanced blend filter to the contents, attaching the pass
962  // texture.
963  auto texture = pass_context.GetTexture();
964  if (!texture) {
965  VALIDATION_LOG << "Failed to fetch the color texture in order to "
966  "apply an advanced blend.";
967  return false;
968  }
969 
970  FilterInput::Vector inputs = {
971  FilterInput::Make(texture, result.entity.GetTransform().Invert()),
972  FilterInput::Make(result.entity.GetContents())};
973  auto contents = ColorFilterContents::MakeBlend(
974  result.entity.GetBlendMode(), inputs);
975  contents->SetCoverageHint(result.entity.GetCoverage());
976  result.entity.SetContents(std::move(contents));
977  result.entity.SetBlendMode(BlendMode::kSource);
978  }
979  }
980 
981  //--------------------------------------------------------------------------
982  /// Render the Element.
983  ///
984  if (!RenderElement(result.entity, clip_height_floor, pass_context,
985  pass_depth, renderer, clip_coverage_stack,
986  global_pass_position)) {
987  // Specific validation logs are handled in `render_element()`.
988  return false;
989  }
990  }
991 
992  return true;
993 }
994 
996  const std::function<bool(Element&)>& iterator) {
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 }
1010 
1012  const std::function<bool(const Element&)>& iterator) const {
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 }
1029 
1031  const std::function<bool(Entity&)>& iterator) {
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 }
1050 
1052  const std::function<bool(const Entity&)>& iterator) const {
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 }
1072 
1074  const std::function<bool(Entity&)>& iterator) {
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 }
1090 
1092  return elements_.size();
1093 }
1094 
1096  transform_ = transform;
1097 }
1098 
1099 void EntityPass::SetClipHeight(size_t clip_height) {
1100  clip_height_ = clip_height;
1101 }
1102 
1104  return clip_height_;
1105 }
1106 
1107 void EntityPass::SetClipDepth(size_t clip_depth) {
1108  clip_depth_ = clip_depth;
1109 }
1110 
1111 uint32_t EntityPass::GetClipDepth() const {
1112  return clip_depth_;
1113 }
1114 
1116  blend_mode_ = blend_mode;
1117  flood_clip_ = Entity::IsBlendModeDestructive(blend_mode);
1118 }
1119 
1121  return GetClearColor(size).value_or(Color::BlackTransparent());
1122 }
1123 
1124 std::optional<Color> EntityPass::GetClearColor(ISize target_size) const {
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 }
1144 
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 }
1153 
1154 } // namespace impeller
impeller::ISize
ISize64 ISize
Definition: size.h:140
impeller::StoreAction::kMultisampleResolve
@ kMultisampleResolve
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::SetClipDepth
void SetClipDepth(uint32_t clip_depth)
Definition: entity.cc:98
impeller::EntityPass::SetBackdropFilter
void SetBackdropFilter(BackdropFilterProc proc)
Definition: entity_pass.cc:1145
impeller::Entity::kLastPipelineBlendMode
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:22
impeller::Capabilities::SupportsReadFromResolve
virtual bool SupportsReadFromResolve() const =0
Whether the context backend supports binding the current RenderPass attachments. This is supported if...
impeller::EntityPass::BackdropFilterProc
std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, const Matrix &effect_transform, Entity::RenderingMode rendering_mode)> BackdropFilterProc
Definition: entity_pass.h:59
impeller::EntityPass::PopAllClips
void PopAllClips(uint64_t depth)
Definition: entity_pass.cc:135
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::Entity::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: entity.cc:115
impeller::ContentBoundsPromise::kMayClipContents
@ kMayClipContents
The caller claims the bounds are a subset of an estimate of the reasonably tight bounds but likely cl...
impeller::EntityPassClipStack::PushSubpass
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
Definition: entity_pass_clip_stack.cc:31
impeller::ContentContext::GetLazyGlyphAtlas
const std::shared_ptr< LazyGlyphAtlas > & GetLazyGlyphAtlas() const
Definition: content_context.h:720
texture_contents.h
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:46
impeller::EntityPass::GetClipDepth
uint32_t GetClipDepth() const
Definition: entity_pass.cc:1111
impeller::EntityPass::GetClipHeight
size_t GetClipHeight() const
Definition: entity_pass.cc:1103
entity.h
impeller::EntityPass::GetSubpassesDepth
size_t GetSubpassesDepth() const
Definition: entity_pass.cc:143
impeller::BlendMode
BlendMode
Definition: color.h:59
impeller::Color
Definition: color.h:124
impeller::EntityPass::GetBoundsLimitMightClipContent
bool GetBoundsLimitMightClipContent() const
Indicates if the bounds limit set using |SetBoundsLimit()| might clip the contents of the pass.
Definition: entity_pass.cc:69
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::EntityPass::AddSubpass
EntityPass * AddSubpass(std::unique_ptr< EntityPass > pass)
Appends a given pass as a subpass.
Definition: entity_pass.cc:267
impeller::EntityPass::IterateUntilSubpass
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-a...
Definition: entity_pass.cc:1073
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
formats.h
impeller::EntityPassClipStack::HasCoverage
bool HasCoverage() const
Definition: entity_pass_clip_stack.cc:27
impeller::TRect< Scalar >::Intersection
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition: rect.h:519
impeller::EntityPass::GetBoundsLimitIsSnug
bool GetBoundsLimitIsSnug() const
Indicates if the bounds limit set using |SetBoundsLimit()| is a reasonably tight estimate of the boun...
Definition: entity_pass.cc:88
impeller::EntityPass::IterateAllElements
void IterateAllElements(const std::function< bool(Element &)> &iterator)
Iterate all elements (entities and subpasses) in this pass, recursively including elements of child p...
Definition: entity_pass.cc:995
impeller::StoreAction::kDontCare
@ kDontCare
impeller::ContentBoundsPromise
ContentBoundsPromise
Definition: entity_pass.h:28
impeller::ContentBoundsPromise::kUnknown
@ kUnknown
The caller makes no claims related to the size of the bounds.
impeller::EntityPassTarget
Definition: entity_pass_target.h:14
impeller::Size
TSize< Scalar > Size
Definition: size.h:137
impeller::EntityPass::GetElementsCoverage
std::optional< Rect > GetElementsCoverage(std::optional< Rect > coverage_limit) const
Definition: entity_pass.cc:154
impeller::EntityPass::~EntityPass
~EntityPass()
framebuffer_blend_contents.h
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
validation.h
subpass_size
ISize subpass_size
The output size of the down-sampling pass.
Definition: gaussian_blur_filter_contents.cc:219
impeller::RenderTarget::AttachmentConfigMSAA
Definition: render_target.h:47
impeller::EntityPass::SetClipDepth
void SetClipDepth(size_t clip_depth)
Definition: entity_pass.cc:1107
impeller::EntityPass::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: entity_pass.cc:1115
impeller::TRect::Shift
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
Definition: rect.h:589
impeller::RenderTarget::AttachmentConfig
Definition: render_target.h:40
impeller::TPoint::IsZero
constexpr bool IsZero() const
Definition: point.h:240
impeller::Entity::SetContents
void SetContents(std::shared_ptr< Contents > contents)
Definition: entity.cc:90
impeller::TRect::RoundOut
RoundOut(const TRect< U > &r)
Definition: rect.h:666
impeller::kDefaultStencilConfig
static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig
Definition: experimental_canvas.cc:48
impeller::Entity
Definition: entity.h:20
impeller::RenderPass::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_pass.cc:43
impeller::TSize
Definition: size.h:19
impeller::StorageMode::kDeviceTransient
@ kDeviceTransient
impeller::Point
TPoint< Scalar > Point
Definition: point.h:322
impeller::EntityPass::SetElements
void SetElements(std::vector< Element > elements)
Definition: entity_pass.cc:139
impeller::EntityPass::GetBoundsLimit
std::optional< Rect > GetBoundsLimit() const
Get the bounds limit, which is provided by the user when creating a SaveLayer.
Definition: entity_pass.cc:65
impeller::RenderTarget::GetRenderTargetTexture
std::shared_ptr< Texture > GetRenderTargetTexture() const
Definition: render_target.cc:144
impeller::Entity::Render
bool Render(const ContentContext &renderer, RenderPass &parent_pass) const
Definition: entity.cc:173
impeller::EntityPass::GetSuperpass
EntityPass * GetSuperpass() const
Definition: entity_pass.cc:263
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:23
impeller::Context::BackendType::kOpenGLES
@ kOpenGLES
impeller::SPrintF
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:231
impeller::Capabilities::SupportsImplicitResolvingMSAA
virtual bool SupportsImplicitResolvingMSAA() const =0
Whether the context backend supports multisampled rendering to the on-screen surface without requirin...
impeller::EntityPass
Definition: entity_pass.h:43
impeller::ContentContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: content_context.cc:553
impeller::StorageMode::kDevicePrivate
@ kDevicePrivate
impeller::EntityPass::Element
std::variant< Entity, std::unique_ptr< EntityPass > > Element
Definition: entity_pass.h:54
impeller::InlinePassContext::GetRenderPass
RenderPassResult GetRenderPass(uint32_t pass_depth)
Definition: inline_pass_context.cc:93
impeller::EntityPass::GetRequiredMipCount
int32_t GetRequiredMipCount() const
Definition: entity_pass.h:175
impeller::TRect< Scalar >::MakeOriginSize
constexpr static TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
Definition: rect.h:140
impeller::EntityPass::GetElementCount
size_t GetElementCount() const
Return the number of elements on this pass.
Definition: entity_pass.cc:1091
impeller::InlinePassContext
Definition: inline_pass_context.h:17
impeller::Entity::GetContents
const std::shared_ptr< Contents > & GetContents() const
Definition: entity.cc:94
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::RenderTarget::AttachmentConfig::storage_mode
StorageMode storage_mode
Definition: render_target.h:41
impeller::InlinePassContext::GetTexture
std::shared_ptr< Texture > GetTexture()
Definition: inline_pass_context.cc:48
impeller::RenderTarget
Definition: render_target.h:38
entity_pass.h
impeller::InlinePassContext::EndPass
bool EndPass()
Definition: inline_pass_context.cc:55
impeller::EntityPass::SetTransform
void SetTransform(Matrix transform)
Definition: entity_pass.cc:1095
filter_input.h
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:769
strings.h
impeller::SetClipScissor
static void SetClipScissor(std::optional< Rect > clip_coverage, RenderPass &pass, Point global_pass_position)
Definition: entity_pass.cc:725
color_filter_contents.h
impeller::EntityPass::SetBoundsLimit
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 al...
Definition: entity_pass.cc:58
impeller::EntityPassClipStack::PopSubpass
void PopSubpass()
Definition: entity_pass_clip_stack.cc:42
impeller::Entity::GetBlendMode
BlendMode GetBlendMode() const
Definition: entity.cc:119
impeller::InlinePassContext::GetPassTarget
EntityPassTarget & GetPassTarget() const
Definition: inline_pass_context.cc:89
entity_pass_clip_stack.h
impeller::RenderPass::SetScissor
virtual void SetScissor(IRect scissor)
Definition: render_pass.cc:115
impeller::RenderTarget::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_target.cc:139
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:33
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
command_buffer.h
content_context.h
impeller::ContentContext::GetRenderTargetCache
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
Definition: content_context.h:724
impeller::Entity::SetTransform
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
Definition: entity.cc:62
impeller::ContentContext::GetDeviceCapabilities
const Capabilities & GetDeviceCapabilities() const
Definition: content_context.cc:557
impeller::Entity::RenderingMode::kSubpassPrependSnapshotTransform
@ kSubpassPrependSnapshotTransform
impeller::RenderTarget::AttachmentConfigMSAA::storage_mode
StorageMode storage_mode
Definition: render_target.h:48
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::LoadAction::kDontCare
@ kDontCare
rect.h
impeller::Entity::Clone
Entity Clone() const
Definition: entity.cc:191
impeller::TPoint< Scalar >
impeller::Color::BlackTransparent
static constexpr Color BlackTransparent()
Definition: color.h:272
impeller::EntityPass::PushClip
void PushClip(Entity entity)
Definition: entity_pass.cc:112
impeller::EntityPass::Render
bool Render(ContentContext &renderer, const RenderTarget &render_target) const
Definition: entity_pass.cc:354
impeller::TRect< Scalar >::Union
constexpr TRect Union(const TRect &o) const
Definition: rect.h:504
color.h
impeller::EntityPassClipStack
A class that tracks all clips that have been recorded in the current entity pass stencil.
Definition: entity_pass_clip_stack.h:24
impeller::IRect
IRect64 IRect
Definition: rect.h:772
impeller::EntityPass::SetDelegate
void SetDelegate(std::shared_ptr< EntityPassDelegate > delgate)
Definition: entity_pass.cc:51
impeller::EntityPass::SetClipHeight
void SetClipHeight(size_t clip_height)
Definition: entity_pass.cc:1099
impeller::FilterInput::Vector
std::vector< FilterInput::Ref > Vector
Definition: filter_input.h:33
impeller::ColorFilterContents::MakeBlend
static std::shared_ptr< ColorFilterContents > MakeBlend(BlendMode blend_mode, FilterInput::Vector inputs, std::optional< Color > foreground_color=std::nullopt)
the [inputs] are expected to be in the order of dst, src.
Definition: color_filter_contents.cc:17
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
Definition: aiks_blend_unittests.cc:18
impeller::EntityPassTarget::GetRenderTarget
const RenderTarget & GetRenderTarget() const
Definition: entity_pass_target.cc:68
impeller::ContentContext
Definition: content_context.h:366
impeller::TRect
Definition: rect.h:122
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Vector3
Definition: vector.h:20
size.h
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
impeller::EntityPass::AddEntity
void AddEntity(Entity entity)
Add an entity to the current entity pass.
Definition: entity_pass.cc:100
inline_pass_context.h