12 #include "flutter/fml/closure.h"
13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/trace_event.h"
34 std::tuple<std::optional<Color>,
BlendMode> ElementAsBackgroundColor(
37 if (
const Entity* entity = std::get_if<Entity>(&element)) {
38 std::optional<Color> entity_color = entity->AsBackgroundColor(target_size);
39 if (entity_color.has_value()) {
40 return {entity_color.value(), entity->GetBlendMode()};
55 delegate_ = std::move(delegate);
60 bounds_limit_ = bounds_limit;
61 bounds_promise_ = bounds_limit.has_value() ? bounds_promise
70 switch (bounds_promise_) {
77 return bounds_limit_.has_value();
79 FML_DCHECK(bounds_limit_.has_value());
82 FML_DCHECK(bounds_limit_.has_value());
89 switch (bounds_promise_) {
94 FML_DCHECK(bounds_limit_.has_value());
107 advanced_blend_reads_from_pass_texture_ =
true;
109 elements_.emplace_back(std::move(entity));
113 elements_.emplace_back(std::move(entity));
114 active_clips_.emplace_back(elements_.size() - 1);
118 if (num_clips > active_clips_.size()) {
120 <<
"Attempted to pop more clips than are currently active. Active: "
121 << active_clips_.size() <<
", Popped: " << num_clips
122 <<
", Depth: " << depth;
125 size_t max = std::min(num_clips, active_clips_.size());
126 for (
size_t i = 0; i < max; i++) {
127 FML_DCHECK(active_clips_.back() < elements_.size());
128 Entity* element = std::get_if<Entity>(&elements_[active_clips_.back()]);
131 active_clips_.pop_back();
136 PopClips(active_clips_.size(), depth);
140 elements_ = std::move(elements);
144 size_t max_subpass_depth = 0u;
145 for (
const auto& element : elements_) {
146 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
148 std::max(max_subpass_depth, subpass->get()->GetSubpassesDepth());
151 return max_subpass_depth + 1u;
155 std::optional<Rect> coverage_limit)
const {
156 std::optional<Rect> accumulated_coverage;
157 for (
const auto& element : elements_) {
158 std::optional<Rect> element_coverage;
160 if (
auto entity = std::get_if<Entity>(&element)) {
161 element_coverage = entity->GetCoverage();
165 if (element_coverage.has_value() && coverage_limit.has_value()) {
166 const auto* filter = entity->GetContents()->AsFilter();
167 if (!filter || filter->IsTranslationOnly()) {
169 element_coverage->Intersection(coverage_limit.value());
172 }
else if (
auto subpass_ptr =
173 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
174 auto& subpass = *subpass_ptr->get();
176 std::optional<Rect> unfiltered_coverage =
182 if (accumulated_coverage.has_value() && subpass.backdrop_filter_proc_) {
183 std::shared_ptr<FilterContents> backdrop_filter =
184 subpass.backdrop_filter_proc_(
188 if (backdrop_filter) {
189 auto backdrop_coverage = backdrop_filter->GetCoverage({});
190 unfiltered_coverage =
191 Rect::Union(unfiltered_coverage, backdrop_coverage);
193 VALIDATION_LOG <<
"The EntityPass backdrop filter proc didn't return "
198 if (!unfiltered_coverage.has_value()) {
210 std::shared_ptr<FilterContents> image_filter =
211 subpass.delegate_->WithImageFilter(*unfiltered_coverage,
216 element_coverage = image_filter->GetCoverage(subpass_entity);
218 element_coverage = unfiltered_coverage;
226 accumulated_coverage =
Rect::Union(accumulated_coverage, element_coverage);
228 return accumulated_coverage;
233 std::optional<Rect> coverage_limit)
const {
235 return subpass.bounds_limit_->TransformBounds(subpass.transform_);
238 std::shared_ptr<FilterContents> image_filter =
239 subpass.delegate_->WithImageFilter(
Rect(), subpass.transform_);
244 if (image_filter && coverage_limit.has_value()) {
245 coverage_limit = image_filter->GetSourceCoverage(subpass.transform_,
246 coverage_limit.value());
251 if (!entities_coverage.has_value()) {
255 if (!subpass.bounds_limit_.has_value()) {
256 return entities_coverage;
258 auto user_bounds_coverage =
259 subpass.bounds_limit_->TransformBounds(subpass.transform_);
260 return entities_coverage->Intersection(user_bounds_coverage);
271 FML_DCHECK(pass->superpass_ ==
nullptr);
272 pass->superpass_ =
this;
274 if (pass->backdrop_filter_proc_) {
275 backdrop_filter_reads_from_pass_texture_ =
true;
278 advanced_blend_reads_from_pass_texture_ =
true;
281 auto subpass_pointer = pass.get();
282 elements_.emplace_back(std::move(pass));
283 return subpass_pointer;
296 const Color& clear_color) {
297 const std::shared_ptr<Context>& context = renderer.
GetContext();
311 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
323 .clear_color = clear_color},
336 .clear_color = clear_color,
347 bool EntityPass::DoesBackdropGetRead(ContentContext& renderer)
const {
348 return renderer.GetDeviceCapabilities().SupportsFramebufferFetch()
349 ? backdrop_filter_reads_from_pass_texture_
350 : backdrop_filter_reads_from_pass_texture_ ||
351 advanced_blend_reads_from_pass_texture_;
357 fml::ScopedCleanupClosure reset_state([&renderer]() {
362 auto root_render_target = render_target;
364 if (root_render_target.GetColorAttachments().find(0u) ==
365 root_render_target.GetColorAttachments().end()) {
366 VALIDATION_LOG <<
"The root RenderTarget must have a color attachment.";
369 if (root_render_target.GetDepthAttachment().has_value() !=
370 root_render_target.GetStencilAttachment().has_value()) {
371 VALIDATION_LOG <<
"The root RenderTarget should have a stencil attachment "
372 "iff it has a depth attachment.";
379 contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
390 if (DoesBackdropGetRead(renderer)) {
392 renderer, root_render_target.GetRenderTargetSize(),
396 if (!OnRender(renderer,
410 auto command_buffer = renderer.
GetContext()->CreateCommandBuffer();
411 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
418 ->SupportsTextureToTextureBlits()) {
419 auto blit_pass = command_buffer->CreateBlitPass();
422 root_render_target.GetRenderTargetTexture());
423 if (!blit_pass->EncodeCommands(
424 renderer.
GetContext()->GetResourceAllocator())) {
430 ->Submit({command_buffer})
435 auto render_pass = command_buffer->CreateRenderPass(root_render_target);
436 render_pass->SetLabel(
"EntityPass Root Render Pass");
442 contents->SetTexture(
444 contents->SetSourceRect(size_rect);
445 contents->SetLabel(
"Root pass blit");
451 if (!entity.
Render(renderer, *render_pass)) {
457 if (!render_pass->EncodeCommands()) {
463 ->Submit({command_buffer})
477 auto color0 = root_render_target.GetColorAttachments().find(0u)->second;
479 auto stencil_attachment = root_render_target.GetStencilAttachment();
480 auto depth_attachment = root_render_target.GetDepthAttachment();
481 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
484 root_render_target.SetupDepthStencilAttachments(
486 color0.texture->GetSize(),
487 renderer.
GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
494 root_render_target.SetColorAttachment(color0, 0);
503 root_render_target.GetRenderTargetSize(),
511 EntityPass::EntityResult EntityPass::GetEntityForElement(
515 ISize root_pass_size,
516 Point global_pass_position,
519 size_t clip_height_floor)
const {
523 if (
const auto& entity = std::get_if<Entity>(&element)) {
526 if (!global_pass_position.
IsZero()) {
534 return EntityPass::EntityResult::Success(std::move(element_entity));
540 if (
const auto& subpass_ptr =
541 std::get_if<std::unique_ptr<EntityPass>>(&element)) {
542 auto subpass = subpass_ptr->get();
543 if (subpass->delegate_->CanElide()) {
544 return EntityPass::EntityResult::Skip();
547 if (!subpass->backdrop_filter_proc_ &&
548 subpass->delegate_->CanCollapseIntoParentPass(subpass)) {
550 if (!subpass->OnRender(
554 global_pass_position,
564 return EntityPass::EntityResult::Failure();
566 return EntityPass::EntityResult::Skip();
569 std::shared_ptr<Contents> subpass_backdrop_filter_contents =
nullptr;
570 if (subpass->backdrop_filter_proc_) {
573 const auto& proc = subpass->backdrop_filter_proc_;
575 subpass_backdrop_filter_contents = proc(
579 subpass->transform_.HasTranslation()
600 return EntityPass::EntityResult::Skip();
603 if (!clip_coverage_back.has_value()) {
604 return EntityPass::EntityResult::Skip();
614 if (!coverage_limit.has_value()) {
615 return EntityPass::EntityResult::Skip();
620 if (!coverage_limit.has_value()) {
621 return EntityPass::EntityResult::Skip();
624 auto subpass_coverage =
625 (subpass->flood_clip_ || subpass_backdrop_filter_contents)
628 if (!subpass_coverage.has_value()) {
629 return EntityPass::EntityResult::Skip();
634 return EntityPass::EntityResult::Skip();
640 subpass->GetRequiredMipCount(),
643 if (!subpass_target.IsValid()) {
645 return EntityPass::EntityResult::Failure();
653 clip_coverage_stack.
PushSubpass(subpass_coverage, subpass->clip_height_);
657 if (!subpass->OnRender(
661 subpass_coverage->GetOrigin(),
662 subpass_coverage->GetOrigin() -
663 global_pass_position,
666 subpass->clip_height_,
667 subpass_backdrop_filter_contents
671 return EntityPass::EntityResult::Failure();
677 auto subpass_texture =
678 subpass_target.GetRenderTarget().GetRenderTargetTexture();
680 auto offscreen_texture_contents =
681 subpass->delegate_->CreateContentsForSubpassTarget(
684 subpass->transform_);
686 if (!offscreen_texture_contents) {
695 return EntityPass::EntityResult::Failure();
710 Point subpass_texture_position =
711 (subpass_coverage->GetOrigin() - global_pass_position).Round();
713 Entity element_entity;
715 element_entity.SetContents(std::move(offscreen_texture_contents));
716 element_entity.SetBlendMode(subpass->blend_mode_);
717 element_entity.SetTransform(
720 return EntityPass::EntityResult::Success(std::move(element_entity));
727 Point global_pass_position) {
731 if (clip_coverage.has_value()) {
732 clip_coverage = clip_coverage->
Shift(-global_pass_position);
741 bool EntityPass::RenderElement(Entity& element_entity,
742 size_t clip_height_floor,
743 InlinePassContext& pass_context,
745 ContentContext& renderer,
746 EntityPassClipStack& clip_coverage_stack,
747 Point global_pass_position)
const {
748 auto result = pass_context.GetRenderPass(pass_depth);
761 if (result.backdrop_texture) {
762 auto size_rect =
Rect::MakeSize(result.pass->GetRenderTargetSize());
764 msaa_backdrop_contents->SetStencilEnabled(
false);
765 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
766 msaa_backdrop_contents->SetSourceRect(size_rect);
767 msaa_backdrop_contents->SetTexture(result.backdrop_texture);
769 Entity msaa_backdrop_entity;
770 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
772 msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
773 if (!msaa_backdrop_entity.Render(renderer, *result.pass)) {
774 VALIDATION_LOG <<
"Failed to render MSAA backdrop filter entity.";
779 if (result.just_created) {
782 auto& replay_entities = clip_coverage_stack.GetReplayEntities();
783 for (
const auto& replay : replay_entities) {
784 SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
785 global_pass_position);
786 if (!replay.entity.Render(renderer, *result.pass)) {
792 auto current_clip_coverage = clip_coverage_stack.CurrentClipCoverage();
793 if (current_clip_coverage.has_value()) {
796 current_clip_coverage = current_clip_coverage->Shift(-global_pass_position);
799 if (!element_entity.ShouldRender(current_clip_coverage)) {
803 auto clip_coverage = element_entity.GetClipCoverage(current_clip_coverage);
804 if (clip_coverage.coverage.has_value()) {
805 clip_coverage.coverage =
806 clip_coverage.coverage->Shift(global_pass_position);
813 auto element_coverage_hint = element_entity.GetContents()->GetCoverageHint();
814 element_entity.GetContents()->SetCoverageHint(
817 EntityPassClipStack::ClipStateResult clip_state_result =
818 clip_coverage_stack.ApplyClipState(clip_coverage, element_entity,
820 global_pass_position);
822 if (clip_state_result.clip_did_change) {
824 SetClipScissor(clip_coverage_stack.CurrentClipCoverage(), *result.pass,
825 global_pass_position);
828 if (!clip_state_result.should_render) {
832 if (!element_entity.Render(renderer, *result.pass)) {
839 bool EntityPass::OnRender(
840 ContentContext& renderer,
841 ISize root_pass_size,
842 EntityPassTarget& pass_target,
843 Point global_pass_position,
844 Point local_pass_position,
846 EntityPassClipStack& clip_coverage_stack,
847 size_t clip_height_floor,
848 std::shared_ptr<Contents> backdrop_filter_contents,
849 const std::optional<InlinePassContext::RenderPassResult>&
850 collapsed_parent_pass)
const {
851 TRACE_EVENT0(
"impeller",
"EntityPass::OnRender");
853 if (!active_clips_.empty()) {
855 "EntityPass (Depth=%d) contains one or more clips with an unresolved "
860 InlinePassContext pass_context(renderer, pass_target,
GetElementCount(),
861 collapsed_parent_pass);
862 if (!pass_context.IsValid()) {
866 auto clear_color_size = pass_target.GetRenderTarget().GetRenderTargetSize();
868 if (!collapsed_parent_pass) {
872 pass_context.GetRenderPass(pass_depth);
875 if (backdrop_filter_proc_) {
876 if (!backdrop_filter_contents) {
878 <<
"EntityPass contains a backdrop filter, but no backdrop filter "
879 "contents was supplied by the parent pass at render time. This is "
880 "a bug in EntityPass. Parent passes are responsible for setting "
881 "up backdrop filters for their children.";
885 Entity backdrop_entity;
886 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
887 backdrop_entity.SetTransform(
889 backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
891 RenderElement(backdrop_entity, clip_height_floor, pass_context, pass_depth,
892 renderer, clip_coverage_stack, global_pass_position);
895 bool is_collapsing_clear_colors = !collapsed_parent_pass &&
898 !backdrop_filter_proc_;
899 for (
const auto& element : elements_) {
901 if (is_collapsing_clear_colors) {
902 auto [entity_color, _] =
903 ElementAsBackgroundColor(element, clear_color_size);
904 if (entity_color.has_value()) {
907 is_collapsing_clear_colors =
false;
910 EntityResult result =
911 GetEntityForElement(element,
915 global_pass_position,
920 switch (result.status) {
921 case EntityResult::kSuccess:
923 case EntityResult::kFailure:
927 case EntityResult::kSkip:
936 if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) {
937 auto src_contents = result.entity.GetContents();
938 auto contents = std::make_shared<FramebufferBlendContents>();
939 contents->SetChildContents(src_contents);
940 contents->SetBlendMode(result.entity.GetBlendMode());
941 result.entity.SetContents(std::move(contents));
954 if (!pass_context.EndPass()) {
956 <<
"Failed to end the current render pass in order to read from "
957 "the backdrop texture and apply an advanced blend.";
963 auto texture = pass_context.GetTexture();
965 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
966 "apply an advanced blend.";
974 result.entity.GetBlendMode(), inputs);
975 contents->SetCoverageHint(result.entity.GetCoverage());
976 result.entity.SetContents(std::move(contents));
984 if (!RenderElement(result.entity, clip_height_floor, pass_context,
985 pass_depth, renderer, clip_coverage_stack,
986 global_pass_position)) {
996 const std::function<
bool(
Element&)>& iterator) {
1001 for (
auto& element : elements_) {
1002 if (!iterator(element)) {
1005 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1006 subpass->get()->IterateAllElements(iterator);
1012 const std::function<
bool(
const Element&)>& iterator)
const {
1019 for (
auto& element : elements_) {
1020 if (!iterator(element)) {
1023 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1024 const EntityPass* entity_pass = subpass->get();
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);
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();
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)) {
1092 return elements_.size();
1100 clip_height_ = clip_height;
1104 return clip_height_;
1108 clip_depth_ = clip_depth;
1116 blend_mode_ = blend_mode;
1125 if (backdrop_filter_proc_) {
1126 return std::nullopt;
1129 std::optional<Color> result = std::nullopt;
1130 for (
const Element& element : elements_) {
1131 auto [entity_color, blend_mode] =
1132 ElementAsBackgroundColor(element, target_size);
1133 if (!entity_color.has_value()) {
1137 .Blend(entity_color.value(), blend_mode);
1139 if (result.has_value()) {
1140 return result->Premultiply();
1147 VALIDATION_LOG <<
"Backdrop filters cannot be set on EntityPasses that "
1148 "have already been appended to another pass.";
1151 backdrop_filter_proc_ = std::move(proc);