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