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_;
253 const Color& clear_color) {
262 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
269 .storage_mode = StorageMode::kDeviceTransient,
270 .resolve_storage_mode = StorageMode::kDevicePrivate,
271 .load_action = LoadAction::kDontCare,
272 .store_action = StoreAction::kMultisampleResolve,
273 .clear_color = clear_color},
283 .storage_mode = StorageMode::kDevicePrivate,
284 .load_action = LoadAction::kDontCare,
285 .store_action = StoreAction::kDontCare,
286 .clear_color = clear_color,
297 uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer)
const {
298 return renderer.GetDeviceCapabilities().SupportsFramebufferFetch()
299 ? backdrop_filter_reads_from_pass_texture_
300 : backdrop_filter_reads_from_pass_texture_ +
301 advanced_blend_reads_from_pass_texture_;
311 auto root_render_target = render_target;
313 if (root_render_target.GetColorAttachments().find(0u) ==
314 root_render_target.GetColorAttachments().end()) {
315 VALIDATION_LOG <<
"The root RenderTarget must have a color attachment.";
319 capture.AddRect(
"Coverage",
323 fml::ScopedCleanupClosure reset_state([&renderer]() {
330 if (const auto& contents = entity.GetContents()) {
331 contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
336 ClipCoverageStack clip_coverage_stack = {ClipCoverageLayer{
337 .coverage =
Rect::MakeSize(root_render_target.GetRenderTargetSize()),
340 bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
344 if (reads_from_onscreen_backdrop) {
346 renderer, root_render_target.GetRenderTargetSize(),
true,
347 GetClearColorOrDefault(render_target.GetRenderTargetSize()));
349 if (!OnRender(renderer,
351 offscreen_target.GetRenderTarget()
352 .GetRenderTargetSize(),
364 auto command_buffer = renderer.GetContext()->CreateCommandBuffer();
365 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
370 if (renderer.GetContext()
372 ->SupportsTextureToTextureBlits()) {
373 auto blit_pass = command_buffer->CreateBlitPass();
375 offscreen_target.GetRenderTarget().GetRenderTargetTexture(),
376 root_render_target.GetRenderTargetTexture());
378 if (!command_buffer->EncodeAndSubmit(
379 blit_pass, renderer.GetContext()->GetResourceAllocator())) {
384 auto render_pass = command_buffer->CreateRenderPass(root_render_target);
385 render_pass->SetLabel(
"EntityPass Root Render Pass");
389 offscreen_target.GetRenderTarget().GetRenderTargetSize());
391 contents->SetTexture(
392 offscreen_target.GetRenderTarget().GetRenderTargetTexture());
393 contents->SetSourceRect(size_rect);
394 contents->SetLabel(
"Root pass blit");
397 entity.SetContents(contents);
400 if (!entity.Render(renderer, *render_pass)) {
406 if (!command_buffer->EncodeAndSubmit(render_pass)) {
420 auto color0 = root_render_target.GetColorAttachments().find(0u)->second;
424 auto stencil_attachment = root_render_target.GetStencilAttachment();
425 if (stencil_attachment.has_value()) {
426 auto stencil_texture = stencil_attachment->texture;
427 if (!stencil_texture) {
428 VALIDATION_LOG <<
"The root RenderTarget must have a stencil texture.";
432 auto stencil_storage_mode =
433 stencil_texture->GetTextureDescriptor().storage_mode;
434 if (reads_from_onscreen_backdrop &&
436 VALIDATION_LOG <<
"The given root RenderTarget stencil needs to be read, "
437 "but it's marked as transient.";
444 root_render_target.SetupStencilAttachment(
445 *renderer.GetContext(), *renderer.GetRenderTargetCache(),
446 color0.texture->GetSize(),
447 renderer.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
454 GetClearColorOrDefault(render_target.GetRenderTargetSize());
455 root_render_target.SetColorAttachment(color0, 0);
457 EntityPassTarget pass_target(
459 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
460 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA());
465 root_render_target.GetRenderTargetSize(),
470 clip_coverage_stack);
473 EntityPass::EntityResult EntityPass::GetEntityForElement(
474 const EntityPass::Element& element,
475 ContentContext& renderer,
477 InlinePassContext& pass_context,
478 ISize root_pass_size,
479 Point global_pass_position,
481 ClipCoverageStack& clip_coverage_stack,
482 size_t clip_depth_floor)
const {
487 if (
const auto& entity = std::get_if<Entity>(&element)) {
488 Entity element_entity = entity->Clone();
489 element_entity.SetCapture(capture.CreateChild(
"Entity"));
490 if (!global_pass_position.IsZero()) {
494 element_entity.SetTransform(
495 Matrix::MakeTranslation(Vector3(-global_pass_position)) *
496 element_entity.GetTransform());
498 return EntityPass::EntityResult::Success(std::move(element_entity));
505 else if (
const auto& subpass_ptr =
506 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
507 auto subpass = subpass_ptr->get();
509 if (subpass->delegate_->CanElide()) {
510 return EntityPass::EntityResult::Skip();
513 if (!subpass->backdrop_filter_proc_ &&
514 subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
515 auto subpass_capture = capture.CreateChild(
"EntityPass (Collapsed)");
517 if (!subpass->OnRender(
521 pass_context.GetPassTarget(),
522 global_pass_position,
528 pass_context.GetRenderPass(pass_depth)
532 return EntityPass::EntityResult::Failure();
534 return EntityPass::EntityResult::Skip();
537 std::shared_ptr<Contents> subpass_backdrop_filter_contents =
nullptr;
538 if (subpass->backdrop_filter_proc_) {
539 auto texture = pass_context.GetTexture();
541 const auto& proc = subpass->backdrop_filter_proc_;
542 subpass_backdrop_filter_contents =
543 proc(FilterInput::Make(std::move(texture)),
544 subpass->transform_.Basis(), Entity::RenderingMode::kSubpass);
552 pass_context.GetRenderPass(pass_depth);
557 pass_context.EndPass();
560 if (clip_coverage_stack.empty()) {
563 capture.CreateChild(
"Subpass Entity (Skipped: Empty clip A)");
564 return EntityPass::EntityResult::Skip();
566 auto clip_coverage_back = clip_coverage_stack.back().coverage;
567 if (!clip_coverage_back.has_value()) {
568 capture.CreateChild(
"Subpass Entity (Skipped: Empty clip B)");
569 return EntityPass::EntityResult::Skip();
574 auto coverage_limit = Rect::MakeOriginSize(global_pass_position,
575 Size(pass_context.GetPassTarget()
577 .GetRenderTargetSize()))
578 .Intersection(clip_coverage_back.value());
579 if (!coverage_limit.has_value()) {
580 capture.CreateChild(
"Subpass Entity (Skipped: Empty coverage limit A)");
581 return EntityPass::EntityResult::Skip();
585 coverage_limit->Intersection(Rect::MakeSize(root_pass_size));
586 if (!coverage_limit.has_value()) {
587 capture.CreateChild(
"Subpass Entity (Skipped: Empty coverage limit B)");
588 return EntityPass::EntityResult::Skip();
591 auto subpass_coverage =
592 (subpass->flood_clip_ || subpass_backdrop_filter_contents)
594 : GetSubpassCoverage(*subpass, coverage_limit);
595 if (!subpass_coverage.has_value()) {
596 capture.CreateChild(
"Subpass Entity (Skipped: Empty subpass coverage A)");
597 return EntityPass::EntityResult::Skip();
600 auto subpass_size =
ISize(subpass_coverage->GetSize());
601 if (subpass_size.IsEmpty()) {
602 capture.CreateChild(
"Subpass Entity (Skipped: Empty subpass coverage B)");
603 return EntityPass::EntityResult::Skip();
609 subpass->GetTotalPassReads(renderer) > 0,
610 subpass->GetClearColorOrDefault(subpass_size));
612 if (!subpass_target.IsValid()) {
614 return EntityPass::EntityResult::Failure();
617 auto subpass_capture = capture.CreateChild(
"EntityPass");
618 subpass_capture.AddRect(
"Coverage", *subpass_coverage, {.readonly =
true});
625 ClipCoverageStack subpass_clip_coverage_stack = {ClipCoverageLayer{
626 .coverage = subpass_coverage, .clip_depth = subpass->clip_depth_}};
630 if (!subpass->OnRender(
635 subpass_coverage->GetOrigin(),
636 subpass_coverage->GetOrigin() -
637 global_pass_position,
639 subpass_clip_coverage_stack,
640 subpass->clip_depth_,
641 subpass_backdrop_filter_contents
645 return EntityPass::EntityResult::Failure();
649 auto subpass_texture =
650 subpass_target.GetRenderTarget().GetRenderTargetTexture();
652 auto offscreen_texture_contents =
653 subpass->delegate_->CreateContentsForSubpassTarget(
655 Matrix::MakeTranslation(Vector3{-global_pass_position}) *
656 subpass->transform_);
658 if (!offscreen_texture_contents) {
667 return EntityPass::EntityResult::Failure();
669 Entity element_entity;
670 Capture subpass_texture_capture =
671 capture.CreateChild(
"Entity (Subpass texture)");
672 element_entity.SetCapture(subpass_texture_capture);
673 element_entity.SetContents(std::move(offscreen_texture_contents));
674 element_entity.SetClipDepth(subpass->clip_depth_);
675 element_entity.SetBlendMode(subpass->blend_mode_);
676 element_entity.SetTransform(subpass_texture_capture.AddMatrix(
678 Matrix::MakeTranslation(
679 Vector3(subpass_coverage->GetOrigin() - global_pass_position))));
681 return EntityPass::EntityResult::Success(std::move(element_entity));
687 bool EntityPass::RenderElement(Entity& element_entity,
688 size_t clip_depth_floor,
689 InlinePassContext& pass_context,
691 ContentContext& renderer,
692 ClipCoverageStack& clip_coverage_stack,
693 Point global_pass_position)
const {
694 auto result = pass_context.GetRenderPass(pass_depth);
707 if (result.backdrop_texture) {
708 auto size_rect = Rect::MakeSize(result.pass->GetRenderTargetSize());
709 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
710 msaa_backdrop_contents->SetStencilEnabled(
false);
711 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
712 msaa_backdrop_contents->SetSourceRect(size_rect);
713 msaa_backdrop_contents->SetTexture(result.backdrop_texture);
715 Entity msaa_backdrop_entity;
716 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
717 msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
718 if (!msaa_backdrop_entity.Render(renderer, *result.pass)) {
719 VALIDATION_LOG <<
"Failed to render MSAA backdrop filter entity.";
724 auto current_clip_coverage = clip_coverage_stack.back().coverage;
725 if (current_clip_coverage.has_value()) {
728 current_clip_coverage = current_clip_coverage->Shift(-global_pass_position);
731 if (!element_entity.ShouldRender(current_clip_coverage)) {
735 auto clip_coverage = element_entity.GetClipCoverage(current_clip_coverage);
736 if (clip_coverage.coverage.has_value()) {
737 clip_coverage.coverage =
738 clip_coverage.coverage->Shift(global_pass_position);
745 auto element_coverage_hint = element_entity.GetContents()->GetCoverageHint();
746 element_entity.GetContents()->SetCoverageHint(
747 Rect::Intersection(element_coverage_hint, current_clip_coverage));
749 switch (clip_coverage.type) {
750 case Contents::ClipCoverage::Type::kNoChange:
752 case Contents::ClipCoverage::Type::kAppend: {
753 auto op = clip_coverage_stack.back().coverage;
754 clip_coverage_stack.push_back(
755 ClipCoverageLayer{.coverage = clip_coverage.coverage,
756 .clip_depth = element_entity.GetClipDepth() + 1});
757 FML_DCHECK(clip_coverage_stack.back().clip_depth ==
758 clip_coverage_stack.front().clip_depth +
759 clip_coverage_stack.size() - 1);
761 if (!op.has_value()) {
768 if (clip_coverage_stack.back().clip_depth <=
769 element_entity.GetClipDepth()) {
774 auto restoration_index = element_entity.GetClipDepth() -
775 clip_coverage_stack.front().clip_depth;
776 FML_DCHECK(restoration_index < clip_coverage_stack.size());
780 std::optional<Rect> restore_coverage =
781 (restoration_index + 1 < clip_coverage_stack.size())
782 ? clip_coverage_stack[restoration_index + 1].coverage
784 if (restore_coverage.has_value()) {
786 restore_coverage = restore_coverage->Shift(-global_pass_position);
788 clip_coverage_stack.resize(restoration_index + 1);
790 if (!clip_coverage_stack.back().coverage.has_value()) {
795 auto restore_contents =
796 static_cast<ClipRestoreContents*
>(element_entity.GetContents().get());
797 restore_contents->SetRestoreCoverage(restore_coverage);
802 #ifdef IMPELLER_ENABLE_CAPTURE
804 auto element_entity_coverage = element_entity.GetCoverage();
805 if (element_entity_coverage.has_value()) {
806 element_entity_coverage =
807 element_entity_coverage->Shift(global_pass_position);
808 element_entity.GetCapture().AddRect(
"Coverage", *element_entity_coverage,
814 element_entity.SetClipDepth(element_entity.GetClipDepth() - clip_depth_floor);
815 if (!element_entity.Render(renderer, *result.pass)) {
822 bool EntityPass::OnRender(
823 ContentContext& renderer,
825 ISize root_pass_size,
826 EntityPassTarget& pass_target,
827 Point global_pass_position,
828 Point local_pass_position,
830 ClipCoverageStack& clip_coverage_stack,
831 size_t clip_depth_floor,
832 std::shared_ptr<Contents> backdrop_filter_contents,
833 const std::optional<InlinePassContext::RenderPassResult>&
834 collapsed_parent_pass)
const {
835 TRACE_EVENT0(
"impeller",
"EntityPass::OnRender");
837 auto context = renderer.GetContext();
838 InlinePassContext pass_context(context, pass_target,
839 GetTotalPassReads(renderer), GetElementCount(),
840 collapsed_parent_pass);
841 if (!pass_context.IsValid()) {
845 auto clear_color_size = pass_target.GetRenderTarget().GetRenderTargetSize();
847 if (!collapsed_parent_pass && GetClearColor(clear_color_size).has_value()) {
850 pass_context.GetRenderPass(pass_depth);
853 if (backdrop_filter_proc_) {
854 if (!backdrop_filter_contents) {
856 <<
"EntityPass contains a backdrop filter, but no backdrop filter "
857 "contents was supplied by the parent pass at render time. This is "
858 "a bug in EntityPass. Parent passes are responsible for setting "
859 "up backdrop filters for their children.";
863 Entity backdrop_entity;
864 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
865 backdrop_entity.SetTransform(
866 Matrix::MakeTranslation(Vector3(-local_pass_position)));
867 backdrop_entity.SetClipDepth(clip_depth_floor);
869 RenderElement(backdrop_entity, clip_depth_floor, pass_context, pass_depth,
870 renderer, clip_coverage_stack, global_pass_position);
873 bool is_collapsing_clear_colors = !collapsed_parent_pass &&
876 !backdrop_filter_proc_;
877 for (
const auto& element : elements_) {
879 if (is_collapsing_clear_colors) {
880 auto [entity_color, _] =
881 ElementAsBackgroundColor(element, clear_color_size);
882 if (entity_color.has_value()) {
885 is_collapsing_clear_colors =
false;
888 EntityResult result =
889 GetEntityForElement(element,
894 global_pass_position,
899 switch (result.status) {
900 case EntityResult::kSuccess:
902 case EntityResult::kFailure:
906 case EntityResult::kSkip:
914 if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
915 if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
916 auto src_contents = result.entity.GetContents();
917 auto contents = std::make_shared<FramebufferBlendContents>();
918 contents->SetChildContents(src_contents);
919 contents->SetBlendMode(result.entity.GetBlendMode());
920 result.entity.SetContents(std::move(contents));
921 result.entity.SetBlendMode(BlendMode::kSource);
933 if (!pass_context.EndPass()) {
935 <<
"Failed to end the current render pass in order to read from "
936 "the backdrop texture and apply an advanced blend.";
942 auto texture = pass_context.GetTexture();
944 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
945 "apply an advanced blend.";
949 FilterInput::Vector inputs = {
950 FilterInput::Make(texture, result.entity.GetTransform().Invert()),
951 FilterInput::Make(result.entity.GetContents())};
952 auto contents = ColorFilterContents::MakeBlend(
953 result.entity.GetBlendMode(), inputs);
954 contents->SetCoverageHint(result.entity.GetCoverage());
955 result.entity.SetContents(std::move(contents));
956 result.entity.SetBlendMode(BlendMode::kSource);
963 if (!RenderElement(result.entity, clip_depth_floor, pass_context,
964 pass_depth, renderer, clip_coverage_stack,
965 global_pass_position)) {
971 #ifdef IMPELLER_DEBUG
978 if (enable_offscreen_debug_checkerboard_ &&
979 !collapsed_parent_pass.has_value() && pass_depth > 0) {
980 auto result = pass_context.GetRenderPass(pass_depth);
986 auto checkerboard = CheckerboardContents();
987 auto color = ColorHSB(0,
989 std::max(0.0, 0.6 - pass_depth / 5),
991 checkerboard.SetColor(Color(color));
992 checkerboard.Render(renderer, {}, *result.pass);
999 void EntityPass::IterateAllElements(
1000 const std::function<
bool(
Element&)>& iterator) {
1005 for (
auto& element : elements_) {
1006 if (!iterator(element)) {
1009 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1010 subpass->get()->IterateAllElements(iterator);
1015 void EntityPass::IterateAllEntities(
1016 const std::function<
bool(
Entity&)>& iterator) {
1021 for (
auto& element : elements_) {
1022 if (
auto entity = std::get_if<Entity>(&element)) {
1023 if (!iterator(*entity)) {
1028 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1029 subpass->get()->IterateAllEntities(iterator);
1036 void EntityPass::IterateAllEntities(
1037 const std::function<
bool(
const Entity&)>& iterator)
const {
1042 for (
const auto& element : elements_) {
1043 if (
auto entity = std::get_if<Entity>(&element)) {
1044 if (!iterator(*entity)) {
1049 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1050 const EntityPass* entity_pass = subpass->get();
1058 bool EntityPass::IterateUntilSubpass(
1059 const std::function<
bool(
Entity&)>& iterator) {
1064 for (
auto& element : elements_) {
1065 if (
auto entity = std::get_if<Entity>(&element)) {
1066 if (!iterator(*entity)) {
1076 size_t EntityPass::GetElementCount()
const {
1077 return elements_.size();
1080 std::unique_ptr<EntityPass> EntityPass::Clone()
const {
1081 std::vector<Element> new_elements;
1082 new_elements.reserve(elements_.size());
1084 for (
const auto& element : elements_) {
1085 if (
auto entity = std::get_if<Entity>(&element)) {
1086 new_elements.push_back(entity->Clone());
1089 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1090 new_elements.push_back(subpass->get()->Clone());
1096 auto pass = std::make_unique<EntityPass>();
1097 pass->SetElements(std::move(new_elements));
1098 pass->backdrop_filter_reads_from_pass_texture_ =
1099 backdrop_filter_reads_from_pass_texture_;
1100 pass->advanced_blend_reads_from_pass_texture_ =
1101 advanced_blend_reads_from_pass_texture_;
1102 pass->backdrop_filter_proc_ = backdrop_filter_proc_;
1103 pass->blend_mode_ = blend_mode_;
1104 pass->delegate_ = delegate_;
1111 void EntityPass::SetTransform(
Matrix transform) {
1112 transform_ = transform;
1115 void EntityPass::SetClipDepth(
size_t clip_depth) {
1116 clip_depth_ = clip_depth;
1119 size_t EntityPass::GetClipDepth() {
1124 blend_mode_ = blend_mode;
1125 flood_clip_ = Entity::IsBlendModeDestructive(blend_mode);
1129 return GetClearColor(size).value_or(Color::BlackTransparent());
1132 std::optional<Color> EntityPass::GetClearColor(
ISize target_size)
const {
1133 if (backdrop_filter_proc_) {
1134 return std::nullopt;
1137 std::optional<Color> result = std::nullopt;
1138 for (
const Element& element : elements_) {
1139 auto [entity_color, blend_mode] =
1140 ElementAsBackgroundColor(element, target_size);
1141 if (!entity_color.has_value()) {
1144 result = result.value_or(Color::BlackTransparent())
1145 .Blend(entity_color.value(), blend_mode);
1147 if (result.has_value()) {
1148 return result->Premultiply();
1155 VALIDATION_LOG <<
"Backdrop filters cannot be set on EntityPasses that "
1156 "have already been appended to another pass.";
1159 backdrop_filter_proc_ = std::move(proc);
1162 void EntityPass::SetEnableOffscreenCheckerboard(
bool enabled) {
1163 enable_offscreen_debug_checkerboard_ = enabled;