Skip to content

Commit c29c132

Browse files
authored
[Impeller] Fix DrawPicture. (flutter#43446)
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).
1 parent 48bf7ac commit c29c132

File tree

5 files changed

+47
-3
lines changed

5 files changed

+47
-3
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,5 +2837,19 @@ TEST_P(AiksTest, TextForegroundShaderWithTransform) {
28372837
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
28382838
}
28392839

2840+
TEST_P(AiksTest, CanCanvasDrawPicture) {
2841+
Canvas subcanvas;
2842+
subcanvas.DrawRect(Rect::MakeLTRB(-100, -50, 100, 50),
2843+
{.color = Color::CornflowerBlue()});
2844+
auto picture = subcanvas.EndRecordingAsPicture();
2845+
2846+
Canvas canvas;
2847+
canvas.Translate({200, 200});
2848+
canvas.Rotate(Radians(kPi / 4));
2849+
canvas.DrawPicture(picture);
2850+
2851+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
2852+
}
2853+
28402854
} // namespace testing
28412855
} // namespace impeller

impeller/aiks/canvas.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,10 +401,14 @@ void Canvas::DrawPoints(std::vector<Point> points,
401401
GetCurrentPass().AddEntity(entity);
402402
}
403403

404-
void Canvas::DrawPicture(Picture picture) {
404+
void Canvas::DrawPicture(const Picture& picture) {
405405
if (!picture.pass) {
406406
return;
407407
}
408+
409+
auto save_count = GetSaveCount();
410+
Save();
411+
408412
// Clone the base pass and account for the CTM updates.
409413
auto pass = picture.pass->Clone();
410414
pass->IterateAllEntities([&](auto& entity) -> bool {
@@ -413,7 +417,9 @@ void Canvas::DrawPicture(Picture picture) {
413417
entity.GetTransformation());
414418
return true;
415419
});
416-
return;
420+
GetCurrentPass().AddSubpassInline(std::move(pass));
421+
422+
RestoreToCount(save_count);
417423
}
418424

419425
void Canvas::DrawImage(const std::shared_ptr<Image>& image,

impeller/aiks/canvas.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class Canvas {
137137
Scalar corner_radius,
138138
Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect);
139139

140-
void DrawPicture(Picture picture);
140+
void DrawPicture(const Picture& picture);
141141

142142
void DrawTextFrame(const TextFrame& text_frame,
143143
Point position,

impeller/entity/entity_pass.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,22 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
167167
return subpass_pointer;
168168
}
169169

170+
void EntityPass::AddSubpassInline(std::unique_ptr<EntityPass> pass) {
171+
if (!pass) {
172+
return;
173+
}
174+
FML_DCHECK(pass->superpass_ == nullptr);
175+
176+
elements_.insert(elements_.end(),
177+
std::make_move_iterator(pass->elements_.begin()),
178+
std::make_move_iterator(pass->elements_.end()));
179+
180+
backdrop_filter_reads_from_pass_texture_ +=
181+
pass->backdrop_filter_reads_from_pass_texture_;
182+
advanced_blend_reads_from_pass_texture_ +=
183+
pass->advanced_blend_reads_from_pass_texture_;
184+
}
185+
170186
static RenderTarget::AttachmentConfig GetDefaultStencilConfig(bool readable) {
171187
return RenderTarget::AttachmentConfig{
172188
.storage_mode = readable ? StorageMode::kDevicePrivate

impeller/entity/entity_pass.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,21 @@ class EntityPass {
6262

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

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

68+
/// @brief Merges a given pass into this pass. Useful for drawing
69+
/// pre-recorded pictures that don't require rendering into a separate
70+
/// subpass.
71+
void AddSubpassInline(std::unique_ptr<EntityPass> pass);
72+
6773
EntityPass* GetSuperpass() const;
6874

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

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

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

0 commit comments

Comments
 (0)