Home | History | Annotate | Download | only in tests
      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