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