[Impeller] Absorb DrawPaints at the beginning of EntityPasses (flutter/engine#40675)

This commit is contained in:
Brandon DeRosier 2023-03-28 12:33:21 -07:00 committed by GitHub
parent 77ccb6fc1e
commit 155e6ccbf2
6 changed files with 79 additions and 23 deletions

View File

@ -1993,5 +1993,17 @@ TEST_P(AiksTest, OpacityPeepHoleApplicationTest) {
ASSERT_TRUE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
}
TEST_P(AiksTest, DrawPaintAbsorbsClears) {
Canvas canvas;
canvas.DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource});
canvas.DrawPaint(
{.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kSource});
Picture picture = canvas.EndRecordingAsPicture();
ASSERT_EQ(picture.pass->GetElementCount(), 0u);
ASSERT_EQ(picture.pass->GetClearColor(), Color::CornflowerBlue());
}
} // namespace testing
} // namespace impeller

View File

@ -167,6 +167,18 @@ void Canvas::DrawPath(const Path& path, const Paint& paint) {
}
void Canvas::DrawPaint(const Paint& paint) {
bool is_clear =
paint.blend_mode == BlendMode::kSource ||
(paint.blend_mode == BlendMode::kSourceOver && paint.color.alpha == 1);
if (xformation_stack_.size() == 1 && // If we're recording the root pass,
GetCurrentPass().GetElementCount() == 0 && // and this is the first item,
is_clear // and the backdrop is being replaced
) {
// Then we can absorb this drawPaint as the clear color of the pass.
GetCurrentPass().SetClearColor(paint.color);
return;
}
Entity entity;
entity.SetTransformation(GetCurrentTransformation());
entity.SetStencilDepth(GetStencilDepth());

View File

@ -85,7 +85,7 @@ bool OpacityPeepholePassDelegate::CanCollapseIntoParentPass(
// command wrapped in save layer. This would indicate something like an
// Opacity or FadeTransition wrapping a very simple widget, like in the
// CupertinoPicker.
if (entity_pass->GetEntityCount() > 3) {
if (entity_pass->GetElementCount() > 3) {
// Single paint command with a save layer would be:
// 1. clip
// 2. draw command

View File

@ -144,7 +144,8 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
static EntityPassTarget CreateRenderTarget(ContentContext& renderer,
ISize size,
bool readable) {
bool readable,
const Color& clear_color) {
auto context = renderer.GetContext();
/// All of the load/store actions are managed by `InlinePassContext` when
@ -163,7 +164,7 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer,
.resolve_storage_mode = StorageMode::kDevicePrivate,
.load_action = LoadAction::kDontCare,
.store_action = StoreAction::kMultisampleResolve,
}, // color_attachment_config
.clear_color = clear_color}, // color_attachment_config
RenderTarget::AttachmentConfig{
.storage_mode = readable ? StorageMode::kDevicePrivate
: StorageMode::kDeviceTransient,
@ -203,13 +204,18 @@ uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer) const {
bool EntityPass::Render(ContentContext& renderer,
const RenderTarget& render_target) const {
if (render_target.GetColorAttachments().empty()) {
VALIDATION_LOG << "The root RenderTarget must have a color attachment.";
return false;
}
StencilCoverageStack stencil_coverage_stack = {StencilCoverageLayer{
.coverage = Rect::MakeSize(render_target.GetRenderTargetSize()),
.stencil_depth = 0}};
if (GetTotalPassReads(renderer) > 0) {
auto offscreen_target =
CreateRenderTarget(renderer, render_target.GetRenderTargetSize(), true);
auto offscreen_target = CreateRenderTarget(
renderer, render_target.GetRenderTargetSize(), true, clear_color_);
if (!OnRender(renderer, // renderer
offscreen_target.GetRenderTarget()
@ -269,18 +275,25 @@ bool EntityPass::Render(ContentContext& renderer,
return true;
}
// Set up the clear color of the root pass.
auto color0 = render_target.GetColorAttachments().find(0)->second;
color0.clear_color = clear_color_;
auto root_render_target = render_target;
root_render_target.SetColorAttachment(color0, 0);
EntityPassTarget pass_target(
render_target,
root_render_target,
renderer.GetDeviceCapabilities().SupportsReadFromResolve());
return OnRender( //
renderer, // renderer
render_target.GetRenderTargetSize(), // root_pass_size
pass_target, // pass_target
Point(), // global_pass_position
Point(), // local_pass_position
0, // pass_depth
stencil_coverage_stack); // stencil_coverage_stack
return OnRender( //
renderer, // renderer
root_render_target.GetRenderTargetSize(), // root_pass_size
pass_target, // pass_target
Point(), // global_pass_position
Point(), // local_pass_position
0, // pass_depth
stencil_coverage_stack); // stencil_coverage_stack
}
EntityPass::EntityResult EntityPass::GetEntityForElement(
@ -386,9 +399,10 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
subpass_coverage->Intersection(Rect::MakeSize(root_pass_size));
auto subpass_target =
CreateRenderTarget(renderer, //
ISize(subpass_coverage->size), //
subpass->GetTotalPassReads(renderer) > 0);
CreateRenderTarget(renderer, //
ISize(subpass_coverage->size), //
subpass->GetTotalPassReads(renderer) > 0, //
clear_color_);
auto subpass_texture =
subpass_target.GetRenderTarget().GetRenderTargetTexture();
@ -701,7 +715,7 @@ bool EntityPass::IterateUntilSubpass(
return false;
}
size_t EntityPass::GetEntityCount() const {
size_t EntityPass::GetElementCount() const {
return elements_.size();
}
@ -739,6 +753,14 @@ void EntityPass::SetBlendMode(BlendMode blend_mode) {
cover_whole_screen_ = Entity::IsBlendModeDestructive(blend_mode);
}
void EntityPass::SetClearColor(Color clear_color) {
clear_color_ = clear_color;
}
Color EntityPass::GetClearColor() const {
return clear_color_;
}
void EntityPass::SetBackdropFilter(std::optional<BackdropFilterProc> proc) {
if (superpass_) {
VALIDATION_LOG << "Backdrop filters cannot be set on EntityPasses that "

View File

@ -77,8 +77,8 @@ class EntityPass {
/// @return Returns whether a subpass was encountered.
bool IterateUntilSubpass(const std::function<bool(Entity&)>& iterator);
/// @brief Return the number of entities on this pass.
size_t GetEntityCount() const;
/// @brief Return the number of elements on this pass.
size_t GetElementCount() const;
void SetTransformation(Matrix xformation);
@ -86,6 +86,10 @@ class EntityPass {
void SetBlendMode(BlendMode blend_mode);
void SetClearColor(Color clear_color);
Color GetClearColor() const;
void SetBackdropFilter(std::optional<BackdropFilterProc> proc);
std::optional<Rect> GetSubpassCoverage(
@ -204,6 +208,7 @@ class EntityPass {
size_t stencil_depth_ = 0u;
BlendMode blend_mode_ = BlendMode::kSourceOver;
bool cover_whole_screen_ = false;
Color clear_color_ = Color::BlackTransparent();
/// These values are incremented whenever something is added to the pass that
/// requires reading from the backdrop texture. Currently, this can happen in

View File

@ -23,6 +23,7 @@ class RenderTarget final {
StorageMode storage_mode;
LoadAction load_action;
StoreAction store_action;
Color clear_color;
};
struct AttachmentConfigMSAA {
@ -30,23 +31,27 @@ class RenderTarget final {
StorageMode resolve_storage_mode;
LoadAction load_action;
StoreAction store_action;
Color clear_color;
};
static constexpr AttachmentConfig kDefaultColorAttachmentConfig = {
.storage_mode = StorageMode::kDevicePrivate,
.load_action = LoadAction::kClear,
.store_action = StoreAction::kStore};
.store_action = StoreAction::kStore,
.clear_color = Color::BlackTransparent()};
static constexpr AttachmentConfigMSAA kDefaultColorAttachmentConfigMSAA = {
.storage_mode = StorageMode::kDeviceTransient,
.resolve_storage_mode = StorageMode::kDevicePrivate,
.load_action = LoadAction::kClear,
.store_action = StoreAction::kMultisampleResolve};
.store_action = StoreAction::kMultisampleResolve,
.clear_color = Color::BlackTransparent()};
static constexpr AttachmentConfig kDefaultStencilAttachmentConfig = {
.storage_mode = StorageMode::kDeviceTransient,
.load_action = LoadAction::kClear,
.store_action = StoreAction::kDontCare};
.store_action = StoreAction::kDontCare,
.clear_color = Color::BlackTransparent()};
static RenderTarget CreateOffscreen(
const Context& context,