Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 29c2845

Browse files
authored
[Impeller] Absorb DrawPaints at the beginning of EntityPasses (#40675)
1 parent f44d020 commit 29c2845

File tree

6 files changed

+79
-23
lines changed

6 files changed

+79
-23
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,5 +1993,17 @@ TEST_P(AiksTest, OpacityPeepHoleApplicationTest) {
19931993
ASSERT_TRUE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
19941994
}
19951995

1996+
TEST_P(AiksTest, DrawPaintAbsorbsClears) {
1997+
Canvas canvas;
1998+
canvas.DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource});
1999+
canvas.DrawPaint(
2000+
{.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kSource});
2001+
2002+
Picture picture = canvas.EndRecordingAsPicture();
2003+
2004+
ASSERT_EQ(picture.pass->GetElementCount(), 0u);
2005+
ASSERT_EQ(picture.pass->GetClearColor(), Color::CornflowerBlue());
2006+
}
2007+
19962008
} // namespace testing
19972009
} // namespace impeller

impeller/aiks/canvas.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,18 @@ void Canvas::DrawPath(const Path& path, const Paint& paint) {
167167
}
168168

169169
void Canvas::DrawPaint(const Paint& paint) {
170+
bool is_clear =
171+
paint.blend_mode == BlendMode::kSource ||
172+
(paint.blend_mode == BlendMode::kSourceOver && paint.color.alpha == 1);
173+
if (xformation_stack_.size() == 1 && // If we're recording the root pass,
174+
GetCurrentPass().GetElementCount() == 0 && // and this is the first item,
175+
is_clear // and the backdrop is being replaced
176+
) {
177+
// Then we can absorb this drawPaint as the clear color of the pass.
178+
GetCurrentPass().SetClearColor(paint.color);
179+
return;
180+
}
181+
170182
Entity entity;
171183
entity.SetTransformation(GetCurrentTransformation());
172184
entity.SetStencilDepth(GetStencilDepth());

impeller/aiks/paint_pass_delegate.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ bool OpacityPeepholePassDelegate::CanCollapseIntoParentPass(
8585
// command wrapped in save layer. This would indicate something like an
8686
// Opacity or FadeTransition wrapping a very simple widget, like in the
8787
// CupertinoPicker.
88-
if (entity_pass->GetEntityCount() > 3) {
88+
if (entity_pass->GetElementCount() > 3) {
8989
// Single paint command with a save layer would be:
9090
// 1. clip
9191
// 2. draw command

impeller/entity/entity_pass.cc

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
144144

145145
static EntityPassTarget CreateRenderTarget(ContentContext& renderer,
146146
ISize size,
147-
bool readable) {
147+
bool readable,
148+
const Color& clear_color) {
148149
auto context = renderer.GetContext();
149150

150151
/// All of the load/store actions are managed by `InlinePassContext` when
@@ -163,7 +164,7 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer,
163164
.resolve_storage_mode = StorageMode::kDevicePrivate,
164165
.load_action = LoadAction::kDontCare,
165166
.store_action = StoreAction::kMultisampleResolve,
166-
}, // color_attachment_config
167+
.clear_color = clear_color}, // color_attachment_config
167168
RenderTarget::AttachmentConfig{
168169
.storage_mode = readable ? StorageMode::kDevicePrivate
169170
: StorageMode::kDeviceTransient,
@@ -203,13 +204,18 @@ uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer) const {
203204

204205
bool EntityPass::Render(ContentContext& renderer,
205206
const RenderTarget& render_target) const {
207+
if (render_target.GetColorAttachments().empty()) {
208+
VALIDATION_LOG << "The root RenderTarget must have a color attachment.";
209+
return false;
210+
}
211+
206212
StencilCoverageStack stencil_coverage_stack = {StencilCoverageLayer{
207213
.coverage = Rect::MakeSize(render_target.GetRenderTargetSize()),
208214
.stencil_depth = 0}};
209215

210216
if (GetTotalPassReads(renderer) > 0) {
211-
auto offscreen_target =
212-
CreateRenderTarget(renderer, render_target.GetRenderTargetSize(), true);
217+
auto offscreen_target = CreateRenderTarget(
218+
renderer, render_target.GetRenderTargetSize(), true, clear_color_);
213219

214220
if (!OnRender(renderer, // renderer
215221
offscreen_target.GetRenderTarget()
@@ -269,18 +275,25 @@ bool EntityPass::Render(ContentContext& renderer,
269275
return true;
270276
}
271277

278+
// Set up the clear color of the root pass.
279+
auto color0 = render_target.GetColorAttachments().find(0)->second;
280+
color0.clear_color = clear_color_;
281+
282+
auto root_render_target = render_target;
283+
root_render_target.SetColorAttachment(color0, 0);
284+
272285
EntityPassTarget pass_target(
273-
render_target,
286+
root_render_target,
274287
renderer.GetDeviceCapabilities().SupportsReadFromResolve());
275288

276-
return OnRender( //
277-
renderer, // renderer
278-
render_target.GetRenderTargetSize(), // root_pass_size
279-
pass_target, // pass_target
280-
Point(), // global_pass_position
281-
Point(), // local_pass_position
282-
0, // pass_depth
283-
stencil_coverage_stack); // stencil_coverage_stack
289+
return OnRender( //
290+
renderer, // renderer
291+
root_render_target.GetRenderTargetSize(), // root_pass_size
292+
pass_target, // pass_target
293+
Point(), // global_pass_position
294+
Point(), // local_pass_position
295+
0, // pass_depth
296+
stencil_coverage_stack); // stencil_coverage_stack
284297
}
285298

286299
EntityPass::EntityResult EntityPass::GetEntityForElement(
@@ -386,9 +399,10 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
386399
subpass_coverage->Intersection(Rect::MakeSize(root_pass_size));
387400

388401
auto subpass_target =
389-
CreateRenderTarget(renderer, //
390-
ISize(subpass_coverage->size), //
391-
subpass->GetTotalPassReads(renderer) > 0);
402+
CreateRenderTarget(renderer, //
403+
ISize(subpass_coverage->size), //
404+
subpass->GetTotalPassReads(renderer) > 0, //
405+
clear_color_);
392406

393407
auto subpass_texture =
394408
subpass_target.GetRenderTarget().GetRenderTargetTexture();
@@ -701,7 +715,7 @@ bool EntityPass::IterateUntilSubpass(
701715
return false;
702716
}
703717

704-
size_t EntityPass::GetEntityCount() const {
718+
size_t EntityPass::GetElementCount() const {
705719
return elements_.size();
706720
}
707721

@@ -739,6 +753,14 @@ void EntityPass::SetBlendMode(BlendMode blend_mode) {
739753
cover_whole_screen_ = Entity::IsBlendModeDestructive(blend_mode);
740754
}
741755

756+
void EntityPass::SetClearColor(Color clear_color) {
757+
clear_color_ = clear_color;
758+
}
759+
760+
Color EntityPass::GetClearColor() const {
761+
return clear_color_;
762+
}
763+
742764
void EntityPass::SetBackdropFilter(std::optional<BackdropFilterProc> proc) {
743765
if (superpass_) {
744766
VALIDATION_LOG << "Backdrop filters cannot be set on EntityPasses that "

impeller/entity/entity_pass.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,19 @@ class EntityPass {
7777
/// @return Returns whether a subpass was encountered.
7878
bool IterateUntilSubpass(const std::function<bool(Entity&)>& iterator);
7979

80-
/// @brief Return the number of entities on this pass.
81-
size_t GetEntityCount() const;
80+
/// @brief Return the number of elements on this pass.
81+
size_t GetElementCount() const;
8282

8383
void SetTransformation(Matrix xformation);
8484

8585
void SetStencilDepth(size_t stencil_depth);
8686

8787
void SetBlendMode(BlendMode blend_mode);
8888

89+
void SetClearColor(Color clear_color);
90+
91+
Color GetClearColor() const;
92+
8993
void SetBackdropFilter(std::optional<BackdropFilterProc> proc);
9094

9195
std::optional<Rect> GetSubpassCoverage(
@@ -204,6 +208,7 @@ class EntityPass {
204208
size_t stencil_depth_ = 0u;
205209
BlendMode blend_mode_ = BlendMode::kSourceOver;
206210
bool cover_whole_screen_ = false;
211+
Color clear_color_ = Color::BlackTransparent();
207212

208213
/// These values are incremented whenever something is added to the pass that
209214
/// requires reading from the backdrop texture. Currently, this can happen in

impeller/renderer/render_target.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,35 @@ class RenderTarget final {
2323
StorageMode storage_mode;
2424
LoadAction load_action;
2525
StoreAction store_action;
26+
Color clear_color;
2627
};
2728

2829
struct AttachmentConfigMSAA {
2930
StorageMode storage_mode;
3031
StorageMode resolve_storage_mode;
3132
LoadAction load_action;
3233
StoreAction store_action;
34+
Color clear_color;
3335
};
3436

3537
static constexpr AttachmentConfig kDefaultColorAttachmentConfig = {
3638
.storage_mode = StorageMode::kDevicePrivate,
3739
.load_action = LoadAction::kClear,
38-
.store_action = StoreAction::kStore};
40+
.store_action = StoreAction::kStore,
41+
.clear_color = Color::BlackTransparent()};
3942

4043
static constexpr AttachmentConfigMSAA kDefaultColorAttachmentConfigMSAA = {
4144
.storage_mode = StorageMode::kDeviceTransient,
4245
.resolve_storage_mode = StorageMode::kDevicePrivate,
4346
.load_action = LoadAction::kClear,
44-
.store_action = StoreAction::kMultisampleResolve};
47+
.store_action = StoreAction::kMultisampleResolve,
48+
.clear_color = Color::BlackTransparent()};
4549

4650
static constexpr AttachmentConfig kDefaultStencilAttachmentConfig = {
4751
.storage_mode = StorageMode::kDeviceTransient,
4852
.load_action = LoadAction::kClear,
49-
.store_action = StoreAction::kDontCare};
53+
.store_action = StoreAction::kDontCare,
54+
.clear_color = Color::BlackTransparent()};
5055

5156
static RenderTarget CreateOffscreen(
5257
const Context& context,

0 commit comments

Comments
 (0)