Skip to content

Commit 65ffd04

Browse files
chinmaygardednfield
authored andcommitted
Rework canvas passes in prep for subpasses.
1 parent 60c3b21 commit 65ffd04

13 files changed

+154
-39
lines changed

impeller/aiks/aiks_unittests.cc

+24
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,30 @@ TEST_F(AiksTest, CanRenderClips) {
103103
canvas.ClipPath(
104104
PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 500, 500)).CreatePath());
105105
canvas.DrawPath(PathBuilder{}.AddCircle({500, 500}, 250).CreatePath(), paint);
106+
// ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
107+
}
108+
109+
TEST_F(AiksTest, CanRenderGroupOpacity) {
110+
Canvas canvas;
111+
112+
Paint red;
113+
red.color = Color::Red(); //.WithAlpha(0.5);
114+
Paint green;
115+
green.color = Color::Green(); //.WithAlpha(0.5);
116+
Paint blue;
117+
blue.color = Color::Blue(); //.WithAlpha(0.5);
118+
119+
Paint alpha;
120+
alpha.color = Color::Red().WithAlpha(0.5);
121+
122+
canvas.SaveLayer(alpha);
123+
124+
canvas.DrawRect({100, 100, 100, 100}, red);
125+
canvas.DrawRect({120, 120, 100, 100}, green);
126+
canvas.DrawRect({140, 140, 100, 100}, blue);
127+
128+
canvas.Restore();
129+
106130
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
107131
}
108132

impeller/aiks/canvas.cc

