| 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
5 #include "impeller/entity/entity_pass.h"
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"
16 #include "impeller/base/validation.h"
17 #include "impeller/core/formats.h"
18 #include "impeller/entity/contents/content_context.h"
19 #include "impeller/entity/contents/filters/color_filter_contents.h"
20 #include "impeller/entity/contents/filters/inputs/filter_input.h"
21 #include "impeller/entity/contents/framebuffer_blend_contents.h"
22 #include "impeller/entity/contents/texture_contents.h"
23 #include "impeller/entity/entity.h"
24 #include "impeller/entity/entity_pass_clip_stack.h"
25 #include "impeller/entity/inline_pass_context.h"
26 #include "impeller/geometry/color.h"
27 #include "impeller/geometry/rect.h"
28 #include "impeller/geometry/size.h"
29 #include "impeller/renderer/command_buffer.h"
30
31 #ifdef IMPELLER_DEBUG
32 #include "impeller/entity/contents/checkerboard_contents.h"
33 #endif // IMPELLER_DEBUG
34
35 namespace impeller {
36
37 namespace {
38 std::tuple<std::optional<Color>, BlendMode> ElementAsBackgroundColor(
39 const EntityPass::Element& element,
40 ISize target_size) {
41 if (const Entity* entity = std::get_if<Entity>(&element)) {
42 std::optional<Color> entity_color = entity->AsBackgroundColor(target_size);
43 if (entity_color.has_value()) {
44 return {entity_color.value(), entity->GetBlendMode()};
45 }
46 }
47 return {};
48 }
49 } // namespace
50
51 const std::string EntityPass::kCaptureDocumentName = "EntityPass";
52
53 EntityPass::EntityPass() = default;
54
55 EntityPass::~EntityPass() = default;
56
57 void EntityPass::SetDelegate(std::shared_ptr<EntityPassDelegate> delegate) {
58 if (!delegate) {
59 return;
60 }
61 delegate_ = std::move(delegate);
62 }
63
64 void EntityPass::SetBoundsLimit(std::optional<Rect> bounds_limit,
65 ContentBoundsPromise bounds_promise) {
66 bounds_limit_ = bounds_limit;
67 bounds_promise_ = bounds_limit.has_value() ? bounds_promise
68 : ContentBoundsPromise::kUnknown;
69 }
70
71 std::optional<Rect> EntityPass::GetBoundsLimit() const {
72 return bounds_limit_;
73 }
74
75 bool EntityPass::GetBoundsLimitMightClipContent() const {
76 switch (bounds_promise_) {
77 case ContentBoundsPromise::kUnknown:
78 // If the promise is unknown due to not having a bounds limit,
79 // then no clipping will occur. But if we have a bounds limit
80 // and it is unkown, then we can make no promises about whether
81 // it causes clipping of the entity pass contents and we
82 // conservatively return true.
83 return bounds_limit_.has_value();
84 case ContentBoundsPromise::kContainsContents:
85 FML_DCHECK(bounds_limit_.has_value());
86 return false;
87 case ContentBoundsPromise::kMayClipContents:
88 FML_DCHECK(bounds_limit_.has_value());
89 return true;
90 }
91 FML_UNREACHABLE();
92 }
93
94 bool EntityPass::GetBoundsLimitIsSnug() const {
95 switch (bounds_promise_) {
96 case ContentBoundsPromise::kUnknown:
97 return false;
98 case ContentBoundsPromise::kContainsContents:
99 case ContentBoundsPromise::kMayClipContents:
100 FML_DCHECK(bounds_limit_.has_value());
101 return true;
102 }
103 FML_UNREACHABLE();
104 }
105
106 void EntityPass::AddEntity(Entity entity) {
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 }
117
118 void EntityPass::PushClip(Entity entity) {
119 elements_.emplace_back(std::move(entity));
120 active_clips_.emplace_back(elements_.size() - 1);
121 }
122
123 void EntityPass::PopClips(size_t num_clips, uint64_t depth) {
124 if (num_clips > active_clips_.size()) {
125 VALIDATION_LOG
126 << "Attempted to pop more clips than are currently active. Active: "
127 << active_clips_.size() << ", Popped: " << num_clips
128 << ", Depth: " << depth;
129 }
130
131 size_t max = std::min(num_clips, active_clips_.size());
132 for (size_t i = 0; i < max; i++) {
133 FML_DCHECK(active_clips_.back() < elements_.size());
134 Entity* element = std::get_if<Entity>(&elements_[active_clips_.back()]);
135 FML_DCHECK(element);
136 element->SetNewClipDepth(depth);
137 active_clips_.pop_back();
138 }
139 }
140
141 void EntityPass::PopAllClips(uint64_t depth) {
142 PopClips(active_clips_.size(), depth);
143 }
144
145 void EntityPass::SetElements(std::vector<Element> elements) {
146 elements_ = std::move(elements);
147 }
148
149 size_t EntityPass::GetSubpassesDepth() const {
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 }
159
160 std::optional<Rect> EntityPass::GetElementsCoverage(
161 std::optional<Rect> coverage_limit) const {
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 }
235
236 std::optional<Rect> EntityPass::GetSubpassCoverage(
237 const EntityPass& subpass,
238 std::optional<Rect> coverage_limit) const {
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 }
267
268 EntityPass* EntityPass::GetSuperpass() const {
269 return superpass_;
270 }
271
272 EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
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 }
290
291 void EntityPass::AddSubpassInline(std::unique_ptr<EntityPass> pass) {
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 }
307
308 static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig =
309 RenderTarget::AttachmentConfig{
310 .storage_mode = StorageMode::kDeviceTransient,
311 .load_action = LoadAction::kDontCare,
312 .store_action = StoreAction::kDontCare,
313 };
314
315 static EntityPassTarget CreateRenderTarget(ContentContext& renderer,
316 ISize size,
317 int mip_count,
318 const Color& clear_color) {
319 const std::shared_ptr<Context>& context = renderer.GetContext();
320
321 /// All of the load/store actions are managed by `InlinePassContext` when
322 /// `RenderPasses` are created, so we just set them to `kDontCare` here.
323 /// What's important is the `StorageMode` of the textures, which cannot be
324 /// changed for the lifetime of the textures.
325
326 if (context->GetBackendType() == Context::BackendType::kOpenGLES) {
327 // TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map
328 // generation on opengles.
329 mip_count = 1;
330 }
331
332 RenderTarget target;
333 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
334 target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
335 /*context=*/*context,
336 /*size=*/size,
337 /*mip_count=*/mip_count,
338 /*label=*/"EntityPass",
339 /*color_attachment_config=*/
340 RenderTarget::AttachmentConfigMSAA{
341 .storage_mode = StorageMode::kDeviceTransient,
342 .resolve_storage_mode = StorageMode::kDevicePrivate,
343 .load_action = LoadAction::kDontCare,
344 .store_action = StoreAction::kMultisampleResolve,
345 .clear_color = clear_color},
346 /*stencil_attachment_config=*/
347 kDefaultStencilConfig);
348 } else {
349 target = renderer.GetRenderTargetCache()->CreateOffscreen(
350 *context, // context
351 size, // size
352 /*mip_count=*/mip_count,
353 "EntityPass", // label
354 RenderTarget::AttachmentConfig{
355 .storage_mode = StorageMode::kDevicePrivate,
356 .load_action = LoadAction::kDontCare,
357 .store_action = StoreAction::kDontCare,
358 .clear_color = clear_color,
359 }, // color_attachment_config
360 kDefaultStencilConfig // stencil_attachment_config
361 );
362 }
363
364 return EntityPassTarget(
365 target, renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
366 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA());
367 }
368
369 uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer) const {
370 return renderer.GetDeviceCapabilities().SupportsFramebufferFetch()
371 ? backdrop_filter_reads_from_pass_texture_
372 : backdrop_filter_reads_from_pass_texture_ +
373 advanced_blend_reads_from_pass_texture_;
374 }
375
376 bool EntityPass::Render(ContentContext& renderer,
377 const RenderTarget& render_target) const {
378 auto capture =
379 renderer.GetContext()->capture.GetDocument(kCaptureDocumentName);
380
381 renderer.GetRenderTargetCache()->Start();
382 fml::ScopedCleanupClosure reset_state([&renderer]() {
383 renderer.GetLazyGlyphAtlas()->ResetTextFrames();
384 renderer.GetRenderTargetCache()->End();
385 });
386
387 auto root_render_target = render_target;
388
389 if (root_render_target.GetColorAttachments().find(0u) ==
390 root_render_target.GetColorAttachments().end()) {
391 VALIDATION_LOG << "The root RenderTarget must have a color attachment.";
392 return false;
393 }
394 if (root_render_target.GetDepthAttachment().has_value() !=
395 root_render_target.GetStencilAttachment().has_value()) {
396 VALIDATION_LOG << "The root RenderTarget should have a stencil attachment "
397 "iff it has a depth attachment.";
398 return false;
399 }
400
401 capture.AddRect("Coverage",
402 Rect::MakeSize(root_render_target.GetRenderTargetSize()),
403 {.readonly = true});
404
405 const auto& lazy_glyph_atlas = renderer.GetLazyGlyphAtlas();
406 IterateAllEntities([&lazy_glyph_atlas](const Entity& entity) {
407 if (const auto& contents = entity.GetContents()) {
408 contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
409 }
410 return true;
411 });
412
413 EntityPassClipStack clip_stack = EntityPassClipStack(
414 Rect::MakeSize(root_render_target.GetRenderTargetSize()));
415
416 bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
417 // In this branch path, we need to render everything to an offscreen texture
418 // and then blit the results onto the onscreen texture. If using this branch,
419 // there's no need to set up a stencil attachment on the root render target.
420 if (reads_from_onscreen_backdrop) {
421 EntityPassTarget offscreen_target = CreateRenderTarget(
422 renderer, root_render_target.GetRenderTargetSize(),
423 GetRequiredMipCount(),
424 GetClearColorOrDefault(render_target.GetRenderTargetSize()));
425
426 if (!OnRender(renderer, // renderer
427 capture, // capture
428 offscreen_target.GetRenderTarget()
429 .GetRenderTargetSize(), // root_pass_size
430 offscreen_target, // pass_target
431 Point(), // global_pass_position
432 Point(), // local_pass_position
433 0, // pass_depth
434 clip_stack // clip_coverage_stack
435 )) {
436 // Validation error messages are triggered for all `OnRender()` failure
437 // cases.
438 return false;
439 }
440
441 auto command_buffer = renderer.GetContext()->CreateCommandBuffer();
442 command_buffer->SetLabel("EntityPass Root Command Buffer");
443
444 // If the context supports blitting, blit the offscreen texture to the
445 // onscreen texture. Otherwise, draw it to the parent texture using a
446 // pipeline (slower).
447 if (renderer.GetContext()
448 ->GetCapabilities()
449 ->SupportsTextureToTextureBlits()) {
450 auto blit_pass = command_buffer->CreateBlitPass();
451 blit_pass->AddCopy(
452 offscreen_target.GetRenderTarget().GetRenderTargetTexture(),
453 root_render_target.GetRenderTargetTexture());
454 if (!blit_pass->EncodeCommands(
455 renderer.GetContext()->GetResourceAllocator())) {
456 VALIDATION_LOG << "Failed to encode root pass blit command.";
457 return false;
458 }
459 if (!renderer.GetContext()
460 ->GetCommandQueue()
461 ->Submit({command_buffer})
462 .ok()) {
463 return false;
464 }
465 } else {
466 auto render_pass = command_buffer->CreateRenderPass(root_render_target);
467 render_pass->SetLabel("EntityPass Root Render Pass");
468
469 {
470 auto size_rect = Rect::MakeSize(
471 offscreen_target.GetRenderTarget().GetRenderTargetSize());
472 auto contents = TextureContents::MakeRect(size_rect);
473 contents->SetTexture(
474 offscreen_target.GetRenderTarget().GetRenderTargetTexture());
475 contents->SetSourceRect(size_rect);
476 contents->SetLabel("Root pass blit");
477
478 Entity entity;
479 entity.SetContents(contents);
480 entity.SetBlendMode(BlendMode::kSource);
481
482 if (!entity.Render(renderer, *render_pass)) {
483 VALIDATION_LOG << "Failed to render EntityPass root blit.";
484 return false;
485 }
486 }
487
488 if (!render_pass->EncodeCommands()) {
489 VALIDATION_LOG << "Failed to encode root pass command buffer.";
490 return false;
491 }
492 if (!renderer.GetContext()
493 ->GetCommandQueue()
494 ->Submit({command_buffer})
495 .ok()) {
496 return false;
497 }
498 }
499
500 return true;
501 }
502
503 // If we make it this far, that means the context is capable of rendering
504 // everything directly to the onscreen texture.
505
506 // The safety check for fetching this color attachment is at the beginning of
507 // this method.
508 auto color0 = root_render_target.GetColorAttachments().find(0u)->second;
509
510 auto stencil_attachment = root_render_target.GetStencilAttachment();
511 auto depth_attachment = root_render_target.GetDepthAttachment();
512 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
513 // Setup a new root stencil with an optimal configuration if one wasn't
514 // provided by the caller.
515 root_render_target.SetupDepthStencilAttachments(
516 *renderer.GetContext(), *renderer.GetContext()->GetResourceAllocator(),
517 color0.texture->GetSize(),
518 renderer.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
519 "ImpellerOnscreen", kDefaultStencilConfig);
520 }
521
522 // Set up the clear color of the root pass.
523 color0.clear_color =
524 GetClearColorOrDefault(render_target.GetRenderTargetSize());
525 root_render_target.SetColorAttachment(color0, 0);
526
527 EntityPassTarget pass_target(
528 root_render_target,
529 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
530 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA());
531
532 return OnRender( //
533 renderer, // renderer
534 capture, // capture
535 root_render_target.GetRenderTargetSize(), // root_pass_size
536 pass_target, // pass_target
537 Point(), // global_pass_position
538 Point(), // local_pass_position
539 0, // pass_depth
540 clip_stack); // clip_coverage_stack
541 }
542
543 EntityPass::EntityResult EntityPass::GetEntityForElement(
544 const EntityPass::Element& element,
545 ContentContext& renderer,
546 Capture& capture,
547 InlinePassContext& pass_context,
548 ISize root_pass_size,
549 Point global_pass_position,
550 uint32_t pass_depth,
551 EntityPassClipStack& clip_coverage_stack,
552 size_t clip_depth_floor) const {
553 //--------------------------------------------------------------------------
554 /// Setup entity element.
555 ///
556 if (const auto& entity = std::get_if<Entity>(&element)) {
557 Entity element_entity = entity->Clone();
558 element_entity.SetCapture(capture.CreateChild("Entity"));
559
560 if (!global_pass_position.IsZero()) {
561 // If the pass image is going to be rendered with a non-zero position,
562 // apply the negative translation to entity copies before rendering them
563 // so that they'll end up rendering to the correct on-screen position.
564 element_entity.SetTransform(
565 Matrix::MakeTranslation(Vector3(-global_pass_position)) *
566 element_entity.GetTransform());
567 }
568 return EntityPass::EntityResult::Success(std::move(element_entity));
569 }
570
571 //--------------------------------------------------------------------------
572 /// Setup subpass element.
573 ///
574 if (const auto& subpass_ptr =
575 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
576 auto subpass = subpass_ptr->get();
577 if (subpass->delegate_->CanElide()) {
578 return EntityPass::EntityResult::Skip();
579 }
580
581 if (!subpass->backdrop_filter_proc_ &&
582 subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
583 auto subpass_capture = capture.CreateChild("EntityPass (Collapsed)");
584 // Directly render into the parent target and move on.
585 if (!subpass->OnRender(
586 renderer, // renderer
587 subpass_capture, // capture
588 root_pass_size, // root_pass_size
589 pass_context.GetPassTarget(), // pass_target
590 global_pass_position, // global_pass_position
591 Point(), // local_pass_position
592 pass_depth, // pass_depth
593 clip_coverage_stack, // clip_coverage_stack
594 clip_depth_, // clip_depth_floor
595 nullptr, // backdrop_filter_contents
596 pass_context.GetRenderPass(pass_depth) // collapsed_parent_pass
597 )) {
598 // Validation error messages are triggered for all `OnRender()` failure
599 // cases.
600 return EntityPass::EntityResult::Failure();
601 }
602 return EntityPass::EntityResult::Skip();
603 }
604
605 std::shared_ptr<Contents> subpass_backdrop_filter_contents = nullptr;
606 if (subpass->backdrop_filter_proc_) {
607 auto texture = pass_context.GetTexture();
608 // Render the backdrop texture before any of the pass elements.
609 const auto& proc = subpass->backdrop_filter_proc_;
610 subpass_backdrop_filter_contents =
611 proc(FilterInput::Make(std::move(texture)),
612 subpass->transform_.Basis(), Entity::RenderingMode::kSubpass);
613
614 // If the very first thing we render in this EntityPass is a subpass that
615 // happens to have a backdrop filter, than that backdrop filter will end
616 // may wind up sampling from the raw, uncleared texture that came straight
617 // out of the texture cache. By calling `pass_context.GetRenderPass` here,
618 // we force the texture to pass through at least one RenderPass with the
619 // correct clear configuration before any sampling occurs.
620 pass_context.GetRenderPass(pass_depth);
621
622 // The subpass will need to read from the current pass texture when
623 // rendering the backdrop, so if there's an active pass, end it prior to
624 // rendering the subpass.
625 pass_context.EndPass();
626 }
627
628 if (!clip_coverage_stack.HasCoverage()) {
629 // The current clip is empty. This means the pass texture won't be
630 // visible, so skip it.
631 capture.CreateChild("Subpass Entity (Skipped: Empty clip A)");
632 return EntityPass::EntityResult::Skip();
633 }
634 auto clip_coverage_back = clip_coverage_stack.CurrentClipCoverage();
635 if (!clip_coverage_back.has_value()) {
636 capture.CreateChild("Subpass Entity (Skipped: Empty clip B)");
637 return EntityPass::EntityResult::Skip();
638 }
639
640 // The maximum coverage of the subpass. Subpasses textures should never
641 // extend outside the parent pass texture or the current clip coverage.
642 auto coverage_limit = Rect::MakeOriginSize(global_pass_position,
643 Size(pass_context.GetPassTarget()
644 .GetRenderTarget()
645 .GetRenderTargetSize()))
646 .Intersection(clip_coverage_back.value());
647 if (!coverage_limit.has_value()) {
648 capture.CreateChild("Subpass Entity (Skipped: Empty coverage limit A)");
649 return EntityPass::EntityResult::Skip();
650 }
651
652 coverage_limit =
653 coverage_limit->Intersection(Rect::MakeSize(root_pass_size));
654 if (!coverage_limit.has_value()) {
655 capture.CreateChild("Subpass Entity (Skipped: Empty coverage limit B)");
656 return EntityPass::EntityResult::Skip();
657 }
658
659 auto subpass_coverage =
660 (subpass->flood_clip_ || subpass_backdrop_filter_contents)
661 ? coverage_limit
662 : GetSubpassCoverage(*subpass, coverage_limit);
663 if (!subpass_coverage.has_value()) {
664 capture.CreateChild("Subpass Entity (Skipped: Empty subpass coverage A)");
665 return EntityPass::EntityResult::Skip();
666 }
667
668 auto subpass_size = ISize(subpass_coverage->GetSize());
669 if (subpass_size.IsEmpty()) {
670 capture.CreateChild("Subpass Entity (Skipped: Empty subpass coverage B)");
671 return EntityPass::EntityResult::Skip();
672 }
673
674 auto subpass_target = CreateRenderTarget(
675 renderer, // renderer
676 subpass_size, // size
677 subpass->GetRequiredMipCount(),
678 subpass->GetClearColorOrDefault(subpass_size)); // clear_color
679
680 if (!subpass_target.IsValid()) {
681 VALIDATION_LOG << "Subpass render target is invalid.";
682 return EntityPass::EntityResult::Failure();
683 }
684
685 auto subpass_capture = capture.CreateChild("EntityPass");
686 subpass_capture.AddRect("Coverage", *subpass_coverage, {.readonly = true});
687
688 // Start non-collapsed subpasses with a fresh clip coverage stack limited by
689 // the subpass coverage. This is important because image filters applied to
690 // save layers may transform the subpass texture after it's rendered,
691 // causing parent clip coverage to get misaligned with the actual area that
692 // the subpass will affect in the parent pass.
693 clip_coverage_stack.PushSubpass(subpass_coverage, subpass->clip_depth_);
694
695 // Stencil textures aren't shared between EntityPasses (as much of the
696 // time they are transient).
697 if (!subpass->OnRender(
698 renderer, // renderer
699 subpass_capture, // capture
700 root_pass_size, // root_pass_size
701 subpass_target, // pass_target
702 subpass_coverage->GetOrigin(), // global_pass_position
703 subpass_coverage->GetOrigin() -
704 global_pass_position, // local_pass_position
705 ++pass_depth, // pass_depth
706 clip_coverage_stack, // clip_coverage_stack
707 subpass->clip_depth_, // clip_depth_floor
708 subpass_backdrop_filter_contents // backdrop_filter_contents
709 )) {
710 // Validation error messages are triggered for all `OnRender()` failure
711 // cases.
712 return EntityPass::EntityResult::Failure();
713 }
714
715 clip_coverage_stack.PopSubpass();
716
717 // The subpass target's texture may have changed during OnRender.
718 auto subpass_texture =
719 subpass_target.GetRenderTarget().GetRenderTargetTexture();
720
721 auto offscreen_texture_contents =
722 subpass->delegate_->CreateContentsForSubpassTarget(
723 subpass_texture,
724 Matrix::MakeTranslation(Vector3{-global_pass_position}) *
725 subpass->transform_);
726
727 if (!offscreen_texture_contents) {
728 // This is an error because the subpass delegate said the pass couldn't
729 // be collapsed into its parent. Yet, when asked how it want's to
730 // postprocess the offscreen texture, it couldn't give us an answer.
731 //
732 // Theoretically, we could collapse the pass now. But that would be
733 // wasteful as we already have the offscreen texture and we don't want
734 // to discard it without ever using it. Just make the delegate do the
735 // right thing.
736 return EntityPass::EntityResult::Failure();
737 }
738 Entity element_entity;
739 Capture subpass_texture_capture =
740 capture.CreateChild("Entity (Subpass texture)");
741 element_entity.SetNewClipDepth(subpass->new_clip_depth_);
742 element_entity.SetCapture(subpass_texture_capture);
743 element_entity.SetContents(std::move(offscreen_texture_contents));
744 element_entity.SetClipDepth(subpass->clip_depth_);
745 element_entity.SetBlendMode(subpass->blend_mode_);
746 element_entity.SetTransform(subpass_texture_capture.AddMatrix(
747 "Transform",
748 Matrix::MakeTranslation(
749 Vector3(subpass_coverage->GetOrigin() - global_pass_position))));
750
751 return EntityPass::EntityResult::Success(std::move(element_entity));
752 }
753 FML_UNREACHABLE();
754 }
755
756 static void SetClipScissor(std::optional<Rect> clip_coverage,
757 RenderPass& pass,
758 Point global_pass_position) {
759 if constexpr (!ContentContext::kEnableStencilThenCover) {
760 return;
761 }
762 // Set the scissor to the clip coverage area. We do this prior to rendering
763 // the clip itself and all its contents.
764 IRect scissor;
765 if (clip_coverage.has_value()) {
766 clip_coverage = clip_coverage->Shift(-global_pass_position);
767 scissor = IRect::RoundOut(clip_coverage.value());
768 // The scissor rect must not exceed the size of the render target.
769 scissor = scissor.Intersection(IRect::MakeSize(pass.GetRenderTargetSize()))
770 .value_or(IRect());
771 }
772 pass.SetScissor(scissor);
773 }
774
775 bool EntityPass::RenderElement(Entity& element_entity,
776 size_t clip_depth_floor,
777 InlinePassContext& pass_context,
778 int32_t pass_depth,
779 ContentContext& renderer,
780 EntityPassClipStack& clip_coverage_stack,
781 Point global_pass_position) const {
782 auto result = pass_context.GetRenderPass(pass_depth);
783 if (!result.pass) {
784 // Failure to produce a render pass should be explained by specific errors
785 // in `InlinePassContext::GetRenderPass()`, so avoid log spam and don't
786 // append a validation log here.
787 return false;
788 }
789
790 // If the pass context returns a backdrop texture, we need to draw it to the
791 // current pass. We do this because it's faster and takes significantly less
792 // memory than storing/loading large MSAA textures. Also, it's not possible to
793 // blit the non-MSAA resolve texture of the previous pass to MSAA textures
794 // (let alone a transient one).
795 if (result.backdrop_texture) {
796 auto size_rect = Rect::MakeSize(result.pass->GetRenderTargetSize());
797 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
798 msaa_backdrop_contents->SetStencilEnabled(false);
799 msaa_backdrop_contents->SetLabel("MSAA backdrop");
800 msaa_backdrop_contents->SetSourceRect(size_rect);
801 msaa_backdrop_contents->SetTexture(result.backdrop_texture);
802
803 Entity msaa_backdrop_entity;
804 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
805 msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
806 msaa_backdrop_entity.SetNewClipDepth(std::numeric_limits<uint32_t>::max());
807 if (!msaa_backdrop_entity.Render(renderer, *result.pass)) {
808 VALIDATION_LOG << "Failed to render MSAA backdrop filter entity.";
809 return false;
810 }
811 }
812
813 if (result.just_created) {
814 // Restore any clips that were recorded before the backdrop filter was
815 // applied.
816 auto& replay_entities = clip_coverage_stack.GetReplayEntities();
817 for (const auto& replay : replay_entities) {
818 SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
819 global_pass_position);
820 if (!replay.entity.Render(renderer, *result.pass)) {
821 VALIDATION_LOG << "Failed to render entity for clip restore.";
822 }
823 }
824 }
825
826 auto current_clip_coverage = clip_coverage_stack.CurrentClipCoverage();
827 if (current_clip_coverage.has_value()) {
828 // Entity transforms are relative to the current pass position, so we need
829 // to check clip coverage in the same space.
830 current_clip_coverage = current_clip_coverage->Shift(-global_pass_position);
831 }
832
833 if (!element_entity.ShouldRender(current_clip_coverage)) {
834 return true; // Nothing to render.
835 }
836
837 auto clip_coverage = element_entity.GetClipCoverage(current_clip_coverage);
838 if (clip_coverage.coverage.has_value()) {
839 clip_coverage.coverage =
840 clip_coverage.coverage->Shift(global_pass_position);
841 }
842
843 // The coverage hint tells the rendered Contents which portion of the
844 // rendered output will actually be used, and so we set this to the current
845 // clip coverage (which is the max clip bounds). The contents may
846 // optionally use this hint to avoid unnecessary rendering work.
847 auto element_coverage_hint = element_entity.GetContents()->GetCoverageHint();
848 element_entity.GetContents()->SetCoverageHint(
849 Rect::Intersection(element_coverage_hint, current_clip_coverage));
850
851 EntityPassClipStack::ClipStateResult clip_state_result =
852 clip_coverage_stack.ApplyClipState(clip_coverage, element_entity,
853 clip_depth_floor,
854 global_pass_position);
855
856 if (clip_state_result.clip_did_change) {
857 // We only need to update the pass scissor if the clip state has changed.
858 SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
859 global_pass_position);
860 }
861
862 if (!clip_state_result.should_render) {
863 return true;
864 }
865
866 if (!element_entity.Render(renderer, *result.pass)) {
867 VALIDATION_LOG << "Failed to render entity.";
868 return false;
869 }
870 return true;
871 }
872
873 bool EntityPass::OnRender(
874 ContentContext& renderer,
875 Capture& capture,
876 ISize root_pass_size,
877 EntityPassTarget& pass_target,
878 Point global_pass_position,
879 Point local_pass_position,
880 uint32_t pass_depth,
881 EntityPassClipStack& clip_coverage_stack,
882 size_t clip_depth_floor,
883 std::shared_ptr<Contents> backdrop_filter_contents,
884 const std::optional<InlinePassContext::RenderPassResult>&
885 collapsed_parent_pass) const {
886 TRACE_EVENT0("impeller", "EntityPass::OnRender");
887
888 if (!active_clips_.empty()) {
889 VALIDATION_LOG << SPrintF(
890 "EntityPass (Depth=%d) contains one or more clips with an unresolved "
891 "depth value.",
892 pass_depth);
893 }
894
895 InlinePassContext pass_context(renderer, pass_target,
896 GetTotalPassReads(renderer), GetElementCount(),
897 collapsed_parent_pass);
898 if (!pass_context.IsValid()) {
899 VALIDATION_LOG << SPrintF("Pass context invalid (Depth=%d)", pass_depth);
900 return false;
901 }
902 auto clear_color_size = pass_target.GetRenderTarget().GetRenderTargetSize();
903
904 if (!collapsed_parent_pass) {
905 // Always force the pass to construct the render pass object, even if there
906 // is not a clear color. This ensures that the attachment textures are
907 // cleared/transitioned to the right state.
908 pass_context.GetRenderPass(pass_depth);
909 }
910
911 if (backdrop_filter_proc_) {
912 if (!backdrop_filter_contents) {
913 VALIDATION_LOG
914 << "EntityPass contains a backdrop filter, but no backdrop filter "
915 "contents was supplied by the parent pass at render time. This is "
916 "a bug in EntityPass. Parent passes are responsible for setting "
917 "up backdrop filters for their children.";
918 return false;
919 }
920
921 Entity backdrop_entity;
922 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
923 backdrop_entity.SetTransform(
924 Matrix::MakeTranslation(Vector3(-local_pass_position)));
925 backdrop_entity.SetClipDepth(clip_depth_floor);
926 backdrop_entity.SetNewClipDepth(std::numeric_limits<uint32_t>::max());
927
928 RenderElement(backdrop_entity, clip_depth_floor, pass_context, pass_depth,
929 renderer, clip_coverage_stack, global_pass_position);
930 }
931
932 bool is_collapsing_clear_colors = !collapsed_parent_pass &&
933 // Backdrop filters act as a entity before
934 // everything and disrupt the optimization.
935 !backdrop_filter_proc_;
936 for (const auto& element : elements_) {
937 // Skip elements that are incorporated into the clear color.
938 if (is_collapsing_clear_colors) {
939 auto [entity_color, _] =
940 ElementAsBackgroundColor(element, clear_color_size);
941 if (entity_color.has_value()) {
942 continue;
943 }
944 is_collapsing_clear_colors = false;
945 }
946
947 EntityResult result =
948 GetEntityForElement(element, // element
949 renderer, // renderer
950 capture, // capture
951 pass_context, // pass_context
952 root_pass_size, // root_pass_size
953 global_pass_position, // global_pass_position
954 pass_depth, // pass_depth
955 clip_coverage_stack, // clip_coverage_stack
956 clip_depth_floor); // clip_depth_floor
957
958 switch (result.status) {
959 case EntityResult::kSuccess:
960 break;
961 case EntityResult::kFailure:
962 // All failure cases should be covered by specific validation messages
963 // in `GetEntityForElement()`.
964 return false;
965 case EntityResult::kSkip:
966 continue;
967 };
968
969 //--------------------------------------------------------------------------
970 /// Setup advanced blends.
971 ///
972
973 if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
974 if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
975 auto src_contents = result.entity.GetContents();
976 auto contents = std::make_shared<FramebufferBlendContents>();
977 contents->SetChildContents(src_contents);
978 contents->SetBlendMode(result.entity.GetBlendMode());
979 result.entity.SetContents(std::move(contents));
980 result.entity.SetBlendMode(BlendMode::kSource);
981 } else {
982 // End the active pass and flush the buffer before rendering "advanced"
983 // blends. Advanced blends work by binding the current render target
984 // texture as an input ("destination"), blending with a second texture
985 // input ("source"), writing the result to an intermediate texture, and
986 // finally copying the data from the intermediate texture back to the
987 // render target texture. And so all of the commands that have written
988 // to the render target texture so far need to execute before it's bound
989 // for blending (otherwise the blend pass will end up executing before
990 // all the previous commands in the active pass).
991
992 if (!pass_context.EndPass()) {
993 VALIDATION_LOG
994 << "Failed to end the current render pass in order to read from "
995 "the backdrop texture and apply an advanced blend.";
996 return false;
997 }
998
999 // Amend an advanced blend filter to the contents, attaching the pass
1000 // texture.
1001 auto texture = pass_context.GetTexture();
1002 if (!texture) {
1003 VALIDATION_LOG << "Failed to fetch the color texture in order to "
1004 "apply an advanced blend.";
1005 return false;
1006 }
1007
1008 FilterInput::Vector inputs = {
1009 FilterInput::Make(texture, result.entity.GetTransform().Invert()),
1010 FilterInput::Make(result.entity.GetContents())};
1011 auto contents = ColorFilterContents::MakeBlend(
1012 result.entity.GetBlendMode(), inputs);
1013 contents->SetCoverageHint(result.entity.GetCoverage());
1014 result.entity.SetContents(std::move(contents));
1015 result.entity.SetBlendMode(BlendMode::kSource);
1016 }
1017 }
1018
1019 //--------------------------------------------------------------------------
1020 /// Render the Element.
1021 ///
1022 if (!RenderElement(result.entity, clip_depth_floor, pass_context,
1023 pass_depth, renderer, clip_coverage_stack,
1024 global_pass_position)) {
1025 // Specific validation logs are handled in `render_element()`.
1026 return false;
1027 }
1028 }
1029
1030 #ifdef IMPELLER_DEBUG
1031 //--------------------------------------------------------------------------
1032 /// Draw debug checkerboard over offscreen textures.
1033 ///
1034
1035 // When the pass depth is > 0, this EntityPass is being rendered to an
1036 // offscreen texture.
1037 if (enable_offscreen_debug_checkerboard_ &&
1038 !collapsed_parent_pass.has_value() && pass_depth > 0) {
1039 auto result = pass_context.GetRenderPass(pass_depth);
1040 if (!result.pass) {
1041 // Failure to produce a render pass should be explained by specific errors
1042 // in `InlinePassContext::GetRenderPass()`.
1043 return false;
1044 }
1045 auto checkerboard = CheckerboardContents();
1046 auto color = ColorHSB(0, // hue
1047 1, // saturation
1048 std::max(0.0, 0.6 - pass_depth / 5), // brightness
1049 0.25); // alpha
1050 checkerboard.SetColor(Color(color));
1051 checkerboard.Render(renderer, {}, *result.pass);
1052 }
1053 #endif
1054
1055 return true;
1056 }
1057
1058 void EntityPass::IterateAllElements(
1059 const std::function<bool(Element&)>& iterator) {
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 }
1073
1074 void EntityPass::IterateAllElements(
1075 const std::function<bool(const Element&)>& iterator) const {
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 }
1092
1093 void EntityPass::IterateAllEntities(
1094 const std::function<bool(Entity&)>& iterator) {
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 }
1113
1114 void EntityPass::IterateAllEntities(
1115 const std::function<bool(const Entity&)>& iterator) const {
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 }
1135
1136 bool EntityPass::IterateUntilSubpass(
1137 const std::function<bool(Entity&)>& iterator) {
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 }
1153
1154 size_t EntityPass::GetElementCount() const {
1155 return elements_.size();
1156 }
1157
1158 void EntityPass::SetTransform(Matrix transform) {
1159 transform_ = transform;
1160 }
1161
1162 void EntityPass::SetClipDepth(size_t clip_depth) {
1163 clip_depth_ = clip_depth;
1164 }
1165
1166 size_t EntityPass::GetClipDepth() const {
1167 return clip_depth_;
1168 }
1169
1170 void EntityPass::SetNewClipDepth(size_t clip_depth) {
1171 new_clip_depth_ = clip_depth;
1172 }
1173
1174 uint32_t EntityPass::GetNewClipDepth() const {
1175 return new_clip_depth_;
1176 }
1177
1178 void EntityPass::SetBlendMode(BlendMode blend_mode) {
1179 blend_mode_ = blend_mode;
1180 flood_clip_ = Entity::IsBlendModeDestructive(blend_mode);
1181 }
1182
1183 Color EntityPass::GetClearColorOrDefault(ISize size) const {
1184 return GetClearColor(size).value_or(Color::BlackTransparent());
1185 }
1186
1187 std::optional<Color> EntityPass::GetClearColor(ISize target_size) const {
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 }
1207
1208 void EntityPass::SetBackdropFilter(BackdropFilterProc proc) {
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 }
1216
1217 void EntityPass::SetEnableOffscreenCheckerboard(bool enabled) {
1218 enable_offscreen_debug_checkerboard_ = enabled;
1219 }
1220
1221 } // namespace impeller
impeller::EntityPass::AddSubpassInline
void AddSubpassInline(std::unique_ptr< EntityPass > pass)
Merges a given pass into this pass. Useful for drawing pre-recorded pictures that don't require rende...
Definition: entity_pass.cc:291
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:1093
impeller::EntityPass::GetNewClipDepth
uint32_t GetNewClipDepth() const
Definition: entity_pass.cc:1174
impeller::EntityPass::SetBackdropFilter
void SetBackdropFilter(BackdropFilterProc proc)
Definition: entity_pass.cc:1208
impeller::Entity::kLastPipelineBlendMode
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:23
impeller::Capture
Definition: capture.h:231
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:61
impeller::EntityPass::PopAllClips
void PopAllClips(uint64_t depth)
Definition: entity_pass.cc:141
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::Entity::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: entity.cc:130
impeller::ContentBoundsPromise::kMayClipContents
@ kMayClipContents
The caller claims the bounds are a subset of an estimate of the reasonably tight bounds but likely cl...
impeller::ContentContext::GetLazyGlyphAtlas
const std::shared_ptr< LazyGlyphAtlas > & GetLazyGlyphAtlas() const
Definition: content_context.h:801
texture_contents.h
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:49
entity.h
impeller::EntityPass::GetSubpassesDepth
size_t GetSubpassesDepth() const
Definition: entity_pass.cc:149
impeller::EntityPass::SetNewClipDepth
void SetNewClipDepth(size_t clip_depth)
Definition: entity_pass.cc:1170
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:75
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:272
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:1136
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
formats.h
impeller::EntityPassClipStack::HasCoverage
bool HasCoverage() const
Definition: entity_pass_clip_stack.cc:28
impeller::TRect< Scalar >::Intersection
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition: rect.h:461
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:94
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:1058
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:15
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:160
impeller::EntityPass::~EntityPass
~EntityPass()
framebuffer_blend_contents.h
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
checkerboard_contents.h
validation.h
impeller::RenderTarget::AttachmentConfigMSAA
Definition: render_target.h:47
impeller::EntityPass::SetClipDepth
void SetClipDepth(size_t clip_depth)
Definition: entity_pass.cc:1162
impeller::EntityPass::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: entity_pass.cc:1178
impeller::EntityPass::GetClipDepth
size_t GetClipDepth() const
Definition: entity_pass.cc:1166
impeller::Entity::SetCapture
void SetCapture(Capture capture) const
Definition: entity.cc:214
impeller::TRect::Shift
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
Definition: rect.h:531
impeller::RenderTarget::AttachmentConfig
Definition: render_target.h:40
impeller::TPoint::IsZero
constexpr bool IsZero() const
Definition: point.h:234
impeller::Entity::SetContents
void SetContents(std::shared_ptr< Contents > contents)
Definition: entity.cc:93
impeller::TRect< int64_t >::RoundOut
RoundOut(const TRect< U > &r)
Definition: rect.h:608
impeller::ContentContext::kEnableStencilThenCover
static constexpr bool kEnableStencilThenCover
Definition: content_context.h:411
impeller::kDefaultStencilConfig
static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig
Definition: entity_pass.cc:308
impeller::Entity
Definition: entity.h:21
impeller::RenderPass::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_pass.cc:43
impeller::TSize< int64_t >
impeller::StorageMode::kDeviceTransient
@ kDeviceTransient
impeller::Point
TPoint< Scalar > Point
Definition: point.h:316
impeller::EntityPass::SetElements
void SetElements(std::vector< Element > elements)
Definition: entity_pass.cc:145
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:71
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:188
impeller::EntityPass::GetSuperpass
EntityPass * GetSuperpass() const
Definition: entity_pass.cc:268
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:24
impeller::Context::BackendType::kOpenGLES
@ kOpenGLES
impeller::SPrintF
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
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:564
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:94
impeller::EntityPass::GetRequiredMipCount
int32_t GetRequiredMipCount() const
Definition: entity_pass.h:186
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:1154
impeller::InlinePassContext
Definition: inline_pass_context.h:17
impeller::Entity::GetContents
const std::shared_ptr< Contents > & GetContents() const
Definition: entity.cc:97
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:49
impeller::EntityPassClipStack::PushSubpass
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_depth)
Definition: entity_pass_clip_stack.cc:32
impeller::RenderTarget
Definition: render_target.h:38
entity_pass.h
impeller::InlinePassContext::EndPass
bool EndPass()
Definition: inline_pass_context.cc:56
impeller::EntityPass::SetTransform
void SetTransform(Matrix transform)
Definition: entity_pass.cc:1158
filter_input.h
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:661
strings.h
impeller::SetClipScissor
static void SetClipScissor(std::optional< Rect > clip_coverage, RenderPass &pass, Point global_pass_position)
Definition: entity_pass.cc:756
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:64
impeller::EntityPassClipStack::PopSubpass
void PopSubpass()
Definition: entity_pass_clip_stack.cc:43
impeller::Entity::RenderingMode::kSubpass
@ kSubpass
impeller::Entity::GetBlendMode
BlendMode GetBlendMode() const
Definition: entity.cc:134
impeller::IRect
TRect< int64_t > IRect
Definition: rect.h:662
impeller::Entity::SetNewClipDepth
void SetNewClipDepth(uint32_t clip_depth)
Definition: entity.cc:109
impeller::InlinePassContext::GetPassTarget
EntityPassTarget & GetPassTarget() const
Definition: inline_pass_context.cc:90
entity_pass_clip_stack.h
impeller::RenderPass::SetScissor
virtual void SetScissor(IRect scissor)
Definition: render_pass.cc:115
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:138
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:805
impeller::Entity::SetTransform
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
Definition: entity.cc:65
impeller::ContentContext::GetDeviceCapabilities
const Capabilities & GetDeviceCapabilities() const
Definition: content_context.cc:568
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:123
impeller::LoadAction::kDontCare
@ kDontCare
rect.h
impeller::Entity::Clone
Entity Clone() const
Definition: entity.cc:210
impeller::TPoint< Scalar >
impeller::Color::BlackTransparent
static constexpr Color BlackTransparent()
Definition: color.h:262
impeller::EntityPass::PushClip
void PushClip(Entity entity)
Definition: entity_pass.cc:118
impeller::CreateRenderTarget
static EntityPassTarget CreateRenderTarget(ContentContext &renderer, ISize size, int mip_count, const Color &clear_color)
Definition: entity_pass.cc:315
impeller::EntityPass::Render
bool Render(ContentContext &renderer, const RenderTarget &render_target) const
Definition: entity_pass.cc:376
impeller::TRect< Scalar >::Union
constexpr TRect Union(const TRect &o) const
Definition: rect.h:446
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::EntityPass::kCaptureDocumentName
static const std::string kCaptureDocumentName
Definition: entity_pass.h:56
impeller::EntityPass::SetDelegate
void SetDelegate(std::shared_ptr< EntityPassDelegate > delgate)
Definition: entity_pass.cc:57
impeller::EntityPass::SetEnableOffscreenCheckerboard
void SetEnableOffscreenCheckerboard(bool enabled)
Definition: entity_pass.cc:1217
impeller::Capture::CreateChild
Capture CreateChild(std::string_view label)
Definition: capture.h:239
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_blur_unittests.cc:20
impeller::EntityPassTarget::GetRenderTarget
const RenderTarget & GetRenderTarget() const
Definition: entity_pass_target.cc:68
impeller::ContentContext
Definition: content_context.h:392
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: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
impeller::EntityPass::AddEntity
void AddEntity(Entity entity)
Add an entity to the current entity pass.
Definition: entity_pass.cc:106
inline_pass_context.h