11 #include "flutter/fml/closure.h"
12 #include "flutter/fml/logging.h"
13 #include "flutter/fml/trace_event.h"
31 #endif // IMPELLER_DEBUG
36 std::tuple<std::optional<Color>,
BlendMode> ElementAsBackgroundColor(
39 if (
const Entity* entity = std::get_if<Entity>(&element)) {
40 std::optional<Color> entity_color = entity->AsBackgroundColor(target_size);
41 if (entity_color.has_value()) {
42 return {entity_color.value(), entity->GetBlendMode()};
59 delegate_ = std::move(delegate);
63 bounds_limit_ = bounds_limit;
77 advanced_blend_reads_from_pass_texture_ += 1;
79 elements_.emplace_back(std::move(entity));
83 elements_ = std::move(elements);
87 size_t max_subpass_depth = 0u;
88 for (
const auto& element : elements_) {
89 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
91 std::max(max_subpass_depth, subpass->get()->GetSubpassesDepth());
94 return max_subpass_depth + 1u;
98 std::optional<Rect> coverage_limit)
const {
99 std::optional<Rect> accumulated_coverage;
100 for (
const auto& element : elements_) {
101 std::optional<Rect> element_coverage;
103 if (
auto entity = std::get_if<Entity>(&element)) {
104 element_coverage = entity->GetCoverage();
108 if (element_coverage.has_value() && coverage_limit.has_value()) {
109 const auto* filter = entity->GetContents()->AsFilter();
110 if (!filter || filter->IsTranslationOnly()) {
112 element_coverage->Intersection(coverage_limit.value());
115 }
else if (
auto subpass_ptr =
116 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
117 auto& subpass = *subpass_ptr->get();
119 std::optional<Rect> unfiltered_coverage =
125 if (accumulated_coverage.has_value() && subpass.backdrop_filter_proc_) {
126 std::shared_ptr<FilterContents> backdrop_filter =
127 subpass.backdrop_filter_proc_(
130 if (backdrop_filter) {
131 auto backdrop_coverage = backdrop_filter->GetCoverage({});
132 unfiltered_coverage =
133 Rect::Union(unfiltered_coverage, backdrop_coverage);
135 VALIDATION_LOG <<
"The EntityPass backdrop filter proc didn't return "
140 if (!unfiltered_coverage.has_value()) {
152 std::shared_ptr<FilterContents> image_filter =
153 subpass.delegate_->WithImageFilter(*unfiltered_coverage,
158 element_coverage = image_filter->GetCoverage(subpass_entity);
160 element_coverage = unfiltered_coverage;
168 accumulated_coverage =
Rect::Union(accumulated_coverage, element_coverage);
170 return accumulated_coverage;
175 std::optional<Rect> coverage_limit)
const {
176 std::shared_ptr<FilterContents> image_filter =
177 subpass.delegate_->WithImageFilter(
Rect(), subpass.transform_);
182 if (image_filter && coverage_limit.has_value()) {
183 coverage_limit = image_filter->GetSourceCoverage(subpass.transform_,
184 coverage_limit.value());
189 if (!entities_coverage.has_value()) {
193 if (!subpass.bounds_limit_.has_value()) {
194 return entities_coverage;
196 auto user_bounds_coverage =
197 subpass.bounds_limit_->TransformBounds(subpass.transform_);
198 return entities_coverage->Intersection(user_bounds_coverage);
209 FML_DCHECK(pass->superpass_ ==
nullptr);
210 pass->superpass_ =
this;
212 if (pass->backdrop_filter_proc_) {
213 backdrop_filter_reads_from_pass_texture_ += 1;
216 advanced_blend_reads_from_pass_texture_ += 1;
219 auto subpass_pointer = pass.get();
220 elements_.emplace_back(std::move(pass));
221 return subpass_pointer;
228 FML_DCHECK(pass->superpass_ ==
nullptr);
230 std::vector<Element>& elements = pass->elements_;
231 for (
auto i = 0u; i < elements.size(); i++) {
232 elements_.emplace_back(std::move(elements[i]));
235 backdrop_filter_reads_from_pass_texture_ +=
236 pass->backdrop_filter_reads_from_pass_texture_;
237 advanced_blend_reads_from_pass_texture_ +=
238 pass->advanced_blend_reads_from_pass_texture_;
250 const Color& clear_color) {
259 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
266 .storage_mode = StorageMode::kDeviceTransient,
267 .resolve_storage_mode = StorageMode::kDevicePrivate,
268 .load_action = LoadAction::kDontCare,
269 .store_action = StoreAction::kMultisampleResolve,
270 .clear_color = clear_color},
280 .storage_mode = StorageMode::kDevicePrivate,
281 .load_action = LoadAction::kDontCare,
282 .store_action = StoreAction::kDontCare,
283 .clear_color = clear_color,
294 uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer)
const {
295 return renderer.GetDeviceCapabilities().SupportsFramebufferFetch()
296 ? backdrop_filter_reads_from_pass_texture_
297 : backdrop_filter_reads_from_pass_texture_ +
298 advanced_blend_reads_from_pass_texture_;
308 auto root_render_target = render_target;
310 if (root_render_target.GetColorAttachments().find(0u) ==
311 root_render_target.GetColorAttachments().end()) {
312 VALIDATION_LOG <<
"The root RenderTarget must have a color attachment.";
316 capture.AddRect(
"Coverage",
320 fml::ScopedCleanupClosure reset_state([&renderer]() {
327 if (const auto& contents = entity.GetContents()) {
328 contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
333 ClipCoverageStack clip_coverage_stack = {ClipCoverageLayer{
334 .coverage =
Rect::MakeSize(root_render_target.GetRenderTargetSize()),
337 bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
341 if (reads_from_onscreen_backdrop) {
343 renderer, root_render_target.GetRenderTargetSize(),
344 GetClearColorOrDefault(render_target.GetRenderTargetSize()));
346 if (!OnRender(renderer,
348 offscreen_target.GetRenderTarget()
349 .GetRenderTargetSize(),
361 auto command_buffer = renderer.GetContext()->CreateCommandBuffer();
362 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
367 if (renderer.GetContext()
369 ->SupportsTextureToTextureBlits()) {
370 auto blit_pass = command_buffer->CreateBlitPass();
372 offscreen_target.GetRenderTarget().GetRenderTargetTexture(),
373 root_render_target.GetRenderTargetTexture());
375 if (!command_buffer->EncodeAndSubmit(
376 blit_pass, renderer.GetContext()->GetResourceAllocator())) {
381 auto render_pass = command_buffer->CreateRenderPass(root_render_target);
382 render_pass->SetLabel(
"EntityPass Root Render Pass");
386 offscreen_target.GetRenderTarget().GetRenderTargetSize());
388 contents->SetTexture(
389 offscreen_target.GetRenderTarget().GetRenderTargetTexture());
390 contents->SetSourceRect(size_rect);
391 contents->SetLabel(
"Root pass blit");
394 entity.SetContents(contents);
397 if (!entity.Render(renderer, *render_pass)) {
403 if (!command_buffer->EncodeAndSubmit(render_pass)) {
417 auto color0 = root_render_target.GetColorAttachments().find(0u)->second;
421 auto stencil_attachment = root_render_target.GetStencilAttachment();
422 if (stencil_attachment.has_value()) {
423 auto stencil_texture = stencil_attachment->texture;
424 if (!stencil_texture) {
425 VALIDATION_LOG <<
"The root RenderTarget must have a stencil texture.";
429 auto stencil_storage_mode =
430 stencil_texture->GetTextureDescriptor().storage_mode;
431 if (reads_from_onscreen_backdrop &&
433 VALIDATION_LOG <<
"The given root RenderTarget stencil needs to be read, "
434 "but it's marked as transient.";
441 root_render_target.SetupStencilAttachment(
442 *renderer.GetContext(), *renderer.GetRenderTargetCache(),
443 color0.texture->GetSize(),
444 renderer.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
450 GetClearColorOrDefault(render_target.GetRenderTargetSize());
451 root_render_target.SetColorAttachment(color0, 0);
453 EntityPassTarget pass_target(
455 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
456 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA());
461 root_render_target.GetRenderTargetSize(),
466 clip_coverage_stack);
469 EntityPass::EntityResult EntityPass::GetEntityForElement(
470 const EntityPass::Element& element,
471 ContentContext& renderer,
473 InlinePassContext& pass_context,
474 ISize root_pass_size,
475 Point global_pass_position,
477 ClipCoverageStack& clip_coverage_stack,
478 size_t clip_depth_floor)
const {
482 if (
const auto& entity = std::get_if<Entity>(&element)) {
483 Entity element_entity = entity->Clone();
484 element_entity.SetCapture(capture.CreateChild(
"Entity"));
486 if (!global_pass_position.IsZero()) {
490 element_entity.SetTransform(
491 Matrix::MakeTranslation(Vector3(-global_pass_position)) *
492 element_entity.GetTransform());
494 return EntityPass::EntityResult::Success(std::move(element_entity));
500 if (
const auto& subpass_ptr =
501 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
502 auto subpass = subpass_ptr->get();
503 if (subpass->delegate_->CanElide()) {
504 return EntityPass::EntityResult::Skip();
507 if (!subpass->backdrop_filter_proc_ &&
508 subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
509 auto subpass_capture = capture.CreateChild(
"EntityPass (Collapsed)");
511 if (!subpass->OnRender(
515 pass_context.GetPassTarget(),
516 global_pass_position,
522 pass_context.GetRenderPass(pass_depth)
526 return EntityPass::EntityResult::Failure();
528 return EntityPass::EntityResult::Skip();
531 std::shared_ptr<Contents> subpass_backdrop_filter_contents =
nullptr;
532 if (subpass->backdrop_filter_proc_) {
533 auto texture = pass_context.GetTexture();
535 const auto& proc = subpass->backdrop_filter_proc_;
536 subpass_backdrop_filter_contents =
537 proc(FilterInput::Make(std::move(texture)),
538 subpass->transform_.Basis(), Entity::RenderingMode::kSubpass);
546 pass_context.GetRenderPass(pass_depth);
551 pass_context.EndPass();
554 if (clip_coverage_stack.empty()) {
557 capture.CreateChild(
"Subpass Entity (Skipped: Empty clip A)");
558 return EntityPass::EntityResult::Skip();
560 auto clip_coverage_back = clip_coverage_stack.back().coverage;
561 if (!clip_coverage_back.has_value()) {
562 capture.CreateChild(
"Subpass Entity (Skipped: Empty clip B)");
563 return EntityPass::EntityResult::Skip();
568 auto coverage_limit = Rect::MakeOriginSize(global_pass_position,
569 Size(pass_context.GetPassTarget()
571 .GetRenderTargetSize()))
572 .Intersection(clip_coverage_back.value());
573 if (!coverage_limit.has_value()) {
574 capture.CreateChild(
"Subpass Entity (Skipped: Empty coverage limit A)");
575 return EntityPass::EntityResult::Skip();
579 coverage_limit->Intersection(Rect::MakeSize(root_pass_size));
580 if (!coverage_limit.has_value()) {
581 capture.CreateChild(
"Subpass Entity (Skipped: Empty coverage limit B)");
582 return EntityPass::EntityResult::Skip();
585 auto subpass_coverage =
586 (subpass->flood_clip_ || subpass_backdrop_filter_contents)
588 : GetSubpassCoverage(*subpass, coverage_limit);
589 if (!subpass_coverage.has_value()) {
590 capture.CreateChild(
"Subpass Entity (Skipped: Empty subpass coverage A)");
591 return EntityPass::EntityResult::Skip();
594 subpass_coverage = Rect::RoundOut(subpass_coverage.value());
596 auto subpass_size =
ISize(subpass_coverage->GetSize());
597 if (subpass_size.IsEmpty()) {
598 capture.CreateChild(
"Subpass Entity (Skipped: Empty subpass coverage B)");
599 return EntityPass::EntityResult::Skip();
605 subpass->GetClearColorOrDefault(subpass_size));
607 if (!subpass_target.IsValid()) {
609 return EntityPass::EntityResult::Failure();
612 auto subpass_capture = capture.CreateChild(
"EntityPass");
613 subpass_capture.AddRect(
"Coverage", *subpass_coverage, {.readonly =
true});
620 ClipCoverageStack subpass_clip_coverage_stack = {ClipCoverageLayer{
621 .coverage = subpass_coverage, .clip_depth = subpass->clip_depth_}};
625 if (!subpass->OnRender(
630 subpass_coverage->GetOrigin(),
631 subpass_coverage->GetOrigin() -
632 global_pass_position,
634 subpass_clip_coverage_stack,
635 subpass->clip_depth_,
636 subpass_backdrop_filter_contents
640 return EntityPass::EntityResult::Failure();
644 auto subpass_texture =
645 subpass_target.GetRenderTarget().GetRenderTargetTexture();
647 auto offscreen_texture_contents =
648 subpass->delegate_->CreateContentsForSubpassTarget(
650 Matrix::MakeTranslation(Vector3{-global_pass_position}) *
651 subpass->transform_);
653 if (!offscreen_texture_contents) {
662 return EntityPass::EntityResult::Failure();
664 Entity element_entity;
665 Capture subpass_texture_capture =
666 capture.CreateChild(
"Entity (Subpass texture)");
667 element_entity.SetCapture(subpass_texture_capture);
668 element_entity.SetContents(std::move(offscreen_texture_contents));
669 element_entity.SetClipDepth(subpass->clip_depth_);
670 element_entity.SetBlendMode(subpass->blend_mode_);
671 element_entity.SetTransform(subpass_texture_capture.AddMatrix(
673 Matrix::MakeTranslation(
674 Vector3(subpass_coverage->GetOrigin() - global_pass_position))));
676 return EntityPass::EntityResult::Success(std::move(element_entity));
681 bool EntityPass::RenderElement(Entity& element_entity,
682 size_t clip_depth_floor,
683 InlinePassContext& pass_context,
685 ContentContext& renderer,
686 ClipCoverageStack& clip_coverage_stack,
687 Point global_pass_position)
const {
688 auto result = pass_context.GetRenderPass(pass_depth);
701 if (result.backdrop_texture) {
704 auto& replay_entities = clip_replay_->GetReplayEntities();
705 for (
const auto& entity : replay_entities) {
706 if (!entity.Render(renderer, *result.pass)) {
711 auto size_rect = Rect::MakeSize(result.pass->GetRenderTargetSize());
712 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
713 msaa_backdrop_contents->SetStencilEnabled(
false);
714 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
715 msaa_backdrop_contents->SetSourceRect(size_rect);
716 msaa_backdrop_contents->SetTexture(result.backdrop_texture);
718 Entity msaa_backdrop_entity;
719 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
720 msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
721 if (!msaa_backdrop_entity.Render(renderer, *result.pass)) {
722 VALIDATION_LOG <<
"Failed to render MSAA backdrop filter entity.";
727 auto current_clip_coverage = clip_coverage_stack.back().coverage;
728 if (current_clip_coverage.has_value()) {
731 current_clip_coverage = current_clip_coverage->Shift(-global_pass_position);
734 if (!element_entity.ShouldRender(current_clip_coverage)) {
738 auto clip_coverage = element_entity.GetClipCoverage(current_clip_coverage);
739 if (clip_coverage.coverage.has_value()) {
740 clip_coverage.coverage =
741 clip_coverage.coverage->Shift(global_pass_position);
748 auto element_coverage_hint = element_entity.GetContents()->GetCoverageHint();
749 element_entity.GetContents()->SetCoverageHint(
750 Rect::Intersection(element_coverage_hint, current_clip_coverage));
752 switch (clip_coverage.type) {
753 case Contents::ClipCoverage::Type::kNoChange:
755 case Contents::ClipCoverage::Type::kAppend: {
756 auto op = clip_coverage_stack.back().coverage;
757 clip_coverage_stack.push_back(
758 ClipCoverageLayer{.coverage = clip_coverage.coverage,
759 .clip_depth = element_entity.GetClipDepth() + 1});
760 FML_DCHECK(clip_coverage_stack.back().clip_depth ==
761 clip_coverage_stack.front().clip_depth +
762 clip_coverage_stack.size() - 1);
764 if (!op.has_value()) {
771 if (clip_coverage_stack.back().clip_depth <=
772 element_entity.GetClipDepth()) {
777 auto restoration_index = element_entity.GetClipDepth() -
778 clip_coverage_stack.front().clip_depth;
779 FML_DCHECK(restoration_index < clip_coverage_stack.size());
783 std::optional<Rect> restore_coverage =
784 (restoration_index + 1 < clip_coverage_stack.size())
785 ? clip_coverage_stack[restoration_index + 1].coverage
787 if (restore_coverage.has_value()) {
789 restore_coverage = restore_coverage->Shift(-global_pass_position);
791 clip_coverage_stack.resize(restoration_index + 1);
793 if (!clip_coverage_stack.back().coverage.has_value()) {
798 auto restore_contents =
799 static_cast<ClipRestoreContents*
>(element_entity.GetContents().get());
800 restore_contents->SetRestoreCoverage(restore_coverage);
805 #ifdef IMPELLER_ENABLE_CAPTURE
807 auto element_entity_coverage = element_entity.GetCoverage();
808 if (element_entity_coverage.has_value()) {
809 element_entity_coverage =
810 element_entity_coverage->Shift(global_pass_position);
811 element_entity.GetCapture().AddRect(
"Coverage", *element_entity_coverage,
817 element_entity.SetClipDepth(element_entity.GetClipDepth() - clip_depth_floor);
818 clip_replay_->RecordEntity(element_entity, clip_coverage.type);
819 if (!element_entity.Render(renderer, *result.pass)) {
826 bool EntityPass::OnRender(
827 ContentContext& renderer,
829 ISize root_pass_size,
830 EntityPassTarget& pass_target,
831 Point global_pass_position,
832 Point local_pass_position,
834 ClipCoverageStack& clip_coverage_stack,
835 size_t clip_depth_floor,
836 std::shared_ptr<Contents> backdrop_filter_contents,
837 const std::optional<InlinePassContext::RenderPassResult>&
838 collapsed_parent_pass)
const {
839 TRACE_EVENT0(
"impeller",
"EntityPass::OnRender");
841 auto context = renderer.GetContext();
842 InlinePassContext pass_context(context, pass_target,
843 GetTotalPassReads(renderer), GetElementCount(),
844 collapsed_parent_pass);
845 if (!pass_context.IsValid()) {
849 auto clear_color_size = pass_target.GetRenderTarget().GetRenderTargetSize();
851 if (!collapsed_parent_pass && GetClearColor(clear_color_size).has_value()) {
854 pass_context.GetRenderPass(pass_depth);
857 if (backdrop_filter_proc_) {
858 if (!backdrop_filter_contents) {
860 <<
"EntityPass contains a backdrop filter, but no backdrop filter "
861 "contents was supplied by the parent pass at render time. This is "
862 "a bug in EntityPass. Parent passes are responsible for setting "
863 "up backdrop filters for their children.";
867 Entity backdrop_entity;
868 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
869 backdrop_entity.SetTransform(
870 Matrix::MakeTranslation(Vector3(-local_pass_position)));
871 backdrop_entity.SetClipDepth(clip_depth_floor);
873 RenderElement(backdrop_entity, clip_depth_floor, pass_context, pass_depth,
874 renderer, clip_coverage_stack, global_pass_position);
877 bool is_collapsing_clear_colors = !collapsed_parent_pass &&
880 !backdrop_filter_proc_;
881 for (
const auto& element : elements_) {
883 if (is_collapsing_clear_colors) {
884 auto [entity_color, _] =
885 ElementAsBackgroundColor(element, clear_color_size);
886 if (entity_color.has_value()) {
889 is_collapsing_clear_colors =
false;
892 EntityResult result =
893 GetEntityForElement(element,
898 global_pass_position,
903 switch (result.status) {
904 case EntityResult::kSuccess:
906 case EntityResult::kFailure:
910 case EntityResult::kSkip:
918 if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
919 if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
920 auto src_contents = result.entity.GetContents();
921 auto contents = std::make_shared<FramebufferBlendContents>();
922 contents->SetChildContents(src_contents);
923 contents->SetBlendMode(result.entity.GetBlendMode());
924 result.entity.SetContents(std::move(contents));
925 result.entity.SetBlendMode(BlendMode::kSource);
937 if (!pass_context.EndPass()) {
939 <<
"Failed to end the current render pass in order to read from "
940 "the backdrop texture and apply an advanced blend.";
946 auto texture = pass_context.GetTexture();
948 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
949 "apply an advanced blend.";
953 FilterInput::Vector inputs = {
954 FilterInput::Make(texture, result.entity.GetTransform().Invert()),
955 FilterInput::Make(result.entity.GetContents())};
956 auto contents = ColorFilterContents::MakeBlend(
957 result.entity.GetBlendMode(), inputs);
958 contents->SetCoverageHint(result.entity.GetCoverage());
959 result.entity.SetContents(std::move(contents));
960 result.entity.SetBlendMode(BlendMode::kSource);
967 if (!RenderElement(result.entity, clip_depth_floor, pass_context,
968 pass_depth, renderer, clip_coverage_stack,
969 global_pass_position)) {
975 #ifdef IMPELLER_DEBUG
982 if (enable_offscreen_debug_checkerboard_ &&
983 !collapsed_parent_pass.has_value() && pass_depth > 0) {
984 auto result = pass_context.GetRenderPass(pass_depth);
990 auto checkerboard = CheckerboardContents();
991 auto color = ColorHSB(0,
993 std::max(0.0, 0.6 - pass_depth / 5),
995 checkerboard.SetColor(Color(color));
996 checkerboard.Render(renderer, {}, *result.pass);
1003 void EntityPass::IterateAllElements(
1004 const std::function<
bool(
Element&)>& iterator) {
1009 for (
auto& element : elements_) {
1010 if (!iterator(element)) {
1013 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1014 subpass->get()->IterateAllElements(iterator);
1019 void EntityPass::IterateAllEntities(
1020 const std::function<
bool(
Entity&)>& iterator) {
1025 for (
auto& element : elements_) {
1026 if (
auto entity = std::get_if<Entity>(&element)) {
1027 if (!iterator(*entity)) {
1032 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1033 subpass->get()->IterateAllEntities(iterator);
1040 void EntityPass::IterateAllEntities(
1041 const std::function<
bool(
const Entity&)>& iterator)
const {
1046 for (
const auto& element : elements_) {
1047 if (
auto entity = std::get_if<Entity>(&element)) {
1048 if (!iterator(*entity)) {
1053 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1054 const EntityPass* entity_pass = subpass->get();
1062 bool EntityPass::IterateUntilSubpass(
1063 const std::function<
bool(
Entity&)>& iterator) {
1068 for (
auto& element : elements_) {
1069 if (
auto entity = std::get_if<Entity>(&element)) {
1070 if (!iterator(*entity)) {
1080 size_t EntityPass::GetElementCount()
const {
1081 return elements_.size();
1084 std::unique_ptr<EntityPass> EntityPass::Clone()
const {
1085 std::vector<Element> new_elements;
1086 new_elements.reserve(elements_.size());
1088 for (
const auto& element : elements_) {
1089 if (
auto entity = std::get_if<Entity>(&element)) {
1090 new_elements.push_back(entity->Clone());
1093 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1094 new_elements.push_back(subpass->get()->Clone());
1100 auto pass = std::make_unique<EntityPass>();
1101 pass->SetElements(std::move(new_elements));
1102 pass->backdrop_filter_reads_from_pass_texture_ =
1103 backdrop_filter_reads_from_pass_texture_;
1104 pass->advanced_blend_reads_from_pass_texture_ =
1105 advanced_blend_reads_from_pass_texture_;
1106 pass->backdrop_filter_proc_ = backdrop_filter_proc_;
1107 pass->blend_mode_ = blend_mode_;
1108 pass->delegate_ = delegate_;
1115 void EntityPass::SetTransform(
Matrix transform) {
1116 transform_ = transform;
1119 void EntityPass::SetClipDepth(
size_t clip_depth) {
1120 clip_depth_ = clip_depth;
1123 size_t EntityPass::GetClipDepth() {
1128 blend_mode_ = blend_mode;
1129 flood_clip_ = Entity::IsBlendModeDestructive(blend_mode);
1133 return GetClearColor(size).value_or(Color::BlackTransparent());
1136 std::optional<Color> EntityPass::GetClearColor(
ISize target_size)
const {
1137 if (backdrop_filter_proc_) {
1138 return std::nullopt;
1141 std::optional<Color> result = std::nullopt;
1142 for (
const Element& element : elements_) {
1143 auto [entity_color, blend_mode] =
1144 ElementAsBackgroundColor(element, target_size);
1145 if (!entity_color.has_value()) {
1148 result = result.value_or(Color::BlackTransparent())
1149 .Blend(entity_color.value(), blend_mode);
1151 if (result.has_value()) {
1152 return result->Premultiply();
1159 VALIDATION_LOG <<
"Backdrop filters cannot be set on EntityPasses that "
1160 "have already been appended to another pass.";
1163 backdrop_filter_proc_ = std::move(proc);
1166 void EntityPass::SetEnableOffscreenCheckerboard(
bool enabled) {
1167 enable_offscreen_debug_checkerboard_ = enabled;
1170 EntityPassClipRecorder::EntityPassClipRecorder() {}
1172 void EntityPassClipRecorder::RecordEntity(
const Entity& entity,
1175 case Contents::ClipCoverage::Type::kNoChange:
1177 case Contents::ClipCoverage::Type::kAppend:
1178 rendered_clip_entities_.push_back(entity.
Clone());
1181 rendered_clip_entities_.pop_back();
1186 const std::vector<Entity>& EntityPassClipRecorder::GetReplayEntities()
const {
1187 return rendered_clip_entities_;