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.
19class A {
20public:
21    A() {};
22    virtual void setValues(int v) {
23        fChar = static_cast<char>(v);
24    }
25    virtual bool checkValues(int v) {
26        return fChar == static_cast<char>(v);
27    }
28    virtual ~A() {};
29
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
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
48    static void SetAllocator(size_t preallocSize, size_t minAllocSize) {
49        GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize);
50        gPool.reset(pool);
51    }
52
53    static void ResetAllocator() {
54        gPool.reset(nullptr);
55    }
56
57private:
58    static SkAutoTDelete<GrMemoryPool> gPool;
59    char fChar;
60};
61
62SkAutoTDelete<GrMemoryPool> A::gPool;
63
64class B : public A {
65public:
66    B() {};
67    virtual void setValues(int v) {
68        fDouble = static_cast<double>(v);
69        this->INHERITED::setValues(v);
70    }
71    virtual bool checkValues(int v) {
72        return fDouble == static_cast<double>(v) &&
73               this->INHERITED::checkValues(v);
74    }
75    virtual ~B() {};
76
77private:
78    double fDouble;
79
80    typedef A INHERITED;
81};
82
83class C : public A {
84public:
85    C() {};
86    virtual void setValues(int v) {
87        fInt64 = static_cast<int64_t>(v);
88        this->INHERITED::setValues(v);
89    }
90    virtual bool checkValues(int v) {
91        return fInt64 == static_cast<int64_t>(v) &&
92               this->INHERITED::checkValues(v);
93    }
94    virtual ~C() {};
95
96private:
97    int64_t fInt64;
98
99    typedef A INHERITED;
100};
101
102// D derives from C and owns a dynamically created B
103class D : public C {
104public:
105    D() {
106        fB = new B();
107    }
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    }
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    }
118    virtual ~D() {
119        delete fB;
120    }
121private:
122    void*   fVoidStar;
123    B*      fB;
124
125    typedef C INHERITED;
126};
127
128class E : public A {
129public:
130    E() {}
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    }
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    }
146    virtual ~E() {}
147private:
148    int   fIntArray[20];
149
150    typedef A INHERITED;
151};
152
153A* 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
171struct Rec {
172    A* fInstance;
173    int fValue;
174};
175
176DEF_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