blob: 5041dd985464ac39afa1a2d707a4101324622cc5 [file] [log] [blame]
cdalton6819df32014-10-15 13:43:48 -07001/*
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
bsalomon77d77f42014-11-21 14:38:06 -08008#include "SkMatrix.h"
9#include "SkRandom.h"
10#include "SkString.h"
cdalton6819df32014-10-15 13:43:48 -070011#include "Test.h"
12
cdalton72badbd2015-04-16 10:42:49 -070013#if SK_SUPPORT_GPU
14
15#include "GrTRecorder.h"
16
cdalton6819df32014-10-15 13:43:48 -070017////////////////////////////////////////////////////////////////////////////////
18
19static int activeRecorderItems = 0;
20
21class IntWrapper {
22public:
23 IntWrapper() {}
24 IntWrapper(int value) : fValue(value) {}
25 operator int() { return fValue; }
26private:
27 int fValue;
28};
29
bsalomon77d77f42014-11-21 14:38:06 -080030static void test_empty_back_and_pop(skiatest::Reporter* reporter) {
31 SkRandom rand;
32 for (int data = 0; data < 2; ++data) {
33 // Do this with different starting sizes to have different alignment between blocks and pops.
34 // pops. We want to test poping the first guy off, guys in the middle of the block, and the
35 // first guy on a non-head block.
36 for (int j = 0; j < 8; ++j) {
37 GrTRecorder<IntWrapper, int> recorder(j);
cdalton6819df32014-10-15 13:43:48 -070038
bsalomon77d77f42014-11-21 14:38:06 -080039 REPORTER_ASSERT(reporter, recorder.empty());
cdalton6819df32014-10-15 13:43:48 -070040
bsalomon77d77f42014-11-21 14:38:06 -080041 for (int i = 0; i < 100; ++i) {
42 if (data) {
halcanary9d524f22016-03-29 09:03:52 -070043 REPORTER_ASSERT(reporter, i == *GrNEW_APPEND_TO_RECORDER(recorder,
bsalomon77d77f42014-11-21 14:38:06 -080044 IntWrapper, (i)));
45 } else {
46 REPORTER_ASSERT(reporter, i ==
47 *GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder,
48 IntWrapper, (i),
49 rand.nextULessThan(10)));
50 }
51 REPORTER_ASSERT(reporter, !recorder.empty());
52 REPORTER_ASSERT(reporter, i == recorder.back());
53 if (0 == (i % 7)) {
54 recorder.pop_back();
55 if (i > 0) {
56 REPORTER_ASSERT(reporter, !recorder.empty());
57 REPORTER_ASSERT(reporter, i-1 == recorder.back());
58 }
59 }
60 }
61
62 REPORTER_ASSERT(reporter, !recorder.empty());
63 recorder.reset();
64 REPORTER_ASSERT(reporter, recorder.empty());
65 }
cdalton6819df32014-10-15 13:43:48 -070066 }
cdalton6819df32014-10-15 13:43:48 -070067}
68
69struct ExtraData {
70 typedef GrTRecorder<ExtraData, int> Recorder;
71
72 ExtraData(int i) : fData(i) {
73 int* extraData = this->extraData();
74 for (int j = 0; j < i; j++) {
75 extraData[j] = i;
76 }
77 ++activeRecorderItems;
78 }
79 ~ExtraData() {
80 --activeRecorderItems;
81 }
82 int* extraData() {
83 return reinterpret_cast<int*>(Recorder::GetDataForItem(this));
84 }
85 int fData;
86};
87
88static void test_extra_data(skiatest::Reporter* reporter) {
89 ExtraData::Recorder recorder(0);
90 for (int i = 0; i < 100; ++i) {
91 GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, ExtraData, (i), i * sizeof(int));
92 }
93 REPORTER_ASSERT(reporter, 100 == activeRecorderItems);
94
95 ExtraData::Recorder::Iter iter(recorder);
96 for (int i = 0; i < 100; ++i) {
97 REPORTER_ASSERT(reporter, iter.next());
98 REPORTER_ASSERT(reporter, i == iter->fData);
99 for (int j = 0; j < i; j++) {
100 REPORTER_ASSERT(reporter, i == iter->extraData()[j]);
101 }
102 }
103 REPORTER_ASSERT(reporter, !iter.next());
104
cdalton72badbd2015-04-16 10:42:49 -0700105 ExtraData::Recorder::ReverseIter reverseIter(recorder);
106 for (int i = 99; i >= 0; --i) {
107 REPORTER_ASSERT(reporter, i == reverseIter->fData);
108 for (int j = 0; j < i; j++) {
109 REPORTER_ASSERT(reporter, i == reverseIter->extraData()[j]);
110 }
111 REPORTER_ASSERT(reporter, reverseIter.previous() == !!i);
112 }
113
cdalton6819df32014-10-15 13:43:48 -0700114 recorder.reset();
115 REPORTER_ASSERT(reporter, 0 == activeRecorderItems);
116}
117
118enum ClassType {
119 kBase_ClassType,
120 kSubclass_ClassType,
121 kSubSubclass_ClassType,
122 kSubclassExtraData_ClassType,
123 kSubclassEmpty_ClassType,
124
125 kNumClassTypes
126};
127
128class Base {
129public:
130 typedef GrTRecorder<Base, void*> Recorder;
131
132 Base() {
133 fMatrix.reset();
134 ++activeRecorderItems;
135 }
136
137 virtual ~Base() { --activeRecorderItems; }
138
139 virtual ClassType getType() { return kBase_ClassType; }
140
141 virtual void validate(skiatest::Reporter* reporter) const {
142 REPORTER_ASSERT(reporter, fMatrix.isIdentity());
143 }
144
145private:
146 SkMatrix fMatrix;
147};
148
149class Subclass : public Base {
150public:
151 Subclass() : fString("Lorem ipsum dolor sit amet") {}
152
153 virtual ClassType getType() { return kSubclass_ClassType; }
154
155 virtual void validate(skiatest::Reporter* reporter) const {
156 Base::validate(reporter);
157 REPORTER_ASSERT(reporter, !strcmp("Lorem ipsum dolor sit amet", fString.c_str()));
158 }
159
160private:
161 SkString fString;
162};
163
164class SubSubclass : public Subclass {
165public:
166 SubSubclass() : fInt(1234), fFloat(1.234f) {}
167
168 virtual ClassType getType() { return kSubSubclass_ClassType; }
169
170 virtual void validate(skiatest::Reporter* reporter) const {
171 Subclass::validate(reporter);
172 REPORTER_ASSERT(reporter, 1234 == fInt);
173 REPORTER_ASSERT(reporter, 1.234f == fFloat);
174 }
175
176private:
177 int fInt;
178 float fFloat;
179};
180
181class SubclassExtraData : public Base {
182public:
183 SubclassExtraData(int length) : fLength(length) {
184 int* data = reinterpret_cast<int*>(Recorder::GetDataForItem(this));
185 for (int i = 0; i < fLength; ++i) {
186 data[i] = ValueAt(i);
187 }
188 }
189
190 virtual ClassType getType() { return kSubclassExtraData_ClassType; }
191
192 virtual void validate(skiatest::Reporter* reporter) const {
193 Base::validate(reporter);
194 const int* data = reinterpret_cast<const int*>(Recorder::GetDataForItem(this));
195 for (int i = 0; i < fLength; ++i) {
196 REPORTER_ASSERT(reporter, ValueAt(i) == data[i]);
197 }
198 }
199
200private:
201 static int ValueAt(uint64_t i) { return static_cast<int>(123456789 + 987654321 * i); }
202 int fLength;
203};
204
205class SubclassEmpty : public Base {
206public:
207 virtual ClassType getType() { return kSubclassEmpty_ClassType; }
208};
209
cdalton72badbd2015-04-16 10:42:49 -0700210class Order {
211public:
212 Order() { this->reset(); }
213 void reset() { fCurrent = 0; }
214 ClassType next() {
215 fCurrent = 1664525 * fCurrent + 1013904223;
216 return static_cast<ClassType>(fCurrent % kNumClassTypes);
217 }
218private:
219 uint32_t fCurrent;
220};
221static void test_subclasses_iters(skiatest::Reporter*, Order&, Base::Recorder::Iter&,
222 Base::Recorder::ReverseIter&, int = 0);
cdalton6819df32014-10-15 13:43:48 -0700223static void test_subclasses(skiatest::Reporter* reporter) {
cdalton6819df32014-10-15 13:43:48 -0700224 Base::Recorder recorder(1024);
225
226 Order order;
227 for (int i = 0; i < 1000; i++) {
228 switch (order.next()) {
229 case kBase_ClassType:
230 GrNEW_APPEND_TO_RECORDER(recorder, Base, ());
231 break;
232
233 case kSubclass_ClassType:
234 GrNEW_APPEND_TO_RECORDER(recorder, Subclass, ());
235 break;
236
237 case kSubSubclass_ClassType:
238 GrNEW_APPEND_TO_RECORDER(recorder, SubSubclass, ());
239 break;
240
241 case kSubclassExtraData_ClassType:
242 GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, SubclassExtraData, (i), sizeof(int) * i);
243 break;
244
245 case kSubclassEmpty_ClassType:
246 GrNEW_APPEND_TO_RECORDER(recorder, SubclassEmpty, ());
247 break;
248
249 default:
scroggo0ee26272014-11-07 06:07:32 -0800250 ERRORF(reporter, "Invalid class type");
cdalton6819df32014-10-15 13:43:48 -0700251 break;
252 }
253 }
254 REPORTER_ASSERT(reporter, 1000 == activeRecorderItems);
255
256 order.reset();
257 Base::Recorder::Iter iter(recorder);
cdalton72badbd2015-04-16 10:42:49 -0700258 Base::Recorder::ReverseIter reverseIter(recorder);
259
260 test_subclasses_iters(reporter, order, iter, reverseIter);
261
cdalton6819df32014-10-15 13:43:48 -0700262 REPORTER_ASSERT(reporter, !iter.next());
263
264 // Don't reset the recorder. It should automatically destruct all its items.
265}
cdalton72badbd2015-04-16 10:42:49 -0700266static void test_subclasses_iters(skiatest::Reporter* reporter, Order& order,
267 Base::Recorder::Iter& iter,
268 Base::Recorder::ReverseIter& reverseIter, int i) {
269 if (i >= 1000) {
270 return;
271 }
272
273 ClassType classType = order.next();
274
275 REPORTER_ASSERT(reporter, iter.next());
276 REPORTER_ASSERT(reporter, classType == iter->getType());
277 iter->validate(reporter);
278
279 test_subclasses_iters(reporter, order, iter, reverseIter, i + 1);
280
281 REPORTER_ASSERT(reporter, classType == reverseIter->getType());
282 reverseIter->validate(reporter);
283 REPORTER_ASSERT(reporter, reverseIter.previous() == !!i);
284}
cdalton6819df32014-10-15 13:43:48 -0700285
Brian Salomondcfca432017-11-15 15:48:03 -0500286DEF_GPUTEST(GrTRecorder, reporter, /* options */) {
bsalomon77d77f42014-11-21 14:38:06 -0800287 test_empty_back_and_pop(reporter);
cdalton6819df32014-10-15 13:43:48 -0700288
289 test_extra_data(reporter);
290 REPORTER_ASSERT(reporter, 0 == activeRecorderItems); // test_extra_data should call reset().
291
292 test_subclasses(reporter);
293 REPORTER_ASSERT(reporter, 0 == activeRecorderItems); // Ensure ~GrTRecorder invokes dtors.
294}
295
296#endif