Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
make clip stack share state.
  • Loading branch information
jonahwilliams committed Mar 25, 2024
commit 2c3fc3f76887e841869801817da5e3800b8b97d0
17 changes: 0 additions & 17 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3376,23 +3376,6 @@ TEST_P(AiksTest, CorrectClipDepthAssignedToEntities) {
}
}

TEST_P(AiksTest, EntityPassClipRecorderRestoresCancelOutClips) {
Canvas canvas;
canvas.Save();
canvas.ClipRRect(Rect::MakeLTRB(0, 0, 50, 50), {10, 10}, {});
canvas.DrawRRect(Rect::MakeLTRB(0, 0, 100, 100), {10, 10}, {});
canvas.Restore();
canvas.DrawRRect(Rect::MakeLTRB(0, 0, 50, 50), {10, 10}, {});

Picture picture = canvas.EndRecordingAsPicture();

AiksContext renderer(GetContext(), nullptr);
std::shared_ptr<Image> image = picture.ToImage(renderer, {300, 300});

EXPECT_EQ(
picture.pass->GetEntityPassClipRecorder().GetReplayEntities().size(), 0u);
}

} // namespace testing
} // namespace impeller

Expand Down
49 changes: 30 additions & 19 deletions impeller/entity/entity_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
#include "impeller/base/strings.h"
#include "impeller/base/validation.h"
#include "impeller/core/formats.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/contents/filters/color_filter_contents.h"
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/framebuffer_blend_contents.h"
#include "impeller/entity/contents/texture_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/entity_pass_clip_stack.h"
#include "impeller/entity/inline_pass_context.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/rect.h"
Expand Down Expand Up @@ -408,8 +410,9 @@ bool EntityPass::Render(ContentContext& renderer,
return true;
});

clip_stack_->Initialize(
Rect::MakeSize(root_render_target.GetRenderTargetSize()));
std::unique_ptr<EntityPassClipStack> clip_stack =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this doesn't even need to be heap allocated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

std::make_unique<EntityPassClipStack>(
Rect::MakeSize(root_render_target.GetRenderTargetSize()));

bool reads_from_onscreen_backdrop = GetTotalPassReads(renderer) > 0;
// In this branch path, we need to render everything to an offscreen texture
Expand All @@ -428,7 +431,8 @@ bool EntityPass::Render(ContentContext& renderer,
offscreen_target, // pass_target
Point(), // global_pass_position
Point(), // local_pass_position
0 // pass_depth
0, // pass_depth
*clip_stack // clip_coverage_stack
)) {
// Validation error messages are triggered for all `OnRender()` failure
// cases.
Expand Down Expand Up @@ -533,7 +537,8 @@ bool EntityPass::Render(ContentContext& renderer,
pass_target, // pass_target
Point(), // global_pass_position
Point(), // local_pass_position
0); // pass_depth
0, // pass_depth
*clip_stack); // clip_coverage_stack
}

EntityPass::EntityResult EntityPass::GetEntityForElement(
Expand All @@ -544,6 +549,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
ISize root_pass_size,
Point global_pass_position,
uint32_t pass_depth,
EntityPassClipStack& clip_coverage_stack,
size_t clip_depth_floor) const {
//--------------------------------------------------------------------------
/// Setup entity element.
Expand Down Expand Up @@ -585,6 +591,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
global_pass_position, // global_pass_position
Point(), // local_pass_position
pass_depth, // pass_depth
clip_coverage_stack, // clip_coverage_stack
clip_depth_, // clip_depth_floor
nullptr, // backdrop_filter_contents
pass_context.GetRenderPass(pass_depth) // collapsed_parent_pass
Expand Down Expand Up @@ -619,13 +626,13 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
pass_context.EndPass();
}

