[Impeller] port clip stack fixes to new canvas. (flutter/engine#54727)

From adbc360970
This commit is contained in:
Jonah Williams 2024-08-28 09:35:37 -07:00 committed by GitHub
parent 62541b1434
commit 5ecc028848
4 changed files with 29 additions and 16 deletions

View File

@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "impeller/aiks/experimental_canvas.h"
#include <limits>
#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<Texture> FlipBackdrop(
std::vector<LazyRenderingConfig>& 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<Texture> 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<uint32_t>::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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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<ClipCoverageLayer> GetClipCoverageLayers() const;