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