cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 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 | |
bsalomon | 77d77f4 | 2014-11-21 14:38:06 -0800 | [diff] [blame] | 8 | #include "SkMatrix.h" |
| 9 | #include "SkRandom.h" |
| 10 | #include "SkString.h" |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 11 | #include "Test.h" |
| 12 | |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 13 | #if SK_SUPPORT_GPU |
| 14 | |
| 15 | #include "GrTRecorder.h" |
| 16 | |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 17 | //////////////////////////////////////////////////////////////////////////////// |
| 18 | |
| 19 | static int activeRecorderItems = 0; |
| 20 | |
| 21 | class IntWrapper { |
| 22 | public: |
| 23 | IntWrapper() {} |
| 24 | IntWrapper(int value) : fValue(value) {} |
| 25 | operator int() { return fValue; } |
| 26 | private: |
| 27 | int fValue; |
| 28 | }; |
| 29 | |
bsalomon | 77d77f4 | 2014-11-21 14:38:06 -0800 | [diff] [blame] | 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); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 38 | |
bsalomon | 77d77f4 | 2014-11-21 14:38:06 -0800 | [diff] [blame] | 39 | REPORTER_ASSERT(reporter, recorder.empty()); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 40 | |
bsalomon | 77d77f4 | 2014-11-21 14:38:06 -0800 | [diff] [blame] | 41 | for (int i = 0; i < 100; ++i) { |
| 42 | if (data) { |
halcanary | 9d524f2 | 2016-03-29 09:03:52 -0700 | [diff] [blame] | 43 | REPORTER_ASSERT(reporter, i == *GrNEW_APPEND_TO_RECORDER(recorder, |
bsalomon | 77d77f4 | 2014-11-21 14:38:06 -0800 | [diff] [blame] | 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 | } |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 66 | } |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 67 | } |
| 68 | |
| 69 | struct 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 | |
| 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 | |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 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 | |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 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 | |
| 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 | |
| 145 | private: |
| 146 | SkMatrix fMatrix; |
| 147 | }; |
| 148 | |
| 149 | class Subclass : public Base { |
| 150 | public: |
| 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 | |
| 160 | private: |
| 161 | SkString fString; |
| 162 | }; |
| 163 | |
| 164 | class SubSubclass : public Subclass { |
| 165 | public: |
| 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 | |
| 176 | private: |
| 177 | int fInt; |
| 178 | float fFloat; |
| 179 | }; |
| 180 | |
| 181 | class SubclassExtraData : public Base { |
| 182 | public: |
| 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 | |
| 200 | private: |
| 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: |
| 207 | virtual ClassType getType() { return kSubclassEmpty_ClassType; } |
| 208 | }; |
| 209 | |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 210 | class Order { |
| 211 | public: |
| 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 | } |
| 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); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 223 | static void test_subclasses(skiatest::Reporter* reporter) { |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 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: |
scroggo | 0ee2627 | 2014-11-07 06:07:32 -0800 | [diff] [blame] | 250 | ERRORF(reporter, "Invalid class type"); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 251 | break; |
| 252 | } |
| 253 | } |
| 254 | REPORTER_ASSERT(reporter, 1000 == activeRecorderItems); |
| 255 | |
| 256 | order.reset(); |
| 257 | Base::Recorder::Iter iter(recorder); |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 258 | Base::Recorder::ReverseIter reverseIter(recorder); |
| 259 | |
| 260 | test_subclasses_iters(reporter, order, iter, reverseIter); |
| 261 | |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 262 | REPORTER_ASSERT(reporter, !iter.next()); |
| 263 | |
| 264 | // Don't reset the recorder. It should automatically destruct all its items. |
| 265 | } |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 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 | } |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 285 | |
Brian Salomon | dcfca43 | 2017-11-15 15:48:03 -0500 | [diff] [blame^] | 286 | DEF_GPUTEST(GrTRecorder, reporter, /* options */) { |
bsalomon | 77d77f4 | 2014-11-21 14:38:06 -0800 | [diff] [blame] | 287 | test_empty_back_and_pop(reporter); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 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 |