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 #include <thread> 13 #include "GrContext.h" 14 #include "GrContextPriv.h" 15 #include "GrContextFactory.h" 16 #include "GrGpu.h" 17 #include "GrGpuResourceCacheAccess.h" 18 #include "GrGpuResourcePriv.h" 19 #include "GrProxyProvider.h" 20 #include "GrRenderTargetPriv.h" 21 #include "GrResourceCache.h" 22 #include "GrResourceProvider.h" 23 #include "GrTest.h" 24 #include "GrTexture.h" 25 26 #include "SkCanvas.h" 27 #include "SkGr.h" 28 #include "SkMessageBus.h" 29 #include "SkMipMap.h" 30 #include "SkSurface.h" 31 #include "Test.h" 32 33 static const int gWidth = 640; 34 static const int gHeight = 480; 35 36 //////////////////////////////////////////////////////////////////////////////// 37 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheCache, reporter, ctxInfo) { 38 GrContext* context = ctxInfo.grContext(); 39 GrSurfaceDesc desc; 40 desc.fConfig = kRGBA_8888_GrPixelConfig; 41 desc.fFlags = kRenderTarget_GrSurfaceFlag; 42 desc.fWidth = gWidth; 43 desc.fHeight = gHeight; 44 SkImageInfo info = SkImageInfo::MakeN32Premul(gWidth, gHeight); 45 auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info)); 46 SkCanvas* canvas = surface->getCanvas(); 47 48 const SkIRect size = SkIRect::MakeWH(gWidth, gHeight); 49 50 SkBitmap src; 51 src.allocN32Pixels(size.width(), size.height()); 52 src.eraseColor(SK_ColorBLACK); 53 size_t srcSize = src.computeByteSize(); 54 55 size_t initialCacheSize; 56 context->getResourceCacheUsage(nullptr, &initialCacheSize); 57 58 int oldMaxNum; 59 size_t oldMaxBytes; 60 context->getResourceCacheLimits(&oldMaxNum, &oldMaxBytes); 61 62 // Set the cache limits so we can fit 10 "src" images and the 63 // max number of textures doesn't matter 64 size_t maxCacheSize = initialCacheSize + 10*srcSize; 65 context->setResourceCacheLimits(1000, maxCacheSize); 66 67 SkBitmap readback; 68 readback.allocN32Pixels(size.width(), size.height()); 69 70 for (int i = 0; i < 100; ++i) { 71 canvas->drawBitmap(src, 0, 0); 72 surface->readPixels(readback, 0, 0); 73 74 // "modify" the src texture 75 src.notifyPixelsChanged(); 76 77 size_t curCacheSize; 78 context->getResourceCacheUsage(nullptr, &curCacheSize); 79 80 // we should never go over the size limit 81 REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize); 82 } 83 84 context->setResourceCacheLimits(oldMaxNum, oldMaxBytes); 85 } 86 87 static bool is_rendering_and_not_angle_es3(sk_gpu_test::GrContextFactory::ContextType type) { 88 if (type == sk_gpu_test::GrContextFactory::kANGLE_D3D11_ES3_ContextType || 89 type == sk_gpu_test::GrContextFactory::kANGLE_GL_ES3_ContextType) { 90 return false; 91 } 92 return sk_gpu_test::GrContextFactory::IsRenderingContext(type); 93 } 94 95 static GrStencilAttachment* get_SB(GrRenderTarget* rt) { 96 return rt->renderTargetPriv().getStencilAttachment(); 97 } 98 99 static sk_sp<GrRenderTarget> create_RT_with_SB(GrResourceProvider* provider, 100 int size, int sampleCount, SkBudgeted budgeted) { 101 GrSurfaceDesc desc; 102 desc.fFlags = kRenderTarget_GrSurfaceFlag; 103 desc.fOrigin = kBottomLeft_GrSurfaceOrigin; 104 desc.fWidth = size; 105 desc.fHeight = size; 106 desc.fConfig = kRGBA_8888_GrPixelConfig; 107 desc.fSampleCnt = sampleCount; 108 109 sk_sp<GrTexture> tex(provider->createTexture(desc, budgeted)); 110 if (!tex || !tex->asRenderTarget()) { 111 return nullptr; 112 } 113 114 if (!provider->attachStencilAttachment(tex->asRenderTarget())) { 115 return nullptr; 116 } 117 SkASSERT(get_SB(tex->asRenderTarget())); 118 119 return sk_ref_sp(tex->asRenderTarget()); 120 } 121 122 // This currently fails on ES3 ANGLE contexts 123 DEF_GPUTEST_FOR_CONTEXTS(ResourceCacheStencilBuffers, &is_rendering_and_not_angle_es3, reporter, 124 ctxInfo, nullptr) { 125 GrContext* context = ctxInfo.grContext(); 126 if (context->caps()->avoidStencilBuffers()) { 127 return; 128 } 129 130 GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); 131 132 sk_sp<GrRenderTarget> smallRT0 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes); 133 REPORTER_ASSERT(reporter, smallRT0); 134 135 { 136 // Two budgeted RTs with the same desc should share a stencil buffer. 137 sk_sp<GrRenderTarget> smallRT1 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes); 138 REPORTER_ASSERT(reporter, smallRT1); 139 140 REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT1.get())); 141 } 142 143 { 144 // An unbudgeted RT with the same desc should also share. 145 sk_sp<GrRenderTarget> smallRT2 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kNo); 146 REPORTER_ASSERT(reporter, smallRT2); 147 148 REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT2.get())); 149 } 150 151 { 152 // An RT with a much larger size should not share. 153 sk_sp<GrRenderTarget> bigRT = create_RT_with_SB(resourceProvider, 400, 1, SkBudgeted::kNo); 154 REPORTER_ASSERT(reporter, bigRT); 155 156 REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(bigRT.get())); 157 } 158 159 int smallSampleCount = context->caps()->getSampleCount(2, kRGBA_8888_GrPixelConfig); 160 if (smallSampleCount > 1) { 161 // An RT with a different sample count should not share. 162 sk_sp<GrRenderTarget> smallMSAART0 = create_RT_with_SB(resourceProvider, 4, 163 smallSampleCount, SkBudgeted::kNo); 164 #ifdef SK_BUILD_FOR_ANDROID 165 if (!smallMSAART0) { 166 // The nexus player seems to fail to create MSAA textures. 167 return; 168 } 169 #else 170 REPORTER_ASSERT(reporter, smallMSAART0); 171 #endif 172 173 REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(smallMSAART0.get())); 174 175 { 176 // A second MSAA RT should share with the first MSAA RT. 177 sk_sp<GrRenderTarget> smallMSAART1 = create_RT_with_SB(resourceProvider, 4, 178 smallSampleCount, 179 SkBudgeted::kNo); 180 REPORTER_ASSERT(reporter, smallMSAART1); 181 182 REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) == get_SB(smallMSAART1.get())); 183 } 184 185 // But one with a larger sample count should not. (Also check that the two requests didn't 186 // rounded up to the same actual sample count or else they could share.). 187 int bigSampleCount = context->caps()->getSampleCount(5, kRGBA_8888_GrPixelConfig); 188 if (bigSampleCount > 0 && bigSampleCount != smallSampleCount) { 189 sk_sp<GrRenderTarget> smallMSAART2 = create_RT_with_SB(resourceProvider, 4, 190 bigSampleCount, 191 SkBudgeted::kNo); 192 REPORTER_ASSERT(reporter, smallMSAART2); 193 194 REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) != get_SB(smallMSAART2.get())); 195 } 196 } 197 } 198 199 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheWrappedResources, reporter, ctxInfo) { 200 GrContext* context = ctxInfo.grContext(); 201 GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); 202 GrGpu* gpu = context->contextPriv().getGpu(); 203 // this test is only valid for GL 204 if (!gpu || !gpu->glContextForTesting()) { 205 return; 206 } 207 208 GrBackendTexture backendTextures[2]; 209 static const int kW = 100; 210 static const int kH = 100; 211 212 backendTextures[0] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, 213 kRGBA_8888_GrPixelConfig, 214 false, GrMipMapped::kNo); 215 backendTextures[1] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, 216 kRGBA_8888_GrPixelConfig, 217 false, GrMipMapped::kNo); 218 REPORTER_ASSERT(reporter, backendTextures[0].isValid()); 219 REPORTER_ASSERT(reporter, backendTextures[1].isValid()); 220 if (!backendTextures[0].isValid() || !backendTextures[1].isValid()) { 221 return; 222 } 223 224 context->resetContext(); 225 226 sk_sp<GrTexture> borrowed(resourceProvider->wrapBackendTexture( 227 backendTextures[0], kBorrow_GrWrapOwnership)); 228 229 sk_sp<GrTexture> adopted(resourceProvider->wrapBackendTexture( 230 backendTextures[1], kAdopt_GrWrapOwnership)); 231 232 REPORTER_ASSERT(reporter, borrowed != nullptr && adopted != nullptr); 233 if (!borrowed || !adopted) { 234 return; 235 } 236 237 borrowed.reset(nullptr); 238 adopted.reset(nullptr); 239 240 context->flush(); 241 242 bool borrowedIsAlive = gpu->isTestingOnlyBackendTexture(backendTextures[0]); 243 bool adoptedIsAlive = gpu->isTestingOnlyBackendTexture(backendTextures[1]); 244 245 REPORTER_ASSERT(reporter, borrowedIsAlive); 246 REPORTER_ASSERT(reporter, !adoptedIsAlive); 247 248 gpu->deleteTestingOnlyBackendTexture(&(backendTextures[0]), !borrowedIsAlive); 249 gpu->deleteTestingOnlyBackendTexture(&(backendTextures[1]), !adoptedIsAlive); 250 251 context->resetContext(); 252 } 253 254 class TestResource : public GrGpuResource { 255 enum ScratchConstructor { kScratchConstructor }; 256 public: 257 static const size_t kDefaultSize = 100; 258 259 /** Property that distinctly categorizes the resource. 260 * For example, textures have width, height, ... */ 261 enum SimulatedProperty { kA_SimulatedProperty, kB_SimulatedProperty }; 262 263 TestResource(GrGpu* gpu, SkBudgeted budgeted = SkBudgeted::kYes, size_t size = kDefaultSize) 264 : INHERITED(gpu) 265 , fToDelete(nullptr) 266 , fSize(size) 267 , fProperty(kA_SimulatedProperty) 268 , fIsScratch(false) { 269 ++fNumAlive; 270 this->registerWithCache(budgeted); 271 } 272 273 static TestResource* CreateScratch(GrGpu* gpu, SkBudgeted budgeted, 274 SimulatedProperty property) { 275 return new TestResource(gpu, budgeted, property, kScratchConstructor); 276 } 277 static TestResource* CreateWrapped(GrGpu* gpu, size_t size = kDefaultSize) { 278 return new TestResource(gpu, size); 279 } 280 281 ~TestResource() override { 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 private: 309 static const int kScratchKeyFieldCnt = 6; 310 311 TestResource(GrGpu* gpu, SkBudgeted budgeted, SimulatedProperty property, ScratchConstructor) 312 : INHERITED(gpu) 313 , fToDelete(nullptr) 314 , fSize(kDefaultSize) 315 , fProperty(property) 316 , fIsScratch(true) { 317 ++fNumAlive; 318 this->registerWithCache(budgeted); 319 } 320 321 // Constructor for simulating resources that wrap backend objects. 322 TestResource(GrGpu* gpu, size_t size) 323 : INHERITED(gpu) 324 , fToDelete(nullptr) 325 , fSize(size) 326 , fProperty(kA_SimulatedProperty) 327 , fIsScratch(false) { 328 ++fNumAlive; 329 this->registerWithCacheWrapped(); 330 } 331 332 void computeScratchKey(GrScratchKey* key) const override { 333 if (fIsScratch) { 334 ComputeScratchKey(fProperty, key); 335 } 336 } 337 338 size_t onGpuMemorySize() const override { return fSize; } 339 340 TestResource* fToDelete; 341 size_t fSize; 342 static int fNumAlive; 343 SimulatedProperty fProperty; 344 bool fIsScratch; 345 typedef GrGpuResource INHERITED; 346 }; 347 int TestResource::fNumAlive = 0; 348 349 class Mock { 350 public: 351 Mock(int maxCnt, size_t maxBytes) { 352 fContext = GrContext::MakeMock(nullptr); 353 SkASSERT(fContext); 354 fContext->setResourceCacheLimits(maxCnt, maxBytes); 355 GrResourceCache* cache = fContext->contextPriv().getResourceCache(); 356 cache->purgeAllUnlocked(); 357 SkASSERT(0 == cache->getResourceCount() && 0 == cache->getResourceBytes()); 358 } 359 360 GrResourceCache* cache() { return fContext->contextPriv().getResourceCache(); } 361 362 GrContext* context() { return fContext.get(); } 363 364 private: 365 sk_sp<GrContext> fContext; 366 }; 367 368 static void test_no_key(skiatest::Reporter* reporter) { 369 Mock mock(10, 30000); 370 GrContext* context = mock.context(); 371 GrResourceCache* cache = mock.cache(); 372 GrGpu* gpu = context->contextPriv().getGpu(); 373 374 // Create a bunch of resources with no keys 375 TestResource* a = new TestResource(gpu); 376 TestResource* b = new TestResource(gpu); 377 TestResource* c = new TestResource(gpu); 378 TestResource* d = new TestResource(gpu); 379 a->setSize(11); 380 b->setSize(12); 381 c->setSize(13); 382 d->setSize(14); 383 384 REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 385 REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 386 REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() + 387 d->gpuMemorySize() == cache->getResourceBytes()); 388 389 // Should be safe to purge without deleting the resources since we still have refs. 390 cache->purgeAllUnlocked(); 391 REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive()); 392 393 // Since the resources have neither unique nor scratch keys, delete immediately upon unref. 394 395 a->unref(); 396 REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive()); 397 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 398 REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() == 399 cache->getResourceBytes()); 400 401 c->unref(); 402 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 403 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 404 REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() == 405 cache->getResourceBytes()); 406 407 d->unref(); 408 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 409 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 410 REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes()); 411 412 b->unref(); 413 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 414 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 415 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 416 } 417 418 // Each integer passed as a template param creates a new domain. 419 template <int> 420 static void make_unique_key(GrUniqueKey* key, int data, const char* tag = nullptr) { 421 static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain(); 422 GrUniqueKey::Builder builder(key, d, 1, tag); 423 builder[0] = data; 424 } 425 426 static void test_budgeting(skiatest::Reporter* reporter) { 427 Mock mock(10, 300); 428 GrContext* context = mock.context(); 429 GrResourceCache* cache = mock.cache(); 430 GrGpu* gpu = context->contextPriv().getGpu(); 431 432 GrUniqueKey uniqueKey; 433 make_unique_key<0>(&uniqueKey, 0); 434 435 // Create a scratch, a unique, and a wrapped resource 436 TestResource* scratch = 437 TestResource::CreateScratch(gpu, SkBudgeted::kYes, TestResource::kB_SimulatedProperty); 438 scratch->setSize(10); 439 TestResource* unique = new TestResource(gpu); 440 unique->setSize(11); 441 unique->resourcePriv().setUniqueKey(uniqueKey); 442 TestResource* wrapped = TestResource::CreateWrapped(gpu); 443 wrapped->setSize(12); 444 TestResource* unbudgeted = new TestResource(gpu, SkBudgeted::kNo); 445 unbudgeted->setSize(13); 446 447 // Make sure we can add a unique key to the wrapped resource 448 GrUniqueKey uniqueKey2; 449 make_unique_key<0>(&uniqueKey2, 1); 450 wrapped->resourcePriv().setUniqueKey(uniqueKey2); 451 GrGpuResource* wrappedViaKey = cache->findAndRefUniqueResource(uniqueKey2); 452 REPORTER_ASSERT(reporter, wrappedViaKey != nullptr); 453 454 // Remove the extra ref we just added. 455 wrappedViaKey->unref(); 456 457 // Make sure sizes are as we expect 458 REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 459 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 460 wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() == 461 cache->getResourceBytes()); 462 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 463 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() == 464 cache->getBudgetedResourceBytes()); 465 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 466 467 // Our refs mean that the resources are non purgeable. 468 cache->purgeAllUnlocked(); 469 REPORTER_ASSERT(reporter, 4 == cache->getResourceCount()); 470 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 471 wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() == 472 cache->getResourceBytes()); 473 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 474 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() == 475 cache->getBudgetedResourceBytes()); 476 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 477 478 // Unreffing the wrapped resource should free it right away. 479 wrapped->unref(); 480 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 481 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() + 482 unbudgeted->gpuMemorySize() == cache->getResourceBytes()); 483 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 484 485 // Now try freeing the budgeted resources first 486 wrapped = TestResource::CreateWrapped(gpu); 487 scratch->setSize(12); 488 unique->unref(); 489 REPORTER_ASSERT(reporter, 11 == cache->getPurgeableBytes()); 490 cache->purgeAllUnlocked(); 491 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 492 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrapped->gpuMemorySize() + 493 unbudgeted->gpuMemorySize() == cache->getResourceBytes()); 494 REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 495 REPORTER_ASSERT(reporter, scratch->gpuMemorySize() == cache->getBudgetedResourceBytes()); 496 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 497 498 scratch->unref(); 499 REPORTER_ASSERT(reporter, 12 == cache->getPurgeableBytes()); 500 cache->purgeAllUnlocked(); 501 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 502 REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() + wrapped->gpuMemorySize() == 503 cache->getResourceBytes()); 504 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 505 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 506 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 507 508 wrapped->unref(); 509 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 510 REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() == cache->getResourceBytes()); 511 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 512 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 513 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 514 515 unbudgeted->unref(); 516 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 517 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 518 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 519 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 520 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 521 } 522 523 static void test_unbudgeted(skiatest::Reporter* reporter) { 524 Mock mock(10, 30000); 525 GrContext* context = mock.context(); 526 GrResourceCache* cache = mock.cache(); 527 GrGpu* gpu = context->contextPriv().getGpu(); 528 529 GrUniqueKey uniqueKey; 530 make_unique_key<0>(&uniqueKey, 0); 531 532 TestResource* scratch; 533 TestResource* unique; 534 TestResource* wrapped; 535 TestResource* unbudgeted; 536 537 // A large uncached or wrapped resource shouldn't evict anything. 538 scratch = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 539 TestResource::kB_SimulatedProperty); 540 541 scratch->setSize(10); 542 scratch->unref(); 543 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 544 REPORTER_ASSERT(reporter, 10 == cache->getResourceBytes()); 545 REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 546 REPORTER_ASSERT(reporter, 10 == cache->getBudgetedResourceBytes()); 547 REPORTER_ASSERT(reporter, 10 == cache->getPurgeableBytes()); 548 549 unique = new TestResource(gpu); 550 unique->setSize(11); 551 unique->resourcePriv().setUniqueKey(uniqueKey); 552 unique->unref(); 553 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 554 REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 555 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 556 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 557 REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 558 559 size_t large = 2 * cache->getResourceBytes(); 560 unbudgeted = new TestResource(gpu, SkBudgeted::kNo, large); 561 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 562 REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes()); 563 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 564 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 565 REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 566 567 unbudgeted->unref(); 568 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 569 REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 570 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 571 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 572 REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 573 574 wrapped = TestResource::CreateWrapped(gpu, large); 575 REPORTER_ASSERT(reporter, 3 == cache->getResourceCount()); 576 REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes()); 577 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 578 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 579 REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 580 581 wrapped->unref(); 582 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 583 REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes()); 584 REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount()); 585 REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes()); 586 REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes()); 587 588 cache->purgeAllUnlocked(); 589 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 590 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 591 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 592 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 593 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 594 } 595 596 // This method can't be static because it needs to friended in GrGpuResource::CacheAccess. 597 void test_unbudgeted_to_scratch(skiatest::Reporter* reporter); 598 /*static*/ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter) { 599 Mock mock(10, 300); 600 GrContext* context = mock.context(); 601 GrResourceCache* cache = mock.cache(); 602 GrGpu* gpu = context->contextPriv().getGpu(); 603 604 TestResource* resource = 605 TestResource::CreateScratch(gpu, SkBudgeted::kNo, TestResource::kA_SimulatedProperty); 606 GrScratchKey key; 607 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &key); 608 609 size_t size = resource->gpuMemorySize(); 610 for (int i = 0; i < 2; ++i) { 611 // Since this resource is unbudgeted, it should not be reachable as scratch. 612 REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key); 613 REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch()); 614 REPORTER_ASSERT(reporter, SkBudgeted::kNo == resource->resourcePriv().isBudgeted()); 615 REPORTER_ASSERT(reporter, nullptr == cache->findAndRefScratchResource(key, TestResource::kDefaultSize, 0)); 616 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 617 REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 618 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 619 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 620 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 621 622 // Once it is unrefed, it should become available as scratch. 623 resource->unref(); 624 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 625 REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 626 REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 627 REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes()); 628 REPORTER_ASSERT(reporter, size == cache->getPurgeableBytes()); 629 resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key, TestResource::kDefaultSize, 0)); 630 REPORTER_ASSERT(reporter, resource); 631 REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key); 632 REPORTER_ASSERT(reporter, resource->cacheAccess().isScratch()); 633 REPORTER_ASSERT(reporter, SkBudgeted::kYes == resource->resourcePriv().isBudgeted()); 634 635 if (0 == i) { 636 // If made unbudgeted, it should return to original state: ref'ed and unbudgeted. Try 637 // the above tests again. 638 resource->resourcePriv().makeUnbudgeted(); 639 } else { 640 // After the second time around, try removing the scratch key 641 resource->resourcePriv().removeScratchKey(); 642 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 643 REPORTER_ASSERT(reporter, size == cache->getResourceBytes()); 644 REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount()); 645 REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes()); 646 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 647 REPORTER_ASSERT(reporter, !resource->resourcePriv().getScratchKey().isValid()); 648 REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch()); 649 REPORTER_ASSERT(reporter, SkBudgeted::kYes == resource->resourcePriv().isBudgeted()); 650 651 // now when it is unrefed it should die since it has no key. 652 resource->unref(); 653 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 654 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 655 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 656 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 657 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 658 } 659 } 660 } 661 662 static void test_duplicate_scratch_key(skiatest::Reporter* reporter) { 663 Mock mock(5, 30000); 664 GrContext* context = mock.context(); 665 GrResourceCache* cache = mock.cache(); 666 GrGpu* gpu = context->contextPriv().getGpu(); 667 668 // Create two resources that have the same scratch key. 669 TestResource* a = TestResource::CreateScratch(gpu, 670 SkBudgeted::kYes, 671 TestResource::kB_SimulatedProperty); 672 TestResource* b = TestResource::CreateScratch(gpu, 673 SkBudgeted::kYes, 674 TestResource::kB_SimulatedProperty); 675 a->setSize(11); 676 b->setSize(12); 677 GrScratchKey scratchKey1; 678 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1); 679 // Check for negative case consistency. (leaks upon test failure.) 680 REPORTER_ASSERT(reporter, nullptr == cache->findAndRefScratchResource(scratchKey1, TestResource::kDefaultSize, 0)); 681 682 GrScratchKey scratchKey; 683 TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 684 685 // Scratch resources are registered with GrResourceCache just by existing. There are 2. 686 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 687 SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));) 688 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 689 REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == 690 cache->getResourceBytes()); 691 692 // Our refs mean that the resources are non purgeable. 693 cache->purgeAllUnlocked(); 694 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 695 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 696 697 // Unref but don't purge 698 a->unref(); 699 b->unref(); 700 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 701 SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));) 702 703 // Purge again. This time resources should be purgeable. 704 cache->purgeAllUnlocked(); 705 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 706 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 707 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 708 } 709 710 static void test_remove_scratch_key(skiatest::Reporter* reporter) { 711 Mock mock(5, 30000); 712 GrContext* context = mock.context(); 713 GrResourceCache* cache = mock.cache(); 714 GrGpu* gpu = context->contextPriv().getGpu(); 715 716 // Create two resources that have the same scratch key. 717 TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 718 TestResource::kB_SimulatedProperty); 719 TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 720 TestResource::kB_SimulatedProperty); 721 a->unref(); 722 b->unref(); 723 724 GrScratchKey scratchKey; 725 // Ensure that scratch key lookup is correct for negative case. 726 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 727 // (following leaks upon test failure). 728 REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0) == nullptr); 729 730 // Scratch resources are registered with GrResourceCache just by existing. There are 2. 731 TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 732 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 733 SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));) 734 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 735 736 // Find the first resource and remove its scratch key 737 GrGpuResource* find; 738 find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0); 739 find->resourcePriv().removeScratchKey(); 740 // It's still alive, but not cached by scratch key anymore 741 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 742 SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));) 743 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 744 745 // The cache should immediately delete it when it's unrefed since it isn't accessible. 746 find->unref(); 747 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 748 SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));) 749 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 750 751 // Repeat for the second resource. 752 find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0); 753 find->resourcePriv().removeScratchKey(); 754 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 755 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 756 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 757 758 // Should be able to call this multiple times with no problem. 759 find->resourcePriv().removeScratchKey(); 760 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 761 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 762 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 763 764 find->unref(); 765 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 766 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));) 767 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 768 } 769 770 static void test_scratch_key_consistency(skiatest::Reporter* reporter) { 771 Mock mock(5, 30000); 772 GrContext* context = mock.context(); 773 GrResourceCache* cache = mock.cache(); 774 GrGpu* gpu = context->contextPriv().getGpu(); 775 776 // Create two resources that have the same scratch key. 777 TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 778 TestResource::kB_SimulatedProperty); 779 TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 780 TestResource::kB_SimulatedProperty); 781 a->unref(); 782 b->unref(); 783 784 GrScratchKey scratchKey; 785 // Ensure that scratch key comparison and assignment is consistent. 786 GrScratchKey scratchKey1; 787 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1); 788 GrScratchKey scratchKey2; 789 TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey2); 790 REPORTER_ASSERT(reporter, scratchKey1.size() == TestResource::ExpectedScratchKeySize()); 791 REPORTER_ASSERT(reporter, scratchKey1 != scratchKey2); 792 REPORTER_ASSERT(reporter, scratchKey2 != scratchKey1); 793 scratchKey = scratchKey1; 794 REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize()); 795 REPORTER_ASSERT(reporter, scratchKey1 == scratchKey); 796 REPORTER_ASSERT(reporter, scratchKey == scratchKey1); 797 REPORTER_ASSERT(reporter, scratchKey2 != scratchKey); 798 REPORTER_ASSERT(reporter, scratchKey != scratchKey2); 799 scratchKey = scratchKey2; 800 REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize()); 801 REPORTER_ASSERT(reporter, scratchKey1 != scratchKey); 802 REPORTER_ASSERT(reporter, scratchKey != scratchKey1); 803 REPORTER_ASSERT(reporter, scratchKey2 == scratchKey); 804 REPORTER_ASSERT(reporter, scratchKey == scratchKey2); 805 806 // Ensure that scratch key lookup is correct for negative case. 807 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 808 // (following leaks upon test failure). 809 REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0) == nullptr); 810 811 // Find the first resource with a scratch key and a copy of a scratch key. 812 TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey); 813 GrGpuResource* find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0); 814 REPORTER_ASSERT(reporter, find != nullptr); 815 find->unref(); 816 817 scratchKey2 = scratchKey; 818 find = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, 0); 819 REPORTER_ASSERT(reporter, find != nullptr); 820 REPORTER_ASSERT(reporter, find == a || find == b); 821 822 GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, 0); 823 REPORTER_ASSERT(reporter, find2 != nullptr); 824 REPORTER_ASSERT(reporter, find2 == a || find2 == b); 825 REPORTER_ASSERT(reporter, find2 != find); 826 find2->unref(); 827 find->unref(); 828 } 829 830 static void test_duplicate_unique_key(skiatest::Reporter* reporter) { 831 Mock mock(5, 30000); 832 GrContext* context = mock.context(); 833 GrResourceCache* cache = mock.cache(); 834 GrGpu* gpu = context->contextPriv().getGpu(); 835 836 GrUniqueKey key; 837 make_unique_key<0>(&key, 0); 838 839 // Create two resources that we will attempt to register with the same unique key. 840 TestResource* a = new TestResource(gpu); 841 a->setSize(11); 842 843 // Set key on resource a. 844 a->resourcePriv().setUniqueKey(key); 845 REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key)); 846 a->unref(); 847 848 // Make sure that redundantly setting a's key works. 849 a->resourcePriv().setUniqueKey(key); 850 REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key)); 851 a->unref(); 852 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 853 REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getResourceBytes()); 854 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 855 856 // Create resource b and set the same key. It should replace a's unique key cache entry. 857 TestResource* b = new TestResource(gpu); 858 b->setSize(12); 859 b->resourcePriv().setUniqueKey(key); 860 REPORTER_ASSERT(reporter, b == cache->findAndRefUniqueResource(key)); 861 b->unref(); 862 863 // Still have two resources because a is still reffed. 864 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 865 REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes()); 866 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 867 868 a->unref(); 869 // Now a should be gone. 870 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 871 REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes()); 872 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 873 874 // Now replace b with c, but make sure c can start with one unique key and change it to b's key. 875 // Also make b be unreffed when replacement occurs. 876 b->unref(); 877 TestResource* c = new TestResource(gpu); 878 GrUniqueKey differentKey; 879 make_unique_key<0>(&differentKey, 1); 880 c->setSize(13); 881 c->resourcePriv().setUniqueKey(differentKey); 882 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 883 REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() == cache->getResourceBytes()); 884 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 885 // c replaces b and b should be immediately purged. 886 c->resourcePriv().setUniqueKey(key); 887 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 888 REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 889 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 890 891 // c shouldn't be purged because it is ref'ed. 892 cache->purgeAllUnlocked(); 893 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 894 REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 895 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 896 897 // Drop the ref on c, it should be kept alive because it has a unique key. 898 c->unref(); 899 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 900 REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes()); 901 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 902 903 // Verify that we can find c, then remove its unique key. It should get purged immediately. 904 REPORTER_ASSERT(reporter, c == cache->findAndRefUniqueResource(key)); 905 c->resourcePriv().removeUniqueKey(); 906 c->unref(); 907 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 908 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 909 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 910 911 { 912 GrUniqueKey key2; 913 make_unique_key<0>(&key2, 0); 914 sk_sp<TestResource> d(new TestResource(gpu)); 915 int foo = 4132; 916 key2.setCustomData(SkData::MakeWithCopy(&foo, sizeof(foo))); 917 d->resourcePriv().setUniqueKey(key2); 918 } 919 920 GrUniqueKey key3; 921 make_unique_key<0>(&key3, 0); 922 sk_sp<GrGpuResource> d2(cache->findAndRefUniqueResource(key3)); 923 REPORTER_ASSERT(reporter, *(int*) d2->getUniqueKey().getCustomData()->data() == 4132); 924 } 925 926 static void test_purge_invalidated(skiatest::Reporter* reporter) { 927 Mock mock(5, 30000); 928 GrContext* context = mock.context(); 929 GrResourceCache* cache = mock.cache(); 930 GrGpu* gpu = context->contextPriv().getGpu(); 931 932 GrUniqueKey key1, key2, key3; 933 make_unique_key<0>(&key1, 1); 934 make_unique_key<0>(&key2, 2); 935 make_unique_key<0>(&key3, 3); 936 937 // Add three resources to the cache. Only c is usable as scratch. 938 TestResource* a = new TestResource(gpu); 939 TestResource* b = new TestResource(gpu); 940 TestResource* c = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 941 TestResource::kA_SimulatedProperty); 942 a->resourcePriv().setUniqueKey(key1); 943 b->resourcePriv().setUniqueKey(key2); 944 c->resourcePriv().setUniqueKey(key3); 945 a->unref(); 946 // hold b until *after* the message is sent. 947 c->unref(); 948 949 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1)); 950 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2)); 951 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3)); 952 REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive()); 953 954 typedef GrUniqueKeyInvalidatedMessage Msg; 955 typedef SkMessageBus<GrUniqueKeyInvalidatedMessage> Bus; 956 957 // Invalidate two of the three, they should be purged and no longer accessible via their keys. 958 Bus::Post(Msg(key1)); 959 Bus::Post(Msg(key2)); 960 cache->purgeAsNeeded(); 961 // a should be deleted now, but we still have a ref on b. 962 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1)); 963 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2)); 964 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 965 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3)); 966 967 // Invalidate the third. 968 Bus::Post(Msg(key3)); 969 cache->purgeAsNeeded(); 970 // we still have a ref on b, c should be recycled as scratch. 971 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 972 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key3)); 973 974 // make b purgeable. It should be immediately deleted since it has no key. 975 b->unref(); 976 REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive()); 977 978 // Make sure we actually get to c via it's scratch key, before we say goodbye. 979 GrScratchKey scratchKey; 980 TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey); 981 GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0); 982 REPORTER_ASSERT(reporter, scratch == c); 983 SkSafeUnref(scratch); 984 985 // Get rid of c. 986 cache->purgeAllUnlocked(); 987 scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0); 988 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 989 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 990 REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes()); 991 REPORTER_ASSERT(reporter, !scratch); 992 SkSafeUnref(scratch); 993 } 994 995 static void test_cache_chained_purge(skiatest::Reporter* reporter) { 996 Mock mock(3, 30000); 997 GrContext* context = mock.context(); 998 GrResourceCache* cache = mock.cache(); 999 GrGpu* gpu = context->contextPriv().getGpu(); 1000 1001 GrUniqueKey key1, key2; 1002 make_unique_key<0>(&key1, 1); 1003 make_unique_key<0>(&key2, 2); 1004 1005 TestResource* a = new TestResource(gpu); 1006 TestResource* b = new TestResource(gpu); 1007 a->resourcePriv().setUniqueKey(key1); 1008 b->resourcePriv().setUniqueKey(key2); 1009 1010 // Make a cycle 1011 a->setUnrefWhenDestroyed(b); 1012 b->setUnrefWhenDestroyed(a); 1013 1014 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1015 1016 a->unref(); 1017 b->unref(); 1018 1019 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1020 1021 cache->purgeAllUnlocked(); 1022 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1023 1024 // Break the cycle 1025 a->setUnrefWhenDestroyed(nullptr); 1026 REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive()); 1027 1028 cache->purgeAllUnlocked(); 1029 REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive()); 1030 } 1031 1032 static void test_resource_size_changed(skiatest::Reporter* reporter) { 1033 GrUniqueKey key1, key2; 1034 make_unique_key<0>(&key1, 1); 1035 make_unique_key<0>(&key2, 2); 1036 1037 // Test changing resources sizes (both increase & decrease). 1038 { 1039 Mock mock(3, 30000); 1040 GrContext* context = mock.context(); 1041 GrResourceCache* cache = mock.cache(); 1042 GrGpu* gpu = context->contextPriv().getGpu(); 1043 1044 TestResource* a = new TestResource(gpu); 1045 a->resourcePriv().setUniqueKey(key1); 1046 a->unref(); 1047 1048 TestResource* b = new TestResource(gpu); 1049 b->resourcePriv().setUniqueKey(key2); 1050 b->unref(); 1051 1052 REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes()); 1053 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 1054 { 1055 sk_sp<TestResource> find2( 1056 static_cast<TestResource*>(cache->findAndRefUniqueResource(key2))); 1057 find2->setSize(200); 1058 sk_sp<TestResource> find1( 1059 static_cast<TestResource*>(cache->findAndRefUniqueResource(key1))); 1060 find1->setSize(50); 1061 } 1062 1063 REPORTER_ASSERT(reporter, 250 == cache->getResourceBytes()); 1064 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 1065 } 1066 1067 // Test increasing a resources size beyond the cache budget. 1068 { 1069 Mock mock(2, 300); 1070 GrContext* context = mock.context(); 1071 GrResourceCache* cache = mock.cache(); 1072 GrGpu* gpu = context->contextPriv().getGpu(); 1073 1074 TestResource* a = new TestResource(gpu); 1075 a->setSize(100); 1076 a->resourcePriv().setUniqueKey(key1); 1077 a->unref(); 1078 1079 TestResource* b = new TestResource(gpu); 1080 b->setSize(100); 1081 b->resourcePriv().setUniqueKey(key2); 1082 b->unref(); 1083 1084 REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes()); 1085 REPORTER_ASSERT(reporter, 2 == cache->getResourceCount()); 1086 1087 { 1088 sk_sp<TestResource> find2(static_cast<TestResource*>( 1089 cache->findAndRefUniqueResource(key2))); 1090 find2->setSize(201); 1091 } 1092 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1)); 1093 1094 REPORTER_ASSERT(reporter, 201 == cache->getResourceBytes()); 1095 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 1096 } 1097 } 1098 1099 static void test_timestamp_wrap(skiatest::Reporter* reporter) { 1100 static const int kCount = 50; 1101 static const int kBudgetCnt = kCount / 2; 1102 static const int kLockedFreq = 8; 1103 static const int kBudgetSize = 0x80000000; 1104 1105 SkRandom random; 1106 1107 // Run the test 2*kCount times; 1108 for (int i = 0; i < 2 * kCount; ++i ) { 1109 Mock mock(kBudgetCnt, kBudgetSize); 1110 GrContext* context = mock.context(); 1111 GrResourceCache* cache = mock.cache(); 1112 GrGpu* gpu = context->contextPriv().getGpu(); 1113 1114 // Pick a random number of resources to add before the timestamp will wrap. 1115 cache->changeTimestamp(SK_MaxU32 - random.nextULessThan(kCount + 1)); 1116 1117 static const int kNumToPurge = kCount - kBudgetCnt; 1118 1119 SkTDArray<int> shouldPurgeIdxs; 1120 int purgeableCnt = 0; 1121 SkTDArray<GrGpuResource*> resourcesToUnref; 1122 1123 // Add kCount resources, holding onto resources at random so we have a mix of purgeable and 1124 // unpurgeable resources. 1125 for (int j = 0; j < kCount; ++j) { 1126 GrUniqueKey key; 1127 make_unique_key<0>(&key, j); 1128 1129 TestResource* r = new TestResource(gpu); 1130 r->resourcePriv().setUniqueKey(key); 1131 if (random.nextU() % kLockedFreq) { 1132 // Make this is purgeable. 1133 r->unref(); 1134 ++purgeableCnt; 1135 if (purgeableCnt <= kNumToPurge) { 1136 *shouldPurgeIdxs.append() = j; 1137 } 1138 } else { 1139 *resourcesToUnref.append() = r; 1140 } 1141 } 1142 1143 // Verify that the correct resources were purged. 1144 int currShouldPurgeIdx = 0; 1145 for (int j = 0; j < kCount; ++j) { 1146 GrUniqueKey key; 1147 make_unique_key<0>(&key, j); 1148 GrGpuResource* res = cache->findAndRefUniqueResource(key); 1149 if (currShouldPurgeIdx < shouldPurgeIdxs.count() && 1150 shouldPurgeIdxs[currShouldPurgeIdx] == j) { 1151 ++currShouldPurgeIdx; 1152 REPORTER_ASSERT(reporter, nullptr == res); 1153 } else { 1154 REPORTER_ASSERT(reporter, nullptr != res); 1155 } 1156 SkSafeUnref(res); 1157 } 1158 1159 for (int j = 0; j < resourcesToUnref.count(); ++j) { 1160 resourcesToUnref[j]->unref(); 1161 } 1162 } 1163 } 1164 1165 static void test_flush(skiatest::Reporter* reporter) { 1166 Mock mock(1000000, 1000000); 1167 GrContext* context = mock.context(); 1168 GrResourceCache* cache = mock.cache(); 1169 GrGpu* gpu = context->contextPriv().getGpu(); 1170 1171 // The current cache impl will round the max flush count to the next power of 2. So we choose a 1172 // power of two here to keep things simpler. 1173 static const int kFlushCount = 16; 1174 cache->setLimits(1000000, 1000000, kFlushCount); 1175 1176 { 1177 // Insert a resource and send a flush notification kFlushCount times. 1178 for (int i = 0; i < kFlushCount; ++i) { 1179 TestResource* r = new TestResource(gpu); 1180 GrUniqueKey k; 1181 make_unique_key<1>(&k, i); 1182 r->resourcePriv().setUniqueKey(k); 1183 r->unref(); 1184 cache->notifyFlushOccurred(GrResourceCache::kExternal); 1185 } 1186 1187 // Send flush notifications to the cache. Each flush should purge the oldest resource. 1188 for (int i = 0; i < kFlushCount; ++i) { 1189 cache->notifyFlushOccurred(GrResourceCache::kExternal); 1190 REPORTER_ASSERT(reporter, kFlushCount - i - 1 == cache->getResourceCount()); 1191 for (int j = 0; j < i; ++j) { 1192 GrUniqueKey k; 1193 make_unique_key<1>(&k, j); 1194 GrGpuResource* r = cache->findAndRefUniqueResource(k); 1195 REPORTER_ASSERT(reporter, !SkToBool(r)); 1196 SkSafeUnref(r); 1197 } 1198 } 1199 1200 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1201 cache->purgeAllUnlocked(); 1202 } 1203 1204 // Do a similar test but where we leave refs on some resources to prevent them from being 1205 // purged. 1206 { 1207 GrGpuResource* refedResources[kFlushCount >> 1]; 1208 for (int i = 0; i < kFlushCount; ++i) { 1209 TestResource* r = new TestResource(gpu); 1210 GrUniqueKey k; 1211 make_unique_key<1>(&k, i); 1212 r->resourcePriv().setUniqueKey(k); 1213 // Leave a ref on every other resource, beginning with the first. 1214 if (SkToBool(i & 0x1)) { 1215 refedResources[i/2] = r; 1216 } else { 1217 r->unref(); 1218 } 1219 cache->notifyFlushOccurred(GrResourceCache::kExternal); 1220 } 1221 1222 for (int i = 0; i < kFlushCount; ++i) { 1223 // Should get a resource purged every other flush. 1224 cache->notifyFlushOccurred(GrResourceCache::kExternal); 1225 REPORTER_ASSERT(reporter, kFlushCount - i/2 - 1 == cache->getResourceCount()); 1226 } 1227 1228 // Unref all the resources that we kept refs on in the first loop. 1229 for (int i = 0; i < kFlushCount >> 1; ++i) { 1230 refedResources[i]->unref(); 1231 } 1232 1233 // After kFlushCount + 1 flushes they all will have sat in the purgeable queue for 1234 // kFlushCount full flushes. 1235 for (int i = 0; i < kFlushCount + 1; ++i) { 1236 REPORTER_ASSERT(reporter, kFlushCount >> 1 == cache->getResourceCount()); 1237 cache->notifyFlushOccurred(GrResourceCache::kExternal); 1238 } 1239 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1240 1241 cache->purgeAllUnlocked(); 1242 } 1243 1244 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1245 1246 // Verify that calling flush() on a GrContext with nothing to do will not trigger resource 1247 // eviction. 1248 context->flush(); 1249 for (int i = 0; i < 10; ++i) { 1250 TestResource* r = new TestResource(gpu); 1251 GrUniqueKey k; 1252 make_unique_key<1>(&k, i); 1253 r->resourcePriv().setUniqueKey(k); 1254 r->unref(); 1255 } 1256 REPORTER_ASSERT(reporter, 10 == cache->getResourceCount()); 1257 for (int i = 0; i < 10 * kFlushCount; ++i) { 1258 context->flush(); 1259 } 1260 REPORTER_ASSERT(reporter, 10 == cache->getResourceCount()); 1261 } 1262 1263 static void test_time_purge(skiatest::Reporter* reporter) { 1264 Mock mock(1000000, 1000000); 1265 GrContext* context = mock.context(); 1266 GrResourceCache* cache = mock.cache(); 1267 GrGpu* gpu = context->contextPriv().getGpu(); 1268 1269 static constexpr int kCnts[] = {1, 10, 1024}; 1270 auto nowish = []() { 1271 // We sleep so that we ensure we get a value that is greater than the last call to 1272 // GrStdSteadyClock::now(). 1273 std::this_thread::sleep_for(GrStdSteadyClock::duration(5)); 1274 auto result = GrStdSteadyClock::now(); 1275 // Also sleep afterwards so we don't get this value again. 1276 std::this_thread::sleep_for(GrStdSteadyClock::duration(5)); 1277 return result; 1278 }; 1279 1280 for (int cnt : kCnts) { 1281 std::unique_ptr<GrStdSteadyClock::time_point[]> timeStamps( 1282 new GrStdSteadyClock::time_point[cnt]); 1283 { 1284 // Insert resources and get time points between each addition. 1285 for (int i = 0; i < cnt; ++i) { 1286 TestResource* r = new TestResource(gpu); 1287 GrUniqueKey k; 1288 make_unique_key<1>(&k, i); 1289 r->resourcePriv().setUniqueKey(k); 1290 r->unref(); 1291 timeStamps.get()[i] = nowish(); 1292 } 1293 1294 // Purge based on the time points between resource additions. Each purge should remove 1295 // the oldest resource. 1296 for (int i = 0; i < cnt; ++i) { 1297 cache->purgeResourcesNotUsedSince(timeStamps[i]); 1298 REPORTER_ASSERT(reporter, cnt - i - 1 == cache->getResourceCount()); 1299 for (int j = 0; j < i; ++j) { 1300 GrUniqueKey k; 1301 make_unique_key<1>(&k, j); 1302 GrGpuResource* r = cache->findAndRefUniqueResource(k); 1303 REPORTER_ASSERT(reporter, !SkToBool(r)); 1304 SkSafeUnref(r); 1305 } 1306 } 1307 1308 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1309 cache->purgeAllUnlocked(); 1310 } 1311 1312 // Do a similar test but where we leave refs on some resources to prevent them from being 1313 // purged. 1314 { 1315 std::unique_ptr<GrGpuResource* []> refedResources(new GrGpuResource*[cnt / 2]); 1316 for (int i = 0; i < cnt; ++i) { 1317 TestResource* r = new TestResource(gpu); 1318 GrUniqueKey k; 1319 make_unique_key<1>(&k, i); 1320 r->resourcePriv().setUniqueKey(k); 1321 // Leave a ref on every other resource, beginning with the first. 1322 if (SkToBool(i & 0x1)) { 1323 refedResources.get()[i / 2] = r; 1324 } else { 1325 r->unref(); 1326 } 1327 timeStamps.get()[i] = nowish(); 1328 } 1329 1330 for (int i = 0; i < cnt; ++i) { 1331 // Should get a resource purged every other frame. 1332 cache->purgeResourcesNotUsedSince(timeStamps[i]); 1333 REPORTER_ASSERT(reporter, cnt - i / 2 - 1 == cache->getResourceCount()); 1334 } 1335 1336 // Unref all the resources that we kept refs on in the first loop. 1337 for (int i = 0; i < (cnt / 2); ++i) { 1338 refedResources.get()[i]->unref(); 1339 cache->purgeResourcesNotUsedSince(nowish()); 1340 REPORTER_ASSERT(reporter, cnt / 2 - i - 1 == cache->getResourceCount()); 1341 } 1342 1343 cache->purgeAllUnlocked(); 1344 } 1345 1346 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1347 1348 // Verify that calling flush() on a GrContext with nothing to do will not trigger resource 1349 // eviction 1350 context->flush(); 1351 for (int i = 0; i < 10; ++i) { 1352 TestResource* r = new TestResource(gpu); 1353 GrUniqueKey k; 1354 make_unique_key<1>(&k, i); 1355 r->resourcePriv().setUniqueKey(k); 1356 r->unref(); 1357 } 1358 REPORTER_ASSERT(reporter, 10 == cache->getResourceCount()); 1359 context->flush(); 1360 REPORTER_ASSERT(reporter, 10 == cache->getResourceCount()); 1361 cache->purgeResourcesNotUsedSince(nowish()); 1362 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 1363 } 1364 } 1365 1366 static void test_partial_purge(skiatest::Reporter* reporter) { 1367 Mock mock(6, 100); 1368 GrContext* context = mock.context(); 1369 GrResourceCache* cache = mock.cache(); 1370 GrGpu* gpu = context->contextPriv().getGpu(); 1371 1372 enum TestsCase { 1373 kOnlyScratch_TestCase = 0, 1374 kPartialScratch_TestCase = 1, 1375 kAllScratch_TestCase = 2, 1376 kPartial_TestCase = 3, 1377 kAll_TestCase = 4, 1378 kNone_TestCase = 5, 1379 kEndTests_TestCase = kNone_TestCase + 1 1380 }; 1381 1382 for (int testCase = 0; testCase < kEndTests_TestCase; testCase++) { 1383 1384 GrUniqueKey key1, key2, key3; 1385 make_unique_key<0>(&key1, 1); 1386 make_unique_key<0>(&key2, 2); 1387 make_unique_key<0>(&key3, 3); 1388 1389 // Add three unique resources to the cache. 1390 TestResource *unique1 = new TestResource(gpu); 1391 TestResource *unique2 = new TestResource(gpu); 1392 TestResource *unique3 = new TestResource(gpu); 1393 1394 unique1->resourcePriv().setUniqueKey(key1); 1395 unique2->resourcePriv().setUniqueKey(key2); 1396 unique3->resourcePriv().setUniqueKey(key3); 1397 1398 unique1->setSize(10); 1399 unique2->setSize(11); 1400 unique3->setSize(12); 1401 1402 // Add two scratch resources to the cache. 1403 TestResource *scratch1 = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 1404 TestResource::kA_SimulatedProperty); 1405 TestResource *scratch2 = TestResource::CreateScratch(gpu, SkBudgeted::kYes, 1406 TestResource::kB_SimulatedProperty); 1407 scratch1->setSize(13); 1408 scratch2->setSize(14); 1409 1410 1411 REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount()); 1412 REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes()); 1413 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 1414 1415 // Add resources to the purgeable queue 1416 unique1->unref(); 1417 scratch1->unref(); 1418 unique2->unref(); 1419 scratch2->unref(); 1420 unique3->unref(); 1421 1422 REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount()); 1423 REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes()); 1424 REPORTER_ASSERT(reporter, 60 == cache->getPurgeableBytes()); 1425 1426 switch(testCase) { 1427 case kOnlyScratch_TestCase: { 1428 context->purgeUnlockedResources(14, true); 1429 REPORTER_ASSERT(reporter, 3 == cache->getBudgetedResourceCount()); 1430 REPORTER_ASSERT(reporter, 33 == cache->getBudgetedResourceBytes()); 1431 break; 1432 } 1433 case kPartialScratch_TestCase: { 1434 context->purgeUnlockedResources(3, true); 1435 REPORTER_ASSERT(reporter, 4 == cache->getBudgetedResourceCount()); 1436 REPORTER_ASSERT(reporter, 47 == cache->getBudgetedResourceBytes()); 1437 break; 1438 } 1439 case kAllScratch_TestCase: { 1440 context->purgeUnlockedResources(50, true); 1441 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 1442 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 1443 break; 1444 } 1445 case kPartial_TestCase: { 1446 context->purgeUnlockedResources(13, false); 1447 REPORTER_ASSERT(reporter, 3 == cache->getBudgetedResourceCount()); 1448 REPORTER_ASSERT(reporter, 37 == cache->getBudgetedResourceBytes()); 1449 break; 1450 } 1451 case kAll_TestCase: { 1452 context->purgeUnlockedResources(50, false); 1453 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 1454 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes()); 1455 break; 1456 } 1457 case kNone_TestCase: { 1458 context->purgeUnlockedResources(0, true); 1459 context->purgeUnlockedResources(0, false); 1460 REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount()); 1461 REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes()); 1462 REPORTER_ASSERT(reporter, 60 == cache->getPurgeableBytes()); 1463 break; 1464 } 1465 }; 1466 1467 // ensure all are purged before the next 1468 context->purgeAllUnlockedResources(); 1469 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount()); 1470 REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes()); 1471 1472 } 1473 } 1474 1475 static void test_large_resource_count(skiatest::Reporter* reporter) { 1476 // Set the cache size to double the resource count because we're going to create 2x that number 1477 // resources, using two different key domains. Add a little slop to the bytes because we resize 1478 // down to 1 byte after creating the resource. 1479 static const int kResourceCnt = 2000; 1480 1481 Mock mock(2 * kResourceCnt, 2 * kResourceCnt + 1000); 1482 GrContext* context = mock.context(); 1483 GrResourceCache* cache = mock.cache(); 1484 GrGpu* gpu = context->contextPriv().getGpu(); 1485 1486 for (int i = 0; i < kResourceCnt; ++i) { 1487 GrUniqueKey key1, key2; 1488 make_unique_key<1>(&key1, i); 1489 make_unique_key<2>(&key2, i); 1490 1491 TestResource* resource; 1492 1493 resource = new TestResource(gpu); 1494 resource->resourcePriv().setUniqueKey(key1); 1495 resource->setSize(1); 1496 resource->unref(); 1497 1498 resource = new TestResource(gpu); 1499 resource->resourcePriv().setUniqueKey(key2); 1500 resource->setSize(1); 1501 resource->unref(); 1502 } 1503 1504 REPORTER_ASSERT(reporter, TestResource::NumAlive() == 2 * kResourceCnt); 1505 REPORTER_ASSERT(reporter, cache->getPurgeableBytes() == 2 * kResourceCnt); 1506 REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 2 * kResourceCnt); 1507 REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 2 * kResourceCnt); 1508 REPORTER_ASSERT(reporter, cache->getResourceBytes() == 2 * kResourceCnt); 1509 REPORTER_ASSERT(reporter, cache->getResourceCount() == 2 * kResourceCnt); 1510 for (int i = 0; i < kResourceCnt; ++i) { 1511 GrUniqueKey key1, key2; 1512 make_unique_key<1>(&key1, i); 1513 make_unique_key<2>(&key2, i); 1514 1515 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1)); 1516 REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2)); 1517 } 1518 1519 cache->purgeAllUnlocked(); 1520 REPORTER_ASSERT(reporter, TestResource::NumAlive() == 0); 1521 REPORTER_ASSERT(reporter, cache->getPurgeableBytes() == 0); 1522 REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 0); 1523 REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 0); 1524 REPORTER_ASSERT(reporter, cache->getResourceBytes() == 0); 1525 REPORTER_ASSERT(reporter, cache->getResourceCount() == 0); 1526 1527 for (int i = 0; i < kResourceCnt; ++i) { 1528 GrUniqueKey key1, key2; 1529 make_unique_key<1>(&key1, i); 1530 make_unique_key<2>(&key2, i); 1531 1532 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1)); 1533 REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2)); 1534 } 1535 } 1536 1537 static void test_custom_data(skiatest::Reporter* reporter) { 1538 GrUniqueKey key1, key2; 1539 make_unique_key<0>(&key1, 1); 1540 make_unique_key<0>(&key2, 2); 1541 int foo = 4132; 1542 key1.setCustomData(SkData::MakeWithCopy(&foo, sizeof(foo))); 1543 REPORTER_ASSERT(reporter, *(int*) key1.getCustomData()->data() == 4132); 1544 REPORTER_ASSERT(reporter, key2.getCustomData() == nullptr); 1545 1546 // Test that copying a key also takes a ref on its custom data. 1547 GrUniqueKey key3 = key1; 1548 REPORTER_ASSERT(reporter, *(int*) key3.getCustomData()->data() == 4132); 1549 } 1550 1551 static void test_abandoned(skiatest::Reporter* reporter) { 1552 Mock mock(10, 300); 1553 GrContext* context = mock.context(); 1554 GrGpu* gpu = context->contextPriv().getGpu(); 1555 1556 sk_sp<GrGpuResource> resource(new TestResource(gpu)); 1557 context->abandonContext(); 1558 1559 REPORTER_ASSERT(reporter, resource->wasDestroyed()); 1560 1561 // Call all the public methods on resource in the abandoned state. They shouldn't crash. 1562 1563 resource->uniqueID(); 1564 resource->getUniqueKey(); 1565 resource->wasDestroyed(); 1566 resource->gpuMemorySize(); 1567 resource->getContext(); 1568 1569 resource->abandon(); 1570 resource->resourcePriv().getScratchKey(); 1571 resource->resourcePriv().isBudgeted(); 1572 resource->resourcePriv().makeBudgeted(); 1573 resource->resourcePriv().makeUnbudgeted(); 1574 resource->resourcePriv().removeScratchKey(); 1575 GrUniqueKey key; 1576 make_unique_key<0>(&key, 1); 1577 resource->resourcePriv().setUniqueKey(key); 1578 resource->resourcePriv().removeUniqueKey(); 1579 } 1580 1581 static void test_tags(skiatest::Reporter* reporter) { 1582 #ifdef SK_DEBUG 1583 // We will insert 1 resource with tag "tag1", 2 with "tag2", and so on, up through kLastTagIdx. 1584 static constexpr int kLastTagIdx = 10; 1585 static constexpr int kNumResources = kLastTagIdx * (kLastTagIdx + 1) / 2; 1586 1587 Mock mock(kNumResources, kNumResources * TestResource::kDefaultSize); 1588 GrContext* context = mock.context(); 1589 GrResourceCache* cache = mock.cache(); 1590 GrGpu* gpu = context->contextPriv().getGpu(); 1591 1592 SkString tagStr; 1593 int tagIdx = 0; 1594 int currTagCnt = 0; 1595 1596 for (int i = 0; i < kNumResources; ++i, ++currTagCnt) { 1597 sk_sp<GrGpuResource> resource(new TestResource(gpu)); 1598 GrUniqueKey key; 1599 if (currTagCnt == tagIdx) { 1600 tagIdx += 1; 1601 currTagCnt = 0; 1602 tagStr.printf("tag%d", tagIdx); 1603 } 1604 make_unique_key<1>(&key, i, tagStr.c_str()); 1605 resource->resourcePriv().setUniqueKey(key); 1606 } 1607 SkASSERT(kLastTagIdx == tagIdx); 1608 SkASSERT(currTagCnt == kLastTagIdx); 1609 1610 // Test i = 0 to exercise unused tag string. 1611 for (int i = 0; i <= kLastTagIdx; ++i) { 1612 tagStr.printf("tag%d", i); 1613 REPORTER_ASSERT(reporter, cache->countUniqueKeysWithTag(tagStr.c_str()) == i); 1614 } 1615 #endif 1616 } 1617 1618 DEF_GPUTEST(ResourceCacheMisc, reporter, /* options */) { 1619 // The below tests create their own mock contexts. 1620 test_no_key(reporter); 1621 test_budgeting(reporter); 1622 test_unbudgeted(reporter); 1623 test_unbudgeted_to_scratch(reporter); 1624 test_duplicate_unique_key(reporter); 1625 test_duplicate_scratch_key(reporter); 1626 test_remove_scratch_key(reporter); 1627 test_scratch_key_consistency(reporter); 1628 test_purge_invalidated(reporter); 1629 test_cache_chained_purge(reporter); 1630 test_resource_size_changed(reporter); 1631 test_timestamp_wrap(reporter); 1632 test_flush(reporter); 1633 test_time_purge(reporter); 1634 test_partial_purge(reporter); 1635 test_large_resource_count(reporter); 1636 test_custom_data(reporter); 1637 test_abandoned(reporter); 1638 test_tags(reporter); 1639 } 1640 1641 //////////////////////////////////////////////////////////////////////////////// 1642 static sk_sp<GrTexture> make_normal_texture(GrResourceProvider* provider, 1643 GrSurfaceFlags flags, 1644 int width, int height, 1645 int sampleCnt) { 1646 GrSurfaceDesc desc; 1647 desc.fFlags = flags; 1648 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 1649 desc.fWidth = width; 1650 desc.fHeight = height; 1651 desc.fConfig = kRGBA_8888_GrPixelConfig; 1652 desc.fSampleCnt = sampleCnt; 1653 1654 return provider->createTexture(desc, SkBudgeted::kYes); 1655 } 1656 1657 static sk_sp<GrTextureProxy> make_mipmap_proxy(GrProxyProvider* proxyProvider, 1658 GrSurfaceFlags flags, 1659 int width, int height, 1660 int sampleCnt) { 1661 SkBitmap bm; 1662 1663 bm.allocN32Pixels(width, height, true); 1664 bm.eraseColor(SK_ColorBLUE); 1665 1666 sk_sp<SkMipMap> mipmaps(SkMipMap::Build(bm, SkDestinationSurfaceColorMode::kLegacy, nullptr)); 1667 SkASSERT(mipmaps); 1668 SkASSERT(mipmaps->countLevels() > 1); 1669 1670 int mipLevelCount = mipmaps->countLevels() + 1; 1671 1672 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]); 1673 1674 texels[0].fPixels = bm.getPixels(); 1675 texels[0].fRowBytes = bm.rowBytes(); 1676 1677 for (int i = 1; i < mipLevelCount; ++i) { 1678 SkMipMap::Level generatedMipLevel; 1679 mipmaps->getLevel(i - 1, &generatedMipLevel); 1680 texels[i].fPixels = generatedMipLevel.fPixmap.addr(); 1681 texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes(); 1682 } 1683 1684 GrSurfaceDesc desc; 1685 desc.fFlags = flags; 1686 desc.fOrigin = (flags & kRenderTarget_GrSurfaceFlag) ? kBottomLeft_GrSurfaceOrigin 1687 : kTopLeft_GrSurfaceOrigin; 1688 desc.fWidth = width; 1689 desc.fHeight = height; 1690 desc.fConfig = kRGBA_8888_GrPixelConfig; 1691 desc.fSampleCnt = sampleCnt; 1692 1693 return proxyProvider->createMipMapProxy(desc, SkBudgeted::kYes, texels.get(), mipLevelCount); 1694 } 1695 1696 // Exercise GrSurface::gpuMemorySize for different combos of MSAA, RT-only, 1697 // Texture-only, both-RT-and-Texture and MIPmapped 1698 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GPUMemorySize, reporter, ctxInfo) { 1699 GrContext* context = ctxInfo.grContext(); 1700 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 1701 GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); 1702 1703 static const int kSize = 64; 1704 1705 // Normal versions 1706 { 1707 sk_sp<GrTexture> tex; 1708 1709 tex = make_normal_texture(resourceProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 1); 1710 size_t size = tex->gpuMemorySize(); 1711 REPORTER_ASSERT(reporter, kSize*kSize*4 == size); 1712 1713 size_t sampleCount = (size_t)context->caps()->getSampleCount(4, kRGBA_8888_GrPixelConfig); 1714 if (sampleCount >= 4) { 1715 tex = make_normal_texture(resourceProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 1716 sampleCount); 1717 size = tex->gpuMemorySize(); 1718 REPORTER_ASSERT(reporter, 1719 kSize*kSize*4 == size || // msaa4 failed 1720 kSize*kSize*4*sampleCount == size || // auto-resolving 1721 kSize*kSize*4*(sampleCount+1) == size); // explicit resolve buffer 1722 } 1723 1724 tex = make_normal_texture(resourceProvider, kNone_GrSurfaceFlags, kSize, kSize, 1); 1725 size = tex->gpuMemorySize(); 1726 REPORTER_ASSERT(reporter, kSize*kSize*4 == size); 1727 } 1728 1729 1730 // Mipmapped versions 1731 if (context->caps()->mipMapSupport()) { 1732 sk_sp<GrTextureProxy> proxy; 1733 1734 proxy = make_mipmap_proxy(proxyProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 1); 1735 size_t size = proxy->gpuMemorySize(); 1736 REPORTER_ASSERT(reporter, kSize*kSize*4+(kSize*kSize*4)/3 == size); 1737 1738 size_t sampleCount = (size_t)context->caps()->getSampleCount(4, kRGBA_8888_GrPixelConfig); 1739 if (sampleCount >= 4) { 1740 proxy = make_mipmap_proxy(proxyProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 1741 sampleCount); 1742 size = proxy->gpuMemorySize(); 1743 REPORTER_ASSERT(reporter, 1744 kSize*kSize*4+(kSize*kSize*4)/3 == size || // msaa4 failed 1745 kSize*kSize*4*sampleCount+(kSize*kSize*4)/3 == size || // auto-resolving 1746 kSize*kSize*4*(sampleCount+1)+(kSize*kSize*4)/3 == size); // explicit resolve buffer 1747 } 1748 1749 proxy = make_mipmap_proxy(proxyProvider, kNone_GrSurfaceFlags, kSize, kSize, 1); 1750 size = proxy->gpuMemorySize(); 1751 REPORTER_ASSERT(reporter, kSize*kSize*4+(kSize*kSize*4)/3 == size); 1752 } 1753 } 1754 1755 #endif 1756