| /* |
| * 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" |
| // This is a GPU-backend specific test |
| #if SK_SUPPORT_GPU |
| #include "GrMemoryPool.h" |
| #include "SkRandom.h" |
| #include "SkTDArray.h" |
| #include "SkTemplates.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); |
| } |
| } |
| |
| static A* Create(SkRandom* r); |
| |
| static void SetAllocator(size_t preallocSize, size_t minAllocSize) { |
| GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize); |
| gPool.reset(pool); |
| } |
| |
| static void ResetAllocator() { |
| gPool.reset(nullptr); |
| } |
| |
| private: |
| static std::unique_ptr<GrMemoryPool> gPool; |
| char fChar; |
| }; |
| |
| std::unique_ptr<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*>(static_cast<intptr_t>(v)); |
| this->INHERITED::setValues(v); |
| fB->setValues(v); |
| } |
| virtual bool checkValues(int v) { |
| return fVoidStar == reinterpret_cast<void*>(static_cast<intptr_t>(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 nullptr; |
| } |
| } |
| |
| 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; |
| } |
| } |
| } |
| } |
| |
| #endif |