blob: 84fc6e6d508a93c3ad12267da9139478a7aa7e90 [file] [log] [blame]
John Reck013127b2020-10-29 20:53:51 -04001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include <canvas/CanvasOpBuffer.h>
20#include <canvas/CanvasOps.h>
21#include <canvas/CanvasOpRasterizer.h>
22
23#include <tests/common/CallCountingCanvas.h>
24
25using namespace android;
26using namespace android::uirenderer;
27using namespace android::uirenderer::test;
28
29// We lazy
30using Op = CanvasOpType;
31
32enum MockTypes {
33 Lifecycle,
34 COUNT
35};
36
37template<MockTypes T>
38struct MockOp;
39
40template<MockTypes T>
41struct MockOpContainer {
42 OpBufferItemHeader<MockTypes> header;
43 MockOp<T> impl;
44};
45
46struct LifecycleTracker {
47 int ctor_count = 0;
48 int dtor_count = 0;
49
50 int alive() { return ctor_count - dtor_count; }
51};
52
53template<>
54struct MockOp<MockTypes::Lifecycle> {
55 MockOp() = delete;
56 void operator=(const MockOp&) = delete;
57
58 MockOp(LifecycleTracker* tracker) : tracker(tracker) {
59 tracker->ctor_count += 1;
60 }
61
62 MockOp(const MockOp& other) {
63 tracker = other.tracker;
64 tracker->ctor_count += 1;
65 }
66
67 ~MockOp() {
68 tracker->dtor_count += 1;
69 }
70
71 LifecycleTracker* tracker = nullptr;
72};
73
74using MockBuffer = OpBuffer<MockTypes, MockOpContainer>;
75
76template<typename T>
77static int countItems(const T& t) {
78 int count = 0;
79 t.for_each([&](auto i) {
80 count++;
81 });
82 return count;
83}
84
85TEST(CanvasOp, lifecycleCheck) {
86 LifecycleTracker tracker;
87 {
88 MockBuffer buffer;
89 buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
90 .impl = MockOp<MockTypes::Lifecycle>{&tracker}
91 });
92 EXPECT_EQ(tracker.alive(), 1);
93 buffer.clear();
94 EXPECT_EQ(tracker.alive(), 0);
95 }
96 EXPECT_EQ(tracker.alive(), 0);
97}
98
99TEST(CanvasOp, lifecycleCheckMove) {
100 LifecycleTracker tracker;
101 {
102 MockBuffer buffer;
103 buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
104 .impl = MockOp<MockTypes::Lifecycle>{&tracker}
105 });
106 EXPECT_EQ(tracker.alive(), 1);
107 {
108 MockBuffer other(std::move(buffer));
109 EXPECT_EQ(tracker.alive(), 1);
110 EXPECT_EQ(buffer.size(), 0);
111 EXPECT_GT(other.size(), 0);
112 EXPECT_EQ(1, countItems(other));
113 EXPECT_EQ(0, countItems(buffer));
114
115 other.push_container(MockOpContainer<MockTypes::Lifecycle> {
116 .impl = MockOp<MockTypes::Lifecycle>{&tracker}
117 });
118
119 EXPECT_EQ(2, countItems(other));
120 EXPECT_EQ(2, tracker.alive());
121
122 buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
123 .impl = MockOp<MockTypes::Lifecycle>{&tracker}
124 });
125 EXPECT_EQ(1, countItems(buffer));
126 EXPECT_EQ(3, tracker.alive());
127
128 buffer = std::move(other);
129 EXPECT_EQ(2, countItems(buffer));
130 EXPECT_EQ(2, tracker.alive());
131 }
132 EXPECT_EQ(2, countItems(buffer));
133 EXPECT_EQ(2, tracker.alive());
134 buffer.clear();
135 EXPECT_EQ(0, countItems(buffer));
136 EXPECT_EQ(0, tracker.alive());
137 }
138 EXPECT_EQ(tracker.alive(), 0);
139}
140
John Reck90b0a1c2020-11-12 12:37:30 -0500141TEST(CanvasOp, verifyConst) {
142 CanvasOpBuffer buffer;
143 buffer.push<Op::DrawColor>({
144 .color = SkColors::kBlack,
145 .mode = SkBlendMode::kSrcOver,
146 });
147 buffer.for_each([](auto op) {
148 static_assert(std::is_const_v<std::remove_reference_t<decltype(*op)>>,
149 "Expected container to be const");
150 static_assert(std::is_const_v<std::remove_reference_t<decltype(op->op())>>,
151 "Expected op to be const");
152 });
153}
154
John Reck013127b2020-10-29 20:53:51 -0400155TEST(CanvasOp, simplePush) {
156 CanvasOpBuffer buffer;
157 EXPECT_EQ(buffer.size(), 0);
158 buffer.push<Op::Save>({});
159 buffer.push<Op::Save>({});
160 buffer.push<Op::Restore>({});
161 EXPECT_GT(buffer.size(), 0);
162
163 int saveCount = 0;
164 int restoreCount = 0;
165 int otherCount = 0;
166
167 buffer.for_each([&](auto op) {
168 switch (op->type()) {
169 case Op::Save:
170 saveCount++;
171 break;
172 case Op::Restore:
173 restoreCount++;
174 break;
175 default:
176 otherCount++;
177 break;
178 }
179 });
180
181 EXPECT_EQ(saveCount, 2);
182 EXPECT_EQ(restoreCount, 1);
183 EXPECT_EQ(otherCount, 0);
184
185 buffer.clear();
186 int itemCount = 0;
187 buffer.for_each([&](auto op) {
188 itemCount++;
189 });
190 EXPECT_EQ(itemCount, 0);
191 buffer.resize(0);
192 EXPECT_EQ(buffer.size(), 0);
193}
194
195TEST(CanvasOp, simpleDrawRect) {
196 CanvasOpBuffer buffer;
197 EXPECT_EQ(buffer.size(), 0);
198 buffer.push(CanvasOp<Op::DrawRect> {
199 .paint = SkPaint{},
200 .rect = SkRect::MakeEmpty()
201 });
202
203 CallCountingCanvas canvas;
204 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
205 rasterizeCanvasBuffer(buffer, &canvas);
206 EXPECT_EQ(1, canvas.drawRectCount);
207 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
208}
209
Nader Jawadd5c2b6d2020-11-05 19:12:29 -0800210TEST(CanvasOp, simpleDrawRoundRect) {
211 CanvasOpBuffer buffer;
212 EXPECT_EQ(buffer.size(), 0);
213 buffer.push(CanvasOp<Op::DrawRoundRect> {
214 .paint = SkPaint{},
215 .rect = SkRect::MakeEmpty(),
216 .rx = 10,
217 .ry = 10
218 });
219
220 CallCountingCanvas canvas;
221 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
222 rasterizeCanvasBuffer(buffer, &canvas);
223 EXPECT_EQ(1, canvas.drawRRectCount);
224 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
225}
226
227TEST(CanvasOp, simpleDrawCircle) {
228 CanvasOpBuffer buffer;
229 EXPECT_EQ(buffer.size(), 0);
230 buffer.push(CanvasOp<Op::DrawCircle> {
231 .cx = 5,
232 .cy = 7,
233 .radius = 10,
234 .paint = SkPaint{}
235 });
236
237 CallCountingCanvas canvas;
238 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
239 rasterizeCanvasBuffer(buffer, &canvas);
240 EXPECT_EQ(1, canvas.drawOvalCount);
241 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
242}
243
244TEST(CanvasOp, simpleDrawOval) {
245 CanvasOpBuffer buffer;
246 EXPECT_EQ(buffer.size(), 0);
247 buffer.push(CanvasOp<Op::DrawOval> {
248 .oval = SkRect::MakeEmpty(),
249 .paint = SkPaint{}
250 });
251
252 CallCountingCanvas canvas;
253 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
254 rasterizeCanvasBuffer(buffer, &canvas);
255 EXPECT_EQ(1, canvas.drawOvalCount);
256 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
257}
258
259TEST(CanvasOp, simpleDrawArc) {
260 CanvasOpBuffer buffer;
261 EXPECT_EQ(buffer.size(), 0);
262 buffer.push(CanvasOp<Op::DrawArc> {
263 .oval = SkRect::MakeWH(100, 100),
264 .startAngle = 120,
265 .sweepAngle = 70,
266 .useCenter = true,
267 .paint = SkPaint{}
268 });
269
270 CallCountingCanvas canvas;
271 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
272 rasterizeCanvasBuffer(buffer, &canvas);
273 EXPECT_EQ(1, canvas.drawArcCount);
274 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
275}
276
John Reck013127b2020-10-29 20:53:51 -0400277TEST(CanvasOp, immediateRendering) {
278 auto canvas = std::make_shared<CallCountingCanvas>();
279
280 EXPECT_EQ(0, canvas->sumTotalDrawCalls());
281 ImmediateModeRasterizer rasterizer{canvas};
282 auto op = CanvasOp<Op::DrawRect> {
283 .paint = SkPaint{},
284 .rect = SkRect::MakeEmpty()
285 };
286 EXPECT_TRUE(CanvasOpTraits::can_draw<decltype(op)>);
287 rasterizer.draw(op);
288 EXPECT_EQ(1, canvas->drawRectCount);
289 EXPECT_EQ(1, canvas->sumTotalDrawCalls());
290}