From 5ecc0288489421645c417624909bddabdbedbafb Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 28 Aug 2024 09:35:37 -0700 Subject: [PATCH] [Impeller] port clip stack fixes to new canvas. (flutter/engine#54727) From https://github.com/flutter/engine/commit/adbc36097065b33206f8fdaffe67c4662349d035 --- .../impeller/aiks/experimental_canvas.cc | 36 ++++++++++++------- .../flutter/impeller/entity/entity_pass.cc | 3 +- .../impeller/entity/entity_pass_clip_stack.cc | 4 +-- .../impeller/entity/entity_pass_clip_stack.h | 2 +- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/engine/src/flutter/impeller/aiks/experimental_canvas.cc b/engine/src/flutter/impeller/aiks/experimental_canvas.cc index b9cd19a12af..374d1a3548d 100644 --- a/engine/src/flutter/impeller/aiks/experimental_canvas.cc +++ b/engine/src/flutter/impeller/aiks/experimental_canvas.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "impeller/aiks/experimental_canvas.h" +#include #include "fml/logging.h" #include "fml/trace_event.h" #include "impeller/aiks/canvas.h" @@ -57,6 +58,7 @@ static void ApplyFramebufferBlend(Entity& entity) { static std::shared_ptr FlipBackdrop( std::vector& render_passes, Point global_pass_position, + size_t current_clip_depth, EntityPassClipStack& clip_coverage_stack, ContentContext& renderer) { auto rendering_config = std::move(render_passes.back()); @@ -132,16 +134,21 @@ static std::shared_ptr FlipBackdrop( // Restore any clips that were recorded before the backdrop filter was // applied. - auto& replay_entities = clip_coverage_stack.GetReplayEntities(); - for (const auto& replay : replay_entities) { + clip_coverage_stack.ActivateClipReplay(); + + // If there are any pending clips to replay, render any that may affect + // the entity we're about to render. + while (const EntityPassClipStack::ReplayResult* next_replay_clip = + clip_coverage_stack.GetNextReplayResult(current_clip_depth)) { + auto& replay_entity = next_replay_clip->entity; SetClipScissor( - clip_coverage_stack.CurrentClipCoverage(), + next_replay_clip->clip_coverage, *render_passes.back().inline_pass_context->GetRenderPass(0).pass, global_pass_position); - if (!replay.entity.Render( + if (!replay_entity.Render( renderer, *render_passes.back().inline_pass_context->GetRenderPass(0).pass)) { - VALIDATION_LOG << "Failed to render entity for clip restore."; + VALIDATION_LOG << "Failed to render entity for clip replay."; } } @@ -375,8 +382,12 @@ void ExperimentalCanvas::SaveLayer( return filter; }; - auto input_texture = FlipBackdrop(render_passes_, GetGlobalPassPosition(), - clip_coverage_stack_, renderer_); + auto input_texture = FlipBackdrop(render_passes_, // + GetGlobalPassPosition(), // + std::numeric_limits::max(), // + clip_coverage_stack_, // + renderer_ // + ); if (!input_texture) { // Validation failures are logged in FlipBackdrop. return; @@ -532,9 +543,9 @@ bool ExperimentalCanvas::Restore() { // to the render target texture so far need to execute before it's bound // for blending (otherwise the blend pass will end up executing before // all the previous commands in the active pass). - auto input_texture = - FlipBackdrop(render_passes_, GetGlobalPassPosition(), - clip_coverage_stack_, renderer_); + auto input_texture = FlipBackdrop( + render_passes_, GetGlobalPassPosition(), + element_entity.GetClipDepth(), clip_coverage_stack_, renderer_); if (!input_texture) { return false; } @@ -712,8 +723,9 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, // to the render target texture so far need to execute before it's bound // for blending (otherwise the blend pass will end up executing before // all the previous commands in the active pass). - auto input_texture = FlipBackdrop(render_passes_, GetGlobalPassPosition(), - clip_coverage_stack_, renderer_); + auto input_texture = + FlipBackdrop(render_passes_, GetGlobalPassPosition(), + entity.GetClipDepth(), clip_coverage_stack_, renderer_); if (!input_texture) { return; } diff --git a/engine/src/flutter/impeller/entity/entity_pass.cc b/engine/src/flutter/impeller/entity/entity_pass.cc index c2eb3b89812..10b1efc3272 100644 --- a/engine/src/flutter/impeller/entity/entity_pass.cc +++ b/engine/src/flutter/impeller/entity/entity_pass.cc @@ -852,7 +852,8 @@ bool EntityPass::RenderElement(Entity& element_entity, // If there are any pending clips to replay, render any that may affect // the entity we're about to render. while (const EntityPassClipStack::ReplayResult* next_replay_clip = - clip_coverage_stack.GetNextReplayResult(element_entity)) { + clip_coverage_stack.GetNextReplayResult( + element_entity.GetClipDepth())) { auto& replay_entity = next_replay_clip->entity; SetClipScissor(next_replay_clip->clip_coverage, *result.pass, global_pass_position); diff --git a/engine/src/flutter/impeller/entity/entity_pass_clip_stack.cc b/engine/src/flutter/impeller/entity/entity_pass_clip_stack.cc index 1cef7a10858..8e6aa1e8d62 100644 --- a/engine/src/flutter/impeller/entity/entity_pass_clip_stack.cc +++ b/engine/src/flutter/impeller/entity/entity_pass_clip_stack.cc @@ -178,7 +178,7 @@ void EntityPassClipStack::ActivateClipReplay() { } const EntityPassClipStack::ReplayResult* -EntityPassClipStack::GetNextReplayResult(const Entity& entity) { +EntityPassClipStack::GetNextReplayResult(size_t current_clip_depth) { if (next_replay_index_ >= subpass_state_.back().rendered_clip_entities.size()) { // No clips need to be replayed. @@ -186,7 +186,7 @@ EntityPassClipStack::GetNextReplayResult(const Entity& entity) { } ReplayResult* next_replay = &subpass_state_.back().rendered_clip_entities[next_replay_index_]; - if (next_replay->entity.GetClipDepth() < entity.GetClipDepth()) { + if (next_replay->entity.GetClipDepth() < current_clip_depth) { // The next replay clip doesn't affect the current entity, so don't replay // it yet. return nullptr; diff --git a/engine/src/flutter/impeller/entity/entity_pass_clip_stack.h b/engine/src/flutter/impeller/entity/entity_pass_clip_stack.h index df230fddd44..9ec26b1d11f 100644 --- a/engine/src/flutter/impeller/entity/entity_pass_clip_stack.h +++ b/engine/src/flutter/impeller/entity/entity_pass_clip_stack.h @@ -68,7 +68,7 @@ class EntityPassClipStack { /// @brief Returns the next Entity that should be replayed. If there are no /// enities to replay, then nullptr is returned. - const ReplayResult* GetNextReplayResult(const Entity& entity); + const ReplayResult* GetNextReplayResult(size_t current_clip_depth); // Visible for testing. const std::vector GetClipCoverageLayers() const;