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