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 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "include/core/SkMatrix.h" |
| 9 | #include "include/core/SkString.h" |
| 10 | #include "include/utils/SkRandom.h" |
| 11 | #include "tests/Test.h" |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 12 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 13 | #include "src/gpu/GrTRecorder.h" |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 14 | |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 15 | //////////////////////////////////////////////////////////////////////////////// |
| 16 | |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 17 | static int gActiveRecorderItems = 0; |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 18 | |
| 19 | class IntWrapper { |
| 20 | public: |
| 21 | IntWrapper() {} |
| 22 | IntWrapper(int value) : fValue(value) {} |
| 23 | operator int() { return fValue; } |
| 24 | private: |
| 25 | int fValue; |
| 26 | }; |
| 27 | |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 28 | struct ExtraData { |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 29 | typedef GrTRecorder<ExtraData> Recorder; |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 30 | |
| 31 | ExtraData(int i) : fData(i) { |
| 32 | int* extraData = this->extraData(); |
| 33 | for (int j = 0; j < i; j++) { |
| 34 | extraData[j] = i; |
| 35 | } |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 36 | ++gActiveRecorderItems; |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 37 | } |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 38 | ~ExtraData() { --gActiveRecorderItems; } |
| 39 | int* extraData() { return reinterpret_cast<int*>(this + 1); } |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 40 | int fData; |
| 41 | }; |
| 42 | |
| 43 | static void test_extra_data(skiatest::Reporter* reporter) { |
| 44 | ExtraData::Recorder recorder(0); |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 45 | REPORTER_ASSERT(reporter, recorder.empty()); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 46 | for (int i = 0; i < 100; ++i) { |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 47 | recorder.emplaceWithData<ExtraData>(i * sizeof(int), i); |
| 48 | REPORTER_ASSERT(reporter, !recorder.empty()); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 49 | } |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 50 | REPORTER_ASSERT(reporter, 100 == gActiveRecorderItems); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 51 | |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 52 | auto iter = recorder.begin(); |
| 53 | for (int i = 0; i < 100; ++i, ++iter) { |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 54 | REPORTER_ASSERT(reporter, i == iter->fData); |
| 55 | for (int j = 0; j < i; j++) { |
| 56 | REPORTER_ASSERT(reporter, i == iter->extraData()[j]); |
| 57 | } |
| 58 | } |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 59 | REPORTER_ASSERT(reporter, iter == recorder.end()); |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 60 | |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 61 | recorder.reset(); |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 62 | REPORTER_ASSERT(reporter, 0 == gActiveRecorderItems); |
| 63 | REPORTER_ASSERT(reporter, recorder.begin() == recorder.end()); |
| 64 | REPORTER_ASSERT(reporter, recorder.empty()); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | enum ClassType { |
| 68 | kBase_ClassType, |
| 69 | kSubclass_ClassType, |
| 70 | kSubSubclass_ClassType, |
| 71 | kSubclassExtraData_ClassType, |
| 72 | kSubclassEmpty_ClassType, |
| 73 | |
| 74 | kNumClassTypes |
| 75 | }; |
| 76 | |
| 77 | class Base { |
| 78 | public: |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 79 | typedef GrTRecorder<Base> Recorder; |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 80 | |
| 81 | Base() { |
| 82 | fMatrix.reset(); |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 83 | ++gActiveRecorderItems; |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 84 | } |
| 85 | |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 86 | virtual ~Base() { --gActiveRecorderItems; } |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 87 | |
| 88 | virtual ClassType getType() { return kBase_ClassType; } |
| 89 | |
| 90 | virtual void validate(skiatest::Reporter* reporter) const { |
| 91 | REPORTER_ASSERT(reporter, fMatrix.isIdentity()); |
| 92 | } |
| 93 | |
| 94 | private: |
| 95 | SkMatrix fMatrix; |
| 96 | }; |
| 97 | |
| 98 | class Subclass : public Base { |
| 99 | public: |
| 100 | Subclass() : fString("Lorem ipsum dolor sit amet") {} |
| 101 | |
| 102 | virtual ClassType getType() { return kSubclass_ClassType; } |
| 103 | |
| 104 | virtual void validate(skiatest::Reporter* reporter) const { |
| 105 | Base::validate(reporter); |
| 106 | REPORTER_ASSERT(reporter, !strcmp("Lorem ipsum dolor sit amet", fString.c_str())); |
| 107 | } |
| 108 | |
| 109 | private: |
| 110 | SkString fString; |
| 111 | }; |
| 112 | |
| 113 | class SubSubclass : public Subclass { |
| 114 | public: |
| 115 | SubSubclass() : fInt(1234), fFloat(1.234f) {} |
| 116 | |
| 117 | virtual ClassType getType() { return kSubSubclass_ClassType; } |
| 118 | |
| 119 | virtual void validate(skiatest::Reporter* reporter) const { |
| 120 | Subclass::validate(reporter); |
| 121 | REPORTER_ASSERT(reporter, 1234 == fInt); |
| 122 | REPORTER_ASSERT(reporter, 1.234f == fFloat); |
| 123 | } |
| 124 | |
| 125 | private: |
| 126 | int fInt; |
| 127 | float fFloat; |
| 128 | }; |
| 129 | |
| 130 | class SubclassExtraData : public Base { |
| 131 | public: |
| 132 | SubclassExtraData(int length) : fLength(length) { |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 133 | int* data = reinterpret_cast<int*>(this + 1); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 134 | for (int i = 0; i < fLength; ++i) { |
| 135 | data[i] = ValueAt(i); |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | virtual ClassType getType() { return kSubclassExtraData_ClassType; } |
| 140 | |
| 141 | virtual void validate(skiatest::Reporter* reporter) const { |
| 142 | Base::validate(reporter); |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 143 | const int* data = reinterpret_cast<const int*>(this + 1); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 144 | for (int i = 0; i < fLength; ++i) { |
| 145 | REPORTER_ASSERT(reporter, ValueAt(i) == data[i]); |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | private: |
Brian Osman | 50ea3c0 | 2019-02-04 10:01:53 -0500 | [diff] [blame] | 150 | static int ValueAt(uint64_t i) { |
| 151 | return static_cast<int>((123456789 + 987654321 * i) & 0xFFFFFFFF); |
| 152 | } |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 153 | int fLength; |
| 154 | }; |
| 155 | |
| 156 | class SubclassEmpty : public Base { |
| 157 | public: |
| 158 | virtual ClassType getType() { return kSubclassEmpty_ClassType; } |
| 159 | }; |
| 160 | |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 161 | class Order { |
| 162 | public: |
| 163 | Order() { this->reset(); } |
| 164 | void reset() { fCurrent = 0; } |
| 165 | ClassType next() { |
| 166 | fCurrent = 1664525 * fCurrent + 1013904223; |
| 167 | return static_cast<ClassType>(fCurrent % kNumClassTypes); |
| 168 | } |
| 169 | private: |
| 170 | uint32_t fCurrent; |
| 171 | }; |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 172 | |
| 173 | static void test_subclasses_iter(skiatest::Reporter*, Order&, Base::Recorder::iterator&, int = 0); |
| 174 | |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 175 | static void test_subclasses(skiatest::Reporter* reporter) { |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 176 | Base::Recorder recorder(1024); |
| 177 | |
| 178 | Order order; |
| 179 | for (int i = 0; i < 1000; i++) { |
| 180 | switch (order.next()) { |
| 181 | case kBase_ClassType: |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 182 | recorder.emplace<Base>(); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 183 | break; |
| 184 | |
| 185 | case kSubclass_ClassType: |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 186 | recorder.emplace<Subclass>(); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 187 | break; |
| 188 | |
| 189 | case kSubSubclass_ClassType: |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 190 | recorder.emplace<SubSubclass>(); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 191 | break; |
| 192 | |
| 193 | case kSubclassExtraData_ClassType: |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 194 | recorder.emplaceWithData<SubclassExtraData>(sizeof(int) * i, i); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 195 | break; |
| 196 | |
| 197 | case kSubclassEmpty_ClassType: |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 198 | recorder.emplace<SubclassEmpty>(); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 199 | break; |
| 200 | |
| 201 | default: |
scroggo | 0ee2627 | 2014-11-07 06:07:32 -0800 | [diff] [blame] | 202 | ERRORF(reporter, "Invalid class type"); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 203 | break; |
| 204 | } |
| 205 | } |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 206 | REPORTER_ASSERT(reporter, 1000 == gActiveRecorderItems); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 207 | |
| 208 | order.reset(); |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 209 | auto iter = recorder.begin(); |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 210 | |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 211 | test_subclasses_iter(reporter, order, iter); |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 212 | |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 213 | REPORTER_ASSERT(reporter, iter == recorder.end()); |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 214 | // Don't reset the recorder. It should automatically destruct all its items. |
| 215 | } |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 216 | static void test_subclasses_iter(skiatest::Reporter* reporter, Order& order, |
| 217 | Base::Recorder::iterator& iter, int i) { |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 218 | if (i >= 1000) { |
| 219 | return; |
| 220 | } |
| 221 | |
| 222 | ClassType classType = order.next(); |
| 223 | |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 224 | REPORTER_ASSERT(reporter, classType == iter->getType()); |
| 225 | iter->validate(reporter); |
| 226 | |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 227 | ++iter; |
| 228 | test_subclasses_iter(reporter, order, iter, i + 1); |
| 229 | } |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 230 | |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 231 | struct AlignBase { |
| 232 | AlignBase() { ++gActiveRecorderItems; } |
| 233 | ~AlignBase() { --gActiveRecorderItems; } |
| 234 | char fValue; |
| 235 | }; |
| 236 | struct alignas(16) Align16 : public AlignBase {}; |
| 237 | struct alignas(32) Align32 : public AlignBase {}; |
| 238 | struct alignas(64) Align64 : public AlignBase {}; |
| 239 | struct alignas(128) Align128 : public AlignBase {}; |
| 240 | |
| 241 | static void test_alignment(skiatest::Reporter* reporter) { |
| 242 | GrTRecorder<AlignBase> recorder(0); |
| 243 | SkTArray<size_t> expectedAlignments; |
| 244 | SkRandom random; |
| 245 | for (int i = 0; i < 100; ++i) { |
| 246 | size_t dataSize = random.nextULessThan(20); |
| 247 | switch (random.nextULessThan(5)) { |
| 248 | case 0: |
| 249 | recorder.emplaceWithData<AlignBase>(dataSize); |
| 250 | expectedAlignments.push_back(alignof(AlignBase)); |
| 251 | break; |
| 252 | case 1: |
| 253 | recorder.emplaceWithData<Align16>(dataSize); |
| 254 | expectedAlignments.push_back(16); |
| 255 | break; |
| 256 | case 2: |
| 257 | recorder.emplaceWithData<Align32>(dataSize); |
| 258 | expectedAlignments.push_back(32); |
| 259 | break; |
| 260 | case 3: |
| 261 | recorder.emplaceWithData<Align64>(dataSize); |
| 262 | expectedAlignments.push_back(64); |
| 263 | break; |
| 264 | case 4: |
| 265 | recorder.emplaceWithData<Align128>(dataSize); |
| 266 | expectedAlignments.push_back(128); |
| 267 | break; |
| 268 | } |
| 269 | recorder.back().fValue = i; |
| 270 | } |
| 271 | int i = 0; |
| 272 | for (const auto& x : recorder) { |
| 273 | REPORTER_ASSERT(reporter, x.fValue == i); |
| 274 | auto pointer = reinterpret_cast<uintptr_t>(&x); |
| 275 | auto mask = static_cast<uintptr_t>(expectedAlignments[i]) - 1; |
| 276 | REPORTER_ASSERT(reporter, !(pointer & mask)); |
| 277 | i++; |
| 278 | } |
| 279 | REPORTER_ASSERT(reporter, i == 100); |
cdalton | 72badbd | 2015-04-16 10:42:49 -0700 | [diff] [blame] | 280 | } |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 281 | |
Brian Salomon | dcfca43 | 2017-11-15 15:48:03 -0500 | [diff] [blame] | 282 | DEF_GPUTEST(GrTRecorder, reporter, /* options */) { |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 283 | test_extra_data(reporter); |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 284 | REPORTER_ASSERT(reporter, 0 == gActiveRecorderItems); // test_extra_data should call reset(). |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 285 | |
| 286 | test_subclasses(reporter); |
Brian Salomon | 24d377e | 2019-04-23 15:24:31 -0400 | [diff] [blame] | 287 | REPORTER_ASSERT(reporter, 0 == gActiveRecorderItems); // Ensure ~GrTRecorder invokes dtors. |
| 288 | |
| 289 | test_alignment(reporter); |
| 290 | REPORTER_ASSERT(reporter, 0 == gActiveRecorderItems); // Ensure ~GrTRecorder invokes dtors. |
cdalton | 6819df3 | 2014-10-15 13:43:48 -0700 | [diff] [blame] | 291 | } |