1 /* 2 * Copyright 2018 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 "SkExchange.h" 9 #include "Test.h" 10 11 #include "GrBackendSurface.h" 12 #include "GrContextPriv.h" 13 #include "GrGpu.h" 14 #include "GrTexture.h" 15 #include "SkImage_Gpu.h" 16 #include "SkPromiseImageTexture.h" 17 18 using namespace sk_gpu_test; 19 20 struct PromiseTextureChecker { 21 // shared indicates whether the backend texture is used to fulfill more than one promise 22 // image. 23 explicit PromiseTextureChecker(const GrBackendTexture& tex, skiatest::Reporter* reporter, 24 bool shared) 25 : fTexture(SkPromiseImageTexture::Make(tex)) 26 , fReporter(reporter) 27 , fShared(shared) 28 , fFulfillCount(0) 29 , fReleaseCount(0) 30 , fDoneCount(0) {} 31 sk_sp<SkPromiseImageTexture> fTexture; 32 skiatest::Reporter* fReporter; 33 bool fShared; 34 int fFulfillCount; 35 int fReleaseCount; 36 int fDoneCount; 37 GrBackendTexture fLastFulfilledTexture; 38 39 /** 40 * Replaces the backend texture that this checker will return from fulfill. Also, transfers 41 * ownership of the previous PromiseImageTexture to the caller, if they want to control when 42 * it is deleted. The default argument will remove the existing texture without installing a 43 * valid replacement. 44 */ 45 sk_sp<const SkPromiseImageTexture> replaceTexture( 46 const GrBackendTexture& tex = GrBackendTexture()) { 47 return skstd::exchange(fTexture, SkPromiseImageTexture::Make(tex)); 48 } 49 50 SkTArray<GrUniqueKey> uniqueKeys() const { 51 return fTexture->testingOnly_uniqueKeysToInvalidate(); 52 } 53 54 static sk_sp<SkPromiseImageTexture> Fulfill(void* self) { 55 auto checker = static_cast<PromiseTextureChecker*>(self); 56 checker->fFulfillCount++; 57 checker->fLastFulfilledTexture = checker->fTexture->backendTexture(); 58 return checker->fTexture; 59 } 60 static void Release(void* self) { 61 auto checker = static_cast<PromiseTextureChecker*>(self); 62 checker->fReleaseCount++; 63 if (!checker->fShared) { 64 // This is only used in a single threaded fashion with a single promise image. So 65 // every fulfill should be balanced by a release before the next fulfill. 66 REPORTER_ASSERT(checker->fReporter, checker->fReleaseCount == checker->fFulfillCount); 67 } 68 } 69 static void Done(void* self) { 70 static_cast<PromiseTextureChecker*>(self)->fDoneCount++; 71 } 72 }; 73 74 enum class ReleaseBalanceExpecation { 75 kBalanced, 76 kBalancedOrPlusOne, 77 kAny 78 }; 79 80 static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseChecker, 81 ReleaseBalanceExpecation balanceExpecation, 82 int expectedFulfillCnt, 83 int expectedReleaseCnt, 84 bool expectedRequired, 85 int expectedDoneCnt, 86 skiatest::Reporter* reporter) { 87 bool result = true; 88 int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount; 89 // FulfillCount should always equal ReleaseCount or be at most one higher 90 if (countDiff != 0) { 91 if (balanceExpecation == ReleaseBalanceExpecation::kBalanced) { 92 result = false; 93 REPORTER_ASSERT(reporter, 0 == countDiff); 94 } else if (countDiff != 1 && 95 balanceExpecation == ReleaseBalanceExpecation::kBalancedOrPlusOne) { 96 result = false; 97 REPORTER_ASSERT(reporter, 0 == countDiff || 1 == countDiff); 98 } else if (countDiff < 0) { 99 result = false; 100 REPORTER_ASSERT(reporter, countDiff >= 0); 101 } 102 } 103 104 int fulfillDiff = expectedFulfillCnt - promiseChecker.fFulfillCount; 105 REPORTER_ASSERT(reporter, fulfillDiff >= 0); 106 if (fulfillDiff != 0) { 107 if (expectedRequired) { 108 result = false; 109 REPORTER_ASSERT(reporter, expectedFulfillCnt == promiseChecker.fFulfillCount); 110 } else if (fulfillDiff > 1) { 111 result = false; 112 REPORTER_ASSERT(reporter, fulfillDiff <= 1); 113 } 114 } 115 116 int releaseDiff = expectedReleaseCnt - promiseChecker.fReleaseCount; 117 REPORTER_ASSERT(reporter, releaseDiff >= 0); 118 if (releaseDiff != 0) { 119 if (expectedRequired) { 120 result = false; 121 REPORTER_ASSERT(reporter, expectedReleaseCnt == promiseChecker.fReleaseCount); 122 } else if (releaseDiff > 1) { 123 result = false; 124 REPORTER_ASSERT(reporter, releaseDiff <= 1); 125 } 126 } 127 128 if (expectedDoneCnt != promiseChecker.fDoneCount) { 129 result = false; 130 REPORTER_ASSERT(reporter, expectedDoneCnt == promiseChecker.fDoneCount); 131 } 132 133 return result; 134 } 135 136 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTestNoDelayedRelease, reporter, ctxInfo) { 137 const int kWidth = 10; 138 const int kHeight = 10; 139 140 GrContext* ctx = ctxInfo.grContext(); 141 GrGpu* gpu = ctx->contextPriv().getGpu(); 142 143 for (bool releaseImageEarly : {true, false}) { 144 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 145 nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, true, GrMipMapped::kNo); 146 REPORTER_ASSERT(reporter, backendTex.isValid()); 147 148 GrBackendFormat backendFormat = backendTex.getBackendFormat(); 149 REPORTER_ASSERT(reporter, backendFormat.isValid()); 150 151 PromiseTextureChecker promiseChecker(backendTex, reporter, false); 152 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin; 153 sk_sp<SkImage> refImg( 154 SkImage_Gpu::MakePromiseTexture( 155 ctx, backendFormat, kWidth, kHeight, 156 GrMipMapped::kNo, texOrigin, 157 kRGBA_8888_SkColorType, kPremul_SkAlphaType, 158 nullptr, 159 PromiseTextureChecker::Fulfill, 160 PromiseTextureChecker::Release, 161 PromiseTextureChecker::Done, 162 &promiseChecker, 163 SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo)); 164 165 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight); 166 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info); 167 SkCanvas* canvas = surface->getCanvas(); 168 169 int expectedFulfillCnt = 0; 170 int expectedReleaseCnt = 0; 171 int expectedDoneCnt = 0; 172 ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced; 173 174 canvas->drawImage(refImg, 0, 0); 175 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 176 balanceExpecation, 177 expectedFulfillCnt, 178 expectedReleaseCnt, 179 true, 180 expectedDoneCnt, 181 reporter)); 182 183 bool isVulkan = GrBackendApi::kVulkan == ctx->backend(); 184 canvas->flush(); 185 expectedFulfillCnt++; 186 expectedReleaseCnt++; 187 if (isVulkan) { 188 balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne; 189 } 190 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 191 balanceExpecation, 192 expectedFulfillCnt, 193 expectedReleaseCnt, 194 !isVulkan, 195 expectedDoneCnt, 196 reporter)); 197 198 gpu->testingOnly_flushGpuAndSync(); 199 balanceExpecation = ReleaseBalanceExpecation::kBalanced; 200 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 201 balanceExpecation, 202 expectedFulfillCnt, 203 expectedReleaseCnt, 204 true, 205 expectedDoneCnt, 206 reporter)); 207 208 canvas->drawImage(refImg, 0, 0); 209 canvas->drawImage(refImg, 0, 0); 210 211 canvas->flush(); 212 expectedFulfillCnt++; 213 expectedReleaseCnt++; 214 215 gpu->testingOnly_flushGpuAndSync(); 216 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 217 balanceExpecation, 218 expectedFulfillCnt, 219 expectedReleaseCnt, 220 true, 221 expectedDoneCnt, 222 reporter)); 223 224 // Now test code path on Vulkan where we released the texture, but the GPU isn't done with 225 // resource yet and we do another draw. We should only call fulfill on the first draw and 226 // use the cached GrBackendTexture on the second. Release should only be called after the 227 // second draw is finished. 228 canvas->drawImage(refImg, 0, 0); 229 canvas->flush(); 230 expectedFulfillCnt++; 231 expectedReleaseCnt++; 232 if (isVulkan) { 233 balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne; 234 } 235 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 236 balanceExpecation, 237 expectedFulfillCnt, 238 expectedReleaseCnt, 239 !isVulkan, 240 expectedDoneCnt, 241 reporter)); 242 243 canvas->drawImage(refImg, 0, 0); 244 245 if (releaseImageEarly) { 246 refImg.reset(); 247 } 248 249 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 250 balanceExpecation, 251 expectedFulfillCnt, 252 expectedReleaseCnt, 253 !isVulkan, 254 expectedDoneCnt, 255 reporter)); 256 257 canvas->flush(); 258 expectedFulfillCnt++; 259 260 gpu->testingOnly_flushGpuAndSync(); 261 expectedReleaseCnt++; 262 if (releaseImageEarly) { 263 expectedDoneCnt++; 264 } 265 balanceExpecation = ReleaseBalanceExpecation::kBalanced; 266 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 267 balanceExpecation, 268 expectedFulfillCnt, 269 expectedReleaseCnt, 270 !isVulkan, 271 expectedDoneCnt, 272 reporter)); 273 expectedFulfillCnt = promiseChecker.fFulfillCount; 274 expectedReleaseCnt = promiseChecker.fReleaseCount; 275 276 if (!releaseImageEarly) { 277 refImg.reset(); 278 expectedDoneCnt++; 279 } 280 281 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 282 balanceExpecation, 283 expectedFulfillCnt, 284 expectedReleaseCnt, 285 true, 286 expectedDoneCnt, 287 reporter)); 288 289 gpu->deleteTestingOnlyBackendTexture(backendTex); 290 } 291 } 292 293 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTestDelayedRelease, reporter, ctxInfo) { 294 const int kWidth = 10; 295 const int kHeight = 10; 296 297 GrContext* ctx = ctxInfo.grContext(); 298 GrGpu* gpu = ctx->contextPriv().getGpu(); 299 300 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 301 nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, true, GrMipMapped::kNo); 302 REPORTER_ASSERT(reporter, backendTex.isValid()); 303 304 GrBackendFormat backendFormat = backendTex.getBackendFormat(); 305 REPORTER_ASSERT(reporter, backendFormat.isValid()); 306 307 PromiseTextureChecker promiseChecker(backendTex, reporter, false); 308 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin; 309 sk_sp<SkImage> refImg( 310 SkImage_Gpu::MakePromiseTexture( 311 ctx, backendFormat, kWidth, kHeight, 312 GrMipMapped::kNo, texOrigin, 313 kRGBA_8888_SkColorType, kPremul_SkAlphaType, 314 nullptr, 315 PromiseTextureChecker::Fulfill, 316 PromiseTextureChecker::Release, 317 PromiseTextureChecker::Done, 318 &promiseChecker, 319 SkDeferredDisplayListRecorder::DelayReleaseCallback::kYes)); 320 321 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight); 322 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info); 323 SkCanvas* canvas = surface->getCanvas(); 324 325 int expectedFulfillCnt = 0; 326 int expectedReleaseCnt = 0; 327 int expectedDoneCnt = 0; 328 ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced; 329 330 canvas->drawImage(refImg, 0, 0); 331 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 332 balanceExpecation, 333 expectedFulfillCnt, 334 expectedReleaseCnt, 335 true, 336 expectedDoneCnt, 337 reporter)); 338 339 bool isVulkan = GrBackendApi::kVulkan == ctx->backend(); 340 canvas->flush(); 341 expectedFulfillCnt++; 342 // Because we've delayed release, we expect a +1 balance. 343 balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne; 344 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 345 balanceExpecation, 346 expectedFulfillCnt, 347 expectedReleaseCnt, 348 !isVulkan, 349 expectedDoneCnt, 350 reporter)); 351 352 gpu->testingOnly_flushGpuAndSync(); 353 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 354 balanceExpecation, 355 expectedFulfillCnt, 356 expectedReleaseCnt, 357 true, 358 expectedDoneCnt, 359 reporter)); 360 361 canvas->drawImage(refImg, 0, 0); 362 canvas->drawImage(refImg, 0, 0); 363 364 canvas->flush(); 365 366 gpu->testingOnly_flushGpuAndSync(); 367 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 368 balanceExpecation, 369 expectedFulfillCnt, 370 expectedReleaseCnt, 371 true, 372 expectedDoneCnt, 373 reporter)); 374 375 canvas->drawImage(refImg, 0, 0); 376 canvas->flush(); 377 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 378 balanceExpecation, 379 expectedFulfillCnt, 380 expectedReleaseCnt, 381 !isVulkan, 382 expectedDoneCnt, 383 reporter)); 384 385 canvas->drawImage(refImg, 0, 0); 386 387 refImg.reset(); 388 389 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 390 balanceExpecation, 391 expectedFulfillCnt, 392 expectedReleaseCnt, 393 !isVulkan, 394 expectedDoneCnt, 395 reporter)); 396 397 canvas->flush(); 398 gpu->testingOnly_flushGpuAndSync(); 399 // We released the image already and we flushed and synced. 400 balanceExpecation = ReleaseBalanceExpecation::kBalanced; 401 expectedReleaseCnt++; 402 expectedDoneCnt++; 403 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 404 balanceExpecation, 405 expectedFulfillCnt, 406 expectedReleaseCnt, 407 !isVulkan, 408 expectedDoneCnt, 409 reporter)); 410 411 gpu->deleteTestingOnlyBackendTexture(backendTex); 412 } 413 414 // Tests replacing the backing texture for a promise image after a release and then refulfilling in 415 // the SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo case. 416 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuse, reporter, ctxInfo) { 417 const int kWidth = 10; 418 const int kHeight = 10; 419 420 GrContext* ctx = ctxInfo.grContext(); 421 GrGpu* gpu = ctx->contextPriv().getGpu(); 422 423 GrBackendTexture backendTex1 = gpu->createTestingOnlyBackendTexture( 424 nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, false, GrMipMapped::kNo); 425 GrBackendTexture backendTex2 = gpu->createTestingOnlyBackendTexture( 426 nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, false, GrMipMapped::kNo); 427 GrBackendTexture backendTex3 = gpu->createTestingOnlyBackendTexture( 428 nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, false, GrMipMapped::kNo); 429 REPORTER_ASSERT(reporter, backendTex1.isValid()); 430 REPORTER_ASSERT(reporter, backendTex2.isValid()); 431 REPORTER_ASSERT(reporter, backendTex3.isValid()); 432 433 GrBackendFormat backendFormat = backendTex1.getBackendFormat(); 434 REPORTER_ASSERT(reporter, backendFormat.isValid()); 435 REPORTER_ASSERT(reporter, backendFormat == backendTex2.getBackendFormat()); 436 REPORTER_ASSERT(reporter, backendFormat == backendTex3.getBackendFormat()); 437 438 PromiseTextureChecker promiseChecker(backendTex1, reporter, true); 439 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin; 440 sk_sp<SkImage> refImg( 441 SkImage_Gpu::MakePromiseTexture( 442 ctx, backendFormat, kWidth, kHeight, 443 GrMipMapped::kNo, texOrigin, 444 kRGBA_8888_SkColorType, kPremul_SkAlphaType, 445 nullptr, 446 PromiseTextureChecker::Fulfill, 447 PromiseTextureChecker::Release, 448 PromiseTextureChecker::Done, 449 &promiseChecker, 450 SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo)); 451 452 SkImageInfo info = 453 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 454 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info); 455 SkCanvas* canvas = surface->getCanvas(); 456 457 int expectedFulfillCnt = 0; 458 int expectedReleaseCnt = 0; 459 int expectedDoneCnt = 0; 460 461 canvas->drawImage(refImg, 0, 0); 462 canvas->drawImage(refImg, 5, 5); 463 ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced; 464 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 465 balanceExpecation, 466 expectedFulfillCnt, 467 expectedReleaseCnt, 468 true, 469 expectedDoneCnt, 470 reporter)); 471 472 bool isVulkan = GrBackendApi::kVulkan == ctx->backend(); 473 canvas->flush(); 474 expectedFulfillCnt++; 475 expectedReleaseCnt++; 476 if (isVulkan) { 477 balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne; 478 } 479 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 480 balanceExpecation, 481 expectedFulfillCnt, 482 expectedReleaseCnt, 483 !isVulkan, 484 expectedDoneCnt, 485 reporter)); 486 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals( 487 promiseChecker.fLastFulfilledTexture, backendTex1)); 488 // We should have put a GrTexture for this fulfillment into the cache. 489 auto keys = promiseChecker.uniqueKeys(); 490 REPORTER_ASSERT(reporter, keys.count() == 1); 491 GrUniqueKey texKey1; 492 if (keys.count()) { 493 texKey1 = keys[0]; 494 } 495 REPORTER_ASSERT(reporter, texKey1.isValid()); 496 REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey1)); 497 498 gpu->testingOnly_flushGpuAndSync(); 499 balanceExpecation = ReleaseBalanceExpecation::kBalanced; 500 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 501 balanceExpecation, 502 expectedFulfillCnt, 503 expectedReleaseCnt, 504 true, 505 expectedDoneCnt, 506 reporter)); 507 REPORTER_ASSERT(reporter, 508 GrBackendTexture::TestingOnly_Equals( 509 promiseChecker.replaceTexture()->backendTexture(), backendTex1)); 510 gpu->deleteTestingOnlyBackendTexture(backendTex1); 511 512 ctx->contextPriv().getResourceCache()->purgeAsNeeded(); 513 // We should have invalidated the key on the previously cached texture (after ensuring 514 // invalidation messages have been processed by calling purgeAsNeeded.) 515 REPORTER_ASSERT(reporter, !ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey1)); 516 517 promiseChecker.replaceTexture(backendTex2); 518 519 canvas->drawImage(refImg, 0, 0); 520 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 521 balanceExpecation, 522 expectedFulfillCnt, 523 expectedReleaseCnt, 524 true, 525 expectedDoneCnt, 526 reporter)); 527 528 canvas->flush(); 529 expectedFulfillCnt++; 530 expectedReleaseCnt++; 531 if (isVulkan) { 532 balanceExpecation = ReleaseBalanceExpecation::kBalancedOrPlusOne; 533 } 534 // Second texture should be in the cache. 535 keys = promiseChecker.uniqueKeys(); 536 REPORTER_ASSERT(reporter, keys.count() == 1); 537 GrUniqueKey texKey2; 538 if (keys.count()) { 539 texKey2 = keys[0]; 540 } 541 REPORTER_ASSERT(reporter, texKey2.isValid() && texKey2 != texKey1); 542 REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2)); 543 544 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 545 balanceExpecation, 546 expectedFulfillCnt, 547 expectedReleaseCnt, 548 !isVulkan, 549 expectedDoneCnt, 550 reporter)); 551 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals( 552 promiseChecker.fLastFulfilledTexture, backendTex2)); 553 554 gpu->testingOnly_flushGpuAndSync(); 555 balanceExpecation = ReleaseBalanceExpecation::kBalanced; 556 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 557 balanceExpecation, 558 expectedFulfillCnt, 559 expectedReleaseCnt, 560 true, 561 expectedDoneCnt, 562 reporter)); 563 564 // Because we have kept the SkPromiseImageTexture alive, we should be able to use it again and 565 // hit the cache. 566 ctx->contextPriv().getResourceCache()->purgeAsNeeded(); 567 REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2)); 568 569 canvas->drawImage(refImg, 0, 0); 570 571 canvas->flush(); 572 gpu->testingOnly_flushGpuAndSync(); 573 expectedFulfillCnt++; 574 expectedReleaseCnt++; 575 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 576 balanceExpecation, 577 expectedFulfillCnt, 578 expectedReleaseCnt, 579 true, 580 expectedDoneCnt, 581 reporter)); 582 583 // Make sure we didn't add another key and that the second texture is still alive in the cache. 584 keys = promiseChecker.uniqueKeys(); 585 REPORTER_ASSERT(reporter, keys.count() == 1); 586 if (keys.count()) { 587 REPORTER_ASSERT(reporter, texKey2 == keys[0]); 588 } 589 ctx->contextPriv().getResourceCache()->purgeAsNeeded(); 590 REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2)); 591 592 // Now we test keeping tex2 alive but fulfilling with a new texture. 593 sk_sp<const SkPromiseImageTexture> promiseImageTexture2 = 594 promiseChecker.replaceTexture(backendTex3); 595 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals( 596 promiseImageTexture2->backendTexture(), backendTex2)); 597 598 canvas->drawImage(refImg, 0, 0); 599 600 canvas->flush(); 601 gpu->testingOnly_flushGpuAndSync(); 602 expectedFulfillCnt++; 603 expectedReleaseCnt++; 604 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 605 balanceExpecation, 606 expectedFulfillCnt, 607 expectedReleaseCnt, 608 true, 609 expectedDoneCnt, 610 reporter)); 611 612 keys = promiseChecker.uniqueKeys(); 613 REPORTER_ASSERT(reporter, keys.count() == 1); 614 GrUniqueKey texKey3; 615 if (keys.count()) { 616 texKey3 = keys[0]; 617 } 618 ctx->contextPriv().getResourceCache()->purgeAsNeeded(); 619 REPORTER_ASSERT(reporter, !ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey2)); 620 REPORTER_ASSERT(reporter, ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey3)); 621 gpu->deleteTestingOnlyBackendTexture(promiseImageTexture2->backendTexture()); 622 623 // Make a new promise image also backed by texture 3. 624 sk_sp<SkImage> refImg2( 625 SkImage_Gpu::MakePromiseTexture( 626 ctx, backendFormat, kWidth, kHeight, 627 GrMipMapped::kNo, texOrigin, 628 kRGBA_8888_SkColorType, kPremul_SkAlphaType, 629 nullptr, 630 PromiseTextureChecker::Fulfill, 631 PromiseTextureChecker::Release, 632 PromiseTextureChecker::Done, 633 &promiseChecker, 634 SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo)); 635 canvas->drawImage(refImg, 0, 0); 636 canvas->drawImage(refImg2, 1, 1); 637 638 canvas->flush(); 639 gpu->testingOnly_flushGpuAndSync(); 640 expectedFulfillCnt += 2; 641 expectedReleaseCnt += 2; 642 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 643 balanceExpecation, 644 expectedFulfillCnt, 645 expectedReleaseCnt, 646 true, 647 expectedDoneCnt, 648 reporter)); 649 650 // The two images should share a single GrTexture by using the same key. The key is only 651 // dependent on the pixel config and the PromiseImageTexture key. 652 keys = promiseChecker.uniqueKeys(); 653 REPORTER_ASSERT(reporter, keys.count() == 1); 654 if (keys.count() > 0) { 655 REPORTER_ASSERT(reporter, texKey3 == keys[0]); 656 } 657 ctx->contextPriv().getResourceCache()->purgeAsNeeded(); 658 659 // If we delete the SkPromiseImageTexture we should trigger both key removals. 660 REPORTER_ASSERT(reporter, 661 GrBackendTexture::TestingOnly_Equals( 662 promiseChecker.replaceTexture()->backendTexture(), backendTex3)); 663 664 ctx->contextPriv().getResourceCache()->purgeAsNeeded(); 665 REPORTER_ASSERT(reporter, !ctx->contextPriv().resourceProvider()->findByUniqueKey<>(texKey3)); 666 gpu->deleteTestingOnlyBackendTexture(backendTex3); 667 668 // After deleting each image we should get a done call. 669 refImg.reset(); 670 ++expectedDoneCnt; 671 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 672 balanceExpecation, 673 expectedFulfillCnt, 674 expectedReleaseCnt, 675 true, 676 expectedDoneCnt, 677 reporter)); 678 refImg2.reset(); 679 ++expectedDoneCnt; 680 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 681 balanceExpecation, 682 expectedFulfillCnt, 683 expectedReleaseCnt, 684 true, 685 expectedDoneCnt, 686 reporter)); 687 } 688 689 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig, reporter, ctxInfo) { 690 // Try making two promise SkImages backed by the same texture but with different configs. 691 // This will only be testable on backends where a single texture format (8bit red unorm) can 692 // be used for alpha and gray image color types. 693 694 const int kWidth = 10; 695 const int kHeight = 10; 696 697 GrContext* ctx = ctxInfo.grContext(); 698 GrGpu* gpu = ctx->contextPriv().getGpu(); 699 700 GrBackendTexture backendTex1 = gpu->createTestingOnlyBackendTexture( 701 nullptr, kWidth, kHeight, GrColorType::kGray_8, false, GrMipMapped::kNo); 702 REPORTER_ASSERT(reporter, backendTex1.isValid()); 703 704 GrBackendTexture backendTex2 = gpu->createTestingOnlyBackendTexture( 705 nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo); 706 REPORTER_ASSERT(reporter, backendTex2.isValid()); 707 if (backendTex1.getBackendFormat() != backendTex2.getBackendFormat()) { 708 gpu->deleteTestingOnlyBackendTexture(backendTex1); 709 return; 710 } 711 // We only needed this texture to check that alpha and gray color types use the same format. 712 gpu->deleteTestingOnlyBackendTexture(backendTex2); 713 714 SkImageInfo info = 715 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 716 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info); 717 SkCanvas* canvas = surface->getCanvas(); 718 719 for (auto delayRelease : {SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo, 720 SkDeferredDisplayListRecorder::DelayReleaseCallback::kYes}) { 721 PromiseTextureChecker promiseChecker(backendTex1, reporter, true); 722 sk_sp<SkImage> alphaImg(SkImage_Gpu::MakePromiseTexture( 723 ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo, 724 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr, 725 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release, 726 PromiseTextureChecker::Done, &promiseChecker, delayRelease)); 727 REPORTER_ASSERT(reporter, alphaImg); 728 729 sk_sp<SkImage> grayImg(SkImage_Gpu::MakePromiseTexture( 730 ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo, 731 kBottomLeft_GrSurfaceOrigin, kGray_8_SkColorType, kOpaque_SkAlphaType, nullptr, 732 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release, 733 PromiseTextureChecker::Done, &promiseChecker, delayRelease)); 734 REPORTER_ASSERT(reporter, grayImg); 735 736 canvas->drawImage(alphaImg, 0, 0); 737 canvas->drawImage(grayImg, 1, 1); 738 canvas->flush(); 739 gpu->testingOnly_flushGpuAndSync(); 740 741 int expectedFulfillCnt = 2; 742 int expectedReleaseCnt = 0; 743 int expectedDoneCnt = 0; 744 ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kAny; 745 if (delayRelease == SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo) { 746 expectedReleaseCnt = 2; 747 balanceExpecation = ReleaseBalanceExpecation::kBalanced; 748 } 749 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 750 balanceExpecation, 751 expectedFulfillCnt, 752 expectedReleaseCnt, 753 true, 754 expectedDoneCnt, 755 reporter)); 756 757 // Because they use different configs, each image should have created a different GrTexture 758 // and they both should still be cached. 759 ctx->contextPriv().getResourceCache()->purgeAsNeeded(); 760 761 auto keys = promiseChecker.uniqueKeys(); 762 REPORTER_ASSERT(reporter, keys.count() == 2); 763 for (const auto& key : keys) { 764 auto surf = ctx->contextPriv().resourceProvider()->findByUniqueKey<GrSurface>(key); 765 REPORTER_ASSERT(reporter, surf && surf->asTexture()); 766 if (surf && surf->asTexture()) { 767 REPORTER_ASSERT(reporter, 768 !GrBackendTexture::TestingOnly_Equals( 769 backendTex1, surf->asTexture()->getBackendTexture())); 770 } 771 } 772 773 // Change the backing texture, this should invalidate the keys. 774 promiseChecker.replaceTexture(); 775 ctx->contextPriv().getResourceCache()->purgeAsNeeded(); 776 777 for (const auto& key : keys) { 778 auto surf = ctx->contextPriv().resourceProvider()->findByUniqueKey<GrSurface>(key); 779 REPORTER_ASSERT(reporter, !surf); 780 } 781 } 782 gpu->deleteTestingOnlyBackendTexture(backendTex1); 783 } 784 785 DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) { 786 const int kWidth = 10; 787 const int kHeight = 10; 788 789 // Different ways of killing contexts. 790 using DeathFn = std::function<void(sk_gpu_test::GrContextFactory*, GrContext*)>; 791 DeathFn destroy = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) { 792 factory->destroyContexts(); 793 }; 794 DeathFn abandon = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) { 795 context->abandonContext(); 796 }; 797 DeathFn releaseResourcesAndAbandon = [](sk_gpu_test::GrContextFactory* factory, 798 GrContext* context) { 799 context->releaseResourcesAndAbandonContext(); 800 }; 801 802 for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) { 803 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type); 804 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705 805 // and http://skbug.com/8275 806 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType); 807 if (api == GrBackendApi::kVulkan) { 808 continue; 809 } 810 DeathFn contextKillers[] = {destroy, abandon, releaseResourcesAndAbandon}; 811 for (auto contextDeath : contextKillers) { 812 sk_gpu_test::GrContextFactory factory; 813 auto ctx = factory.get(contextType); 814 if (!ctx) { 815 continue; 816 } 817 GrGpu* gpu = ctx->contextPriv().getGpu(); 818 819 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 820 nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo); 821 REPORTER_ASSERT(reporter, backendTex.isValid()); 822 823 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, 824 kPremul_SkAlphaType); 825 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info); 826 SkCanvas* canvas = surface->getCanvas(); 827 828 PromiseTextureChecker promiseChecker(backendTex, reporter, false); 829 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture( 830 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo, 831 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr, 832 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release, 833 PromiseTextureChecker::Done, &promiseChecker, 834 SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo)); 835 REPORTER_ASSERT(reporter, image); 836 837 canvas->drawImage(image, 0, 0); 838 image.reset(); 839 // If the surface still holds a ref to the context then the factory will not be able 840 // to destroy the context (and instead will release-all-and-abandon). 841 surface.reset(); 842 843 ctx->flush(); 844 contextDeath(&factory, ctx); 845 846 int expectedFulfillCnt = 1; 847 int expectedReleaseCnt = 1; 848 int expectedDoneCnt = 1; 849 ReleaseBalanceExpecation balanceExpecation = ReleaseBalanceExpecation::kBalanced; 850 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker, 851 balanceExpecation, 852 expectedFulfillCnt, 853 expectedReleaseCnt, 854 true, 855 expectedDoneCnt, 856 reporter)); 857 } 858 } 859 } 860 861 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxInfo) { 862 const int kWidth = 10; 863 const int kHeight = 10; 864 865 GrContext* ctx = ctxInfo.grContext(); 866 GrGpu* gpu = ctx->contextPriv().getGpu(); 867 868 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 869 nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo); 870 REPORTER_ASSERT(reporter, backendTex.isValid()); 871 872 SkImageInfo info = 873 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 874 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info); 875 SkCanvas* canvas = surface->getCanvas(); 876 877 PromiseTextureChecker promiseChecker(backendTex, reporter, false); 878 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture( 879 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo, 880 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr, 881 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release, 882 PromiseTextureChecker::Done, &promiseChecker, 883 SkDeferredDisplayListRecorder::DelayReleaseCallback::kNo)); 884 REPORTER_ASSERT(reporter, image); 885 886 // Make the cache full. This tests that we don't preemptively purge cached textures for 887 // fulfillment due to cache pressure. 888 static constexpr int kMaxResources = 10; 889 static constexpr int kMaxBytes = 100; 890 ctx->setResourceCacheLimits(kMaxResources, kMaxBytes); 891 sk_sp<GrTexture> textures[2 * kMaxResources]; 892 for (int i = 0; i < 2 * kMaxResources; ++i) { 893 GrSurfaceDesc desc; 894 desc.fConfig = kRGBA_8888_GrPixelConfig; 895 desc.fWidth = desc.fHeight = 100; 896 textures[i] = ctx->contextPriv().resourceProvider()->createTexture(desc, SkBudgeted::kYes); 897 REPORTER_ASSERT(reporter, textures[i]); 898 } 899 900 // Relying on the asserts in the promiseImageChecker to ensure that fulfills and releases are 901 // properly ordered. 902 canvas->drawImage(image, 0, 0); 903 canvas->flush(); 904 canvas->drawImage(image, 1, 0); 905 canvas->flush(); 906 canvas->drawImage(image, 2, 0); 907 canvas->flush(); 908 canvas->drawImage(image, 3, 0); 909 canvas->flush(); 910 canvas->drawImage(image, 4, 0); 911 canvas->flush(); 912 canvas->drawImage(image, 5, 0); 913 canvas->flush(); 914 // Must call this to ensure that all callbacks are performed before the checker is destroyed. 915 gpu->testingOnly_flushGpuAndSync(); 916 gpu->deleteTestingOnlyBackendTexture(backendTex); 917 } 918