1/* 2 * Copyright 2013 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 here to ensure SK_SUPPORT_GPU is set correctly before it is examined. 9#include "SkTypes.h" 10 11#if SK_SUPPORT_GPU 12 13#include "GrContext.h" 14#include "GrContextFactory.h" 15#include "GrGpu.h" 16#include "GrGpuResourceCacheAccess.h" 17#include "GrGpuResourcePriv.h" 18#include "GrRenderTarget.h" 19#include "GrRenderTargetPriv.h" 20#include "GrResourceCache.h" 21#include "SkCanvas.h" 22#include "SkGr.h" 23#include "SkMessageBus.h" 24#include "SkSurface.h" 25#include "Test.h" 26 27static const int gWidth = 640; 28static const int gHeight = 480; 29 30//////////////////////////////////////////////////////////////////////////////// 31static void test_cache(skiatest::Reporter* reporter, GrContext* context, SkCanvas* canvas) { 32 const SkIRect size = SkIRect::MakeWH(gWidth, gHeight); 33 34 SkBitmap src; 35 src.allocN32Pixels(size.width(), size.height()); 36 src.eraseColor(SK_ColorBLACK); 37 size_t srcSize = src.getSize(); 38 39 size_t initialCacheSize; 40 context->getResourceCacheUsage(NULL, &initialCacheSize); 41 42 int oldMaxNum; 43 size_t oldMaxBytes; 44 context->getResourceCacheLimits(&oldMaxNum, &oldMaxBytes); 45 46 // Set the cache limits so we can fit 10 "src" images and the 47 // max number of textures doesn't matter 48 size_t maxCacheSize = initialCacheSize + 10*srcSize; 49 context->setResourceCacheLimits(1000, maxCacheSize); 50 51 SkBitmap readback; 52 readback.allocN32Pixels(size.width(), size.height()); 53 54 for (int i = 0; i < 100; ++i) { 55 canvas->drawBitmap(src, 0, 0); 56 canvas->readPixels(size, &readback); 57 58 // "modify" the src texture 59 src.notifyPixelsChanged(); 60 61 size_t curCacheSize; 62 context->getResourceCacheUsage(NULL, &curCacheSize); 63 64 // we should never go over the size limit 65 REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize); 66 } 67 68 context->setResourceCacheLimits(oldMaxNum, oldMaxBytes); 69} 70 71static void test_stencil_buffers(skiatest::Reporter* reporter, GrContext* context) { 72 GrSurfaceDesc smallDesc; 73 smallDesc.fFlags = kRenderTarget_GrSurfaceFlag; 74 smallDesc.fConfig = kSkia8888_GrPixelConfig; 75 smallDesc.fWidth = 4; 76 smallDesc.fHeight = 4; 77 smallDesc.fSampleCnt = 0; 78 79 GrTextureProvider* cache = context->textureProvider(); 80 // Test that two budgeted RTs with the same desc share a stencil buffer. 81 SkAutoTUnref<GrTexture> smallRT0(cache->createTexture(smallDesc, true)); 82 if (smallRT0 && smallRT0->asRenderTarget()) { 83 smallRT0->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); 84 } 85 86 SkAutoTUnref<GrTexture> smallRT1(cache->createTexture(smallDesc, true)); 87 if (smallRT1 && smallRT1->asRenderTarget()) { 88 smallRT1->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); 89 } 90 91 REPORTER_ASSERT(reporter, 92 smallRT0 && smallRT1 && 93 smallRT0->asRenderTarget() && smallRT1->asRenderTarget() && 94 smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() == 95 smallRT1->asRenderTarget()->renderTargetPriv().getStencilAttachment()); 96 97 // An unbudgeted RT with the same desc should also share. 98 SkAutoTUnref<GrTexture> smallRT2(cache->createTexture(smallDesc, false)); 99 if (smallRT2 && smallRT2->asRenderTarget()) { 100 smallRT2->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); 101 } 102 REPORTER_ASSERT(reporter, 103 smallRT0 && smallRT2 && 104 smallRT0->asRenderTarget() && smallRT2->asRenderTarget() && 105 smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() == 106 smallRT2->asRenderTarget()->renderTargetPriv().getStencilAttachment()); 107 108 // An RT with a much larger size should not share. 109 GrSurfaceDesc bigDesc; 110 bigDesc.fFlags = kRenderTarget_GrSurfaceFlag; 111 bigDesc.fConfig = kSkia8888_GrPixelConfig; 112 bigDesc.fWidth = 400; 113 bigDesc.fHeight = 200; 114 bigDesc.fSampleCnt = 0; 115 SkAutoTUnref<GrTexture> bigRT(cache->createTexture(bigDesc, false)); 116 if (bigRT && bigRT->asRenderTarget()) { 117 bigRT->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); 118 } 119 REPORTER_ASSERT(reporter, 120 smallRT0 && bigRT && 121 smallRT0->asRenderTarget() && bigRT->asRenderTarget() && 122 smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() != 123 bigRT->asRenderTarget()->renderTargetPriv().getStencilAttachment()); 124 125 if (context->getMaxSampleCount() >= 4) { 126 // An RT with a different sample count should not share. 127 GrSurfaceDesc smallMSAADesc = smallDesc; 128 smallMSAADesc.fSampleCnt = 4; 129 SkAutoTUnref<GrTexture> smallMSAART0(cache->createTexture(smallMSAADesc, false)); 130 if (smallMSAART0 && smallMSAART0->asRenderTarget()) { 131 smallMSAART0->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); 132 } 133#ifdef SK_BUILD_FOR_ANDROID 134 if (!smallMSAART0) { 135 // The nexus player seems to fail to create MSAA textures. 136 return; 137 } 138#endif 139 REPORTER_ASSERT(reporter, 140 smallRT0 && smallMSAART0 && 141 smallRT0->asRenderTarget() && smallMSAART0->asRenderTarget() && 142 smallRT0->asRenderTarget()->renderTargetPriv().getStencilAttachment() != 143 smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment()); 144 // A second MSAA RT should share with the first MSAA RT. 145 SkAutoTUnref<GrTexture> smallMSAART1(cache->createTexture(smallMSAADesc, false)); 146 if (smallMSAART1 && smallMSAART1->asRenderTarget()) { 147 smallMSAART1->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); 148 } 149 REPORTER_ASSERT(reporter, 150 smallMSAART0 && smallMSAART1 && 151 smallMSAART0->asRenderTarget() && 152 smallMSAART1->asRenderTarget() && 153 smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment() == 154 smallMSAART1->asRenderTarget()->renderTargetPriv().getStencilAttachment()); 155 // But not one with a larger sample count should not. (Also check that the request for 4 156 // samples didn't get rounded up to >= 8 or else they could share.). 157 if (context->getMaxSampleCount() >= 8 && smallMSAART0 && smallMSAART0->asRenderTarget() && 158 smallMSAART0->asRenderTarget()->numSamples() < 8) { 159 smallMSAADesc.fSampleCnt = 8; 160 smallMSAART1.reset(cache->createTexture(smallMSAADesc, false)); 161 SkAutoTUnref<GrTexture> smallMSAART1(cache->createTexture(smallMSAADesc, false)); 162 if (smallMSAART1 && smallMSAART1->asRenderTarget()) { 163 smallMSAART1->asRenderTarget()->renderTargetPriv().attachStencilAttachment(); 164 } 165 REPORTER_ASSERT(reporter, 166 smallMSAART0 && smallMSAART1 && 167 smallMSAART0->asRenderTarget() && 168 smallMSAART1->asRenderTarget() && 169 smallMSAART0->asRenderTarget()->renderTargetPriv().getStencilAttachment() != 170 smallMSAART1->asRenderTarget()->renderTargetPriv().getStencilAttachment()); 171 } 172 } 173} 174 175class TestResource : public GrGpuResource { 176 static const size_t kDefaultSize = 100; 177 enum ScratchConstructor { kScratchConstructor }; 178public: 179 SK_DECLARE_INST_COUNT(TestResource); 180 /** Property that distinctly categorizes the resource. 181 * For example, textures have width, height, ... */ 182 enum SimulatedProperty { kA_SimulatedProperty, kB_SimulatedProperty }; 183 184 TestResource(GrGpu* gpu, size_t size, GrGpuResource::LifeCycle lifeCycle) 185 : INHERITED(gpu, lifeCycle) 186 , fToDelete(NULL) 187 , fSize(size) 188 , fProperty(kA_SimulatedProperty) { 189 ++fNumAlive; 190 this->registerWithCache(); 191 } 192 193 TestResource(GrGpu* gpu, GrGpuResource::LifeCycle lifeCycle) 194 : INHERITED(gpu, lifeCycle) 195 , fToDelete(NULL) 196 , fSize(kDefaultSize) 197 , fProperty(kA_SimulatedProperty) { 198 ++fNumAlive; 199 this->registerWithCache(); 200 } 201 202 TestResource(GrGpu* gpu) 203 : INHERITED(gpu, kCached_LifeCycle) 204 , fToDelete(NULL) 205 , fSize(kDefaultSize) 206 , fProperty(kA_SimulatedProperty) { 207 ++fNumAlive; 208 this->registerWithCache(); 209 } 210 211 static TestResource* CreateScratch(GrGpu* gpu, SimulatedProperty property, bool cached = true) { 212 return SkNEW_ARGS(TestResource, (gpu, property, cached, kScratchConstructor)); 213 } 214 215 ~TestResource() { 216 --fNumAlive; 217 SkSafeUnref(fToDelete); 218 } 219 220 void setSize(size_t size) { 221 fSize = size; 222 this->didChangeGpuMemorySize(); 223 } 224 225 static int NumAlive() { return fNumAlive; } 226 227 void setUnrefWhenDestroyed(TestResource* resource) { 228 SkRefCnt_SafeAssign(fToDelete, resource); 229 } 230 231 static void ComputeScratchKey(SimulatedProperty property, GrScratchKey* key) { 232 static GrScratchKey::ResourceType t = GrScratchKey::GenerateResourceType(); 233 GrScratchKey::Builder builder(key, t, kScratchKeyFieldCnt); 234 for (int i = 0; i < kScratchKeyFieldCnt; ++i) { 235 builder[i] = static_cast<uint32_t>(i + property); 236 } 237 } 238 239 static size_t ExpectedScratchKeySize() { 240 return sizeof(uint32_t) * (kScratchKeyFieldCnt + GrScratchKey::kMetaDataCnt); 241 } 242 243private: 244 static const int kScratchKeyFieldCnt = 6; 245 246 TestResource(GrGpu* gpu, SimulatedProperty property, bool cached, ScratchConstructor) 247 : INHERITED(gpu, cached ? kCached_LifeCycle : kUncached_LifeCycle) 248 , fToDelete(NULL) 249 , fSize(kDefaultSize) 250 , fProperty(property) { 251 GrScratchKey scratchKey; 252 ComputeScratchKey(fProperty, &scratchKey); 253 this->setScratchKey(scratchKey); 254 ++fNumAlive; 255 this->registerWithCache(); 256 } 257 258 size_t onGpuMemorySize() const override { return fSize; } 259 260 TestResource* fToDelete; 261 size_t fSize; 262 static int fNumAlive; 263 SimulatedProperty fProperty; 264 typedef GrGpuResource INHERITED; 265}; 266int TestResource::fNumAlive = 0; 267 268class Mock { 269public: 270 Mock(int maxCnt, size_t maxBytes) { 271 fContext.reset(GrContext::CreateMockContext()); 272 SkASSERT(fContext); 273 fContext->setResourceCacheLimits(maxCnt, maxBytes); 274 GrResourceCache* cache = fContext->getResourceCache(); 275 cache->purgeAllUnlocked(); 276 SkASSERT(0 == cache->getResourceCount() && 0 == cache->getResourceBytes()); 277 } 278 279 GrResourceCache* cache() { return fContext->getResourceCache(); } 280 281 GrContext* context() { return fContext; } 282 283private: 284 SkAutoTUnref<GrContext> fContext; 285}; 286 287static void test_no_key(skiatest::Reporter* reporter) { 288 Mock mock(10, 30000); 289 GrContext* context = mock.context(); 290 GrResourceCache* cache = mock.cache(); 291 292 // Create a bunch of resources with no keys 293 TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu())); 294 TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu())); 295 TestResource* c = SkNEW_ARGS(TestResource, (context->getGpu())); 296 TestResource* d = SkNEW_ARGS(TestResource, (context->getGpu())); 297 a->setSize(11); 298 b->setSize(12); 299 c->setSize(13); 300 d->setSize(14); 301 302 REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 303 REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 304 REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() + 305 d->gpuMemorySize() == cache->getResourceBytes()); 306 307 // Should be safe to purge without deleting the resources since we still have refs. 308 cache->purgeAllUnlocked(); 309 REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 310 311 // Since the resources have neither unique nor scratch keys, delete immediately upon unref. 312 313 a->unref(); 314 REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive()); 315 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 316 REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() == 317 cache->getResourceBytes()); 318 319 c->unref(); 320 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 321 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 322 REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() == 323 cache->getResourceBytes()); 324 325 d->unref(); 326 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 327 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 328 REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes()); 329 330 b->unref(); 331 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 332 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 333 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 334} 335 336// Each integer passed as a template param creates a new domain. 337template <int> static void make_unique_key(GrUniqueKey* key, int data) { 338 static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain(); 339 GrUniqueKey::Builder builder(key, d, 1); 340 builder[0] = data; 341} 342 343static void test_budgeting(skiatest::Reporter* reporter) { 344 Mock mock(10, 300); 345 GrContext* context = mock.context(); 346 GrResourceCache* cache = mock.cache(); 347 348 GrUniqueKey uniqueKey; 349 make_unique_key<0>(&uniqueKey, 0); 350 351 // Create a scratch, a unique, and a wrapped resource 352 TestResource* scratch = 353 TestResource::CreateScratch(context->getGpu(), TestResource::kB_SimulatedProperty); 354 scratch->setSize(10); 355 TestResource* unique = SkNEW_ARGS(TestResource, (context->getGpu())); 356 unique->setSize(11); 357 unique->resourcePriv().setUniqueKey(uniqueKey); 358 TestResource* wrapped = SkNEW_ARGS(TestResource, 359 (context->getGpu(), GrGpuResource::kWrapped_LifeCycle)); 360 wrapped->setSize(12); 361 TestResource* unbudgeted = SkNEW_ARGS(TestResource, 362 (context->getGpu(), GrGpuResource::kUncached_LifeCycle)); 363 unbudgeted->setSize(13); 364 365 // Make sure we can't add a unique key to the wrapped resource 366 GrUniqueKey uniqueKey2; 367 make_unique_key<0>(&uniqueKey2, 1); 368 wrapped->resourcePriv().setUniqueKey(uniqueKey2); 369 REPORTER_ASSERT(reporter, NULL == cache->findAndRefUniqueResource(uniqueKey2)); 370 371 // Make sure sizes are as we expect 372 REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 373 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 374 wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() == 375 cache->getResourceBytes()); 376 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 377 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() == 378 cache->getBudgetedResourceBytes()); 379 380 // Our refs mean that the resources are non purgeable. 381 cache->purgeAllUnlocked(); 382 REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 383 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 384 wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() == 385 cache->getResourceBytes()); 386 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 387 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() == 388 cache->getBudgetedResourceBytes()); 389 390 // Unreffing the wrapped resource should free it right away. 391 wrapped->unref(); 392 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 393 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 394 unbudgeted->gpuMemorySize() == cache->getResourceBytes()); 395 396 // Now try freeing the budgeted resources first 397 wrapped = SkNEW_ARGS(TestResource, (context->getGpu(), GrGpuResource::kWrapped_LifeCycle)); 398 scratch->setSize(12); 399 unique->unref(); 400 cache->purgeAllUnlocked(); 401 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 402 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrapped->gpuMemorySize() + 403 unbudgeted->gpuMemorySize() == cache->getResourceBytes()); 404 REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 405 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() == cache->getBudgetedResourceBytes()); 406 407 scratch->unref(); 408 cache->purgeAllUnlocked(); 409 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 410 REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() + wrapped->gpuMemorySize() == 411 cache->getResourceBytes()); 412 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 413 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 414 415 wrapped->unref(); 416 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 417 REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() == cache->getResourceBytes()); 418 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 419 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 420 421 unbudgeted->unref(); 422 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 423 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 424 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 425 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 426} 427 428static void test_unbudgeted(skiatest::Reporter* reporter) { 429 Mock mock(10, 30000); 430 GrContext* context = mock.context(); 431 GrResourceCache* cache = mock.cache(); 432 433 GrUniqueKey uniqueKey; 434 make_unique_key<0>(&uniqueKey, 0); 435 436 TestResource* scratch; 437 TestResource* unique; 438 TestResource* wrapped; 439 TestResource* unbudgeted; 440 441 // A large uncached or wrapped resource shouldn't evict anything. 442 scratch = TestResource::CreateScratch(context->getGpu(), TestResource::kB_SimulatedProperty); 443 scratch->setSize(10); 444 scratch->unref(); 445 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 446 REPORTER_ASSERT(reporter, 10 == cache->getResourceBytes()); 447 REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 448 REPORTER_ASSERT(reporter, 10 == cache->getBudgetedResourceBytes()); 449 450 unique = SkNEW_ARGS(TestResource, (context->getGpu())); 451 unique->setSize(11); 452 unique->resourcePriv().setUniqueKey(uniqueKey); 453 unique->unref(); 454 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 455 REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 456 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 457 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 458 459 size_t large = 2 * cache->getResourceBytes(); 460 unbudgeted = SkNEW_ARGS(TestResource, 461 (context->getGpu(), large, GrGpuResource::kUncached_LifeCycle)); 462 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 463 REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes()); 464 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 465 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 466 467 unbudgeted->unref(); 468 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 469 REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 470 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 471 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 472 473 wrapped = SkNEW_ARGS(TestResource, 474 (context->getGpu(), large, GrGpuResource::kWrapped_LifeCycle)); 475 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 476 REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes()); 477 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 478 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 479 480 wrapped->unref(); 481 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 482 REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 483 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 484 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 485 486 cache->purgeAllUnlocked(); 487 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 488 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 489 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 490 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 491} 492 493// This method can't be static because it needs to friended in GrGpuResource::CacheAccess. 494void test_unbudgeted_to_scratch(skiatest::Reporter* reporter); 495/*static*/ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter) { 496 Mock mock(10, 300); 497 GrContext* context = mock.context(); 498 GrResourceCache* cache = mock.cache(); 499 500 TestResource* resource = 501 TestResource::CreateScratch(context->getGpu(), TestResource::kA_SimulatedProperty, false); 502 GrScratchKey key; 503 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &key); 504 505 size_t size = resource->gpuMemorySize(); 506 for (int i = 0; i < 2; ++i) { 507 // Since this resource is unbudgeted, it should not be reachable as scratch. 508 REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key); 509 REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch()); 510 REPORTER_ASSERT(reporter, !resource->resourcePriv().isBudgeted()); 511 REPORTER_ASSERT(reporter, NULL == cache->findAndRefScratchResource(key)); 512 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 513 REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 514 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 515 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 516 517 // Once it is unrefed, it should become available as scratch. 518 resource->unref(); 519 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 520 REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 521 REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 522 REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes()); 523 resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key)); 524 REPORTER_ASSERT(reporter, resource); 525 REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key); 526 REPORTER_ASSERT(reporter, resource->cacheAccess().isScratch()); 527 REPORTER_ASSERT(reporter, resource->resourcePriv().isBudgeted()); 528 529 if (0 == i) { 530 // If made unbudgeted, it should return to original state: ref'ed and unbudgeted. Try 531 // the above tests again. 532 resource->resourcePriv().makeUnbudgeted(); 533 } else { 534 // After the second time around, try removing the scratch key 535 resource->resourcePriv().removeScratchKey(); 536 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 537 REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 538 REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 539 REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes()); 540 REPORTER_ASSERT(reporter, !resource->resourcePriv().getScratchKey().isValid()); 541 REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch()); 542 REPORTER_ASSERT(reporter, resource->resourcePriv().isBudgeted()); 543 544 // now when it is unrefed it should die since it has no key. 545 resource->unref(); 546 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 547 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 548 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 549 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 550 } 551 } 552} 553 554static void test_duplicate_scratch_key(skiatest::Reporter* reporter) { 555 Mock mock(5, 30000); 556 GrContext* context = mock.context(); 557 GrResourceCache* cache = mock.cache(); 558 559 // Create two resources that have the same scratch key. 560 TestResource* a = TestResource::CreateScratch(context->getGpu(), 561 TestResource::kB_SimulatedProperty); 562 TestResource* b = TestResource::CreateScratch(context->getGpu(), 563 TestResource::kB_SimulatedProperty); 564 a->setSize(11); 565 b->setSize(12); 566 GrScratchKey scratchKey1; 567 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1); 568 // Check for negative case consistency. (leaks upon test failure.) 569 REPORTER_ASSERT(reporter, NULL == cache->findAndRefScratchResource(scratchKey1)); 570 571 GrScratchKey scratchKey; 572 TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 573 574 // Scratch resources are registered with GrResourceCache just by existing. There are 2. 575 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 576 SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));) 577 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 578 REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == 579 cache->getResourceBytes()); 580 581 // Our refs mean that the resources are non purgeable. 582 cache->purgeAllUnlocked(); 583 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 584 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 585 586 // Unref but don't purge 587 a->unref(); 588 b->unref(); 589 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 590 SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));) 591 592 // Purge again. This time resources should be purgeable. 593 cache->purgeAllUnlocked(); 594 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 595 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 596 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 597} 598 599static void test_remove_scratch_key(skiatest::Reporter* reporter) { 600 Mock mock(5, 30000); 601 GrContext* context = mock.context(); 602 GrResourceCache* cache = mock.cache(); 603 604 // Create two resources that have the same scratch key. 605 TestResource* a = TestResource::CreateScratch(context->getGpu(), 606 TestResource::kB_SimulatedProperty); 607 TestResource* b = TestResource::CreateScratch(context->getGpu(), 608 TestResource::kB_SimulatedProperty); 609 a->unref(); 610 b->unref(); 611 612 GrScratchKey scratchKey; 613 // Ensure that scratch key lookup is correct for negative case. 614 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 615 // (following leaks upon test failure). 616 REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey) == NULL); 617 618 // Scratch resources are registered with GrResourceCache just by existing. There are 2. 619 TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 620 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 621 SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));) 622 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 623 624 // Find the first resource and remove its scratch key 625 GrGpuResource* find; 626 find = cache->findAndRefScratchResource(scratchKey); 627 find->resourcePriv().removeScratchKey(); 628 // It's still alive, but not cached by scratch key anymore 629 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 630 SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));) 631 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 632 633 // The cache should immediately delete it when it's unrefed since it isn't accessible. 634 find->unref(); 635 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 636 SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));) 637 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 638 639 // Repeat for the second resource. 640 find = cache->findAndRefScratchResource(scratchKey); 641 find->resourcePriv().removeScratchKey(); 642 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 643 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 644 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 645 646 // Should be able to call this multiple times with no problem. 647 find->resourcePriv().removeScratchKey(); 648 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 649 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 650 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 651 652 find->unref(); 653 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 654 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 655 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 656} 657 658static void test_scratch_key_consistency(skiatest::Reporter* reporter) { 659 Mock mock(5, 30000); 660 GrContext* context = mock.context(); 661 GrResourceCache* cache = mock.cache(); 662 663 // Create two resources that have the same scratch key. 664 TestResource* a = TestResource::CreateScratch(context->getGpu(), 665 TestResource::kB_SimulatedProperty); 666 TestResource* b = TestResource::CreateScratch(context->getGpu(), 667 TestResource::kB_SimulatedProperty); 668 a->unref(); 669 b->unref(); 670 671 GrScratchKey scratchKey; 672 // Ensure that scratch key comparison and assignment is consistent. 673 GrScratchKey scratchKey1; 674 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1); 675 GrScratchKey scratchKey2; 676 TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey2); 677 REPORTER_ASSERT(reporter, scratchKey1.size() == TestResource::ExpectedScratchKeySize()); 678 REPORTER_ASSERT(reporter, scratchKey1 != scratchKey2); 679 REPORTER_ASSERT(reporter, scratchKey2 != scratchKey1); 680 scratchKey = scratchKey1; 681 REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize()); 682 REPORTER_ASSERT(reporter, scratchKey1 == scratchKey); 683 REPORTER_ASSERT(reporter, scratchKey == scratchKey1); 684 REPORTER_ASSERT(reporter, scratchKey2 != scratchKey); 685 REPORTER_ASSERT(reporter, scratchKey != scratchKey2); 686 scratchKey = scratchKey2; 687 REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize()); 688 REPORTER_ASSERT(reporter, scratchKey1 != scratchKey); 689 REPORTER_ASSERT(reporter, scratchKey != scratchKey1); 690 REPORTER_ASSERT(reporter, scratchKey2 == scratchKey); 691 REPORTER_ASSERT(reporter, scratchKey == scratchKey2); 692 693 // Ensure that scratch key lookup is correct for negative case. 694 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 695 // (following leaks upon test failure). 696 REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey) == NULL); 697 698 // Find the first resource with a scratch key and a copy of a scratch key. 699 TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 700 GrGpuResource* find = cache->findAndRefScratchResource(scratchKey); 701 REPORTER_ASSERT(reporter, find != NULL); 702 find->unref(); 703 704 scratchKey2 = scratchKey; 705 find = cache->findAndRefScratchResource(scratchKey2); 706 REPORTER_ASSERT(reporter, find != NULL); 707 REPORTER_ASSERT(reporter, find == a || find == b); 708 709 GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2); 710 REPORTER_ASSERT(reporter, find2 != NULL); 711 REPORTER_ASSERT(reporter, find2 == a || find2 == b); 712 REPORTER_ASSERT(reporter, find2 != find); 713 find2->unref(); 714 find->unref(); 715} 716 717static void test_duplicate_unique_key(skiatest::Reporter* reporter) { 718 Mock mock(5, 30000); 719 GrContext* context = mock.context(); 720 GrResourceCache* cache = mock.cache(); 721 722 GrUniqueKey key; 723 make_unique_key<0>(&key, 0); 724 725 // Create two resources that we will attempt to register with the same unique key. 726 TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu())); 727 a->setSize(11); 728 729 // Set key on resource a. 730 a->resourcePriv().setUniqueKey(key); 731 REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key)); 732 a->unref(); 733 734 // Make sure that redundantly setting a's key works. 735 a->resourcePriv().setUniqueKey(key); 736 REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key)); 737 a->unref(); 738 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 739 REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getResourceBytes()); 740 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 741 742 // Create resource b and set the same key. It should replace a's unique key cache entry. 743 TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu())); 744 b->setSize(12); 745 b->resourcePriv().setUniqueKey(key); 746 REPORTER_ASSERT(reporter, b == cache->findAndRefUniqueResource(key)); 747 b->unref(); 748 749 // Still have two resources because a is still reffed. 750 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 751 REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes()); 752 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 753 754 a->unref(); 755 // Now a should be gone. 756 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 757 REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes()); 758 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 759 760 // Now replace b with c, but make sure c can start with one unique key and change it to b's key. 761 // Also make b be unreffed when replacement occurs. 762 b->unref(); 763 TestResource* c = SkNEW_ARGS(TestResource, (context->getGpu())); 764 GrUniqueKey differentKey; 765 make_unique_key<0>(&differentKey, 1); 766 c->setSize(13); 767 c->resourcePriv().setUniqueKey(differentKey); 768 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 769 REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() == cache->getResourceBytes()); 770 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 771 // c replaces b and b should be immediately purged. 772 c->resourcePriv().setUniqueKey(key); 773 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 774 REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 775 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 776 777 // c shouldn't be purged because it is ref'ed. 778 cache->purgeAllUnlocked(); 779 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 780 REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 781 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 782 783 // Drop the ref on c, it should be kept alive because it has a unique key. 784 c->unref(); 785 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 786 REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 787 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 788 789 // Verify that we can find c, then remove its unique key. It should get purged immediately. 790 REPORTER_ASSERT(reporter, c == cache->findAndRefUniqueResource(key)); 791 c->resourcePriv().removeUniqueKey(); 792 c->unref(); 793 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 794 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 795 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 796} 797 798static void test_purge_invalidated(skiatest::Reporter* reporter) { 799 Mock mock(5, 30000); 800 GrContext* context = mock.context(); 801 GrResourceCache* cache = mock.cache(); 802 803 GrUniqueKey key1, key2, key3; 804 make_unique_key<0>(&key1, 1); 805 make_unique_key<0>(&key2, 2); 806 make_unique_key<0>(&key3, 3); 807 808 // Add three resources to the cache. Only c is usable as scratch. 809 TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu())); 810 TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu())); 811 TestResource* c = TestResource::CreateScratch(context->getGpu(), 812 TestResource::kA_SimulatedProperty); 813 a->resourcePriv().setUniqueKey(key1); 814 b->resourcePriv().setUniqueKey(key2); 815 c->resourcePriv().setUniqueKey(key3); 816 a->unref(); 817 // hold b until *after* the message is sent. 818 c->unref(); 819 820 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1)); 821 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2)); 822 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3)); 823 REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive()); 824 825 typedef GrUniqueKeyInvalidatedMessage Msg; 826 typedef SkMessageBus<GrUniqueKeyInvalidatedMessage> Bus; 827 828 // Invalidate two of the three, they should be purged and no longer accessible via their keys. 829 Bus::Post(Msg(key1)); 830 Bus::Post(Msg(key2)); 831 cache->purgeAsNeeded(); 832 // a should be deleted now, but we still have a ref on b. 833 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1)); 834 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2)); 835 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 836 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3)); 837 838 // Invalidate the third. 839 Bus::Post(Msg(key3)); 840 cache->purgeAsNeeded(); 841 // we still have a ref on b, c should be recycled as scratch. 842 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 843 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key3)); 844 845 // make b purgeable. It should be immediately deleted since it has no key. 846 b->unref(); 847 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 848 849 // Make sure we actually get to c via it's scratch key, before we say goodbye. 850 GrScratchKey scratchKey; 851 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 852 GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey); 853 REPORTER_ASSERT(reporter, scratch == c); 854 SkSafeUnref(scratch); 855 856 // Get rid of c. 857 cache->purgeAllUnlocked(); 858 scratch = cache->findAndRefScratchResource(scratchKey); 859 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 860 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 861 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 862 REPORTER_ASSERT(reporter, !scratch); 863 SkSafeUnref(scratch); 864} 865 866static void test_cache_chained_purge(skiatest::Reporter* reporter) { 867 Mock mock(3, 30000); 868 GrContext* context = mock.context(); 869 GrResourceCache* cache = mock.cache(); 870 871 GrUniqueKey key1, key2; 872 make_unique_key<0>(&key1, 1); 873 make_unique_key<0>(&key2, 2); 874 875 876 TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu())); 877 TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu())); 878 a->resourcePriv().setUniqueKey(key1); 879 b->resourcePriv().setUniqueKey(key2); 880 881 // Make a cycle 882 a->setUnrefWhenDestroyed(b); 883 b->setUnrefWhenDestroyed(a); 884 885 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 886 887 a->unref(); 888 b->unref(); 889 890 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 891 892 cache->purgeAllUnlocked(); 893 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 894 895 // Break the cycle 896 a->setUnrefWhenDestroyed(NULL); 897 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 898 899 cache->purgeAllUnlocked(); 900 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 901} 902 903static void test_resource_size_changed(skiatest::Reporter* reporter) { 904 GrUniqueKey key1, key2; 905 make_unique_key<0>(&key1, 1); 906 make_unique_key<0>(&key2, 2); 907 908 // Test changing resources sizes (both increase & decrease). 909 { 910 Mock mock(3, 30000); 911 GrContext* context = mock.context(); 912 GrResourceCache* cache = mock.cache(); 913 914 TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu())); 915 a->resourcePriv().setUniqueKey(key1); 916 a->unref(); 917 918 TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu())); 919 b->resourcePriv().setUniqueKey(key2); 920 b->unref(); 921 922 REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes()); 923 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 924 { 925 SkAutoTUnref<TestResource> find2( 926 static_cast<TestResource*>(cache->findAndRefUniqueResource(key2))); 927 find2->setSize(200); 928 SkAutoTUnref<TestResource> find1( 929 static_cast<TestResource*>(cache->findAndRefUniqueResource(key1))); 930 find1->setSize(50); 931 } 932 933 REPORTER_ASSERT(reporter, 250 == cache->getResourceBytes()); 934 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 935 } 936 937 // Test increasing a resources size beyond the cache budget. 938 { 939 Mock mock(2, 300); 940 GrContext* context = mock.context(); 941 GrResourceCache* cache = mock.cache(); 942 943 TestResource* a = SkNEW_ARGS(TestResource, (context->getGpu())); 944 a->setSize(100); 945 a->resourcePriv().setUniqueKey(key1); 946 a->unref(); 947 948 TestResource* b = SkNEW_ARGS(TestResource, (context->getGpu())); 949 b->setSize(100); 950 b->resourcePriv().setUniqueKey(key2); 951 b->unref(); 952 953 REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes()); 954 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 955 956 { 957 SkAutoTUnref<TestResource> find2(static_cast<TestResource*>( 958 cache->findAndRefUniqueResource(key2))); 959 find2->setSize(201); 960 } 961 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1)); 962 963 REPORTER_ASSERT(reporter, 201 == cache->getResourceBytes()); 964 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 965 } 966} 967 968static void test_timestamp_wrap(skiatest::Reporter* reporter) { 969 static const int kCount = 50; 970 static const int kBudgetCnt = kCount / 2; 971 static const int kLockedFreq = 8; 972 static const int kBudgetSize = 0x80000000; 973 974 SkRandom random; 975 976 // Run the test 2*kCount times; 977 for (int i = 0; i < 2 * kCount; ++i ) { 978 Mock mock(kBudgetCnt, kBudgetSize); 979 GrContext* context = mock.context(); 980 GrResourceCache* cache = mock.cache(); 981 982 // Pick a random number of resources to add before the timestamp will wrap. 983 cache->changeTimestamp(SK_MaxU32 - random.nextULessThan(kCount + 1)); 984 985 static const int kNumToPurge = kCount - kBudgetCnt; 986 987 SkTDArray<int> shouldPurgeIdxs; 988 int purgeableCnt = 0; 989 SkTDArray<GrGpuResource*> resourcesToUnref; 990 991 // Add kCount resources, holding onto resources at random so we have a mix of purgeable and 992 // unpurgeable resources. 993 for (int j = 0; j < kCount; ++j) { 994 GrUniqueKey key; 995 make_unique_key<0>(&key, j); 996 997 TestResource* r = SkNEW_ARGS(TestResource, (context->getGpu())); 998 r->resourcePriv().setUniqueKey(key); 999 if (random.nextU() % kLockedFreq) { 1000 // Make this is purgeable. 1001 r->unref(); 1002 ++purgeableCnt; 1003 if (purgeableCnt <= kNumToPurge) { 1004 *shouldPurgeIdxs.append() = j; 1005 } 1006 } else { 1007 *resourcesToUnref.append() = r; 1008 } 1009 } 1010 1011 // Verify that the correct resources were purged. 1012 int currShouldPurgeIdx = 0; 1013 for (int j = 0; j < kCount; ++j) { 1014 GrUniqueKey key; 1015 make_unique_key<0>(&key, j); 1016 GrGpuResource* res = cache->findAndRefUniqueResource(key); 1017 if (currShouldPurgeIdx < shouldPurgeIdxs.count() && 1018 shouldPurgeIdxs[currShouldPurgeIdx] == j) { 1019 ++currShouldPurgeIdx; 1020 REPORTER_ASSERT(reporter, NULL == res); 1021 } else { 1022 REPORTER_ASSERT(reporter, NULL != res); 1023 } 1024 SkSafeUnref(res); 1025 } 1026 1027 for (int j = 0; j < resourcesToUnref.count(); ++j) { 1028 resourcesToUnref[j]->unref(); 1029 } 1030 } 1031} 1032 1033static void test_flush(skiatest::Reporter* reporter) { 1034 Mock mock(1000000, 1000000); 1035 GrContext* context = mock.context(); 1036 GrResourceCache* cache = mock.cache(); 1037 1038 // The current cache impl will round the max flush count to the next power of 2. So we choose a 1039 // power of two here to keep things simpler. 1040 static const int kFlushCount = 16; 1041 cache->setLimits(1000000, 1000000, kFlushCount); 1042 1043 { 1044 // Insert a resource and send a flush notification kFlushCount times. 1045 for (int i = 0; i < kFlushCount; ++i) { 1046 TestResource* r = SkNEW_ARGS(TestResource, (context->getGpu())); 1047 GrUniqueKey k; 1048 make_unique_key<1>(&k, i); 1049 r->resourcePriv().setUniqueKey(k); 1050 r->unref(); 1051 cache->notifyFlushOccurred(); 1052 } 1053 1054 // Send flush notifications to the cache. Each flush should purge the oldest resource. 1055 for (int i = 0; i < kFlushCount - 1; ++i) { 1056 // The first resource was purged after the last flush in the initial loop, hence the -1. 1057 REPORTER_ASSERT(reporter, kFlushCount - i - 1 == cache->getResourceCount()); 1058 for (int j = 0; j < i; ++j) { 1059 GrUniqueKey k; 1060 make_unique_key<1>(&k, j); 1061 GrGpuResource* r = cache->findAndRefUniqueResource(k); 1062 REPORTER_ASSERT(reporter, !SkToBool(r)); 1063 SkSafeUnref(r); 1064 } 1065 cache->notifyFlushOccurred(); 1066 } 1067 1068 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1069 cache->purgeAllUnlocked(); 1070 } 1071 1072 // Do a similar test but where we leave refs on some resources to prevent them from being 1073 // purged. 1074 { 1075 GrGpuResource* refedResources[kFlushCount >> 1]; 1076 for (int i = 0; i < kFlushCount; ++i) { 1077 TestResource* r = SkNEW_ARGS(TestResource, (context->getGpu())); 1078 GrUniqueKey k; 1079 make_unique_key<1>(&k, i); 1080 r->resourcePriv().setUniqueKey(k); 1081 // Leave a ref on every other resource, beginning with the first. 1082 if (SkToBool(i & 0x1)) { 1083 refedResources[i/2] = r; 1084 } else { 1085 r->unref(); 1086 } 1087 cache->notifyFlushOccurred(); 1088 } 1089 1090 for (int i = 0; i < kFlushCount; ++i) { 1091 // Should get a resource purged every other flush. 1092 REPORTER_ASSERT(reporter, kFlushCount - i/2 - 1 == cache->getResourceCount()); 1093 cache->notifyFlushOccurred(); 1094 } 1095 1096 // Unref all the resources that we kept refs on in the first loop. 1097 for (int i = 0; i < kFlushCount >> 1; ++i) { 1098 refedResources[i]->unref(); 1099 } 1100 1101 // When we unref'ed them their timestamps got updated. So nothing should be purged until we 1102 // get kFlushCount additional flushes. Then everything should be purged. 1103 for (int i = 0; i < kFlushCount; ++i) { 1104 REPORTER_ASSERT(reporter, kFlushCount >> 1 == cache->getResourceCount()); 1105 cache->notifyFlushOccurred(); 1106 } 1107 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1108 1109 cache->purgeAllUnlocked(); 1110 } 1111 1112 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1113} 1114 1115static void test_large_resource_count(skiatest::Reporter* reporter) { 1116 // Set the cache size to double the resource count because we're going to create 2x that number 1117 // resources, using two different key domains. Add a little slop to the bytes because we resize 1118 // down to 1 byte after creating the resource. 1119 static const int kResourceCnt = 2000; 1120 1121 Mock mock(2 * kResourceCnt, 2 * kResourceCnt + 1000); 1122 GrContext* context = mock.context(); 1123 GrResourceCache* cache = mock.cache(); 1124 1125 for (int i = 0; i < kResourceCnt; ++i) { 1126 GrUniqueKey key1, key2; 1127 make_unique_key<1>(&key1, i); 1128 make_unique_key<2>(&key2, i); 1129 1130 TestResource* resource; 1131 1132 resource = SkNEW_ARGS(TestResource, (context->getGpu())); 1133 resource->resourcePriv().setUniqueKey(key1); 1134 resource->setSize(1); 1135 resource->unref(); 1136 1137 resource = SkNEW_ARGS(TestResource, (context->getGpu())); 1138 resource->resourcePriv().setUniqueKey(key2); 1139 resource->setSize(1); 1140 resource->unref(); 1141 } 1142 1143 REPORTER_ASSERT(reporter, TestResource::NumAlive() == 2 * kResourceCnt); 1144 REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 2 * kResourceCnt); 1145 REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 2 * kResourceCnt); 1146 REPORTER_ASSERT(reporter, cache->getResourceBytes() == 2 * kResourceCnt); 1147 REPORTER_ASSERT(reporter, cache->getResourceCount() == 2 * kResourceCnt); 1148 for (int i = 0; i < kResourceCnt; ++i) { 1149 GrUniqueKey key1, key2; 1150 make_unique_key<1>(&key1, i); 1151 make_unique_key<2>(&key2, i); 1152 1153 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1)); 1154 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2)); 1155 } 1156 1157 cache->purgeAllUnlocked(); 1158 REPORTER_ASSERT(reporter, TestResource::NumAlive() == 0); 1159 REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 0); 1160 REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 0); 1161 REPORTER_ASSERT(reporter, cache->getResourceBytes() == 0); 1162 REPORTER_ASSERT(reporter, cache->getResourceCount() == 0); 1163 1164 for (int i = 0; i < kResourceCnt; ++i) { 1165 GrUniqueKey key1, key2; 1166 make_unique_key<1>(&key1, i); 1167 make_unique_key<2>(&key2, i); 1168 1169 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1)); 1170 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2)); 1171 } 1172} 1173 1174//////////////////////////////////////////////////////////////////////////////// 1175DEF_GPUTEST(ResourceCache, reporter, factory) { 1176 for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) { 1177 GrContextFactory::GLContextType glType = static_cast<GrContextFactory::GLContextType>(type); 1178 if (!GrContextFactory::IsRenderingGLContext(glType)) { 1179 continue; 1180 } 1181 GrContext* context = factory->get(glType); 1182 if (NULL == context) { 1183 continue; 1184 } 1185 GrSurfaceDesc desc; 1186 desc.fConfig = kSkia8888_GrPixelConfig; 1187 desc.fFlags = kRenderTarget_GrSurfaceFlag; 1188 desc.fWidth = gWidth; 1189 desc.fHeight = gHeight; 1190 SkImageInfo info = SkImageInfo::MakeN32Premul(gWidth, gHeight); 1191 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context, 1192 SkSurface::kNo_Budgeted, info)); 1193 test_cache(reporter, context, surface->getCanvas()); 1194 test_stencil_buffers(reporter, context); 1195 } 1196 1197 // The below tests create their own mock contexts. 1198 test_no_key(reporter); 1199 test_budgeting(reporter); 1200 test_unbudgeted(reporter); 1201 test_unbudgeted_to_scratch(reporter); 1202 test_duplicate_unique_key(reporter); 1203 test_duplicate_scratch_key(reporter); 1204 test_remove_scratch_key(reporter); 1205 test_scratch_key_consistency(reporter); 1206 test_purge_invalidated(reporter); 1207 test_cache_chained_purge(reporter); 1208 test_resource_size_changed(reporter); 1209 test_timestamp_wrap(reporter); 1210 test_flush(reporter); 1211 test_large_resource_count(reporter); 1212} 1213 1214#endif 1215