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 all commits
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
27 changes: 27 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4040,5 +4040,32 @@ TEST_P(AiksTest, ImageColorSourceEffectTransform) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CorrectClipDepthAssignedToEntities) {
Canvas canvas; // Depth 1 (base pass)
canvas.DrawRRect(Rect::MakeLTRB(0, 0, 100, 100), {10, 10}, {}); // Depth 2
canvas.ClipRRect(Rect::MakeLTRB(0, 0, 50, 50), {10, 10}, {}); // Depth 4
canvas.SaveLayer({}); // Depth 3
canvas.DrawRRect(Rect::MakeLTRB(0, 0, 50, 50), {10, 10}, {}); // Depth 4

auto picture = canvas.EndRecordingAsPicture();
std::array<uint32_t, 4> expected = {2, 4, 3, 4};
std::vector<uint32_t> actual;

picture.pass->IterateAllElements([&](EntityPass::Element& element) -> bool {
if (auto* subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
actual.push_back(subpass->get()->GetNewClipDepth());
}
if (Entity* entity = std::get_if<Entity>(&element)) {
actual.push_back(entity->GetNewClipDepth());
}
return true;
});

ASSERT_EQ(actual.size(), expected.size());
for (size_t i = 0; i < expected.size(); i++) {
EXPECT_EQ(actual[i], expected[i]) << "Index: " << i;
}
}

} // namespace testing
} // namespace impeller
55 changes: 35 additions & 20 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ Canvas::~Canvas() = default;
void Canvas::Initialize(std::optional<Rect> cull_rect) {
initial_cull_rect_ = cull_rect;
base_pass_ = std::make_unique<EntityPass>();
base_pass_->SetNewClipDepth(++current_depth_);
current_pass_ = base_pass_.get();
transform_stack_.emplace_back(CanvasStackEntry{.cull_rect = cull_rect});
FML_DCHECK(GetSaveCount() == 1u);
Expand All @@ -126,6 +127,7 @@ void Canvas::Initialize(std::optional<Rect> cull_rect) {
void Canvas::Reset() {
base_pass_ = nullptr;
current_pass_ = nullptr;
current_depth_ = 0u;
transform_stack_ = {};
}

Expand Down Expand Up @@ -174,6 +176,7 @@ void Canvas::Save(bool create_subpass,
if (create_subpass) {
entry.rendering_mode = Entity::RenderingMode::kSubpass;
auto subpass = std::make_unique<EntityPass>();
subpass->SetNewClipDepth(++current_depth_);
subpass->SetEnableOffscreenCheckerboard(
debug_options.offscreen_texture_checkerboard);
if (backdrop_filter) {
Expand Down Expand Up @@ -206,16 +209,16 @@ bool Canvas::Restore() {
if (transform_stack_.size() == 1) {
return false;
}
size_t num_clips = transform_stack_.back().num_clips;
if (transform_stack_.back().rendering_mode ==
Entity::RenderingMode::kSubpass) {
current_pass_->PopClips(num_clips, current_depth_);
current_pass_ = GetCurrentPass().GetSuperpass();
FML_DCHECK(current_pass_);
}

bool contains_clips = transform_stack_.back().contains_clips;
transform_stack_.pop_back();

if (contains_clips) {
if (num_clips > 0) {
RestoreClip();
}

Expand Down Expand Up @@ -290,7 +293,7 @@ void Canvas::DrawPath(const Path& path, const Paint& paint) {
entity.SetBlendMode(paint.blend_mode);
entity.SetContents(CreatePathContentsWithFilters(paint, path));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

void Canvas::DrawPaint(const Paint& paint) {
Expand All @@ -300,7 +303,7 @@ void Canvas::DrawPaint(const Paint& paint) {
entity.SetBlendMode(paint.blend_mode);
entity.SetContents(CreateCoverContentsWithFilters(paint));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

bool Canvas::AttemptDrawBlurredRRect(const Rect& rect,
Expand Down Expand Up @@ -338,7 +341,7 @@ bool Canvas::AttemptDrawBlurredRRect(const Rect& rect,
entity.SetBlendMode(new_paint.blend_mode);
entity.SetContents(new_paint.WithFilters(std::move(contents)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));

return true;
}
Expand All @@ -351,7 +354,7 @@ void Canvas::DrawLine(const Point& p0, const Point& p1, const Paint& paint) {
entity.SetContents(CreateContentsForGeometryWithFilters(
paint, Geometry::MakeLine(p0, p1, paint.stroke_width, paint.stroke_cap)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

void Canvas::DrawRect(const Rect& rect, const Paint& paint) {
Expand All @@ -371,7 +374,7 @@ void Canvas::DrawRect(const Rect& rect, const Paint& paint) {
entity.SetContents(
CreateContentsForGeometryWithFilters(paint, Geometry::MakeRect(rect)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

void Canvas::DrawOval(const Rect& rect, const Paint& paint) {
Expand All @@ -398,7 +401,7 @@ void Canvas::DrawOval(const Rect& rect, const Paint& paint) {
entity.SetContents(
CreateContentsForGeometryWithFilters(paint, Geometry::MakeOval(rect)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

void Canvas::DrawRRect(const Rect& rect,
Expand All @@ -416,7 +419,7 @@ void Canvas::DrawRRect(const Rect& rect,
entity.SetContents(CreateContentsForGeometryWithFilters(
paint, Geometry::MakeRoundRect(rect, corner_radii)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
return;
}

Expand Down Expand Up @@ -449,7 +452,7 @@ void Canvas::DrawCircle(const Point& center,
entity.SetContents(
CreateContentsForGeometryWithFilters(paint, std::move(geometry)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

void Canvas::ClipPath(const Path& path, Entity::ClipOperation clip_op) {
Expand Down Expand Up @@ -554,10 +557,10 @@ void Canvas::ClipGeometry(const std::shared_ptr<Geometry>& geometry,
entity.SetContents(std::move(contents));
entity.SetClipDepth(GetClipDepth());

GetCurrentPass().AddEntity(std::move(entity));
GetCurrentPass().PushClip(std::move(entity));

++transform_stack_.back().clip_depth;
transform_stack_.back().contains_clips = true;
++transform_stack_.back().num_clips;
}

void Canvas::IntersectCulling(Rect clip_rect) {
Expand Down Expand Up @@ -593,7 +596,8 @@ void Canvas::RestoreClip() {
entity.SetContents(std::make_shared<ClipRestoreContents>());
entity.SetClipDepth(GetClipDepth());

GetCurrentPass().AddEntity(std::move(entity));
// TODO(bdero): To be removed when swapping the clip strategy.
AddEntityToCurrentPass(std::move(entity));
}

void Canvas::DrawPoints(std::vector<Point> points,
Expand All @@ -613,7 +617,7 @@ void Canvas::DrawPoints(std::vector<Point> points,
Geometry::MakePointField(std::move(points), radius,
/*round=*/point_style == PointStyle::kRound)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

void Canvas::DrawPicture(const Picture& picture) {
Expand Down Expand Up @@ -690,10 +694,16 @@ void Canvas::DrawImageRect(const std::shared_ptr<Image>& image,
entity.SetContents(paint.WithFilters(contents));
entity.SetTransform(GetCurrentTransform());

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

Picture Canvas::EndRecordingAsPicture() {
// Assign clip depths to any outstanding clip entities.
while (current_pass_ != nullptr) {
current_pass_->PopAllClips(current_depth_);
current_pass_ = current_pass_->GetSuperpass();
}

Picture picture;
picture.pass = std::move(base_pass_);

Expand All @@ -712,6 +722,11 @@ size_t Canvas::GetClipDepth() const {
return transform_stack_.back().clip_depth;
}

void Canvas::AddEntityToCurrentPass(Entity entity) {
entity.SetNewClipDepth(++current_depth_);
GetCurrentPass().AddEntity(std::move(entity));
}

void Canvas::SaveLayer(const Paint& paint,
std::optional<Rect> bounds,
const std::shared_ptr<ImageFilter>& backdrop_filter) {
Expand Down Expand Up @@ -768,7 +783,7 @@ void Canvas::DrawTextFrame(const std::shared_ptr<TextFrame>& text_frame,
entity.SetContents(
paint.WithFilters(paint.WithMaskBlur(std::move(text_contents), true)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

static bool UseColorSourceContents(
Expand Down Expand Up @@ -807,7 +822,7 @@ void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& vertices,
// are vertex coordinates then only if the contents are an image.
if (UseColorSourceContents(vertices, paint)) {
entity.SetContents(CreateContentsForGeometryWithFilters(paint, vertices));
GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
return;
}

Expand Down Expand Up @@ -845,7 +860,7 @@ void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& vertices,
contents->SetSourceContents(std::move(src_contents));
entity.SetContents(paint.WithFilters(std::move(contents)));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

void Canvas::DrawAtlas(const std::shared_ptr<Image>& atlas,
Expand Down Expand Up @@ -876,7 +891,7 @@ void Canvas::DrawAtlas(const std::shared_ptr<Image>& atlas,
entity.SetBlendMode(paint.blend_mode);
entity.SetContents(paint.WithFilters(contents));

GetCurrentPass().AddEntity(std::move(entity));
AddEntityToCurrentPass(std::move(entity));
}

} // namespace impeller
6 changes: 5 additions & 1 deletion impeller/aiks/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ struct CanvasStackEntry {
// |cull_rect| is conservative screen-space bounds of the clipped output area
std::optional<Rect> cull_rect;
size_t clip_depth = 0u;
// The number of clips tracked for this canvas stack entry.
size_t num_clips = 0u;
Entity::RenderingMode rendering_mode = Entity::RenderingMode::kDirect;
bool contains_clips = false;
};

enum class PointStyle {
Expand Down Expand Up @@ -181,6 +182,7 @@ class Canvas {
private:
std::unique_ptr<EntityPass> base_pass_;
EntityPass* current_pass_ = nullptr;
uint64_t current_depth_ = 0u;
std::deque<CanvasStackEntry> transform_stack_;
std::optional<Rect> initial_cull_rect_;

Expand All @@ -192,6 +194,8 @@ class Canvas {

size_t GetClipDepth() const;

void AddEntityToCurrentPass(Entity entity);

void ClipGeometry(const std::shared_ptr<Geometry>& geometry,
Entity::ClipOperation clip_op);

Expand Down
3 changes: 3 additions & 0 deletions impeller/entity/contents/atlas_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ bool AtlasContents::Render(const ContentContext& renderer,

FS::FragInfo frag_info;
VS::FrameInfo frame_info;
frame_info.depth = entity.GetShaderClipDepth();

auto dst_sampler_descriptor = sampler_descriptor_;
if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
Expand Down Expand Up @@ -404,6 +405,7 @@ bool AtlasTextureContents::Render(const ContentContext& renderer,
auto& host_buffer = renderer.GetTransientsBuffer();

VS::FrameInfo frame_info;
frame_info.depth = entity.GetShaderClipDepth();
frame_info.mvp = pass.GetOrthographicTransform() * entity.GetTransform();
frame_info.texture_sampler_y_coord_scale = texture->GetYCoordScale();
frame_info.alpha = alpha_;
Expand Down Expand Up @@ -490,6 +492,7 @@ bool AtlasColorContents::Render(const ContentContext& renderer,
auto& host_buffer = renderer.GetTransientsBuffer();

VS::FrameInfo frame_info;
frame_info.depth = entity.GetShaderClipDepth();
frame_info.mvp = pass.GetOrthographicTransform() * entity.GetTransform();

FS::FragInfo frag_info;
Expand Down
6 changes: 4 additions & 2 deletions impeller/entity/contents/clip_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,19 @@ bool ClipContents::Render(const ContentContext& renderer,
using VS = ClipPipeline::VertexShader;

VS::FrameInfo info;
info.depth = entity.GetShaderClipDepth();

auto options = OptionsFromPass(pass);
options.blend_mode = BlendMode::kDestination;
pass.SetStencilReference(entity.GetClipDepth());
options.stencil_compare = CompareFunction::kEqual;
options.stencil_operation = StencilOperation::kIncrementClamp;

if (clip_op_ == Entity::ClipOperation::kDifference) {
{
pass.SetCommandLabel("Difference Clip (Increment)");

options.stencil_compare = CompareFunction::kEqual;
options.stencil_operation = StencilOperation::kIncrementClamp;

auto points = Rect::MakeSize(pass.GetRenderTargetSize()).GetPoints();
auto vertices =
VertexBufferBuilder<VS::PerVertexData>{}
Expand Down
2 changes: 2 additions & 0 deletions impeller/entity/contents/conical_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ bool ConicalGradientContents::RenderSSBO(const ContentContext& renderer,
DefaultUniformAlignment());

VS::FrameInfo frame_info;
frame_info.depth = entity.GetShaderClipDepth();
frame_info.mvp = pass.GetOrthographicTransform() * entity.GetTransform();
frame_info.matrix = GetInverseEffectTransform();

Expand Down Expand Up @@ -155,6 +156,7 @@ bool ConicalGradientContents::RenderTexture(const ContentContext& renderer,
GetGeometry()->GetPositionBuffer(renderer, entity, pass);

VS::FrameInfo frame_info;
frame_info.depth = entity.GetShaderClipDepth();
frame_info.mvp = geometry_result.transform;
frame_info.matrix = GetInverseEffectTransform();

Expand Down
5 changes: 3 additions & 2 deletions impeller/entity/contents/content_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,9 @@ void ContentContextOptions::ApplyToPipelineDescriptor(
}
if (maybe_depth.has_value()) {
DepthAttachmentDescriptor depth = maybe_depth.value();
depth.depth_compare = CompareFunction::kAlways;
depth.depth_write_enabled = false;
depth.depth_write_enabled = depth_write_enabled;
depth.depth_compare = depth_compare;
desc.SetDepthStencilAttachmentDescriptor(depth);
}

desc.SetPrimitiveType(primitive_type);
Expand Down
15 changes: 11 additions & 4 deletions impeller/entity/contents/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,11 +288,13 @@ struct PendingCommandBuffers {
struct ContentContextOptions {
SampleCount sample_count = SampleCount::kCount1;
BlendMode blend_mode = BlendMode::kSourceOver;
CompareFunction depth_compare = CompareFunction::kAlways;
CompareFunction stencil_compare = CompareFunction::kEqual;
StencilOperation stencil_operation = StencilOperation::kKeep;
PrimitiveType primitive_type = PrimitiveType::kTriangle;
PixelFormat color_attachment_pixel_format = PixelFormat::kUnknown;
bool has_depth_stencil_attachments = true;
bool depth_write_enabled = false;
bool wireframe = false;
bool is_for_rrect_blur_clear = false;

Expand All @@ -301,6 +303,7 @@ struct ContentContextOptions {
static_assert(sizeof(o.sample_count) == 1);
static_assert(sizeof(o.blend_mode) == 1);
static_assert(sizeof(o.sample_count) == 1);
static_assert(sizeof(o.depth_compare) == 1);
static_assert(sizeof(o.stencil_compare) == 1);
static_assert(sizeof(o.stencil_operation) == 1);
static_assert(sizeof(o.primitive_type) == 1);
Expand All @@ -309,11 +312,13 @@ struct ContentContextOptions {
return (o.is_for_rrect_blur_clear ? 1llu : 0llu) << 0 |
(o.wireframe ? 1llu : 0llu) << 1 |
(o.has_depth_stencil_attachments ? 1llu : 0llu) << 2 |
(o.depth_write_enabled ? 1llu : 0llu) << 3 |
// enums
static_cast<uint64_t>(o.color_attachment_pixel_format) << 16 |
static_cast<uint64_t>(o.primitive_type) << 24 |
static_cast<uint64_t>(o.stencil_operation) << 32 |
static_cast<uint64_t>(o.stencil_compare) << 40 |
static_cast<uint64_t>(o.color_attachment_pixel_format) << 8 |
static_cast<uint64_t>(o.primitive_type) << 16 |
static_cast<uint64_t>(o.stencil_operation) << 24 |
static_cast<uint64_t>(o.stencil_compare) << 32 |
static_cast<uint64_t>(o.depth_compare) << 40 |
static_cast<uint64_t>(o.blend_mode) << 48 |
static_cast<uint64_t>(o.sample_count) << 56;
}
Expand All @@ -324,6 +329,8 @@ struct ContentContextOptions {
const ContentContextOptions& rhs) const {
return lhs.sample_count == rhs.sample_count &&
lhs.blend_mode == rhs.blend_mode &&
lhs.depth_write_enabled == rhs.depth_write_enabled &&
lhs.depth_compare == rhs.depth_compare &&
lhs.stencil_compare == rhs.stencil_compare &&
lhs.stencil_operation == rhs.stencil_operation &&
lhs.primitive_type == rhs.primitive_type &&
Expand Down
Loading