13 #include "flutter/fml/closure.h"
14 #include "flutter/fml/logging.h"
15 #include "flutter/fml/macros.h"
16 #include "flutter/fml/trace_event.h"
38 #endif // IMPELLER_DEBUG
43 std::tuple<std::optional<Color>,
BlendMode> ElementAsBackgroundColor(
46 if (
const Entity* entity = std::get_if<Entity>(&element)) {
47 std::optional<Color> entity_color = entity->AsBackgroundColor(target_size);
48 if (entity_color.has_value()) {
49 return {entity_color.value(), entity->GetBlendMode()};
66 delegate_ = std::move(delegate);
70 bounds_limit_ = bounds_limit;
84 advanced_blend_reads_from_pass_texture_ += 1;
86 elements_.emplace_back(std::move(entity));
90 elements_ = std::move(elements);
94 size_t max_subpass_depth = 0u;
95 for (
const auto& element : elements_) {
96 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
98 std::max(max_subpass_depth, subpass->get()->GetSubpassesDepth());
101 return max_subpass_depth + 1u;
105 std::optional<Rect> coverage_limit)
const {
106 std::optional<Rect> result;
107 for (
const auto& element : elements_) {
108 std::optional<Rect> coverage;
110 if (
auto entity = std::get_if<Entity>(&element)) {
111 coverage = entity->GetCoverage();
115 if (coverage.has_value() && coverage_limit.has_value()) {
116 const auto* filter = entity->GetContents()->AsFilter();
117 if (!filter || filter->IsTranslationOnly()) {
118 coverage = coverage->Intersection(coverage_limit.value());
121 }
else if (
auto subpass_ptr =
122 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
123 auto& subpass = *subpass_ptr->get();
125 std::optional<Rect> unfiltered_coverage =
131 if (result.has_value() && subpass.backdrop_filter_proc_) {
132 std::shared_ptr<FilterContents> backdrop_filter =
136 if (backdrop_filter) {
137 auto backdrop_coverage = backdrop_filter->GetCoverage({});
138 backdrop_coverage->origin += result->origin;
139 if (backdrop_coverage.has_value()) {
140 if (unfiltered_coverage.has_value()) {
141 unfiltered_coverage = coverage->Union(*backdrop_coverage);
143 unfiltered_coverage = backdrop_coverage;
147 VALIDATION_LOG <<
"The EntityPass backdrop filter proc didn't return "
152 if (!unfiltered_coverage.has_value()) {
164 std::shared_ptr<FilterContents> image_filter =
165 subpass.delegate_->WithImageFilter(*unfiltered_coverage,
166 subpass.xformation_);
170 coverage = image_filter->GetCoverage(subpass_entity);
172 coverage = unfiltered_coverage;
175 if (coverage.has_value() && coverage_limit.has_value() &&
176 (!image_filter || image_filter->IsTranslationOnly())) {
177 coverage = coverage->Intersection(coverage_limit.value());
183 if (!result.has_value() && coverage.has_value()) {
187 if (!coverage.has_value()) {
190 result = result->Union(coverage.value());
197 std::optional<Rect> coverage_limit)
const {
198 std::shared_ptr<FilterContents> image_filter =
199 subpass.delegate_->WithImageFilter(
Rect(), subpass.xformation_);
205 (image_filter && !image_filter->IsTranslationOnly() ? std::nullopt
210 if (!entities_coverage.has_value()) {
214 if (!subpass.bounds_limit_.has_value()) {
215 return entities_coverage;
217 auto user_bounds_coverage =
218 subpass.bounds_limit_->TransformBounds(subpass.xformation_);
219 return entities_coverage->Intersection(user_bounds_coverage);
230 FML_DCHECK(pass->superpass_ ==
nullptr);
231 pass->superpass_ =
this;
233 if (pass->backdrop_filter_proc_) {
234 backdrop_filter_reads_from_pass_texture_ += 1;
237 advanced_blend_reads_from_pass_texture_ += 1;
240 auto subpass_pointer = pass.get();
241 elements_.emplace_back(std::move(pass));
242 return subpass_pointer;
249 FML_DCHECK(pass->superpass_ ==
nullptr);
251 elements_.insert(elements_.end(),
252 std::make_move_iterator(pass->elements_.begin()),
253 std::make_move_iterator(pass->elements_.end()));
255 backdrop_filter_reads_from_pass_texture_ +=
256 pass->backdrop_filter_reads_from_pass_texture_;
257 advanced_blend_reads_from_pass_texture_ +=
258 pass->advanced_blend_reads_from_pass_texture_;
273 const Color& clear_color) {
282 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
289 .storage_mode = StorageMode::kDeviceTransient,
290 .resolve_storage_mode = StorageMode::kDevicePrivate,
291 .load_action = LoadAction::kDontCare,
292 .store_action = StoreAction::kMultisampleResolve,
293 .clear_color = clear_color},
303 .storage_mode = StorageMode::kDevicePrivate,
304 .load_action = LoadAction::kDontCare,
305 .store_action = StoreAction::kDontCare,
306 .clear_color = clear_color,
316 uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer)
const {
317 return renderer.GetDeviceCapabilities().SupportsFramebufferFetch()
318 ? backdrop_filter_reads_from_pass_texture_
319 : backdrop_filter_reads_from_pass_texture_ +
320 advanced_blend_reads_from_pass_texture_;
330 auto root_render_target = render_target;
332 if (root_render_target.GetColorAttachments().find(0u) ==
333 root_render_target.GetColorAttachments().end()) {
334 VALIDATION_LOG <<
"The root RenderTarget must have a color attachment.";
338 capture.AddRect(
"Coverage",
342 fml::ScopedCleanupClosure reset_state([&renderer]() {
349 if (auto contents = entity.GetContents()) {
350 contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
355 StencilCoverageStack stencil_coverage_stack = {StencilCoverageLayer{
356 .coverage =
Rect::MakeSize(root_render_target.GetRenderTargetSize()),
357 .stencil_depth = 0}};
359 bool supports_onscreen_backdrop_reads =
360 renderer.GetDeviceCapabilities().SupportsReadFromOnscreenTexture() &&
363 renderer.GetDeviceCapabilities().SupportsReadFromResolve();
364 bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
368 if (!supports_onscreen_backdrop_reads && reads_from_onscreen_backdrop) {
370 renderer, root_render_target.GetRenderTargetSize(),
true,
371 GetClearColor(render_target.GetRenderTargetSize()));
373 if (!OnRender(renderer,
375 offscreen_target.GetRenderTarget()
376 .GetRenderTargetSize(),
381 stencil_coverage_stack
388 auto command_buffer = renderer.GetContext()->CreateCommandBuffer();
389 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
394 if (renderer.GetContext()
396 ->SupportsTextureToTextureBlits()) {
397 auto blit_pass = command_buffer->CreateBlitPass();
399 offscreen_target.GetRenderTarget().GetRenderTargetTexture(),
400 root_render_target.GetRenderTargetTexture());
402 if (!blit_pass->EncodeCommands(
403 renderer.GetContext()->GetResourceAllocator())) {
408 auto render_pass = command_buffer->CreateRenderPass(root_render_target);
409 render_pass->SetLabel(
"EntityPass Root Render Pass");
413 offscreen_target.GetRenderTarget().GetRenderTargetSize());
415 contents->SetTexture(
416 offscreen_target.GetRenderTarget().GetRenderTargetTexture());
417 contents->SetSourceRect(size_rect);
418 contents->SetLabel(
"Root pass blit");
421 entity.SetContents(contents);
424 entity.Render(renderer, *render_pass);
427 if (!render_pass->EncodeCommands()) {
432 if (!command_buffer->SubmitCommands()) {
445 auto color0 = root_render_target.GetColorAttachments().find(0u)->second;
449 auto stencil_attachment = root_render_target.GetStencilAttachment();
450 if (stencil_attachment.has_value()) {
451 auto stencil_texture = stencil_attachment->texture;
452 if (!stencil_texture) {
453 VALIDATION_LOG <<
"The root RenderTarget must have a stencil texture.";
457 auto stencil_storage_mode =
458 stencil_texture->GetTextureDescriptor().storage_mode;
459 if (reads_from_onscreen_backdrop &&
461 VALIDATION_LOG <<
"The given root RenderTarget stencil needs to be read, "
462 "but it's marked as transient.";
469 root_render_target.SetupStencilAttachment(
470 *renderer.GetContext(), *renderer.GetRenderTargetCache(),
471 color0.texture->GetSize(),
472 renderer.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
478 color0.clear_color = GetClearColor(render_target.GetRenderTargetSize());
479 root_render_target.SetColorAttachment(color0, 0);
481 EntityPassTarget pass_target(
483 renderer.GetDeviceCapabilities().SupportsReadFromResolve());
488 root_render_target.GetRenderTargetSize(),
493 stencil_coverage_stack);
496 EntityPass::EntityResult EntityPass::GetEntityForElement(
497 const EntityPass::Element& element,
498 ContentContext& renderer,
500 InlinePassContext& pass_context,
501 ISize root_pass_size,
502 Point global_pass_position,
504 StencilCoverageStack& stencil_coverage_stack,
505 size_t stencil_depth_floor)
const {
506 Entity element_entity;
512 if (
const auto& entity = std::get_if<Entity>(&element)) {
513 element_entity = *entity;
514 element_entity.SetCapture(capture.CreateChild(
"Entity"));
515 if (!global_pass_position.IsZero()) {
519 element_entity.SetTransformation(
520 Matrix::MakeTranslation(Vector3(-global_pass_position)) *
521 element_entity.GetTransformation());
529 else if (
const auto& subpass_ptr =
530 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
531 auto subpass = subpass_ptr->get();
533 if (subpass->delegate_->CanElide()) {
534 return EntityPass::EntityResult::Skip();
537 if (!subpass->backdrop_filter_proc_ &&
538 subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
539 auto subpass_capture = capture.CreateChild(
"EntityPass (Collapsed)");
541 if (!subpass->OnRender(
545 pass_context.GetPassTarget(),
546 global_pass_position,
549 stencil_coverage_stack,
552 pass_context.GetRenderPass(pass_depth)
556 return EntityPass::EntityResult::Failure();
558 return EntityPass::EntityResult::Skip();
561 std::shared_ptr<Contents> subpass_backdrop_filter_contents =
nullptr;
562 if (subpass->backdrop_filter_proc_) {
563 auto texture = pass_context.GetTexture();
565 const auto& proc = subpass->backdrop_filter_proc_;
566 subpass_backdrop_filter_contents =
567 proc(FilterInput::Make(std::move(texture)),
568 subpass->xformation_.Basis(), Entity::RenderingMode::kSubpass);
576 pass_context.GetRenderPass(pass_depth);
581 pass_context.EndPass();
584 if (stencil_coverage_stack.empty()) {
587 capture.CreateChild(
"Subpass Entity (Skipped: Empty clip A)");
588 return EntityPass::EntityResult::Skip();
590 auto stencil_coverage_back = stencil_coverage_stack.back().coverage;
591 if (!stencil_coverage_back.has_value()) {
592 capture.CreateChild(
"Subpass Entity (Skipped: Empty clip B)");
593 return EntityPass::EntityResult::Skip();
598 auto coverage_limit =
599 Rect(global_pass_position,
Size(pass_context.GetPassTarget()
601 .GetRenderTargetSize()))
603 if (!coverage_limit.has_value()) {
604 capture.CreateChild(
"Subpass Entity (Skipped: Empty coverage limit A)");
605 return EntityPass::EntityResult::Skip();
609 coverage_limit->Intersection(Rect::MakeSize(root_pass_size));
610 if (!coverage_limit.has_value()) {
611 capture.CreateChild(
"Subpass Entity (Skipped: Empty coverage limit B)");
612 return EntityPass::EntityResult::Skip();
615 auto subpass_coverage =
616 (subpass->flood_clip_ || subpass_backdrop_filter_contents)
618 : GetSubpassCoverage(*subpass, coverage_limit);
619 if (!subpass_coverage.has_value()) {
620 capture.CreateChild(
"Subpass Entity (Skipped: Empty subpass coverage A)");
621 return EntityPass::EntityResult::Skip();
624 auto subpass_size =
ISize(subpass_coverage->size);
625 if (subpass_size.IsEmpty()) {
626 capture.CreateChild(
"Subpass Entity (Skipped: Empty subpass coverage B)");
627 return EntityPass::EntityResult::Skip();
633 subpass->GetTotalPassReads(renderer) > 0,
634 subpass->GetClearColor(subpass_size));
636 if (!subpass_target.IsValid()) {
638 return EntityPass::EntityResult::Failure();
641 auto subpass_capture = capture.CreateChild(
"EntityPass");
642 subpass_capture.AddRect(
"Coverage", *subpass_coverage, {.readonly =
true});
646 if (!subpass->OnRender(
651 subpass_coverage->origin,
652 subpass_coverage->origin -
653 global_pass_position,
655 stencil_coverage_stack,
656 subpass->stencil_depth_,
657 subpass_backdrop_filter_contents
661 return EntityPass::EntityResult::Failure();
665 auto subpass_texture =
666 subpass_target.GetRenderTarget().GetRenderTargetTexture();
668 auto offscreen_texture_contents =
669 subpass->delegate_->CreateContentsForSubpassTarget(
671 Matrix::MakeTranslation(Vector3{-global_pass_position}) *
672 subpass->xformation_);
674 if (!offscreen_texture_contents) {
683 return EntityPass::EntityResult::Failure();
685 Capture subpass_texture_capture =
686 capture.CreateChild(
"Entity (Subpass texture)");
687 element_entity.SetCapture(subpass_texture_capture);
688 element_entity.SetContents(std::move(offscreen_texture_contents));
689 element_entity.SetStencilDepth(subpass->stencil_depth_);
690 element_entity.SetBlendMode(subpass->blend_mode_);
691 element_entity.SetTransformation(subpass_texture_capture.AddMatrix(
692 "Transform", Matrix::MakeTranslation(Vector3(subpass_coverage->origin -
693 global_pass_position))));
698 return EntityPass::EntityResult::Success(element_entity);
701 bool EntityPass::OnRender(
702 ContentContext& renderer,
704 ISize root_pass_size,
705 EntityPassTarget& pass_target,
706 Point global_pass_position,
707 Point local_pass_position,
709 StencilCoverageStack& stencil_coverage_stack,
710 size_t stencil_depth_floor,
711 std::shared_ptr<Contents> backdrop_filter_contents,
712 const std::optional<InlinePassContext::RenderPassResult>&
713 collapsed_parent_pass)
const {
714 TRACE_EVENT0(
"impeller",
"EntityPass::OnRender");
716 auto context = renderer.GetContext();
717 InlinePassContext pass_context(
718 context, pass_target, GetTotalPassReads(renderer), collapsed_parent_pass);
719 if (!pass_context.IsValid()) {
723 auto clear_color_size = pass_target.GetRenderTarget().GetRenderTargetSize();
725 if (!collapsed_parent_pass &&
726 !GetClearColor(clear_color_size).IsTransparent()) {
729 pass_context.GetRenderPass(pass_depth);
732 auto render_element = [&stencil_depth_floor, &pass_context, &pass_depth,
733 &renderer, &stencil_coverage_stack,
734 &global_pass_position](Entity& element_entity) {
735 auto result = pass_context.GetRenderPass(pass_depth);
749 if (result.backdrop_texture) {
750 auto size_rect = Rect::MakeSize(result.pass->GetRenderTargetSize());
751 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
752 msaa_backdrop_contents->SetStencilEnabled(
false);
753 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
754 msaa_backdrop_contents->SetSourceRect(size_rect);
755 msaa_backdrop_contents->SetTexture(result.backdrop_texture);
757 Entity msaa_backdrop_entity;
758 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
759 msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
760 if (!msaa_backdrop_entity.Render(renderer, *result.pass)) {
761 VALIDATION_LOG <<
"Failed to render MSAA backdrop filter entity.";
766 auto current_stencil_coverage = stencil_coverage_stack.back().coverage;
767 if (current_stencil_coverage.has_value()) {
770 current_stencil_coverage->origin -= global_pass_position;
773 if (!element_entity.ShouldRender(current_stencil_coverage)) {
777 auto stencil_coverage =
778 element_entity.GetStencilCoverage(current_stencil_coverage);
779 if (stencil_coverage.coverage.has_value()) {
780 stencil_coverage.coverage->origin += global_pass_position;
787 if (element_entity.GetContents()->GetCoverageHint().has_value()) {
791 element_entity.GetContents()->SetCoverageHint(
792 current_stencil_coverage->Intersection(
793 element_entity.GetContents()->GetCoverageHint().value()));
795 element_entity.GetContents()->SetCoverageHint(current_stencil_coverage);
798 switch (stencil_coverage.type) {
799 case Contents::StencilCoverage::Type::kNoChange:
801 case Contents::StencilCoverage::Type::kAppend: {
802 auto op = stencil_coverage_stack.back().coverage;
803 stencil_coverage_stack.push_back(StencilCoverageLayer{
804 .coverage = stencil_coverage.coverage,
805 .stencil_depth = element_entity.GetStencilDepth() + 1});
806 FML_DCHECK(stencil_coverage_stack.back().stencil_depth ==
807 stencil_coverage_stack.size() - 1);
809 if (!op.has_value()) {
815 case Contents::StencilCoverage::Type::kRestore: {
816 if (stencil_coverage_stack.back().stencil_depth <=
817 element_entity.GetStencilDepth()) {
822 auto restoration_depth = element_entity.GetStencilDepth();
823 FML_DCHECK(restoration_depth < stencil_coverage_stack.size());
827 std::optional<Rect> restore_coverage =
828 (restoration_depth + 1 < stencil_coverage_stack.size())
829 ? stencil_coverage_stack[restoration_depth + 1].coverage
831 if (restore_coverage.has_value()) {
833 restore_coverage->origin -= global_pass_position;
835 stencil_coverage_stack.resize(restoration_depth + 1);
837 if (!stencil_coverage_stack.back().coverage.has_value()) {
842 auto restore_contents =
static_cast<ClipRestoreContents*
>(
843 element_entity.GetContents().get());
844 restore_contents->SetRestoreCoverage(restore_coverage);
849 #ifdef IMPELLER_ENABLE_CAPTURE
851 auto element_entity_coverage = element_entity.GetCoverage();
852 if (element_entity_coverage.has_value()) {
853 element_entity_coverage->origin += global_pass_position;
854 element_entity.GetCapture().AddRect(
855 "Coverage", *element_entity_coverage, {.readonly =
true});
860 element_entity.SetStencilDepth(element_entity.GetStencilDepth() -
861 stencil_depth_floor);
862 if (!element_entity.Render(renderer, *result.pass)) {
869 if (backdrop_filter_proc_) {
870 if (!backdrop_filter_contents) {
872 <<
"EntityPass contains a backdrop filter, but no backdrop filter "
873 "contents was supplied by the parent pass at render time. This is "
874 "a bug in EntityPass. Parent passes are responsible for setting "
875 "up backdrop filters for their children.";
879 Entity backdrop_entity;
880 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
881 backdrop_entity.SetTransformation(
882 Matrix::MakeTranslation(Vector3(-local_pass_position)));
883 backdrop_entity.SetStencilDepth(stencil_depth_floor);
885 render_element(backdrop_entity);
888 bool is_collapsing_clear_colors = !collapsed_parent_pass &&
891 !backdrop_filter_proc_;
892 for (
const auto& element : elements_) {
894 if (is_collapsing_clear_colors) {
895 auto [entity_color, _] =
896 ElementAsBackgroundColor(element, clear_color_size);
897 if (entity_color.has_value()) {
900 is_collapsing_clear_colors =
false;
903 EntityResult result =
904 GetEntityForElement(element,
909 global_pass_position,
911 stencil_coverage_stack,
912 stencil_depth_floor);
914 switch (result.status) {
915 case EntityResult::kSuccess:
917 case EntityResult::kFailure:
921 case EntityResult::kSkip:
929 if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
930 if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
931 auto src_contents = result.entity.GetContents();
932 auto contents = std::make_shared<FramebufferBlendContents>();
933 contents->SetChildContents(src_contents);
934 contents->SetBlendMode(result.entity.GetBlendMode());
935 result.entity.SetContents(std::move(contents));
936 result.entity.SetBlendMode(BlendMode::kSource);
948 if (!pass_context.EndPass()) {
950 <<
"Failed to end the current render pass in order to read from "
951 "the backdrop texture and apply an advanced blend.";
957 auto texture = pass_context.GetTexture();
959 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
960 "apply an advanced blend.";
964 FilterInput::Vector inputs = {
965 FilterInput::Make(texture,
966 result.entity.GetTransformation().Invert()),
967 FilterInput::Make(result.entity.GetContents())};
968 auto contents = ColorFilterContents::MakeBlend(
969 result.entity.GetBlendMode(), inputs);
970 contents->SetCoverageHint(result.entity.GetCoverage());
971 result.entity.SetContents(std::move(contents));
972 result.entity.SetBlendMode(BlendMode::kSource);
980 if (!render_element(result.entity)) {
986 #ifdef IMPELLER_DEBUG
993 if (enable_offscreen_debug_checkerboard_ &&
994 !collapsed_parent_pass.has_value() && pass_depth > 0) {
995 auto result = pass_context.GetRenderPass(pass_depth);
1001 auto checkerboard = CheckerboardContents();
1002 auto color = ColorHSB(0,
1004 std::max(0.0, 0.6 - pass_depth / 5),
1006 checkerboard.SetColor(Color(color));
1007 checkerboard.Render(renderer, {}, *result.pass);
1014 void EntityPass::IterateAllElements(
1015 const std::function<
bool(
Element&)>& iterator) {
1020 for (
auto& element : elements_) {
1021 if (!iterator(element)) {
1024 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1025 subpass->get()->IterateAllElements(iterator);
1030 void EntityPass::IterateAllEntities(
1031 const std::function<
bool(
Entity&)>& iterator) {
1036 for (
auto& element : elements_) {
1037 if (
auto entity = std::get_if<Entity>(&element)) {
1038 if (!iterator(*entity)) {
1043 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1044 subpass->get()->IterateAllEntities(iterator);
1051 void EntityPass::IterateAllEntities(
1052 const std::function<
bool(
const Entity&)>& iterator)
const {
1057 for (
const auto& element : elements_) {
1058 if (
auto entity = std::get_if<Entity>(&element)) {
1059 if (!iterator(*entity)) {
1064 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1065 const EntityPass* entity_pass = subpass->get();
1073 bool EntityPass::IterateUntilSubpass(
1074 const std::function<
bool(
Entity&)>& iterator) {
1079 for (
auto& element : elements_) {
1080 if (
auto entity = std::get_if<Entity>(&element)) {
1081 if (!iterator(*entity)) {
1091 size_t EntityPass::GetElementCount()
const {
1092 return elements_.size();
1095 std::unique_ptr<EntityPass> EntityPass::Clone()
const {
1096 std::vector<Element> new_elements;
1097 new_elements.reserve(elements_.size());
1099 for (
const auto& element : elements_) {
1100 if (
auto entity = std::get_if<Entity>(&element)) {
1101 new_elements.push_back(*entity);
1104 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1105 new_elements.push_back(subpass->get()->Clone());
1111 auto pass = std::make_unique<EntityPass>();
1112 pass->SetElements(std::move(new_elements));
1113 pass->backdrop_filter_reads_from_pass_texture_ =
1114 backdrop_filter_reads_from_pass_texture_;
1115 pass->advanced_blend_reads_from_pass_texture_ =
1116 advanced_blend_reads_from_pass_texture_;
1117 pass->backdrop_filter_proc_ = backdrop_filter_proc_;
1118 pass->blend_mode_ = blend_mode_;
1119 pass->delegate_ = delegate_;
1126 void EntityPass::SetTransformation(
Matrix xformation) {
1127 xformation_ = xformation;
1130 void EntityPass::SetStencilDepth(
size_t stencil_depth) {
1131 stencil_depth_ = stencil_depth;
1134 size_t EntityPass::GetStencilDepth() {
1135 return stencil_depth_;
1139 blend_mode_ = blend_mode;
1140 flood_clip_ = Entity::IsBlendModeDestructive(blend_mode);
1144 Color result = Color::BlackTransparent();
1145 if (backdrop_filter_proc_) {
1149 for (
const Element& element : elements_) {
1150 auto [entity_color, blend_mode] =
1151 ElementAsBackgroundColor(element, target_size);
1152 if (!entity_color.has_value()) {
1155 result = result.
Blend(entity_color.value(), blend_mode);
1162 VALIDATION_LOG <<
"Backdrop filters cannot be set on EntityPasses that "
1163 "have already been appended to another pass.";
1166 backdrop_filter_proc_ = std::move(proc);
1169 void EntityPass::SetEnableOffscreenCheckerboard(
bool enabled) {
1170 enable_offscreen_debug_checkerboard_ = enabled;