| /* | 
 |  * Copyright 2011 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "Test.h" | 
 | #include "TestClassDef.h" | 
 | // This is a GPU-backend specific test | 
 | #if SK_SUPPORT_GPU | 
 | #include "GrMemoryPool.h" | 
 | #include "SkRandom.h" | 
 | #include "SkTDArray.h" | 
 | #include "SkTemplates.h" | 
 | #include "SkInstCnt.h" | 
 |  | 
 | // A is the top of an inheritance tree of classes that overload op new and | 
 | // and delete to use a GrMemoryPool. The objects have values of different types | 
 | // that can be set and checked. | 
 | class A { | 
 | public: | 
 |     A() {}; | 
 |     virtual void setValues(int v) { | 
 |         fChar = static_cast<char>(v); | 
 |     } | 
 |     virtual bool checkValues(int v) { | 
 |         return fChar == static_cast<char>(v); | 
 |     } | 
 |     virtual ~A() {}; | 
 |  | 
 |     void* operator new(size_t size) { | 
 |         if (!gPool.get()) { | 
 |             return ::operator new(size); | 
 |         } else { | 
 |             return gPool->allocate(size); | 
 |         } | 
 |     } | 
 |  | 
 |     void operator delete(void* p) { | 
 |         if (!gPool.get()) { | 
 |             ::operator delete(p); | 
 |         } else { | 
 |             return gPool->release(p); | 
 |         } | 
 |     } | 
 |  | 
 |     SK_DECLARE_INST_COUNT_ROOT(A); | 
 |  | 
 |     static A* Create(SkRandom* r); | 
 |  | 
 |     static void SetAllocator(size_t preallocSize, size_t minAllocSize) { | 
 | #if SK_ENABLE_INST_COUNT | 
 |         SkASSERT(0 == GetInstanceCount()); | 
 | #endif | 
 |         GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize); | 
 |         gPool.reset(pool); | 
 |     } | 
 |  | 
 |     static void ResetAllocator() { | 
 | #if SK_ENABLE_INST_COUNT | 
 |         SkASSERT(0 == GetInstanceCount()); | 
 | #endif | 
 |         gPool.reset(NULL); | 
 |     } | 
 |  | 
 | private: | 
 |     static SkAutoTDelete<GrMemoryPool> gPool; | 
 |     char fChar; | 
 | }; | 
 |  | 
 | SkAutoTDelete<GrMemoryPool> A::gPool; | 
 |  | 
 | class B : public A { | 
 | public: | 
 |     B() {}; | 
 |     virtual void setValues(int v) { | 
 |         fDouble = static_cast<double>(v); | 
 |         this->INHERITED::setValues(v); | 
 |     } | 
 |     virtual bool checkValues(int v) { | 
 |         return fDouble == static_cast<double>(v) && | 
 |                this->INHERITED::checkValues(v); | 
 |     } | 
 |     virtual ~B() {}; | 
 |  | 
 | private: | 
 |     double fDouble; | 
 |  | 
 |     typedef A INHERITED; | 
 | }; | 
 |  | 
 | class C : public A { | 
 | public: | 
 |     C() {}; | 
 |     virtual void setValues(int v) { | 
 |         fInt64 = static_cast<int64_t>(v); | 
 |         this->INHERITED::setValues(v); | 
 |     } | 
 |     virtual bool checkValues(int v) { | 
 |         return fInt64 == static_cast<int64_t>(v) && | 
 |                this->INHERITED::checkValues(v); | 
 |     } | 
 |     virtual ~C() {}; | 
 |  | 
 | private: | 
 |     int64_t fInt64; | 
 |  | 
 |     typedef A INHERITED; | 
 | }; | 
 |  | 
 | // D derives from C and owns a dynamically created B | 
 | class D : public C { | 
 | public: | 
 |     D() { | 
 |         fB = new B(); | 
 |     } | 
 |     virtual void setValues(int v) { | 
 |         fVoidStar = reinterpret_cast<void*>(v); | 
 |         this->INHERITED::setValues(v); | 
 |         fB->setValues(v); | 
 |     } | 
 |     virtual bool checkValues(int v) { | 
 |         return fVoidStar == reinterpret_cast<void*>(v) && | 
 |                fB->checkValues(v) && | 
 |                this->INHERITED::checkValues(v); | 
 |     } | 
 |     virtual ~D() { | 
 |         delete fB; | 
 |     } | 
 | private: | 
 |     void*   fVoidStar; | 
 |     B*      fB; | 
 |  | 
 |     typedef C INHERITED; | 
 | }; | 
 |  | 
 | class E : public A { | 
 | public: | 
 |     E() {} | 
 |     virtual void setValues(int v) { | 
 |         for (size_t i = 0; i < SK_ARRAY_COUNT(fIntArray); ++i) { | 
 |             fIntArray[i] = v; | 
 |         } | 
 |         this->INHERITED::setValues(v); | 
 |     } | 
 |     virtual bool checkValues(int v) { | 
 |         bool ok = true; | 
 |         for (size_t i = 0; ok && i < SK_ARRAY_COUNT(fIntArray); ++i) { | 
 |             if (fIntArray[i] != v) { | 
 |                 ok = false; | 
 |             } | 
 |         } | 
 |         return ok && this->INHERITED::checkValues(v); | 
 |     } | 
 |     virtual ~E() {} | 
 | private: | 
 |     int   fIntArray[20]; | 
 |  | 
 |     typedef A INHERITED; | 
 | }; | 
 |  | 
 | A* A::Create(SkRandom* r) { | 
 |     switch (r->nextRangeU(0, 4)) { | 
 |         case 0: | 
 |             return new A; | 
 |         case 1: | 
 |             return new B; | 
 |         case 2: | 
 |             return new C; | 
 |         case 3: | 
 |             return new D; | 
 |         case 4: | 
 |             return new E; | 
 |         default: | 
 |             // suppress warning | 
 |             return NULL; | 
 |     } | 
 | } | 
 |  | 
 | struct Rec { | 
 |     A* fInstance; | 
 |     int fValue; | 
 | }; | 
 |  | 
 | DEF_TEST(GrMemoryPool, reporter) { | 
 |     // prealloc and min alloc sizes for the pool | 
 |     static const size_t gSizes[][2] = { | 
 |         {0, 0}, | 
 |         {10 * sizeof(A), 20 * sizeof(A)}, | 
 |         {100 * sizeof(A), 100 * sizeof(A)}, | 
 |         {500 * sizeof(A), 500 * sizeof(A)}, | 
 |         {10000 * sizeof(A), 0}, | 
 |         {1, 100 * sizeof(A)}, | 
 |     }; | 
 |     // different percentages of creation vs deletion | 
 |     static const float gCreateFraction[] = {1.f, .95f, 0.75f, .5f}; | 
 |     // number of create/destroys per test | 
 |     static const int kNumIters = 20000; | 
 |     // check that all the values stored in A objects are correct after this | 
 |     // number of iterations | 
 |     static const int kCheckPeriod = 500; | 
 |  | 
 |     SkRandom r; | 
 |     for (size_t s = 0; s < SK_ARRAY_COUNT(gSizes); ++s) { | 
 |         A::SetAllocator(gSizes[s][0], gSizes[s][1]); | 
 |         for (size_t c = 0; c < SK_ARRAY_COUNT(gCreateFraction); ++c) { | 
 |             SkTDArray<Rec> instanceRecs; | 
 |             for (int i = 0; i < kNumIters; ++i) { | 
 |                 float createOrDestroy = r.nextUScalar1(); | 
 |                 if (createOrDestroy < gCreateFraction[c] || | 
 |                     0 == instanceRecs.count()) { | 
 |                     Rec* rec = instanceRecs.append(); | 
 |                     rec->fInstance = A::Create(&r); | 
 |                     rec->fValue = static_cast<int>(r.nextU()); | 
 |                     rec->fInstance->setValues(rec->fValue); | 
 |                 } else { | 
 |                     int d = r.nextRangeU(0, instanceRecs.count() - 1); | 
 |                     Rec& rec = instanceRecs[d]; | 
 |                     REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); | 
 |                     delete rec.fInstance; | 
 |                     instanceRecs.removeShuffle(d); | 
 |                 } | 
 |                 if (0 == i % kCheckPeriod) { | 
 |                     for (int r = 0; r < instanceRecs.count(); ++r) { | 
 |                         Rec& rec = instanceRecs[r]; | 
 |                         REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); | 
 |                     } | 
 |                 } | 
 |             } | 
 |             for (int i = 0; i < instanceRecs.count(); ++i) { | 
 |                 Rec& rec = instanceRecs[i]; | 
 |                 REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); | 
 |                 delete rec.fInstance; | 
 |             } | 
 | #if SK_ENABLE_INST_COUNT | 
 |             REPORTER_ASSERT(reporter, !A::GetInstanceCount()); | 
 | #endif | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | #endif |