1 /*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkMatrix.h"
9 #include "include/core/SkString.h"
10 #include "include/utils/SkRandom.h"
11 #include "tests/Test.h"
12
13 #include "src/gpu/GrTRecorder.h"
14
15 ////////////////////////////////////////////////////////////////////////////////
16
17 static int gActiveRecorderItems = 0;
18
19 class IntWrapper {
20 public:
IntWrapper()21 IntWrapper() {}
IntWrapper(int value)22 IntWrapper(int value) : fValue(value) {}
operator int()23 operator int() { return fValue; }
24 private:
25 int fValue;
26 };
27
28 struct ExtraData {
29 typedef GrTRecorder<ExtraData> Recorder;
30
ExtraDataExtraData31 ExtraData(int i) : fData(i) {
32 int* extraData = this->extraData();
33 for (int j = 0; j < i; j++) {
34 extraData[j] = i;
35 }
36 ++gActiveRecorderItems;
37 }
~ExtraDataExtraData38 ~ExtraData() { --gActiveRecorderItems; }
extraDataExtraData39 int* extraData() { return reinterpret_cast<int*>(this + 1); }
40 int fData;
41 };
42
test_extra_data(skiatest::Reporter * reporter)43 static void test_extra_data(skiatest::Reporter* reporter) {
44 ExtraData::Recorder recorder(0);
45 REPORTER_ASSERT(reporter, recorder.empty());
46 for (int i = 0; i < 100; ++i) {
47 recorder.emplaceWithData<ExtraData>(i * sizeof(int), i);
48 REPORTER_ASSERT(reporter, !recorder.empty());
49 }
50 REPORTER_ASSERT(reporter, 100 == gActiveRecorderItems);
51
52 auto iter = recorder.begin();
53 for (int i = 0; i < 100; ++i, ++iter) {
54 REPORTER_ASSERT(reporter, i == iter->fData);
55 for (int j = 0; j < i; j++) {
56 REPORTER_ASSERT(reporter, i == iter->extraData()[j]);
57 }
58 }
59 REPORTER_ASSERT(reporter, iter == recorder.end());
60
61 recorder.reset();
62 REPORTER_ASSERT(reporter, 0 == gActiveRecorderItems);
63 REPORTER_ASSERT(reporter, recorder.begin() == recorder.end());
64 REPORTER_ASSERT(reporter, recorder.empty());
65 }
66
67 enum ClassType {
68 kBase_ClassType,
69 kSubclass_ClassType,
70 kSubSubclass_ClassType,
71 kSubclassExtraData_ClassType,
72 kSubclassEmpty_ClassType,
73
74 kNumClassTypes
75 };
76
77 class Base {
78 public:
79 typedef GrTRecorder<Base> Recorder;
80
Base()81 Base() {
82 fMatrix.reset();
83 ++gActiveRecorderItems;
84 }
85
~Base()86 virtual ~Base() { --gActiveRecorderItems; }
87
getType()88 virtual ClassType getType() { return kBase_ClassType; }
89
validate(skiatest::Reporter * reporter) const90 virtual void validate(skiatest::Reporter* reporter) const {
91 REPORTER_ASSERT(reporter, fMatrix.isIdentity());
92 }
93
94 private:
95 SkMatrix fMatrix;
96 };
97
98 class Subclass : public Base {
99 public:
Subclass()100 Subclass() : fString("Lorem ipsum dolor sit amet") {}
101
getType()102 virtual ClassType getType() { return kSubclass_ClassType; }
103
validate(skiatest::Reporter * reporter) const104 virtual void validate(skiatest::Reporter* reporter) const {
105 Base::validate(reporter);
106 REPORTER_ASSERT(reporter, !strcmp("Lorem ipsum dolor sit amet", fString.c_str()));
107 }
108
109 private:
110 SkString fString;
111 };
112
113 class SubSubclass : public Subclass {
114 public:
SubSubclass()115 SubSubclass() : fInt(1234), fFloat(1.234f) {}
116
getType()117 virtual ClassType getType() { return kSubSubclass_ClassType; }
118
validate(skiatest::Reporter * reporter) const119 virtual void validate(skiatest::Reporter* reporter) const {
120 Subclass::validate(reporter);
121 REPORTER_ASSERT(reporter, 1234 == fInt);
122 REPORTER_ASSERT(reporter, 1.234f == fFloat);
123 }
124
125 private:
126 int fInt;
127 float fFloat;
128 };
129
130 class SubclassExtraData : public Base {
131 public:
SubclassExtraData(int length)132 SubclassExtraData(int length) : fLength(length) {
133 int* data = reinterpret_cast<int*>(this + 1);
134 for (int i = 0; i < fLength; ++i) {
135 data[i] = ValueAt(i);
136 }
137 }
138
getType()139 virtual ClassType getType() { return kSubclassExtraData_ClassType; }
140
validate(skiatest::Reporter * reporter) const141 virtual void validate(skiatest::Reporter* reporter) const {
142 Base::validate(reporter);
143 const int* data = reinterpret_cast<const int*>(this + 1);
144 for (int i = 0; i < fLength; ++i) {
145 REPORTER_ASSERT(reporter, ValueAt(i) == data[i]);
146 }
147 }
148
149 private:
ValueAt(uint64_t i)150 static int ValueAt(uint64_t i) {
151 return static_cast<int>((123456789 + 987654321 * i) & 0xFFFFFFFF);
152 }
153 int fLength;
154 };
155
156 class SubclassEmpty : public Base {
157 public:
getType()158 virtual ClassType getType() { return kSubclassEmpty_ClassType; }
159 };
160
161 class Order {
162 public:
Order()163 Order() { this->reset(); }
reset()164 void reset() { fCurrent = 0; }
next()165 ClassType next() {
166 fCurrent = 1664525 * fCurrent + 1013904223;
167 return static_cast<ClassType>(fCurrent % kNumClassTypes);
168 }
169 private:
170 uint32_t fCurrent;
171 };
172
173 static void test_subclasses_iter(skiatest::Reporter*, Order&, Base::Recorder::iterator&, int = 0);
174
test_subclasses(skiatest::Reporter * reporter)175 static void test_subclasses(skiatest::Reporter* reporter) {
176 Base::Recorder recorder(1024);
177
178 Order order;
179 for (int i = 0; i < 1000; i++) {
180 switch (order.next()) {
181 case kBase_ClassType:
182 recorder.emplace<Base>();
183 break;
184
185 case kSubclass_ClassType:
186 recorder.emplace<Subclass>();
187 break;
188
189 case kSubSubclass_ClassType:
190 recorder.emplace<SubSubclass>();
191 break;
192
193 case kSubclassExtraData_ClassType:
194 recorder.emplaceWithData<SubclassExtraData>(sizeof(int) * i, i);
195 break;
196
197 case kSubclassEmpty_ClassType:
198 recorder.emplace<SubclassEmpty>();
199 break;
200
201 default:
202 ERRORF(reporter, "Invalid class type");
203 break;
204 }
205 }
206 REPORTER_ASSERT(reporter, 1000 == gActiveRecorderItems);
207
208 order.reset();
209 auto iter = recorder.begin();
210
211 test_subclasses_iter(reporter, order, iter);
212
213 REPORTER_ASSERT(reporter, iter == recorder.end());
214 // Don't reset the recorder. It should automatically destruct all its items.
215 }
test_subclasses_iter(skiatest::Reporter * reporter,Order & order,Base::Recorder::iterator & iter,int i)216 static void test_subclasses_iter(skiatest::Reporter* reporter, Order& order,
217 Base::Recorder::iterator& iter, int i) {
218 if (i >= 1000) {
219 return;
220 }
221
222 ClassType classType = order.next();
223
224 REPORTER_ASSERT(reporter, classType == iter->getType());
225 iter->validate(reporter);
226
227 ++iter;
228 test_subclasses_iter(reporter, order, iter, i + 1);
229 }
230
231 struct AlignBase {
AlignBaseAlignBase232 AlignBase() { ++gActiveRecorderItems; }
~AlignBaseAlignBase233 ~AlignBase() { --gActiveRecorderItems; }
234 char fValue;
235 };
236 struct alignas(16) Align16 : public AlignBase {};
237 struct alignas(32) Align32 : public AlignBase {};
238 struct alignas(64) Align64 : public AlignBase {};
239 struct alignas(128) Align128 : public AlignBase {};
240
test_alignment(skiatest::Reporter * reporter)241 static void test_alignment(skiatest::Reporter* reporter) {
242 GrTRecorder<AlignBase> recorder(0);
243 SkTArray<size_t> expectedAlignments;
244 SkRandom random;
245 for (int i = 0; i < 100; ++i) {
246 size_t dataSize = random.nextULessThan(20);
247 switch (random.nextULessThan(5)) {
248 case 0:
249 recorder.emplaceWithData<AlignBase>(dataSize);
250 expectedAlignments.push_back(alignof(AlignBase));
251 break;
252 case 1:
253 recorder.emplaceWithData<Align16>(dataSize);
254 expectedAlignments.push_back(16);
255 break;
256 case 2:
257 recorder.emplaceWithData<Align32>(dataSize);
258 expectedAlignments.push_back(32);
259 break;
260 case 3:
261 recorder.emplaceWithData<Align64>(dataSize);
262 expectedAlignments.push_back(64);
263 break;
264 case 4:
265 recorder.emplaceWithData<Align128>(dataSize);
266 expectedAlignments.push_back(128);
267 break;
268 }
269 recorder.back().fValue = i;
270 }
271 int i = 0;
272 for (const auto& x : recorder) {
273 REPORTER_ASSERT(reporter, x.fValue == i);
274 auto pointer = reinterpret_cast<uintptr_t>(&x);
275 auto mask = static_cast<uintptr_t>(expectedAlignments[i]) - 1;
276 REPORTER_ASSERT(reporter, !(pointer & mask));
277 i++;
278 }
279 REPORTER_ASSERT(reporter, i == 100);
280 }
281
282 DEF_GPUTEST(GrTRecorder, reporter, /* options */) {
283 test_extra_data(reporter);
284 REPORTER_ASSERT(reporter, 0 == gActiveRecorderItems); // test_extra_data should call reset().
285
286 test_subclasses(reporter);
287 REPORTER_ASSERT(reporter, 0 == gActiveRecorderItems); // Ensure ~GrTRecorder invokes dtors.
288
289 test_alignment(reporter);
290 REPORTER_ASSERT(reporter, 0 == gActiveRecorderItems); // Ensure ~GrTRecorder invokes dtors.
291 }
292