if (!clip_stack_->HasCoverage()) {
if (!clip_coverage_stack.HasCoverage()) {
// The current clip is empty. This means the pass texture won't be
// visible, so skip it.
capture.CreateChild("Subpass Entity (Skipped: Empty clip A)");
return EntityPass::EntityResult::Skip();
}
auto clip_coverage_back = clip_stack_->CurrentClipCoverage();
auto clip_coverage_back = clip_coverage_stack.CurrentClipCoverage();
if (!clip_coverage_back.has_value()) {
capture.CreateChild("Subpass Entity (Skipped: Empty clip B)");
return EntityPass::EntityResult::Skip();
Expand Down Expand Up @@ -684,7 +691,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
// save layers may transform the subpass texture after it's rendered,
// causing parent clip coverage to get misaligned with the actual area that
// the subpass will affect in the parent pass.
clip_stack_->PushSubpass(subpass_coverage, subpass->clip_depth_);
clip_coverage_stack.PushSubpass(subpass_coverage, subpass->clip_depth_);

// Stencil textures aren't shared between EntityPasses (as much of the
// time they are transient).
Expand All @@ -697,14 +704,16 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
subpass_coverage->GetOrigin() -
global_pass_position, // local_pass_position
++pass_depth, // pass_depth
clip_coverage_stack, // clip_coverage_stack
subpass->clip_depth_, // clip_depth_floor
subpass_backdrop_filter_contents // backdrop_filter_contents
)) {
// Validation error messages are triggered for all `OnRender()` failure
// cases.
return EntityPass::EntityResult::Failure();
}
clip_stack_->PopSubpass();

clip_coverage_stack.PopSubpass();

