Skip to content

Commit

Permalink
[Impeller] Fix DrawPicture. (flutter#43446)
Browse files Browse the repository at this point in the history
Prior to this patch, `DrawPicture` was untested and a no-op.

We needed a new routine to absorb Elements of a cloned pass into another pass, since appending a `Picture` as a subpass would be incorrect behavior for drawing a picture (since subpasses start with a blank image, which gets drawn to and then composited with the parent pass via a separate blending operation).
  • Loading branch information
bdero authored Jul 6, 2023
1 parent 48bf7ac commit c29c132
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 3 deletions.
14 changes: 14 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2837,5 +2837,19 @@ TEST_P(AiksTest, TextForegroundShaderWithTransform) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanCanvasDrawPicture) {
Canvas subcanvas;
subcanvas.DrawRect(Rect::MakeLTRB(-100, -50, 100, 50),
{.color = Color::CornflowerBlue()});
auto picture = subcanvas.EndRecordingAsPicture();

Canvas canvas;
canvas.Translate({200, 200});
canvas.Rotate(Radians(kPi / 4));
canvas.DrawPicture(picture);

ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

} // namespace testing
} // namespace impeller
10 changes: 8 additions & 2 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,14 @@ void Canvas::DrawPoints(std::vector<Point> points,
GetCurrentPass().AddEntity(entity);
}

void Canvas::DrawPicture(Picture picture) {
void Canvas::DrawPicture(const Picture& picture) {
if (!picture.pass) {
return;
}

auto save_count = GetSaveCount();
Save();

// Clone the base pass and account for the CTM updates.
auto pass = picture.pass->Clone();
pass->IterateAllEntities([&](auto& entity) -> bool {
Expand All @@ -413,7 +417,9 @@ void Canvas::DrawPicture(Picture picture) {
entity.GetTransformation());
return true;
});
return;
GetCurrentPass().AddSubpassInline(std::move(pass));

RestoreToCount(save_count);
}

void Canvas::DrawImage(const std::shared_ptr<Image>& image,
Expand Down
2 changes: 1 addition & 1 deletion impeller/aiks/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class Canvas {
Scalar corner_radius,
Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect);

void DrawPicture(Picture picture);
void DrawPicture(const Picture& picture);

void DrawTextFrame(const TextFrame& text_frame,
Point position,
Expand Down
16 changes: 16 additions & 0 deletions impeller/entity/entity_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,22 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
return subpass_pointer;
}

void EntityPass::AddSubpassInline(std::unique_ptr<EntityPass> pass) {
if (!pass) {
return;
}
FML_DCHECK(pass->superpass_ == nullptr);

elements_.insert(elements_.end(),
std::make_move_iterator(pass->elements_.begin()),
std::make_move_iterator(pass->elements_.end()));

backdrop_filter_reads_from_pass_texture_ +=
pass->backdrop_filter_reads_from_pass_texture_;
advanced_blend_reads_from_pass_texture_ +=
pass->advanced_blend_reads_from_pass_texture_;
}

static RenderTarget::AttachmentConfig GetDefaultStencilConfig(bool readable) {
return RenderTarget::AttachmentConfig{
.storage_mode = readable ? StorageMode::kDevicePrivate
Expand Down
8 changes: 8 additions & 0 deletions impeller/entity/entity_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,21 @@ class EntityPass {

void SetElements(std::vector<Element> elements);

/// @brief Appends a given pass as a subpass.
EntityPass* AddSubpass(std::unique_ptr<EntityPass> pass);

/// @brief Merges a given pass into this pass. Useful for drawing
/// pre-recorded pictures that don't require rendering into a separate
/// subpass.
void AddSubpassInline(std::unique_ptr<EntityPass> pass);

EntityPass* GetSuperpass() const;

bool Render(ContentContext& renderer,
const RenderTarget& render_target) const;

/// @brief Iterate all entities in this pass, recursively including entities
/// of child passes. The iteration order is depth-first.
void IterateAllEntities(const std::function<bool(Entity&)>& iterator);

/// @brief Iterate entities in this pass up until the first subpass is found.
Expand Down

0 comments on commit c29c132

Please sign in to comment.