1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "tests/Test.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h"
11cb93a386Sopenharmony_ci#include "include/core/SkPromiseImageTexture.h"
12cb93a386Sopenharmony_ci#include "include/gpu/GrBackendSurface.h"
13cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrGpu.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h"
18cb93a386Sopenharmony_ci#include "src/image/SkImage_Gpu.h"
19cb93a386Sopenharmony_ci#include "tools/gpu/ManagedBackendTexture.h"
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ciusing namespace sk_gpu_test;
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_cistruct PromiseTextureChecker {
24cb93a386Sopenharmony_ci    // shared indicates whether the backend texture is used to fulfill more than one promise
25cb93a386Sopenharmony_ci    // image.
26cb93a386Sopenharmony_ci    explicit PromiseTextureChecker(const GrBackendTexture& tex,
27cb93a386Sopenharmony_ci                                   skiatest::Reporter* reporter,
28cb93a386Sopenharmony_ci                                   bool shared)
29cb93a386Sopenharmony_ci            : fTexture(SkPromiseImageTexture::Make(tex)), fReporter(reporter), fShared(shared) {}
30cb93a386Sopenharmony_ci    sk_sp<SkPromiseImageTexture> fTexture;
31cb93a386Sopenharmony_ci    skiatest::Reporter* fReporter;
32cb93a386Sopenharmony_ci    bool fShared;
33cb93a386Sopenharmony_ci    int fFulfillCount = 0;
34cb93a386Sopenharmony_ci    int fReleaseCount = 0;
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci    /**
37cb93a386Sopenharmony_ci     * Releases the SkPromiseImageTexture. Used to test that cached GrTexture representations
38cb93a386Sopenharmony_ci     * in the cache are freed.
39cb93a386Sopenharmony_ci     */
40cb93a386Sopenharmony_ci    void releaseTexture() { fTexture.reset(); }
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci    SkTArray<GrUniqueKey> uniqueKeys() const {
43cb93a386Sopenharmony_ci        return fTexture->testingOnly_uniqueKeysToInvalidate();
44cb93a386Sopenharmony_ci    }
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci    static sk_sp<SkPromiseImageTexture> Fulfill(void* self) {
47cb93a386Sopenharmony_ci        auto checker = static_cast<PromiseTextureChecker*>(self);
48cb93a386Sopenharmony_ci        checker->fFulfillCount++;
49cb93a386Sopenharmony_ci        return checker->fTexture;
50cb93a386Sopenharmony_ci    }
51cb93a386Sopenharmony_ci    static void Release(void* self) { static_cast<PromiseTextureChecker*>(self)->fReleaseCount++; }
52cb93a386Sopenharmony_ci};
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_cienum class ReleaseBalanceExpectation {
55cb93a386Sopenharmony_ci    kBalanced,
56cb93a386Sopenharmony_ci    kAllUnbalanced,
57cb93a386Sopenharmony_ci    kUnknown,
58cb93a386Sopenharmony_ci    kUnbalancedByOne,
59cb93a386Sopenharmony_ci    kBalancedOrOffByOne,
60cb93a386Sopenharmony_ci};
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_cistatic void check_fulfill_and_release_cnts(skiatest::Reporter* reporter,
63cb93a386Sopenharmony_ci                                           const PromiseTextureChecker& promiseChecker,
64cb93a386Sopenharmony_ci                                           int expectedFulfillCnt,
65cb93a386Sopenharmony_ci                                           ReleaseBalanceExpectation releaseBalanceExpecation) {
66cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, promiseChecker.fFulfillCount == expectedFulfillCnt);
67cb93a386Sopenharmony_ci    if (!expectedFulfillCnt) {
68cb93a386Sopenharmony_ci        // Release and Done should only ever be called after Fulfill.
69cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !promiseChecker.fReleaseCount);
70cb93a386Sopenharmony_ci        return;
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci    int releaseDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
73cb93a386Sopenharmony_ci    switch (releaseBalanceExpecation) {
74cb93a386Sopenharmony_ci        case ReleaseBalanceExpectation::kBalanced:
75cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, !releaseDiff);
76cb93a386Sopenharmony_ci            break;
77cb93a386Sopenharmony_ci        case ReleaseBalanceExpectation::kAllUnbalanced:
78cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, releaseDiff == promiseChecker.fFulfillCount);
79cb93a386Sopenharmony_ci            break;
80cb93a386Sopenharmony_ci        case ReleaseBalanceExpectation::kUnknown:
81cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter,
82cb93a386Sopenharmony_ci                            releaseDiff >= 0 && releaseDiff <= promiseChecker.fFulfillCount);
83cb93a386Sopenharmony_ci            break;
84cb93a386Sopenharmony_ci        case ReleaseBalanceExpectation::kUnbalancedByOne:
85cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, releaseDiff == 1);
86cb93a386Sopenharmony_ci            break;
87cb93a386Sopenharmony_ci        case ReleaseBalanceExpectation::kBalancedOrOffByOne:
88cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, releaseDiff == 0 || releaseDiff == 1);
89cb93a386Sopenharmony_ci            break;
90cb93a386Sopenharmony_ci    }
91cb93a386Sopenharmony_ci}
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_cistatic void check_unfulfilled(const PromiseTextureChecker& promiseChecker,
94cb93a386Sopenharmony_ci                              skiatest::Reporter* reporter) {
95cb93a386Sopenharmony_ci    check_fulfill_and_release_cnts(reporter, promiseChecker, 0,
96cb93a386Sopenharmony_ci                                   ReleaseBalanceExpectation::kBalanced);
97cb93a386Sopenharmony_ci}
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_cistatic void check_only_fulfilled(skiatest::Reporter* reporter,
100cb93a386Sopenharmony_ci                                 const PromiseTextureChecker& promiseChecker,
101cb93a386Sopenharmony_ci                                 int expectedFulfillCnt = 1) {
102cb93a386Sopenharmony_ci    check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
103cb93a386Sopenharmony_ci                                   ReleaseBalanceExpectation::kAllUnbalanced);
104cb93a386Sopenharmony_ci}
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_cistatic void check_all_flushed_but_not_synced(skiatest::Reporter* reporter,
107cb93a386Sopenharmony_ci                                             const PromiseTextureChecker& promiseChecker,
108cb93a386Sopenharmony_ci                                             GrBackendApi api,
109cb93a386Sopenharmony_ci                                             int expectedFulfillCnt = 1) {
110cb93a386Sopenharmony_ci    ReleaseBalanceExpectation releaseBalanceExpectation = ReleaseBalanceExpectation::kBalanced;
111cb93a386Sopenharmony_ci    // On Vulkan and D3D Done isn't guaranteed to be called until a sync has occurred.
112cb93a386Sopenharmony_ci    if (api == GrBackendApi::kVulkan || api == GrBackendApi::kDirect3D) {
113cb93a386Sopenharmony_ci        releaseBalanceExpectation = expectedFulfillCnt == 1
114cb93a386Sopenharmony_ci                                            ? ReleaseBalanceExpectation::kBalancedOrOffByOne
115cb93a386Sopenharmony_ci                                            : ReleaseBalanceExpectation::kUnknown;
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci    check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
118cb93a386Sopenharmony_ci                                   releaseBalanceExpectation);
119cb93a386Sopenharmony_ci}
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_cistatic void check_all_done(skiatest::Reporter* reporter,
122cb93a386Sopenharmony_ci                           const PromiseTextureChecker& promiseChecker,
123cb93a386Sopenharmony_ci                           int expectedFulfillCnt = 1) {
124cb93a386Sopenharmony_ci    check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
125cb93a386Sopenharmony_ci                                   ReleaseBalanceExpectation::kBalanced);
126cb93a386Sopenharmony_ci}
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
129cb93a386Sopenharmony_ci    const int kWidth = 10;
130cb93a386Sopenharmony_ci    const int kHeight = 10;
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci    auto ctx = ctxInfo.directContext();
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    GrBackendTexture backendTex = ctx->createBackendTexture(
135cb93a386Sopenharmony_ci            kWidth, kHeight, kRGBA_8888_SkColorType,
136cb93a386Sopenharmony_ci            SkColors::kTransparent, GrMipmapped::kNo, GrRenderable::kYes, GrProtected::kNo);
137cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, backendTex.isValid());
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    GrBackendFormat backendFormat = backendTex.getBackendFormat();
140cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, backendFormat.isValid());
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci    PromiseTextureChecker promiseChecker(backendTex, reporter, false);
143cb93a386Sopenharmony_ci    GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
144cb93a386Sopenharmony_ci    sk_sp<SkImage> refImg(SkImage_Gpu::MakePromiseTexture(ctx->threadSafeProxy(),
145cb93a386Sopenharmony_ci                                                          backendFormat,
146cb93a386Sopenharmony_ci                                                          {kWidth, kHeight},
147cb93a386Sopenharmony_ci                                                          GrMipmapped::kNo,
148cb93a386Sopenharmony_ci                                                          texOrigin,
149cb93a386Sopenharmony_ci                                                          kRGBA_8888_SkColorType,
150cb93a386Sopenharmony_ci                                                          kPremul_SkAlphaType,
151cb93a386Sopenharmony_ci                                                          nullptr,
152cb93a386Sopenharmony_ci                                                          PromiseTextureChecker::Fulfill,
153cb93a386Sopenharmony_ci                                                          PromiseTextureChecker::Release,
154cb93a386Sopenharmony_ci                                                          &promiseChecker));
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
157cb93a386Sopenharmony_ci    sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
158cb93a386Sopenharmony_ci    SkCanvas* canvas = surface->getCanvas();
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ci    canvas->drawImage(refImg, 0, 0);
161cb93a386Sopenharmony_ci    check_unfulfilled(promiseChecker, reporter);
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_ci    surface->flushAndSubmit();
164cb93a386Sopenharmony_ci    // We still own the image so we should not have called Release or Done.
165cb93a386Sopenharmony_ci    check_only_fulfilled(reporter, promiseChecker);
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci    ctx->submit(true);
168cb93a386Sopenharmony_ci    check_only_fulfilled(reporter, promiseChecker);
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci    canvas->drawImage(refImg, 0, 0);
171cb93a386Sopenharmony_ci    canvas->drawImage(refImg, 0, 0);
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci    surface->flushAndSubmit(true);
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ci    // Image should still be fulfilled from the first time we drew/flushed it.
176cb93a386Sopenharmony_ci    check_only_fulfilled(reporter, promiseChecker);
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ci    canvas->drawImage(refImg, 0, 0);
179cb93a386Sopenharmony_ci    surface->flushAndSubmit();
180cb93a386Sopenharmony_ci    check_only_fulfilled(reporter, promiseChecker);
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci    canvas->drawImage(refImg, 0, 0);
183cb93a386Sopenharmony_ci    refImg.reset();
184cb93a386Sopenharmony_ci    // We no longer own the image but the last draw is still unflushed.
185cb93a386Sopenharmony_ci    check_only_fulfilled(reporter, promiseChecker);
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ci    surface->flushAndSubmit();
188cb93a386Sopenharmony_ci    // Flushing should have called Release. Depending on the backend and timing it may have called
189cb93a386Sopenharmony_ci    // done.
190cb93a386Sopenharmony_ci    check_all_flushed_but_not_synced(reporter, promiseChecker, ctx->backend());
191cb93a386Sopenharmony_ci    ctx->submit(true);
192cb93a386Sopenharmony_ci    // Now Done should definitely have been called.
193cb93a386Sopenharmony_ci    check_all_done(reporter, promiseChecker);
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_ci    ctx->deleteBackendTexture(backendTex);
196cb93a386Sopenharmony_ci}
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_ciDEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
199cb93a386Sopenharmony_ci    const int kWidth = 10;
200cb93a386Sopenharmony_ci    const int kHeight = 10;
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ci    // Different ways of killing contexts.
203cb93a386Sopenharmony_ci    using DeathFn = std::function<void(sk_gpu_test::GrContextFactory*, GrDirectContext*)>;
204cb93a386Sopenharmony_ci    DeathFn destroy = [](sk_gpu_test::GrContextFactory* factory, GrDirectContext*) {
205cb93a386Sopenharmony_ci        factory->destroyContexts();
206cb93a386Sopenharmony_ci    };
207cb93a386Sopenharmony_ci    DeathFn abandon = [](sk_gpu_test::GrContextFactory* factory, GrDirectContext* dContext) {
208cb93a386Sopenharmony_ci        dContext->abandonContext();
209cb93a386Sopenharmony_ci    };
210cb93a386Sopenharmony_ci    DeathFn releaseResourcesAndAbandon = [](sk_gpu_test::GrContextFactory* factory,
211cb93a386Sopenharmony_ci                                            GrDirectContext* dContext) {
212cb93a386Sopenharmony_ci        dContext->releaseResourcesAndAbandonContext();
213cb93a386Sopenharmony_ci    };
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_ci    for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
216cb93a386Sopenharmony_ci        auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
217cb93a386Sopenharmony_ci        // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
218cb93a386Sopenharmony_ci        // and http://skbug.com/8275
219cb93a386Sopenharmony_ci        // Also problematic on Dawn; see http://skbug.com/10326
220cb93a386Sopenharmony_ci        // And Direct3D, for similar reasons.
221cb93a386Sopenharmony_ci        GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
222cb93a386Sopenharmony_ci        if (api == GrBackendApi::kVulkan || api == GrBackendApi::kDawn ||
223cb93a386Sopenharmony_ci            api == GrBackendApi::kDirect3D) {
224cb93a386Sopenharmony_ci            continue;
225cb93a386Sopenharmony_ci        }
226cb93a386Sopenharmony_ci        DeathFn contextKillers[] = {destroy, abandon, releaseResourcesAndAbandon};
227cb93a386Sopenharmony_ci        for (const DeathFn& contextDeath : contextKillers) {
228cb93a386Sopenharmony_ci            sk_gpu_test::GrContextFactory factory;
229cb93a386Sopenharmony_ci            auto ctx = factory.get(contextType);
230cb93a386Sopenharmony_ci            if (!ctx) {
231cb93a386Sopenharmony_ci                continue;
232cb93a386Sopenharmony_ci            }
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci            auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(ctx,
235cb93a386Sopenharmony_ci                                                                            kWidth,
236cb93a386Sopenharmony_ci                                                                            kHeight,
237cb93a386Sopenharmony_ci                                                                            kAlpha_8_SkColorType,
238cb93a386Sopenharmony_ci                                                                            GrMipmapped::kNo,
239cb93a386Sopenharmony_ci                                                                            GrRenderable::kNo);
240cb93a386Sopenharmony_ci            if (!mbet) {
241cb93a386Sopenharmony_ci                ERRORF(reporter, "Could not create texture alpha texture.");
242cb93a386Sopenharmony_ci                continue;
243cb93a386Sopenharmony_ci            }
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci            SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
246cb93a386Sopenharmony_ci                                                 kPremul_SkAlphaType);
247cb93a386Sopenharmony_ci            sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
248cb93a386Sopenharmony_ci            SkCanvas* canvas = surface->getCanvas();
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_ci            PromiseTextureChecker promiseChecker(mbet->texture(), reporter, false);
251cb93a386Sopenharmony_ci            sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(ctx->threadSafeProxy(),
252cb93a386Sopenharmony_ci                                                                 mbet->texture().getBackendFormat(),
253cb93a386Sopenharmony_ci                                                                 {kWidth, kHeight},
254cb93a386Sopenharmony_ci                                                                 GrMipmapped::kNo,
255cb93a386Sopenharmony_ci                                                                 kTopLeft_GrSurfaceOrigin,
256cb93a386Sopenharmony_ci                                                                 kAlpha_8_SkColorType,
257cb93a386Sopenharmony_ci                                                                 kPremul_SkAlphaType,
258cb93a386Sopenharmony_ci                                                                 /*color space*/ nullptr,
259cb93a386Sopenharmony_ci                                                                 PromiseTextureChecker::Fulfill,
260cb93a386Sopenharmony_ci                                                                 PromiseTextureChecker::Release,
261cb93a386Sopenharmony_ci                                                                 &promiseChecker));
262cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, image);
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci            canvas->drawImage(image, 0, 0);
265cb93a386Sopenharmony_ci            image.reset();
266cb93a386Sopenharmony_ci            // If the surface still holds a ref to the context then the factory will not be able
267cb93a386Sopenharmony_ci            // to destroy the context (and instead will release-all-and-abandon).
268cb93a386Sopenharmony_ci            surface.reset();
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci            ctx->flushAndSubmit();
271cb93a386Sopenharmony_ci            contextDeath(&factory, ctx);
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci            check_all_done(reporter, promiseChecker);
274cb93a386Sopenharmony_ci        }
275cb93a386Sopenharmony_ci    }
276cb93a386Sopenharmony_ci}
277cb93a386Sopenharmony_ci
278cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxInfo) {
279cb93a386Sopenharmony_ci    const int kWidth = 10;
280cb93a386Sopenharmony_ci    const int kHeight = 10;
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_ci    auto dContext = ctxInfo.directContext();
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci    GrBackendTexture backendTex = dContext->createBackendTexture(
285cb93a386Sopenharmony_ci            kWidth, kHeight, kAlpha_8_SkColorType,
286cb93a386Sopenharmony_ci            SkColors::kTransparent, GrMipmapped::kNo, GrRenderable::kNo, GrProtected::kNo);
287cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, backendTex.isValid());
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci    SkImageInfo info =
290cb93a386Sopenharmony_ci            SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
291cb93a386Sopenharmony_ci    sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, info);
292cb93a386Sopenharmony_ci    SkCanvas* canvas = surface->getCanvas();
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci    PromiseTextureChecker promiseChecker(backendTex, reporter, false);
295cb93a386Sopenharmony_ci    sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(dContext->threadSafeProxy(),
296cb93a386Sopenharmony_ci                                                         backendTex.getBackendFormat(),
297cb93a386Sopenharmony_ci                                                         {kWidth, kHeight},
298cb93a386Sopenharmony_ci                                                         GrMipmapped::kNo,
299cb93a386Sopenharmony_ci                                                         kTopLeft_GrSurfaceOrigin,
300cb93a386Sopenharmony_ci                                                         kAlpha_8_SkColorType,
301cb93a386Sopenharmony_ci                                                         kPremul_SkAlphaType,
302cb93a386Sopenharmony_ci                                                         nullptr,
303cb93a386Sopenharmony_ci                                                         PromiseTextureChecker::Fulfill,
304cb93a386Sopenharmony_ci                                                         PromiseTextureChecker::Release,
305cb93a386Sopenharmony_ci                                                         &promiseChecker));
306cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, image);
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci    // Make the cache full. This tests that we don't preemptively purge cached textures for
309cb93a386Sopenharmony_ci    // fulfillment due to cache pressure.
310cb93a386Sopenharmony_ci    static constexpr int kMaxBytes = 1;
311cb93a386Sopenharmony_ci    dContext->setResourceCacheLimit(kMaxBytes);
312cb93a386Sopenharmony_ci    SkTArray<sk_sp<GrTexture>> textures;
313cb93a386Sopenharmony_ci    for (int i = 0; i < 5; ++i) {
314cb93a386Sopenharmony_ci        auto format = dContext->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
315cb93a386Sopenharmony_ci                                                                       GrRenderable::kNo);
316cb93a386Sopenharmony_ci        textures.emplace_back(dContext->priv().resourceProvider()->createTexture(
317cb93a386Sopenharmony_ci                {100, 100}, format, GrTextureType::k2D, GrRenderable::kNo, 1, GrMipmapped::kNo,
318cb93a386Sopenharmony_ci                SkBudgeted::kYes, GrProtected::kNo));
319cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, textures[i]);
320cb93a386Sopenharmony_ci    }
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_ci    size_t bytesUsed;
323cb93a386Sopenharmony_ci
324cb93a386Sopenharmony_ci    dContext->getResourceCacheUsage(nullptr, &bytesUsed);
325cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, bytesUsed > kMaxBytes);
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_ci    // Relying on the asserts in the promiseImageChecker to ensure that fulfills and releases are
328cb93a386Sopenharmony_ci    // properly ordered.
329cb93a386Sopenharmony_ci    canvas->drawImage(image, 0, 0);
330cb93a386Sopenharmony_ci    surface->flushAndSubmit();
331cb93a386Sopenharmony_ci    canvas->drawImage(image, 1, 0);
332cb93a386Sopenharmony_ci    surface->flushAndSubmit();
333cb93a386Sopenharmony_ci    canvas->drawImage(image, 2, 0);
334cb93a386Sopenharmony_ci    surface->flushAndSubmit();
335cb93a386Sopenharmony_ci    canvas->drawImage(image, 3, 0);
336cb93a386Sopenharmony_ci    surface->flushAndSubmit();
337cb93a386Sopenharmony_ci    canvas->drawImage(image, 4, 0);
338cb93a386Sopenharmony_ci    surface->flushAndSubmit();
339cb93a386Sopenharmony_ci    canvas->drawImage(image, 5, 0);
340cb93a386Sopenharmony_ci    surface->flushAndSubmit();
341cb93a386Sopenharmony_ci    // Must call these to ensure that all callbacks are performed before the checker is destroyed.
342cb93a386Sopenharmony_ci    image.reset();
343cb93a386Sopenharmony_ci    dContext->flushAndSubmit(true);
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_ci    dContext->deleteBackendTexture(backendTex);
346cb93a386Sopenharmony_ci}
347cb93a386Sopenharmony_ci
348cb93a386Sopenharmony_ci// Test case where promise image fulfill returns nullptr.
349cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageNullFulfill, reporter, ctxInfo) {
350cb93a386Sopenharmony_ci    const int kWidth = 10;
351cb93a386Sopenharmony_ci    const int kHeight = 10;
352cb93a386Sopenharmony_ci
353cb93a386Sopenharmony_ci    auto dContext = ctxInfo.directContext();
354cb93a386Sopenharmony_ci
355cb93a386Sopenharmony_ci    GrBackendFormat backendFormat =
356cb93a386Sopenharmony_ci            dContext->defaultBackendFormat(kRGBA_8888_SkColorType, GrRenderable::kYes);
357cb93a386Sopenharmony_ci    if (!backendFormat.isValid()) {
358cb93a386Sopenharmony_ci        ERRORF(reporter, "No valid default kRGBA_8888 texture format.");
359cb93a386Sopenharmony_ci        return;
360cb93a386Sopenharmony_ci    }
361cb93a386Sopenharmony_ci
362cb93a386Sopenharmony_ci    struct Counts {
363cb93a386Sopenharmony_ci        int fFulfillCount = 0;
364cb93a386Sopenharmony_ci        int fReleaseCount = 0;
365cb93a386Sopenharmony_ci    } counts;
366cb93a386Sopenharmony_ci    auto fulfill = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
367cb93a386Sopenharmony_ci        ++static_cast<Counts*>(ctx)->fFulfillCount;
368cb93a386Sopenharmony_ci        return sk_sp<SkPromiseImageTexture>();
369cb93a386Sopenharmony_ci    };
370cb93a386Sopenharmony_ci    auto release = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
371cb93a386Sopenharmony_ci        ++static_cast<Counts*>(ctx)->fReleaseCount;
372cb93a386Sopenharmony_ci    };
373cb93a386Sopenharmony_ci    GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
374cb93a386Sopenharmony_ci    sk_sp<SkImage> refImg(SkImage_Gpu::MakePromiseTexture(dContext->threadSafeProxy(),
375cb93a386Sopenharmony_ci                                                          backendFormat,
376cb93a386Sopenharmony_ci                                                          {kWidth, kHeight},
377cb93a386Sopenharmony_ci                                                          GrMipmapped::kNo,
378cb93a386Sopenharmony_ci                                                          texOrigin,
379cb93a386Sopenharmony_ci                                                          kRGBA_8888_SkColorType,
380cb93a386Sopenharmony_ci                                                          kPremul_SkAlphaType,
381cb93a386Sopenharmony_ci                                                          nullptr,
382cb93a386Sopenharmony_ci                                                          fulfill,
383cb93a386Sopenharmony_ci                                                          release,
384cb93a386Sopenharmony_ci                                                          &counts));
385cb93a386Sopenharmony_ci
386cb93a386Sopenharmony_ci    SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
387cb93a386Sopenharmony_ci    sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, info);
388cb93a386Sopenharmony_ci    SkCanvas* canvas = surface->getCanvas();
389cb93a386Sopenharmony_ci    // Draw the image a few different ways.
390cb93a386Sopenharmony_ci    canvas->drawImage(refImg, 0, 0);
391cb93a386Sopenharmony_ci    SkPaint paint;
392cb93a386Sopenharmony_ci    paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
393cb93a386Sopenharmony_ci    canvas->drawImage(refImg, 0, 0, SkSamplingOptions(), &paint);
394cb93a386Sopenharmony_ci    auto shader = refImg->makeShader(SkSamplingOptions());
395cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, shader);
396cb93a386Sopenharmony_ci    paint.setShader(std::move(shader));
397cb93a386Sopenharmony_ci    canvas->drawRect(SkRect::MakeWH(1,1), paint);
398cb93a386Sopenharmony_ci    paint.setShader(nullptr);
399cb93a386Sopenharmony_ci    refImg.reset();
400cb93a386Sopenharmony_ci    surface->flushAndSubmit();
401cb93a386Sopenharmony_ci    // We should only call each callback once and we should have made all the calls by this point.
402cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, counts.fFulfillCount == 1);
403cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, counts.fReleaseCount == 1);
404cb93a386Sopenharmony_ci}
405