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();
751 Point subpass_texture_position =
752 (subpass_coverage->GetOrigin() - global_pass_position).Round();
754 Entity element_entity;
755 Capture subpass_texture_capture =
757 element_entity.SetNewClipDepth(subpass->new_clip_depth_);
758 element_entity.SetCapture(subpass_texture_capture);
759 element_entity.SetContents(std::move(offscreen_texture_contents));
760 element_entity.SetClipDepth(subpass->clip_depth_);
761 element_entity.SetBlendMode(subpass->blend_mode_);
762 element_entity.SetTransform(
765 return EntityPass::EntityResult::Success(std::move(element_entity));
772 Point global_pass_position) {
779 if (clip_coverage.has_value()) {
780 clip_coverage = clip_coverage->
Shift(-global_pass_position);
789 bool EntityPass::RenderElement(Entity& element_entity,
790 size_t clip_depth_floor,
791 InlinePassContext& pass_context,
793 ContentContext& renderer,
794 EntityPassClipStack& clip_coverage_stack,
795 Point global_pass_position)
const {
796 auto result = pass_context.GetRenderPass(pass_depth);
809 if (result.backdrop_texture) {
810 auto size_rect =
Rect::MakeSize(result.pass->GetRenderTargetSize());
812 msaa_backdrop_contents->SetStencilEnabled(
false);
813 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
814 msaa_backdrop_contents->SetSourceRect(size_rect);
815 msaa_backdrop_contents->SetTexture(result.backdrop_texture);
817 Entity msaa_backdrop_entity;
818 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
820 msaa_backdrop_entity.SetNewClipDepth(std::numeric_limits<uint32_t>::max());
821 if (!msaa_backdrop_entity.Render(renderer, *result.pass)) {
822 VALIDATION_LOG <<
"Failed to render MSAA backdrop filter entity.";
827 if (result.just_created) {
830 auto& replay_entities = clip_coverage_stack.GetReplayEntities();
831 for (
const auto& replay : replay_entities) {
832 SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
833 global_pass_position);
834 if (!replay.entity.Render(renderer, *result.pass)) {
840 auto current_clip_coverage = clip_coverage_stack.CurrentClipCoverage();
841 if (current_clip_coverage.has_value()) {
844 current_clip_coverage = current_clip_coverage->Shift(-global_pass_position);
847 if (!element_entity.ShouldRender(current_clip_coverage)) {
851 auto clip_coverage = element_entity.GetClipCoverage(current_clip_coverage);
852 if (clip_coverage.coverage.has_value()) {
853 clip_coverage.coverage =
854 clip_coverage.coverage->Shift(global_pass_position);
861 auto element_coverage_hint = element_entity.GetContents()->GetCoverageHint();
862 element_entity.GetContents()->SetCoverageHint(
865 EntityPassClipStack::ClipStateResult clip_state_result =
866 clip_coverage_stack.ApplyClipState(clip_coverage, element_entity,
868 global_pass_position);
870 if (clip_state_result.clip_did_change) {
872 SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
873 global_pass_position);
876 if (!clip_state_result.should_render) {
880 if (!element_entity.Render(renderer, *result.pass)) {
887 bool EntityPass::OnRender(
888 ContentContext& renderer,
890 ISize root_pass_size,
891 EntityPassTarget& pass_target,
892 Point global_pass_position,
893 Point local_pass_position,
895 EntityPassClipStack& clip_coverage_stack,
896 size_t clip_depth_floor,
897 std::shared_ptr<Contents> backdrop_filter_contents,
898 const std::optional<InlinePassContext::RenderPassResult>&
899 collapsed_parent_pass)
const {
900 TRACE_EVENT0(
"impeller",
"EntityPass::OnRender");
902 if (!active_clips_.empty()) {
904 "EntityPass (Depth=%d) contains one or more clips with an unresolved "
909 InlinePassContext pass_context(renderer, pass_target,
911 collapsed_parent_pass);
912 if (!pass_context.IsValid()) {
916 auto clear_color_size = pass_target.GetRenderTarget().GetRenderTargetSize();
918 if (!collapsed_parent_pass) {
922 pass_context.GetRenderPass(pass_depth);
925 if (backdrop_filter_proc_) {
926 if (!backdrop_filter_contents) {
928 <<
"EntityPass contains a backdrop filter, but no backdrop filter "
929 "contents was supplied by the parent pass at render time. This is "
930 "a bug in EntityPass. Parent passes are responsible for setting "
931 "up backdrop filters for their children.";
935 Entity backdrop_entity;
936 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
937 backdrop_entity.SetTransform(
939 backdrop_entity.SetClipDepth(clip_depth_floor);
940 backdrop_entity.SetNewClipDepth(std::numeric_limits<uint32_t>::max());
942 RenderElement(backdrop_entity, clip_depth_floor, pass_context, pass_depth,
943 renderer, clip_coverage_stack, global_pass_position);
946 bool is_collapsing_clear_colors = !collapsed_parent_pass &&
949 !backdrop_filter_proc_;
950 for (
const auto& element : elements_) {
952 if (is_collapsing_clear_colors) {
953 auto [entity_color, _] =
954 ElementAsBackgroundColor(element, clear_color_size);
955 if (entity_color.has_value()) {
958 is_collapsing_clear_colors =
false;
961 EntityResult result =
962 GetEntityForElement(element,
967 global_pass_position,
972 switch (result.status) {
973 case EntityResult::kSuccess:
975 case EntityResult::kFailure:
979 case EntityResult::kSkip:
988 if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
989 auto src_contents = result.entity.GetContents();
990 auto contents = std::make_shared<FramebufferBlendContents>();
991 contents->SetChildContents(src_contents);
992 contents->SetBlendMode(result.entity.GetBlendMode());
993 result.entity.SetContents(std::move(contents));
1006 if (!pass_context.EndPass()) {
1008 <<
"Failed to end the current render pass in order to read from "
1009 "the backdrop texture and apply an advanced blend.";
1015 auto texture = pass_context.GetTexture();
1017 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
1018 "apply an advanced blend.";
1026 result.entity.GetBlendMode(), inputs);
1027 contents->SetCoverageHint(result.entity.GetCoverage());
1028 result.entity.SetContents(std::move(contents));
1036 if (!RenderElement(result.entity, clip_depth_floor, pass_context,
1037 pass_depth, renderer, clip_coverage_stack,
1038 global_pass_position)) {
1044 #ifdef IMPELLER_DEBUG
1051 if (enable_offscreen_debug_checkerboard_ &&
1052 !collapsed_parent_pass.has_value() && pass_depth > 0) {
1053 auto result = pass_context.GetRenderPass(pass_depth);
1059 auto checkerboard = CheckerboardContents();
1060 auto color = ColorHSB(0,
1062 std::max(0.0, 0.6 - pass_depth / 5),
1064 checkerboard.SetColor(Color(color));
1065 checkerboard.Render(renderer, {}, *result.pass);
1073 const std::function<
bool(
Element&)>& iterator) {
1078 for (
auto& element : elements_) {
1079 if (!iterator(element)) {
1082 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1083 subpass->get()->IterateAllElements(iterator);
1089 const std::function<
bool(
const Element&)>& iterator)
const {
1096 for (
auto& element : elements_) {
1097 if (!iterator(element)) {
1100 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1101 const EntityPass* entity_pass = subpass->get();
1108 const std::function<
bool(
Entity&)>& iterator) {
1113 for (
auto& element : elements_) {
1114 if (
auto entity = std::get_if<Entity>(&element)) {
1115 if (!iterator(*entity)) {
1120 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1121 subpass->get()->IterateAllEntities(iterator);
1129 const std::function<
bool(
const Entity&)>& iterator)
const {
1134 for (
const auto& element : elements_) {
1135 if (
auto entity = std::get_if<Entity>(&element)) {
1136 if (!iterator(*entity)) {
1141 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1142 const EntityPass* entity_pass = subpass->get();
1151 const std::function<
bool(
Entity&)>& iterator) {
1156 for (
auto& element : elements_) {
1157 if (
auto entity = std::get_if<Entity>(&element)) {
1158 if (!iterator(*entity)) {
1169 return elements_.size();
1173 transform_ = transform;
1177 clip_depth_ = clip_depth;
1185 new_clip_depth_ = clip_depth;
1189 return new_clip_depth_;
1193 blend_mode_ = blend_mode;
1202 if (backdrop_filter_proc_) {
1203 return std::nullopt;
1206 std::optional<Color> result = std::nullopt;
1207 for (
const Element& element : elements_) {
1208 auto [entity_color, blend_mode] =
1209 ElementAsBackgroundColor(element, target_size);
1210 if (!entity_color.has_value()) {
1214 .Blend(entity_color.value(), blend_mode);
1216 if (result.has_value()) {
1217 return result->Premultiply();
1224 VALIDATION_LOG <<
"Backdrop filters cannot be set on EntityPasses that "
1225 "have already been appended to another pass.";
1228 backdrop_filter_proc_ = std::move(proc);
1232 enable_offscreen_debug_checkerboard_ = enabled;