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