+49-21
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,30 @@
1212
namespace impeller {
1313

1414
Canvas::Canvas() {
15-
xformation_stack_.push({});
16-
passes_.emplace_back(CanvasPass{});
15+
Save(true);
1716
}
1817

1918
Canvas::~Canvas() = default;
2019

2120
void Canvas::Save() {
22-
FML_DCHECK(xformation_stack_.size() > 0);
23-
xformation_stack_.push(xformation_stack_.top());
21+
Save(false);
2422
}
2523

2624
bool Canvas::Restore() {
2725
FML_DCHECK(xformation_stack_.size() > 0);
2826
if (xformation_stack_.size() == 1) {
2927
return false;
3028
}
31-
xformation_stack_.pop();
29+
xformation_stack_.pop_back();
3230
return true;
3331
}
3432

3533
void Canvas::Concat(const Matrix& xformation) {
36-
const auto current_xformation = xformation_stack_.top().xformation;
37-
xformation_stack_.top().xformation = xformation * current_xformation;
34+
xformation_stack_.back().xformation = xformation * GetCurrentTransformation();
3835
}
3936

4037
const Matrix& Canvas::GetCurrentTransformation() const {
41-
return xformation_stack_.top().xformation;
38+
return xformation_stack_.back().xformation;
4239
}
4340

4441
void Canvas::Translate(const Vector3& offset) {
@@ -71,6 +68,7 @@ void Canvas::DrawPath(Path path, Paint paint) {
7168
entity.SetPath(std::move(path));
7269
entity.SetStencilDepth(GetStencilDepth());
7370
entity.SetContents(paint.CreateContentsForEntity());
71+
7472
GetCurrentPass().PushEntity(std::move(entity));
7573
}
7674

@@ -86,21 +84,23 @@ void Canvas::ClipPath(Path path) {
8684
entity.SetPath(std::move(path));
8785
entity.SetContents(std::make_shared<ClipContents>());
8886
entity.SetStencilDepth(GetStencilDepth());
87+
8988
GetCurrentPass().PushEntity(std::move(entity));
9089
}
9190

9291
void Canvas::DrawShadow(Path path, Color color, Scalar elevation) {}
9392

9493
void Canvas::DrawPicture(const Picture& picture) {
95-
for (const auto& pass : picture.passes) {
96-
CanvasPass new_pass;
97-
for (const auto& entity : pass.GetPassEntities()) {
98-
auto new_entity = entity;
99-
new_entity.SetTransformation(GetCurrentTransformation() *
100-
entity.GetTransformation());
101-
new_pass.PushEntity(std::move(new_entity));
94+
for (const auto& stack_entry : picture.entries) {
95+
auto new_stack_entry = stack_entry;
96+
if (auto pass = new_stack_entry.pass) {
97+
for (auto entity : pass->GetPassEntities()) {
98+
entity.IncrementStencilDepth(GetStencilDepth());
99+
entity.SetTransformation(GetCurrentTransformation() *
100+
entity.GetTransformation());
101+
}
102102
}
103-
passes_.emplace_back(std::move(new_pass));
103+
xformation_stack_.emplace_back(std::move(new_stack_entry));
104104
}
105105
}
106106

@@ -145,21 +145,49 @@ void Canvas::DrawImageRect(std::shared_ptr<Image> image,
145145

146146
Picture Canvas::EndRecordingAsPicture() {
147147
Picture picture;
148-
picture.passes = std::move(passes_);
148+
picture.entries = std::move(xformation_stack_);
149149
return picture;
150150
}
151151

152152
CanvasPass& Canvas::GetCurrentPass() {
153-
FML_DCHECK(!passes_.empty());
154-
return passes_.back();
153+
for (auto i = xformation_stack_.rbegin(), end = xformation_stack_.rend();
154+
i < end; i++) {
155+
if (i->pass.has_value()) {
156+
return i->pass.value();
157+
}
158+
}
159+
FML_UNREACHABLE();
155160
}
156161

157162
void Canvas::IncrementStencilDepth() {
158-
++xformation_stack_.top().stencil_depth;
163+
++xformation_stack_.back().stencil_depth;
159164
}
160165

161166
size_t Canvas::GetStencilDepth() const {
162-
return xformation_stack_.top().stencil_depth;
167+
return xformation_stack_.back().stencil_depth;
168+
}
169+
170+
void Canvas::DrawRect(Rect rect, Paint paint) {
171+
DrawPath(PathBuilder{}.AddRect(rect).CreatePath(), std::move(paint));
172+
}
173+
174+
void Canvas::Save(bool create_subpass) {
175+
// Check if called from the ctor.
176+
if (xformation_stack_.empty()) {
177+
FML_DCHECK(create_subpass) << "Base entries must have a pass.";
178+
CanvasStackEntry entry;
179+
entry.pass = CanvasPass{};
180+
xformation_stack_.emplace_back(std::move(entry));
181+
}
182+
183+
auto entry = CanvasStackEntry{};
184+
185+
entry.xformation = xformation_stack_.back().xformation;
186+
entry.stencil_depth = xformation_stack_.back().stencil_depth;
187+
if (create_subpass) {
188+
entry.pass = CanvasPass{};
189+
}
190+
xformation_stack_.emplace_back(std::move(entry));
163191
}
164192

165193
} // namespace impeller

impeller/aiks/canvas.h

+6-8
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
#pragma once
66

7+
#include <deque>
78
#include <memory>
89
#include <optional>
9-
#include <stack>
1010
#include <vector>
1111

1212
#include "flutter/fml/macros.h"
@@ -23,11 +23,6 @@ namespace impeller {
2323

2424
class Entity;
2525

26-
struct CanvasStackEntry {
27-
Matrix xformation;
28-
size_t stencil_depth = 0u;
29-
};
30-
3126
class Canvas {
3227
public:
3328
Canvas();
@@ -56,6 +51,8 @@ class Canvas {
5651

5752
void DrawPath(Path path, Paint paint);
5853

54+
void DrawRect(Rect rect, Paint paint);
55+
5956
void DrawImage(std::shared_ptr<Image> image, Point offset, Paint paint);
6057

6158
void DrawImageRect(std::shared_ptr<Image> image,
@@ -72,15 +69,16 @@ class Canvas {
7269
Picture EndRecordingAsPicture();
7370

7471
private:
75-
std::stack<CanvasStackEntry> xformation_stack_;
76-
std::vector<CanvasPass> passes_;
72+
std::deque<CanvasStackEntry> xformation_stack_;
7773

7874
CanvasPass& GetCurrentPass();
7975

8076
void IncrementStencilDepth();
8177

8278
size_t GetStencilDepth() const;
8379

80+
void Save(bool create_subpass);
81+
8482
FML_DISALLOW_COPY_AND_ASSIGN(Canvas);
8583
};
8684

impeller/aiks/canvas_pass.cc

+23
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,27 @@ const Entity& CanvasPass::GetPostProcessingEntity() const {
2626
return post_processing_entity_;
2727
}
2828

29+
Rect CanvasPass::GetCoverageRect() const {
30+
std::optional<Point> min, max;
31+
for (const auto& entity : ops_) {
32+
auto coverage = entity.GetPath().GetMinMaxCoveragePoints();
33+
if (!coverage.has_value()) {
34+
continue;
35+
}
36+
if (!min.has_value()) {
37+
min = coverage->first;
38+
}
39+
if (!max.has_value()) {
40+
max = coverage->second;
41+
}
42+
min = min->Min(coverage->first);
43+
max = max->Max(coverage->second);
44+
}
45+
if (!min.has_value() || !max.has_value()) {
46+
return {};
47+
}
48+
const auto diff = *max - *min;
49+
return {min->x, min->y, diff.x, diff.y};
50+
}
51+
2952
} // namespace impeller

impeller/aiks/canvas_pass.h

+9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include <memory>
8+
#include <optional>
89

910
#include "flutter/fml/macros.h"
1011
#include "impeller/entity/contents.h"
@@ -20,6 +21,8 @@ class CanvasPass {
2021

2122
void PushEntity(Entity entity);
2223

24+
Rect GetCoverageRect() const;
25+
2326
const std::vector<Entity>& GetPassEntities() const;
2427

2528
void SetPostProcessingEntity(Entity entity);
@@ -31,4 +34,10 @@ class CanvasPass {
3134
Entity post_processing_entity_;
3235
};
3336

37+
struct CanvasStackEntry {
38+
Matrix xformation;
39+
size_t stencil_depth = 0u;
40+
std::optional<CanvasPass> pass;
41+
};
42+
3443
} // namespace impeller

impeller/aiks/picture.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
#pragma once
66

7+
#include <deque>
78
#include <memory>
8-
#include <vector>
99

1010
#include "flutter/fml/macros.h"
1111
#include "impeller/aiks/canvas_pass.h"
@@ -14,7 +14,7 @@
1414
namespace impeller {
1515

1616
struct Picture {
17-
std::vector<CanvasPass> passes;
17+
std::deque<CanvasStackEntry> entries;
1818
};
1919

2020
} // namespace impeller

impeller/aiks/picture_renderer.cc

+6-4
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ bool PictureRenderer::Render(const Surface& surface,
2929
return false;
3030
}
3131

32-
for (const auto& pass : picture.passes) {
33-
if (!entity_renderer_.RenderEntities(surface, parent_pass,
34-
pass.GetPassEntities())) {
35-
return false;
32+
for (const auto& entry : picture.entries) {
33+
if (auto pass = entry.pass) {
34+
if (!entity_renderer_.RenderEntities(surface, parent_pass,
35+
pass->GetPassEntities())) {
36+
return false;
37+
}
3638
}
3739
}
3840

impeller/entity/entity.cc

+4
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,8 @@ uint32_t Entity::GetStencilDepth() const {
4242
return stencil_depth_;
4343
}
4444

45+
void Entity::IncrementStencilDepth(uint32_t increment) {
46+
stencil_depth_ += increment;
47+
}
48+
4549
} // namespace impeller

impeller/entity/entity.h

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class Entity {
3333

3434
void SetStencilDepth(uint32_t stencil_depth);
3535

36+
void IncrementStencilDepth(uint32_t increment);
37+
3638
uint32_t GetStencilDepth() const;
3739

3840
private:

impeller/geometry/color.h

+4
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ struct Color {
6262

6363
static constexpr Color Blue() { return {0.0, 0.0, 1.0, 1.0}; }
6464

65+
constexpr Color WithAlpha(Scalar new_alpha) const {
66+
return {red, green, blue, new_alpha};
67+
}
68+
6569
static constexpr Color AliceBlue() {
6670
return {240.0 / 255.0, 248.0 / 255.0, 255.0 / 255.0, 1.0};
6771
}

impeller/geometry/path.cc

+13-4
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,20 @@ std::vector<Point> Path::CreatePolyline(
174174
}
175175

176176
Rect Path::GetBoundingBox() const {
177-
if (linears_.empty() && quads_.empty() && cubics_.empty()) {
177+
auto min_max = GetMinMaxCoveragePoints();
178+
if (!min_max.has_value()) {
178179
return {};
179180
}
181+
auto min = min_max->first;
182+
auto max = min_max->second;
183+
const auto difference = max - min;
184+
return {min.x, min.y, difference.x, difference.y};
185+
}
186+
187+
std::optional<std::pair<Point, Point>> Path::GetMinMaxCoveragePoints() const {
188+
if (linears_.empty() && quads_.empty() && cubics_.empty()) {
189+
return std::nullopt;
190+
}
180191

181192
std::optional<Point> min, max;
182193

@@ -209,9 +220,7 @@ Rect Path::GetBoundingBox() const {
209220
clamp(cubic.Extrema());
210221
}
211222

212-
const auto difference = *max - *min;
213-
214-
return {min->x, min->y, difference.x, difference.y};
223+
return std::make_pair(min.value(), max.value());
215224
}
216225

217226
} // namespace impeller

impeller/geometry/path.h

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include <functional>
8+
#include <optional>
89
#include <vector>
910

1011
#include "impeller/geometry/path_component.h"
@@ -68,6 +69,8 @@ class Path {
6869

6970
Rect GetBoundingBox() const;
7071

72+
std::optional<std::pair<Point, Point>> GetMinMaxCoveragePoints() const;
73+
7174
private:
7275
struct ComponentIndexPair {
7376
ComponentType type = ComponentType::kLinear;

0 commit comments

Comments
 (0)