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 "SkMatrix.h"
9 #include "SkRandom.h"
10 #include "SkString.h"
11 #include "Test.h"
12 
13 #if SK_SUPPORT_GPU
14 
15 #include "GrTRecorder.h"
16 
17 ////////////////////////////////////////////////////////////////////////////////
18 
19 static int activeRecorderItems = 0;
20 
21 class IntWrapper {
22 public:
IntWrapper()23     IntWrapper() {}
IntWrapper(int value)24     IntWrapper(int value) : fValue(value) {}
operator int()25     operator int() { return fValue; }
26 private:
27     int fValue;
28 };
29 
test_empty_back_and_pop(skiatest::Reporter * reporter)30 static 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);
38 
39             REPORTER_ASSERT(reporter, recorder.empty());
40 
41             for (int i = 0; i < 100; ++i) {
42                 if (data) {
43                     REPORTER_ASSERT(reporter, i == *GrNEW_APPEND_TO_RECORDER(recorder,
44                                                                              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         }
66     }
67 }
68 
69 struct ExtraData {
70     typedef GrTRecorder<ExtraData, int> Recorder;
71 
ExtraDataExtraData72     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     }
~ExtraDataExtraData79     ~ExtraData() {
80         --activeRecorderItems;
81     }
extraDataExtraData82     int* extraData() {
83         return reinterpret_cast<int*>(Recorder::GetDataForItem(this));
84     }
85     int fData;
86 };
87 
test_extra_data(skiatest::Reporter * reporter)88 static 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 
105     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 
114     recorder.reset();
115     REPORTER_ASSERT(reporter, 0 == activeRecorderItems);
116 }
117 
118 enum ClassType {
119     kBase_ClassType,
120     kSubclass_ClassType,
121     kSubSubclass_ClassType,
122     kSubclassExtraData_ClassType,
123     kSubclassEmpty_ClassType,
124 
125     kNumClassTypes
126 };
127 
128 class Base {
129 public:
130     typedef GrTRecorder<Base, void*> Recorder;
131 
Base()132     Base() {
133         fMatrix.reset();
134         ++activeRecorderItems;
135     }
136 
~Base()137     virtual ~Base() { --activeRecorderItems; }
138 
getType()139     virtual ClassType getType() { return kBase_ClassType; }
140 
validate(skiatest::Reporter * reporter) const141     virtual void validate(skiatest::Reporter* reporter) const {
142         REPORTER_ASSERT(reporter, fMatrix.isIdentity());
143     }
144 
145 private:
146     SkMatrix fMatrix;
147 };
148 
149 class Subclass : public Base {
150 public:
Subclass()151     Subclass() : fString("Lorem ipsum dolor sit amet") {}
152 
getType()153     virtual ClassType getType() { return kSubclass_ClassType; }
154 
validate(skiatest::Reporter * reporter) const155     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 
160 private:
161     SkString fString;
162 };
163 
164 class SubSubclass : public Subclass {
165 public:
SubSubclass()166     SubSubclass() : fInt(1234), fFloat(1.234f) {}
167 
getType()168     virtual ClassType getType() { return kSubSubclass_ClassType; }
169 
validate(skiatest::Reporter * reporter) const170     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 
176 private:
177     int fInt;
178     float fFloat;
179 };
180 
181 class SubclassExtraData : public Base {
182 public:
SubclassExtraData(int length)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 
getType()190     virtual ClassType getType() { return kSubclassExtraData_ClassType; }
191 
validate(skiatest::Reporter * reporter) const192     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 
200 private:
ValueAt(uint64_t i)201     static int ValueAt(uint64_t i) { return static_cast<int>(123456789 + 987654321 * i); }
202     int fLength;
203 };
204 
205 class SubclassEmpty : public Base {
206 public:
getType()207     virtual ClassType getType() { return kSubclassEmpty_ClassType; }
208 };
209 
210 class Order {
211 public:
Order()212     Order() { this->reset(); }
reset()213     void reset() { fCurrent = 0; }
next()214     ClassType next() {
215         fCurrent = 1664525 * fCurrent + 1013904223;
216         return static_cast<ClassType>(fCurrent % kNumClassTypes);
217     }
218 private:
219     uint32_t fCurrent;
220 };
221 static void test_subclasses_iters(skiatest::Reporter*, Order&, Base::Recorder::Iter&,
222                                   Base::Recorder::ReverseIter&, int = 0);
test_subclasses(skiatest::Reporter * reporter)223 static void test_subclasses(skiatest::Reporter* reporter) {
224     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:
250                 ERRORF(reporter, "Invalid class type");
251                 break;
252         }
253     }
254     REPORTER_ASSERT(reporter, 1000 == activeRecorderItems);
255 
256     order.reset();
257     Base::Recorder::Iter iter(recorder);
258     Base::Recorder::ReverseIter reverseIter(recorder);
259 
260     test_subclasses_iters(reporter, order, iter, reverseIter);
261 
262     REPORTER_ASSERT(reporter, !iter.next());
263 
264     // Don't reset the recorder. It should automatically destruct all its items.
265 }
test_subclasses_iters(skiatest::Reporter * reporter,Order & order,Base::Recorder::Iter & iter,Base::Recorder::ReverseIter & reverseIter,int i)266 static 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 }
285 
DEF_GPUTEST(GrTRecorder,reporter,factory)286 DEF_GPUTEST(GrTRecorder, reporter, factory) {
287     test_empty_back_and_pop(reporter);
288 
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
297