12 #include "flutter/fml/closure.h"
13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/trace_event.h"
33 #endif // IMPELLER_DEBUG
38 std::tuple<std::optional<Color>,
BlendMode> ElementAsBackgroundColor(
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()};
61 delegate_ = std::move(delegate);
66 bounds_limit_ = bounds_limit;
67 bounds_promise_ = bounds_limit.has_value() ? bounds_promise
76 switch (bounds_promise_) {
83 return bounds_limit_.has_value();
85 FML_DCHECK(bounds_limit_.has_value());
88 FML_DCHECK(bounds_limit_.has_value());
95 switch (bounds_promise_) {
100 FML_DCHECK(bounds_limit_.has_value());
113 advanced_blend_reads_from_pass_texture_ += 1;
115 elements_.emplace_back(std::move(entity));
119 elements_.emplace_back(std::move(entity));
120 active_clips_.emplace_back(elements_.size() - 1);
124 if (num_clips > active_clips_.size()) {
126 <<
"Attempted to pop more clips than are currently active. Active: "
127 << active_clips_.size() <<
", Popped: " << num_clips
128 <<
", Depth: " << depth;
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()]);
137 active_clips_.pop_back();
142 PopClips(active_clips_.size(), depth);
146 elements_ = std::move(elements);
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)) {
154 std::max(max_subpass_depth, subpass->get()->GetSubpassesDepth());
157 return max_subpass_depth + 1u;
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;
166 if (
auto entity = std::get_if<Entity>(&element)) {
167 element_coverage = entity->GetCoverage();
171 if (element_coverage.has_value() && coverage_limit.has_value()) {
172 const auto* filter = entity->GetContents()->AsFilter();
173 if (!filter || filter->IsTranslationOnly()) {
175 element_coverage->Intersection(coverage_limit.value());
178 }
else if (
auto subpass_ptr =
179 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
180 auto& subpass = *subpass_ptr->get();
182 std::optional<Rect> unfiltered_coverage =
188 if (accumulated_coverage.has_value() && subpass.backdrop_filter_proc_) {
189 std::shared_ptr<FilterContents> backdrop_filter =
190 subpass.backdrop_filter_proc_(
193 if (backdrop_filter) {
194 auto backdrop_coverage = backdrop_filter->GetCoverage({});
195 unfiltered_coverage =
196 Rect::Union(unfiltered_coverage, backdrop_coverage);
198 VALIDATION_LOG <<
"The EntityPass backdrop filter proc didn't return "
203 if (!unfiltered_coverage.has_value()) {
215 std::shared_ptr<FilterContents> image_filter =
216 subpass.delegate_->WithImageFilter(*unfiltered_coverage,
221 element_coverage = image_filter->GetCoverage(subpass_entity);
223 element_coverage = unfiltered_coverage;
231 accumulated_coverage =
Rect::Union(accumulated_coverage, element_coverage);
233 return accumulated_coverage;
238 std::optional<Rect> coverage_limit)
const {
240 return subpass.bounds_limit_->TransformBounds(subpass.transform_);
243 std::shared_ptr<FilterContents> image_filter =
244 subpass.delegate_->WithImageFilter(
Rect(), subpass.transform_);
249 if (image_filter && coverage_limit.has_value()) {
250 coverage_limit = image_filter->GetSourceCoverage(subpass.transform_,
251 coverage_limit.value());
256 if (!entities_coverage.has_value()) {
260 if (!subpass.bounds_limit_.has_value()) {
261 return entities_coverage;
263 auto user_bounds_coverage =
264 subpass.bounds_limit_->TransformBounds(subpass.transform_);
265 return entities_coverage->Intersection(user_bounds_coverage);
276 FML_DCHECK(pass->superpass_ ==
nullptr);
277 pass->superpass_ =
this;
279 if (pass->backdrop_filter_proc_) {
280 backdrop_filter_reads_from_pass_texture_ += 1;
283 advanced_blend_reads_from_pass_texture_ += 1;
286 auto subpass_pointer = pass.get();
287 elements_.emplace_back(std::move(pass));
288 return subpass_pointer;
295 FML_DCHECK(pass->superpass_ ==
nullptr);
297 std::vector<Element>& elements = pass->elements_;
298 for (
auto i = 0u; i < elements.size(); i++) {
299 elements_.emplace_back(std::move(elements[i]));
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_;
318 const Color& clear_color) {
319 const std::shared_ptr<Context>& context = renderer.
GetContext();
333 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
345 .clear_color = clear_color},
358 .clear_color = clear_color,
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_;
382 fml::ScopedCleanupClosure reset_state([&renderer]() {
387 auto root_render_target = render_target;
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.";
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.";
401 capture.AddRect(
"Coverage",
408 contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
416 bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
420 if (reads_from_onscreen_backdrop) {
422 renderer, root_render_target.GetRenderTargetSize(),
426 if (!OnRender(renderer,
441 auto command_buffer = renderer.
GetContext()->CreateCommandBuffer();
442 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
449 ->SupportsTextureToTextureBlits()) {
450 auto blit_pass = command_buffer->CreateBlitPass();
453 root_render_target.GetRenderTargetTexture());
454 if (!blit_pass->EncodeCommands(
455 renderer.
GetContext()->GetResourceAllocator())) {
461 ->Submit({command_buffer})
466 auto render_pass = command_buffer->CreateRenderPass(root_render_target);
467 render_pass->SetLabel(
"EntityPass Root Render Pass");
473 contents->SetTexture(
475 contents->SetSourceRect(size_rect);
476 contents->SetLabel(
"Root pass blit");
482 if (!entity.
Render(renderer, *render_pass)) {
488 if (!render_pass->EncodeCommands()) {
494 ->Submit({command_buffer})
508 auto color0 = root_render_target.GetColorAttachments().find(0u)->second;
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()) {
515 root_render_target.SetupDepthStencilAttachments(
517 color0.texture->GetSize(),
518 renderer.
GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
525 root_render_target.SetColorAttachment(color0, 0);
535 root_render_target.GetRenderTargetSize(),
543 EntityPass::EntityResult EntityPass::GetEntityForElement(
548 ISize root_pass_size,
549 Point global_pass_position,
552 size_t clip_depth_floor)
const {
556 if (
const auto& entity = std::get_if<Entity>(&element)) {
560 if (!global_pass_position.
IsZero()) {
568 return EntityPass::EntityResult::Success(std::move(element_entity));
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();
581 if (!subpass->backdrop_filter_proc_ &&
582 subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
583 auto subpass_capture = capture.
CreateChild(
"EntityPass (Collapsed)");
585 if (!subpass->OnRender(
590 global_pass_position,
600 return EntityPass::EntityResult::Failure();
602 return EntityPass::EntityResult::Skip();
605 std::shared_ptr<Contents> subpass_backdrop_filter_contents =
nullptr;
606 if (subpass->backdrop_filter_proc_) {
609 const auto& proc = subpass->backdrop_filter_proc_;
610 subpass_backdrop_filter_contents =
631 capture.
CreateChild(
"Subpass Entity (Skipped: Empty clip A)");
632 return EntityPass::EntityResult::Skip();
635 if (!clip_coverage_back.has_value()) {
636 capture.
CreateChild(
"Subpass Entity (Skipped: Empty clip B)");
637 return EntityPass::EntityResult::Skip();
647 if (!coverage_limit.has_value()) {
648 capture.
CreateChild(
"Subpass Entity (Skipped: Empty coverage limit A)");
649 return EntityPass::EntityResult::Skip();
654 if (!coverage_limit.has_value()) {
655 capture.
CreateChild(
"Subpass Entity (Skipped: Empty coverage limit B)");
656 return EntityPass::EntityResult::Skip();
659 auto subpass_coverage =
660 (subpass->flood_clip_ || subpass_backdrop_filter_contents)
663 if (!subpass_coverage.has_value()) {
664 capture.
CreateChild(
"Subpass Entity (Skipped: Empty subpass coverage A)");
665 return EntityPass::EntityResult::Skip();
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();
677 subpass->GetRequiredMipCount(),
678 subpass->GetClearColorOrDefault(subpass_size));
680 if (!subpass_target.IsValid()) {
682 return EntityPass::EntityResult::Failure();
685 auto subpass_capture = capture.
CreateChild(
"EntityPass");
686 subpass_capture.AddRect(
"Coverage", *subpass_coverage, {.readonly =
true});
693 clip_coverage_stack.
PushSubpass(subpass_coverage, subpass->clip_depth_);
697 if (!subpass->OnRender(
702 subpass_coverage->GetOrigin(),
703 subpass_coverage->GetOrigin() -
704 global_pass_position,
707 subpass->clip_depth_,
708 subpass_backdrop_filter_contents
712 return EntityPass::EntityResult::Failure();
718 auto subpass_texture =
719 subpass_target.GetRenderTarget().GetRenderTargetTexture();
721 auto offscreen_texture_contents =
722 subpass->delegate_->CreateContentsForSubpassTarget(
725 subpass->transform_);
727 if (!offscreen_texture_contents) {
736 return EntityPass::EntityResult::Failure();
738 Entity element_entity;
739 Capture subpass_texture_capture =
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(
749 Vector3(subpass_coverage->GetOrigin() - global_pass_position))));
751 return EntityPass::EntityResult::Success(std::move(element_entity));
758 Point global_pass_position) {
765 if (clip_coverage.has_value()) {
766 clip_coverage = clip_coverage->
Shift(-global_pass_position);
775 bool EntityPass::RenderElement(Entity& element_entity,
776 size_t clip_depth_floor,
777 InlinePassContext& pass_context,
779 ContentContext& renderer,
780 EntityPassClipStack& clip_coverage_stack,
781 Point global_pass_position)
const {
782 auto result = pass_context.GetRenderPass(pass_depth);
795 if (result.backdrop_texture) {
796 auto size_rect =
Rect::MakeSize(result.pass->GetRenderTargetSize());
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);
803 Entity msaa_backdrop_entity;
804 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
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.";
813 if (result.just_created) {
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)) {
826 auto current_clip_coverage = clip_coverage_stack.CurrentClipCoverage();
827 if (current_clip_coverage.has_value()) {
830 current_clip_coverage = current_clip_coverage->Shift(-global_pass_position);
833 if (!element_entity.ShouldRender(current_clip_coverage)) {
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);
847 auto element_coverage_hint = element_entity.GetContents()->GetCoverageHint();
848 element_entity.GetContents()->SetCoverageHint(
851 EntityPassClipStack::ClipStateResult clip_state_result =
852 clip_coverage_stack.ApplyClipState(clip_coverage, element_entity,
854 global_pass_position);
856 if (clip_state_result.clip_did_change) {
858 SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
859 global_pass_position);
862 if (!clip_state_result.should_render) {
866 if (!element_entity.Render(renderer, *result.pass)) {
873 bool EntityPass::OnRender(
874 ContentContext& renderer,
876 ISize root_pass_size,
877 EntityPassTarget& pass_target,
878 Point global_pass_position,
879 Point local_pass_position,
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");
888 if (!active_clips_.empty()) {
890 "EntityPass (Depth=%d) contains one or more clips with an unresolved "
895 InlinePassContext pass_context(renderer, pass_target,
897 collapsed_parent_pass);
898 if (!pass_context.IsValid()) {
902 auto clear_color_size = pass_target.GetRenderTarget().GetRenderTargetSize();
904 if (!collapsed_parent_pass) {
908 pass_context.GetRenderPass(pass_depth);
911 if (backdrop_filter_proc_) {
912 if (!backdrop_filter_contents) {
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.";
921 Entity backdrop_entity;
922 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
923 backdrop_entity.SetTransform(
925 backdrop_entity.SetClipDepth(clip_depth_floor);
926 backdrop_entity.SetNewClipDepth(std::numeric_limits<uint32_t>::max());
928 RenderElement(backdrop_entity, clip_depth_floor, pass_context, pass_depth,
929 renderer, clip_coverage_stack, global_pass_position);
932 bool is_collapsing_clear_colors = !collapsed_parent_pass &&
935 !backdrop_filter_proc_;
936 for (
const auto& element : elements_) {
938 if (is_collapsing_clear_colors) {
939 auto [entity_color, _] =
940 ElementAsBackgroundColor(element, clear_color_size);
941 if (entity_color.has_value()) {
944 is_collapsing_clear_colors =
false;
947 EntityResult result =
948 GetEntityForElement(element,
953 global_pass_position,
958 switch (result.status) {
959 case EntityResult::kSuccess:
961 case EntityResult::kFailure:
965 case EntityResult::kSkip:
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));
992 if (!pass_context.EndPass()) {
994 <<
"Failed to end the current render pass in order to read from "
995 "the backdrop texture and apply an advanced blend.";
1001 auto texture = pass_context.GetTexture();
1003 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
1004 "apply an advanced blend.";
1012 result.entity.GetBlendMode(), inputs);
1013 contents->SetCoverageHint(result.entity.GetCoverage());
1014 result.entity.SetContents(std::move(contents));
1022 if (!RenderElement(result.entity, clip_depth_floor, pass_context,
1023 pass_depth, renderer, clip_coverage_stack,
1024 global_pass_position)) {
1030 #ifdef IMPELLER_DEBUG
1037 if (enable_offscreen_debug_checkerboard_ &&
1038 !collapsed_parent_pass.has_value() && pass_depth > 0) {
1039 auto result = pass_context.GetRenderPass(pass_depth);
1045 auto checkerboard = CheckerboardContents();
1046 auto color = ColorHSB(0,
1048 std::max(0.0, 0.6 - pass_depth / 5),
1050 checkerboard.SetColor(Color(color));
1051 checkerboard.Render(renderer, {}, *result.pass);
1059 const std::function<
bool(
Element&)>& iterator) {
1064 for (
auto& element : elements_) {
1065 if (!iterator(element)) {
1068 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1069 subpass->get()->IterateAllElements(iterator);
1075 const std::function<
bool(
const Element&)>& iterator)
const {
1082 for (
auto& element : elements_) {
1083 if (!iterator(element)) {
1086 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1087 const EntityPass* entity_pass = subpass->get();
1094 const std::function<
bool(
Entity&)>& iterator) {
1099 for (
auto& element : elements_) {
1100 if (
auto entity = std::get_if<Entity>(&element)) {
1101 if (!iterator(*entity)) {
1106 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1107 subpass->get()->IterateAllEntities(iterator);
1115 const std::function<
bool(
const Entity&)>& iterator)
const {
1120 for (
const auto& element : elements_) {
1121 if (
auto entity = std::get_if<Entity>(&element)) {
1122 if (!iterator(*entity)) {
1127 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1128 const EntityPass* entity_pass = subpass->get();
1137 const std::function<
bool(
Entity&)>& iterator) {
1142 for (
auto& element : elements_) {
1143 if (
auto entity = std::get_if<Entity>(&element)) {
1144 if (!iterator(*entity)) {
1155 return elements_.size();
1159 transform_ = transform;
1163 clip_depth_ = clip_depth;
1171 new_clip_depth_ = clip_depth;
1175 return new_clip_depth_;
1179 blend_mode_ = blend_mode;
1188 if (backdrop_filter_proc_) {
1189 return std::nullopt;
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()) {
1200 .Blend(entity_color.value(), blend_mode);
1202 if (result.has_value()) {
1203 return result->Premultiply();
1210 VALIDATION_LOG <<
"Backdrop filters cannot be set on EntityPasses that "
1211 "have already been appended to another pass.";
1214 backdrop_filter_proc_ = std::move(proc);
1218 enable_offscreen_debug_checkerboard_ = enabled;