blob: 0815d15d29f2cb9f7954438b5f78905ace9e1b03 [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
141TEST(CanvasOp, simplePush) {
142 CanvasOpBuffer buffer;
143 EXPECT_EQ(buffer.size(), 0);
144 buffer.push<Op::Save>({});
145 buffer.push<Op::Save>({});
146 buffer.push<Op::Restore>({});
147 EXPECT_GT(buffer.size(), 0);
148
149 int saveCount = 0;
150 int restoreCount = 0;
151 int otherCount = 0;
152
153 buffer.for_each([&](auto op) {
154 switch (op->type()) {
155 case Op::Save:
156 saveCount++;
157 break;
158 case Op::Restore:
159 restoreCount++;
160 break;
161 default:
162 otherCount++;
163 break;
164 }
165 });
166
167 EXPECT_EQ(saveCount, 2);
168 EXPECT_EQ(restoreCount, 1);
169 EXPECT_EQ(otherCount, 0);
170
171 buffer.clear();
172 int itemCount = 0;
173 buffer.for_each([&](auto op) {
174 itemCount++;
175 });
176 EXPECT_EQ(itemCount, 0);
177 buffer.resize(0);
178 EXPECT_EQ(buffer.size(), 0);
179}
180
181TEST(CanvasOp, simpleDrawRect) {
182 CanvasOpBuffer buffer;
183 EXPECT_EQ(buffer.size(), 0);
184 buffer.push(CanvasOp<Op::DrawRect> {
185 .paint = SkPaint{},
186 .rect = SkRect::MakeEmpty()
187 });
188
189 CallCountingCanvas canvas;
190 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
191 rasterizeCanvasBuffer(buffer, &canvas);
192 EXPECT_EQ(1, canvas.drawRectCount);
193 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
194}
195
196TEST(CanvasOp, immediateRendering) {
197 auto canvas = std::make_shared<CallCountingCanvas>();
198
199 EXPECT_EQ(0, canvas->sumTotalDrawCalls());
200 ImmediateModeRasterizer rasterizer{canvas};
201 auto op = CanvasOp<Op::DrawRect> {
202 .paint = SkPaint{},
203 .rect = SkRect::MakeEmpty()
204 };
205 EXPECT_TRUE(CanvasOpTraits::can_draw<decltype(op)>);
206 rasterizer.draw(op);
207 EXPECT_EQ(1, canvas->drawRectCount);
208 EXPECT_EQ(1, canvas->sumTotalDrawCalls());
209}