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
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
30static 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
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
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
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
210class 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);
223static 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}
266static 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
286DEF_GPUTEST(GrTRecorder, reporter, /* options */) {
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