mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Absorb DrawPaints at the beginning of EntityPasses (flutter/engine#40675)
This commit is contained in:
parent
77ccb6fc1e
commit
155e6ccbf2
@ -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
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 "
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user