// The subpass target's texture may have changed during OnRender.
auto subpass_texture =
Expand Down Expand Up @@ -750,6 +759,7 @@ bool EntityPass::RenderElement(Entity& element_entity,
InlinePassContext& pass_context,
int32_t pass_depth,
ContentContext& renderer,
EntityPassClipStack& clip_coverage_stack,
Point global_pass_position) const {
auto result = pass_context.GetRenderPass(pass_depth);
if (!result.pass) {
Expand All @@ -762,7 +772,7 @@ bool EntityPass::RenderElement(Entity& element_entity,
if (result.just_created) {
// Restore any clips that were recorded before the backdrop filter was
// applied.
auto& replay_entities = clip_stack_->GetReplayEntities();
auto& replay_entities = clip_coverage_stack.GetReplayEntities();
for (const auto& entity : replay_entities) {
if (!entity.Render(renderer, *result.pass)) {
VALIDATION_LOG << "Failed to render entity for clip restore.";
Expand Down Expand Up @@ -793,7 +803,7 @@ bool EntityPass::RenderElement(Entity& element_entity,
}
}

auto current_clip_coverage = clip_stack_->CurrentClipCoverage();
auto current_clip_coverage = clip_coverage_stack.CurrentClipCoverage();
if (current_clip_coverage.has_value()) {
// Entity transforms are relative to the current pass position, so we need
// to check clip coverage in the same space.
Expand All @@ -818,9 +828,11 @@ bool EntityPass::RenderElement(Entity& element_entity,
element_entity.GetContents()->SetCoverageHint(
Rect::Intersection(element_coverage_hint, current_clip_coverage));

if (!clip_stack_->AppendClipCoverage(clip_coverage, element_entity,
clip_depth_floor,
global_pass_position)) {
if (!clip_coverage_stack.AppendClipCoverage(clip_coverage, element_entity,
clip_depth_floor,
global_pass_position)) {
// If the entity's coverage change did not change the clip coverage, we
// don't need to render it.
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe store the 1-line comment explaining why this state is terminal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

Expand All @@ -839,6 +851,7 @@ bool EntityPass::OnRender(
Point global_pass_position,
Point local_pass_position,
uint32_t pass_depth,
EntityPassClipStack& clip_coverage_stack,
size_t clip_depth_floor,
std::shared_ptr<Contents> backdrop_filter_contents,
const std::optional<InlinePassContext::RenderPassResult>&
Expand Down Expand Up @@ -886,7 +899,7 @@ bool EntityPass::OnRender(
backdrop_entity.SetNewClipDepth(std::numeric_limits<uint32_t>::max());

RenderElement(backdrop_entity, clip_depth_floor, pass_context, pass_depth,
renderer, global_pass_position);
renderer, clip_coverage_stack, global_pass_position);
}

bool is_collapsing_clear_colors = !collapsed_parent_pass &&
Expand All @@ -912,6 +925,7 @@ bool EntityPass::OnRender(
root_pass_size, // root_pass_size
global_pass_position, // global_pass_position
pass_depth, // pass_depth
clip_coverage_stack, // clip_coverage_stack
clip_depth_floor); // clip_depth_floor

switch (result.status) {
Expand Down Expand Up @@ -979,7 +993,8 @@ bool EntityPass::OnRender(
/// Render the Element.
///
if (!RenderElement(result.entity, clip_depth_floor, pass_context,
pass_depth, renderer, global_pass_position)) {
pass_depth, renderer, clip_coverage_stack,
global_pass_position)) {
// Specific validation logs are handled in `render_element()`.
return false;
}
Expand Down Expand Up @@ -1176,8 +1191,4 @@ void EntityPass::SetEnableOffscreenCheckerboard(bool enabled) {
enable_offscreen_debug_checkerboard_ = enabled;
}

const EntityPassClipStack& EntityPass::GetEntityPassClipRecorder() const {
return *clip_stack_;
}

} // namespace impeller
14 changes: 11 additions & 3 deletions impeller/entity/entity_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
namespace impeller {

class ContentContext;
class EntityPassClipRecorder;

/// Specifies how much to trust the bounds rectangle provided for a list
/// of contents. Used by both |EntityPass| and |Canvas::SaveLayer|.
Expand Down Expand Up @@ -214,7 +215,7 @@ class EntityPass {
std::optional<Rect> coverage_limit) const;

/// Exposed for testing purposes only.
const EntityPassClipStack& GetEntityPassClipRecorder() const;
const EntityPassClipRecorder& GetEntityPassClipRecorder() const;

private:
struct EntityResult {
Expand Down Expand Up @@ -245,6 +246,7 @@ class EntityPass {
InlinePassContext& pass_context,
int32_t pass_depth,
ContentContext& renderer,
EntityPassClipStack& clip_coverage_stack,
Point global_pass_position) const;

EntityResult GetEntityForElement(const EntityPass::Element& element,
Expand All @@ -254,6 +256,7 @@ class EntityPass {
ISize root_pass_size,
Point global_pass_position,
uint32_t pass_depth,
EntityPassClipStack& clip_coverage_stack,
size_t clip_depth_floor) const;

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -288,6 +291,12 @@ class EntityPass {
/// and debugging purposes. This can vary
/// depending on whether passes are
/// collapsed or not.
/// @param[in] clip_coverage_stack A global stack of coverage rectangles
/// for the clip buffer at each depth.
/// Higher depths are more restrictive.
/// Used to cull Elements that we
/// know won't result in a visible
/// change.
/// @param[in] clip_depth_floor The clip depth that a value of
/// zero corresponds to in the given
/// `pass_target` clip buffer.
Expand All @@ -314,6 +323,7 @@ class EntityPass {
Point global_pass_position,
Point local_pass_position,
uint32_t pass_depth,
EntityPassClipStack& clip_coverage_stack,
size_t clip_depth_floor = 0,
std::shared_ptr<Contents> backdrop_filter_contents = nullptr,
const std::optional<InlinePassContext::RenderPassResult>&
Expand All @@ -338,8 +348,6 @@ class EntityPass {
bool enable_offscreen_debug_checkerboard_ = false;
std::optional<Rect> bounds_limit_;
ContentBoundsPromise bounds_promise_ = ContentBoundsPromise::kUnknown;
std::unique_ptr<EntityPassClipStack> clip_stack_ =
std::make_unique<EntityPassClipStack>();
int32_t required_mip_count_ = 1;

/// These values are incremented whenever something is added to the pass that
Expand Down
Loading