1 /* 2 * Copyright 2014 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 #if SK_SUPPORT_GPU 9 10 #include "gl/GrGLNameAllocator.h" 11 #include "Test.h" 12 13 //////////////////////////////////////////////////////////////////////////////// 14 15 class NameLeakTest { 16 static const GrGLuint kFirstName = 101; 17 static const GrGLuint kRange = 1013; 18 19 public: 20 NameLeakTest(skiatest::Reporter* reporter) 21 : fReporter(reporter), 22 fAllocator(kFirstName, kFirstName + kRange), 23 fAllocatedCount(0), 24 fRandomName(kFirstName + 4 * kRange / 7) { 25 memset(fAllocatedNames, 0, sizeof(fAllocatedNames)); 26 } 27 28 bool run() { 29 if (!this->allocateAllRemaining()) { 30 return false; 31 } 32 33 for (GrGLuint freeCount = 1; freeCount <= kRange; ++freeCount) { 34 if (!this->freeRandomNames(freeCount)) { 35 return false; 36 } 37 if (!this->allocateAllRemaining()) { 38 return false; 39 } 40 } 41 42 return true; 43 } 44 45 private: 46 bool isAllocated(GrGLuint name) const { 47 return fAllocatedNames[name - kFirstName]; 48 } 49 50 void setAllocated(GrGLuint name, bool allocated) { 51 fAllocatedNames[name - kFirstName] = allocated; 52 } 53 54 bool allocateAllRemaining() { 55 for (; fAllocatedCount < kRange; ++fAllocatedCount) { 56 GrGLuint name = fAllocator.allocateName(); 57 if (0 == name) { 58 ERRORF(fReporter, 59 "Name allocate failed, but there should still be %u free names", 60 kRange - fAllocatedCount); 61 return false; 62 } 63 if (name < kFirstName || name >= kFirstName + kRange) { 64 ERRORF(fReporter, 65 "Name allocate returned name %u outside its bounds [%u, %u)", 66 name, kFirstName, kFirstName + kRange); 67 return false; 68 } 69 if (this->isAllocated(name)) { 70 ERRORF(fReporter, "Name allocate returned name that is already allocated"); 71 return false; 72 } 73 74 this->setAllocated(name, true); 75 } 76 77 // Ensure it returns 0 once all the names are allocated. 78 GrGLuint name = fAllocator.allocateName(); 79 if (0 != name) { 80 ERRORF(fReporter, 81 "Name allocate did not fail when all names were already in use"); 82 return false; 83 } 84 85 // Ensure every unique name is allocated. 86 for (GrGLuint i = 0; i < kRange; ++i) { 87 if (!this->isAllocated(kFirstName + i)) { 88 ERRORF(fReporter, "Not all unique names are allocated after allocateAllRemaining()"); 89 return false; 90 } 91 } 92 93 return true; 94 } 95 96 bool freeRandomNames(GrGLuint count) { 97 // The values a and c make up an LCG (pseudo-random generator). These 98 // values must satisfy the Hull-Dobell Theorem (with m=kRange): 99 // http://en.wikipedia.org/wiki/Linear_congruential_generator 100 // We use our own generator to guarantee it hits each unique value 101 // within kRange exactly once before repeating. 102 const GrGLuint seed = (count + fRandomName) / 2; 103 const GrGLuint a = seed * kRange + 1; 104 const GrGLuint c = (seed * 743) % kRange; 105 106 for (GrGLuint i = 0; i < count; ++i) { 107 fRandomName = (a * fRandomName + c) % kRange; 108 const GrGLuint name = kFirstName + fRandomName; 109 if (!this->isAllocated(name)) { 110 ERRORF(fReporter, "Test bug: Should not free a not-allocated name at this point (%u)", i); 111 return false; 112 } 113 114 fAllocator.free(name); 115 this->setAllocated(name, false); 116 --fAllocatedCount; 117 } 118 119 return true; 120 } 121 122 skiatest::Reporter* fReporter; 123 GrGLNameAllocator fAllocator; 124 bool fAllocatedNames[kRange]; 125 GrGLuint fAllocatedCount; 126 GrGLuint fRandomName; 127 }; 128 129 DEF_GPUTEST(NameAllocator, reporter, factory) { 130 // Ensure no names are leaked or double-allocated during heavy usage. 131 { 132 NameLeakTest nameLeakTest(reporter); 133 nameLeakTest.run(); 134 } 135 136 static const GrGLuint range = 32; 137 GrGLNameAllocator allocator(1, 1 + range); 138 for (GrGLuint i = 1; i <= range; ++i) { 139 allocator.allocateName(); 140 } 141 REPORTER_ASSERT(reporter, 0 == allocator.allocateName()); 142 143 // Test freeing names out of range. 144 allocator.free(allocator.firstName() - 1); 145 allocator.free(allocator.endName()); 146 REPORTER_ASSERT(reporter, 0 == allocator.allocateName()); 147 148 // Test freeing not-allocated names. 149 for (GrGLuint i = 1; i <= range/2; i += 2) { 150 allocator.free(i); 151 } 152 for (GrGLuint i = 1; i <= range/2; i += 2) { 153 // None of these names will be allocated. 154 allocator.free(i); 155 } 156 for (GrGLuint i = 1; i <= range/2; ++i) { 157 // Every other name will not be be allocated. 158 allocator.free(i); 159 } 160 for (GrGLuint i = 1; i <= range/2; ++i) { 161 if (0 == allocator.allocateName()) { 162 ERRORF(reporter, "Name allocate failed when there should be free names"); 163 break; 164 } 165 } 166 REPORTER_ASSERT(reporter, 0 == allocator.allocateName()); 167 } 168 169 #endif 170