[Impeller] Keep track of a stencil depth floor for non-collapsed subpasses (flutter/engine#33473)

This commit is contained in:
Brandon DeRosier 2022-05-19 01:13:21 -07:00 committed by GitHub
parent 8af07c92c5
commit 1a8ff96a0d
4 changed files with 48 additions and 10 deletions

View File

@ -805,5 +805,29 @@ TEST_P(AiksTest, SiblingSaveLayerBoundsAreRespected) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
TEST_P(AiksTest, CanRenderClippedLayers) {
Canvas canvas;
canvas.DrawPaint({.color = Color::White()});
// Draw a green circle on the screen.
{
// Increase the clip depth for the savelayer to contend with.
canvas.ClipPath(PathBuilder{}.AddCircle({100, 100}, 50).TakePath());
canvas.SaveLayer({}, Rect::MakeXYWH(50, 50, 100, 100));
// Fill the layer with white.
canvas.DrawRect(Rect::MakeSize({400, 400}), {.color = Color::White()});
// Fill the layer with green, but do so with a color blend that can't be
// collapsed into the parent pass.
canvas.DrawRect(
Rect::MakeSize({400, 400}),
{.color = Color::Green(), .blend_mode = Entity::BlendMode::kColorBurn});
}
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}
} // namespace testing
} // namespace impeller

View File

@ -266,7 +266,8 @@ size_t Canvas::GetStencilDepth() const {
void Canvas::SaveLayer(Paint paint, std::optional<Rect> bounds) {
Save(true, paint.blend_mode);
GetCurrentPass().SetDelegate(
auto& new_layer_pass = GetCurrentPass();
new_layer_pass.SetDelegate(
std::make_unique<PaintPassDelegate>(paint, bounds));
if (bounds.has_value()) {

View File

@ -180,7 +180,8 @@ bool EntityPass::Render(ContentContext& renderer,
bool EntityPass::RenderInternal(ContentContext& renderer,
RenderTarget render_target,
Point position,
uint32_t depth) const {
uint32_t pass_depth,
size_t stencil_depth_floor) const {
TRACE_EVENT0("impeller", "EntityPass::Render");
auto context = renderer.GetContext();
@ -233,7 +234,7 @@ bool EntityPass::RenderInternal(ContentContext& renderer,
if (subpass->delegate_->CanCollapseIntoParentPass()) {
// Directly render into the parent target and move on.
if (!subpass->RenderInternal(renderer, render_target, position,
depth)) {
pass_depth, stencil_depth_floor)) {
return false;
}
continue;
@ -286,13 +287,16 @@ bool EntityPass::RenderInternal(ContentContext& renderer,
return false;
}
// Stencil textures aren't shared between EntityPasses (as much of the
// time they are transient).
if (!subpass->RenderInternal(renderer, subpass_target,
subpass_coverage->origin, ++depth)) {
subpass_coverage->origin, ++pass_depth,
subpass->stencil_depth_)) {
return false;
}
element_entity.SetContents(std::move(offscreen_texture_contents));
element_entity.SetStencilDepth(stencil_depth_);
element_entity.SetStencilDepth(subpass->stencil_depth_);
element_entity.SetBlendMode(subpass->blend_mode_);
// Once we have filters being applied for SaveLayer, some special sauce
// may be needed here (or in PaintPassDelegate) to ensure the filter
@ -305,7 +309,7 @@ bool EntityPass::RenderInternal(ContentContext& renderer,
}
// =========================================================================
// Render the element ======================================================
// Configure the RenderPass ================================================
// =========================================================================
if (pass && element_entity.GetBlendMode() >
@ -350,7 +354,7 @@ bool EntityPass::RenderInternal(ContentContext& renderer,
}
command_buffer->SetLabel(
"EntityPass Command Buffer: Depth=" + std::to_string(depth) +
"EntityPass Command Buffer: Depth=" + std::to_string(pass_depth) +
" Count=" + std::to_string(pass_count));
// Never clear the texture for subsequent passes.
@ -373,12 +377,20 @@ bool EntityPass::RenderInternal(ContentContext& renderer,
return false;
}
pass->SetLabel("EntityPass Render Pass: Depth=" + std::to_string(depth) +
" Count=" + std::to_string(pass_count));
pass->SetLabel(
"EntityPass Render Pass: Depth=" + std::to_string(pass_depth) +
" Count=" + std::to_string(pass_count));
++pass_count;
}
// =========================================================================
// Render the element ======================================================
// =========================================================================
element_entity.SetStencilDepth(element_entity.GetStencilDepth() -
stencil_depth_floor);
if (!element_entity.Render(renderer, *pass)) {
return false;
}

View File

@ -61,7 +61,8 @@ class EntityPass {
bool RenderInternal(ContentContext& renderer,
RenderTarget render_target,
Point position,
uint32_t depth) const;
uint32_t pass_depth,
size_t stencil_depth_floor = 0) const;
std::vector<Element> elements_;