1 /*
2 * Copyright 2011 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 "Test.h"
9 // This is a GPU-backend specific test
10 #if SK_SUPPORT_GPU
11 #include "GrMemoryPool.h"
12 #include "SkRandom.h"
13 #include "SkTDArray.h"
14 #include "SkTemplates.h"
15
16 // A is the top of an inheritance tree of classes that overload op new and
17 // and delete to use a GrMemoryPool. The objects have values of different types
18 // that can be set and checked.
19 class A {
20 public:
A()21 A() {};
setValues(int v)22 virtual void setValues(int v) {
23 fChar = static_cast<char>(v);
24 }
checkValues(int v)25 virtual bool checkValues(int v) {
26 return fChar == static_cast<char>(v);
27 }
~A()28 virtual ~A() {};
29
operator new(size_t size)30 void* operator new(size_t size) {
31 if (!gPool.get()) {
32 return ::operator new(size);
33 } else {
34 return gPool->allocate(size);
35 }
36 }
37
operator delete(void * p)38 void operator delete(void* p) {
39 if (!gPool.get()) {
40 ::operator delete(p);
41 } else {
42 return gPool->release(p);
43 }
44 }
45
46 static A* Create(SkRandom* r);
47
SetAllocator(size_t preallocSize,size_t minAllocSize)48 static void SetAllocator(size_t preallocSize, size_t minAllocSize) {
49 GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize);
50 gPool.reset(pool);
51 }
52
ResetAllocator()53 static void ResetAllocator() {
54 gPool.reset(nullptr);
55 }
56
57 private:
58 static SkAutoTDelete<GrMemoryPool> gPool;
59 char fChar;
60 };
61
62 SkAutoTDelete<GrMemoryPool> A::gPool;
63
64 class B : public A {
65 public:
B()66 B() {};
setValues(int v)67 virtual void setValues(int v) {
68 fDouble = static_cast<double>(v);
69 this->INHERITED::setValues(v);
70 }
checkValues(int v)71 virtual bool checkValues(int v) {
72 return fDouble == static_cast<double>(v) &&
73 this->INHERITED::checkValues(v);
74 }
~B()75 virtual ~B() {};
76
77 private:
78 double fDouble;
79
80 typedef A INHERITED;
81 };
82
83 class C : public A {
84 public:
C()85 C() {};
setValues(int v)86 virtual void setValues(int v) {
87 fInt64 = static_cast<int64_t>(v);
88 this->INHERITED::setValues(v);
89 }
checkValues(int v)90 virtual bool checkValues(int v) {
91 return fInt64 == static_cast<int64_t>(v) &&
92 this->INHERITED::checkValues(v);
93 }
~C()94 virtual ~C() {};
95
96 private:
97 int64_t fInt64;
98
99 typedef A INHERITED;
100 };
101
102 // D derives from C and owns a dynamically created B
103 class D : public C {
104 public:
D()105 D() {
106 fB = new B();
107 }
setValues(int v)108 virtual void setValues(int v) {
109 fVoidStar = reinterpret_cast<void*>(static_cast<intptr_t>(v));
110 this->INHERITED::setValues(v);
111 fB->setValues(v);
112 }
checkValues(int v)113 virtual bool checkValues(int v) {
114 return fVoidStar == reinterpret_cast<void*>(static_cast<intptr_t>(v)) &&
115 fB->checkValues(v) &&
116 this->INHERITED::checkValues(v);
117 }
~D()118 virtual ~D() {
119 delete fB;
120 }
121 private:
122 void* fVoidStar;
123 B* fB;
124
125 typedef C INHERITED;
126 };
127
128 class E : public A {
129 public:
E()130 E() {}
setValues(int v)131 virtual void setValues(int v) {
132 for (size_t i = 0; i < SK_ARRAY_COUNT(fIntArray); ++i) {
133 fIntArray[i] = v;
134 }
135 this->INHERITED::setValues(v);
136 }
checkValues(int v)137 virtual bool checkValues(int v) {
138 bool ok = true;
139 for (size_t i = 0; ok && i < SK_ARRAY_COUNT(fIntArray); ++i) {
140 if (fIntArray[i] != v) {
141 ok = false;
142 }
143 }
144 return ok && this->INHERITED::checkValues(v);
145 }
~E()146 virtual ~E() {}
147 private:
148 int fIntArray[20];
149
150 typedef A INHERITED;
151 };
152
Create(SkRandom * r)153 A* A::Create(SkRandom* r) {
154 switch (r->nextRangeU(0, 4)) {
155 case 0:
156 return new A;
157 case 1:
158 return new B;
159 case 2:
160 return new C;
161 case 3:
162 return new D;
163 case 4:
164 return new E;
165 default:
166 // suppress warning
167 return nullptr;
168 }
169 }
170
171 struct Rec {
172 A* fInstance;
173 int fValue;
174 };
175
DEF_TEST(GrMemoryPool,reporter)176 DEF_TEST(GrMemoryPool, reporter) {
177 // prealloc and min alloc sizes for the pool
178 static const size_t gSizes[][2] = {
179 {0, 0},
180 {10 * sizeof(A), 20 * sizeof(A)},
181 {100 * sizeof(A), 100 * sizeof(A)},
182 {500 * sizeof(A), 500 * sizeof(A)},
183 {10000 * sizeof(A), 0},
184 {1, 100 * sizeof(A)},
185 };
186 // different percentages of creation vs deletion
187 static const float gCreateFraction[] = {1.f, .95f, 0.75f, .5f};
188 // number of create/destroys per test
189 static const int kNumIters = 20000;
190 // check that all the values stored in A objects are correct after this
191 // number of iterations
192 static const int kCheckPeriod = 500;
193
194 SkRandom r;
195 for (size_t s = 0; s < SK_ARRAY_COUNT(gSizes); ++s) {
196 A::SetAllocator(gSizes[s][0], gSizes[s][1]);
197 for (size_t c = 0; c < SK_ARRAY_COUNT(gCreateFraction); ++c) {
198 SkTDArray<Rec> instanceRecs;
199 for (int i = 0; i < kNumIters; ++i) {
200 float createOrDestroy = r.nextUScalar1();
201 if (createOrDestroy < gCreateFraction[c] ||
202 0 == instanceRecs.count()) {
203 Rec* rec = instanceRecs.append();
204 rec->fInstance = A::Create(&r);
205 rec->fValue = static_cast<int>(r.nextU());
206 rec->fInstance->setValues(rec->fValue);
207 } else {
208 int d = r.nextRangeU(0, instanceRecs.count() - 1);
209 Rec& rec = instanceRecs[d];
210 REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
211 delete rec.fInstance;
212 instanceRecs.removeShuffle(d);
213 }
214 if (0 == i % kCheckPeriod) {
215 for (int r = 0; r < instanceRecs.count(); ++r) {
216 Rec& rec = instanceRecs[r];
217 REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
218 }
219 }
220 }
221 for (int i = 0; i < instanceRecs.count(); ++i) {
222 Rec& rec = instanceRecs[i];
223 REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
224 delete rec.fInstance;
225 }
226 }
227 }
228 }
229
230 #endif
231