blob: 38c513e0997b5663143eee9eb8a91e78884c31da [file] [log] [blame]
Greg Daniela8d92112018-03-09 12:05:04 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tests/Test.h"
Greg Daniela8d92112018-03-09 12:05:04 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkColorFilter.h"
11#include "include/core/SkPromiseImageTexture.h"
12#include "include/gpu/GrBackendSurface.h"
13#include "include/gpu/GrTexture.h"
14#include "src/gpu/GrContextPriv.h"
15#include "src/gpu/GrGpu.h"
16#include "src/image/SkImage_Gpu.h"
Greg Daniela8d92112018-03-09 12:05:04 -050017
18using namespace sk_gpu_test;
19
20struct PromiseTextureChecker {
Brian Salomon9bc76d92019-01-24 12:18:33 -050021 // 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)
Brian Salomon3f4cd772019-01-11 16:03:19 -050025 : fTexture(SkPromiseImageTexture::Make(tex))
Brian Salomon9bc76d92019-01-24 12:18:33 -050026 , fReporter(reporter)
27 , fShared(shared)
Greg Daniela8d92112018-03-09 12:05:04 -050028 , fFulfillCount(0)
Greg Daniel7278d682018-03-16 14:57:21 -040029 , fReleaseCount(0)
30 , fDoneCount(0) {}
Brian Salomon3f4cd772019-01-11 16:03:19 -050031 sk_sp<SkPromiseImageTexture> fTexture;
Brian Salomon9bc76d92019-01-24 12:18:33 -050032 skiatest::Reporter* fReporter;
33 bool fShared;
Greg Daniela8d92112018-03-09 12:05:04 -050034 int fFulfillCount;
35 int fReleaseCount;
Greg Daniel7278d682018-03-16 14:57:21 -040036 int fDoneCount;
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050037
38 /**
Brian Salomon7d88f312019-02-28 10:03:03 -050039 * Releases the SkPromiseImageTexture. Used to test that cached GrTexture representations
40 * in the cache are freed.
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050041 */
Brian Salomon7d88f312019-02-28 10:03:03 -050042 void releaseTexture() { fTexture.reset(); }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050043
44 SkTArray<GrUniqueKey> uniqueKeys() const {
Brian Salomon3f4cd772019-01-11 16:03:19 -050045 return fTexture->testingOnly_uniqueKeysToInvalidate();
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050046 }
47
Brian Salomon3f4cd772019-01-11 16:03:19 -050048 static sk_sp<SkPromiseImageTexture> Fulfill(void* self) {
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050049 auto checker = static_cast<PromiseTextureChecker*>(self);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050050 checker->fFulfillCount++;
Brian Salomon3f4cd772019-01-11 16:03:19 -050051 return checker->fTexture;
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050052 }
Brian Salomon9bc76d92019-01-24 12:18:33 -050053 static void Release(void* self) {
54 auto checker = static_cast<PromiseTextureChecker*>(self);
55 checker->fReleaseCount++;
56 if (!checker->fShared) {
57 // This is only used in a single threaded fashion with a single promise image. So
58 // every fulfill should be balanced by a release before the next fulfill.
59 REPORTER_ASSERT(checker->fReporter, checker->fReleaseCount == checker->fFulfillCount);
60 }
61 }
Greg Daniel7278d682018-03-16 14:57:21 -040062 static void Done(void* self) {
63 static_cast<PromiseTextureChecker*>(self)->fDoneCount++;
64 }
Greg Daniela8d92112018-03-09 12:05:04 -050065};
66
Brian Salomon0cc57542019-03-08 13:28:46 -050067enum class ReleaseBalanceExpectation {
Brian Salomonf55e8d52019-01-30 17:28:20 -050068 kBalanced,
Brian Salomon0cc57542019-03-08 13:28:46 -050069 kAllUnbalanced,
70 kUnbalancedByOne,
Brian Salomonf55e8d52019-01-30 17:28:20 -050071};
72
Brian Salomon0cc57542019-03-08 13:28:46 -050073enum class DoneBalanceExpectation {
74 kBalanced,
75 kAllUnbalanced,
76 kUnknown,
77 kUnbalancedByOne,
78 kBalancedOrOffByOne,
79};
80
81static void check_fulfill_and_release_cnts(skiatest::Reporter* reporter,
82 const PromiseTextureChecker& promiseChecker,
Greg Daniela8d92112018-03-09 12:05:04 -050083 int expectedFulfillCnt,
Brian Salomon0cc57542019-03-08 13:28:46 -050084 ReleaseBalanceExpectation releaseBalanceExpecation,
85 DoneBalanceExpectation doneBalanceExpecation) {
86 REPORTER_ASSERT(reporter, promiseChecker.fFulfillCount == expectedFulfillCnt);
87 if (!expectedFulfillCnt) {
88 // Release and Done should only ever be called after Fulfill.
89 REPORTER_ASSERT(reporter, !promiseChecker.fReleaseCount);
90 REPORTER_ASSERT(reporter, !promiseChecker.fDoneCount);
91 return;
Greg Daniela8d92112018-03-09 12:05:04 -050092 }
Brian Salomon0cc57542019-03-08 13:28:46 -050093 int releaseDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
94 switch (releaseBalanceExpecation) {
95 case ReleaseBalanceExpectation::kBalanced:
96 REPORTER_ASSERT(reporter, !releaseDiff);
97 break;
98 case ReleaseBalanceExpectation::kAllUnbalanced:
99 REPORTER_ASSERT(reporter, releaseDiff == promiseChecker.fFulfillCount);
100 break;
101 case ReleaseBalanceExpectation::kUnbalancedByOne:
102 REPORTER_ASSERT(reporter, releaseDiff == 1);
103 break;
Greg Daniela8d92112018-03-09 12:05:04 -0500104 }
Brian Salomon0cc57542019-03-08 13:28:46 -0500105 int doneDiff = promiseChecker.fFulfillCount - promiseChecker.fDoneCount;
106 switch (doneBalanceExpecation) {
107 case DoneBalanceExpectation::kBalanced:
108 REPORTER_ASSERT(reporter, !doneDiff);
109 break;
110 case DoneBalanceExpectation::kAllUnbalanced:
111 REPORTER_ASSERT(reporter, doneDiff == promiseChecker.fFulfillCount);
112 break;
113 case DoneBalanceExpectation::kUnknown:
114 REPORTER_ASSERT(reporter, doneDiff >= 0 && doneDiff <= promiseChecker.fFulfillCount);
115 break;
116 case DoneBalanceExpectation::kUnbalancedByOne:
117 REPORTER_ASSERT(reporter, doneDiff == 1);
118 break;
119 case DoneBalanceExpectation::kBalancedOrOffByOne:
120 REPORTER_ASSERT(reporter, doneDiff == 0 || doneDiff == 1);
121 break;
Greg Daniela8d92112018-03-09 12:05:04 -0500122 }
Brian Salomon0cc57542019-03-08 13:28:46 -0500123}
Greg Daniela8d92112018-03-09 12:05:04 -0500124
Brian Salomon0cc57542019-03-08 13:28:46 -0500125static void check_unfulfilled(const PromiseTextureChecker& promiseChecker,
126 skiatest::Reporter* reporter) {
127 check_fulfill_and_release_cnts(reporter, promiseChecker, 0,
128 ReleaseBalanceExpectation::kBalanced,
129 DoneBalanceExpectation::kBalanced);
130}
131
132static void check_only_fulfilled(skiatest::Reporter* reporter,
133 const PromiseTextureChecker& promiseChecker,
134 int expectedFulfillCnt = 1) {
135 check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
136 ReleaseBalanceExpectation::kAllUnbalanced,
137 DoneBalanceExpectation::kAllUnbalanced);
138}
139
140static void check_all_flushed_but_not_synced(skiatest::Reporter* reporter,
141 const PromiseTextureChecker& promiseChecker,
142 GrBackendApi api,
143 int expectedFulfillCnt = 1) {
144 DoneBalanceExpectation doneBalanceExpectation = DoneBalanceExpectation::kBalanced;
145 // On Vulkan Done isn't guaranteed to be called until a sync has occurred.
146 if (api == GrBackendApi::kVulkan) {
147 doneBalanceExpectation = expectedFulfillCnt == 1
148 ? DoneBalanceExpectation::kBalancedOrOffByOne
149 : DoneBalanceExpectation::kUnknown;
Greg Daniel7278d682018-03-16 14:57:21 -0400150 }
Brian Salomon0cc57542019-03-08 13:28:46 -0500151 check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
152 ReleaseBalanceExpectation::kBalanced, doneBalanceExpectation);
153}
Greg Daniel7278d682018-03-16 14:57:21 -0400154
Brian Salomon0cc57542019-03-08 13:28:46 -0500155static void check_all_done(skiatest::Reporter* reporter,
156 const PromiseTextureChecker& promiseChecker,
157 int expectedFulfillCnt = 1) {
158 check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
159 ReleaseBalanceExpectation::kBalanced,
160 DoneBalanceExpectation::kBalanced);
Greg Daniela8d92112018-03-09 12:05:04 -0500161}
162
Brian Salomon7d88f312019-02-28 10:03:03 -0500163DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
Brian Salomonf55e8d52019-01-30 17:28:20 -0500164 const int kWidth = 10;
165 const int kHeight = 10;
166
167 GrContext* ctx = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500168 GrGpu* gpu = ctx->priv().getGpu();
Brian Salomonf55e8d52019-01-30 17:28:20 -0500169
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400170 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400171 kWidth, kHeight, kRGBA_8888_SkColorType,
172 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kYes);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500173 REPORTER_ASSERT(reporter, backendTex.isValid());
174
175 GrBackendFormat backendFormat = backendTex.getBackendFormat();
176 REPORTER_ASSERT(reporter, backendFormat.isValid());
177
178 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
179 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
180 sk_sp<SkImage> refImg(
181 SkImage_Gpu::MakePromiseTexture(
182 ctx, backendFormat, kWidth, kHeight,
183 GrMipMapped::kNo, texOrigin,
184 kRGBA_8888_SkColorType, kPremul_SkAlphaType,
185 nullptr,
186 PromiseTextureChecker::Fulfill,
187 PromiseTextureChecker::Release,
188 PromiseTextureChecker::Done,
Brian Salomon0cc57542019-03-08 13:28:46 -0500189 &promiseChecker,
190 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomonf55e8d52019-01-30 17:28:20 -0500191
192 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
193 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
194 SkCanvas* canvas = surface->getCanvas();
195
Brian Salomond716d442019-03-07 15:23:30 +0000196 canvas->drawImage(refImg, 0, 0);
Brian Salomon0cc57542019-03-08 13:28:46 -0500197 check_unfulfilled(promiseChecker, reporter);
Brian Salomond716d442019-03-07 15:23:30 +0000198
Robert Phillips9882dae2019-03-04 11:00:10 -0500199 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500200 // We still own the image so we should not have called Release or Done.
201 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500202
203 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500204 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500205
206 canvas->drawImage(refImg, 0, 0);
207 canvas->drawImage(refImg, 0, 0);
208
Robert Phillips9882dae2019-03-04 11:00:10 -0500209 surface->flush();
Brian Salomonf55e8d52019-01-30 17:28:20 -0500210
211 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500212 // Image should still be fulfilled from the first time we drew/flushed it.
213 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500214
215 canvas->drawImage(refImg, 0, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500216 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500217 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500218
219 canvas->drawImage(refImg, 0, 0);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500220 refImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500221 // We no longer own the image but the last draw is still unflushed.
222 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500223
Robert Phillips9882dae2019-03-04 11:00:10 -0500224 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500225 // Flushing should have called Release. Depending on the backend and timing it may have called
226 // done.
227 check_all_flushed_but_not_synced(reporter, promiseChecker, ctx->backend());
Brian Salomonf55e8d52019-01-30 17:28:20 -0500228 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500229 // Now Done should definitely have been called.
230 check_all_done(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500231
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400232 ctx->deleteBackendTexture(backendTex);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500233}
234
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500235DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig, reporter, ctxInfo) {
236 // Try making two promise SkImages backed by the same texture but with different configs.
237 // This will only be testable on backends where a single texture format (8bit red unorm) can
238 // be used for alpha and gray image color types.
239
240 const int kWidth = 10;
241 const int kHeight = 10;
242
243 GrContext* ctx = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500244 GrGpu* gpu = ctx->priv().getGpu();
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500245
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400246 GrBackendTexture backendTex1 = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400247 kWidth, kHeight, kGray_8_SkColorType,
248 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500249 REPORTER_ASSERT(reporter, backendTex1.isValid());
250
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400251 GrBackendTexture backendTex2 = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400252 kWidth, kHeight, kAlpha_8_SkColorType,
253 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500254 REPORTER_ASSERT(reporter, backendTex2.isValid());
Brian Salomonf55e8d52019-01-30 17:28:20 -0500255 if (backendTex1.getBackendFormat() != backendTex2.getBackendFormat()) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400256 ctx->deleteBackendTexture(backendTex1);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500257 return;
258 }
259 // We only needed this texture to check that alpha and gray color types use the same format.
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400260 ctx->deleteBackendTexture(backendTex2);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500261
262 SkImageInfo info =
263 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
264 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
265 SkCanvas* canvas = surface->getCanvas();
266
Brian Salomon7d88f312019-02-28 10:03:03 -0500267 PromiseTextureChecker promiseChecker(backendTex1, reporter, true);
268 sk_sp<SkImage> alphaImg(SkImage_Gpu::MakePromiseTexture(
269 ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
270 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
271 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500272 PromiseTextureChecker::Done, &promiseChecker,
273 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon7d88f312019-02-28 10:03:03 -0500274 REPORTER_ASSERT(reporter, alphaImg);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500275
Brian Salomon7d88f312019-02-28 10:03:03 -0500276 sk_sp<SkImage> grayImg(SkImage_Gpu::MakePromiseTexture(
277 ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
278 kBottomLeft_GrSurfaceOrigin, kGray_8_SkColorType, kOpaque_SkAlphaType, nullptr,
279 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500280 PromiseTextureChecker::Done, &promiseChecker,
281 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon7d88f312019-02-28 10:03:03 -0500282 REPORTER_ASSERT(reporter, grayImg);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500283
Brian Salomon7d88f312019-02-28 10:03:03 -0500284 canvas->drawImage(alphaImg, 0, 0);
285 canvas->drawImage(grayImg, 1, 1);
Robert Phillips9882dae2019-03-04 11:00:10 -0500286 surface->flush();
Brian Salomon7d88f312019-02-28 10:03:03 -0500287 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500288 check_only_fulfilled(reporter, promiseChecker, 2);
Brian Salomon7d88f312019-02-28 10:03:03 -0500289
290 // Because they use different configs, each image should have created a different GrTexture
291 // and they both should still be cached.
292 ctx->priv().getResourceCache()->purgeAsNeeded();
293
294 auto keys = promiseChecker.uniqueKeys();
295 REPORTER_ASSERT(reporter, keys.count() == 2);
296 for (const auto& key : keys) {
297 auto surf = ctx->priv().resourceProvider()->findByUniqueKey<GrSurface>(key);
298 REPORTER_ASSERT(reporter, surf && surf->asTexture());
299 if (surf && surf->asTexture()) {
300 REPORTER_ASSERT(reporter,
301 !GrBackendTexture::TestingOnly_Equals(
302 backendTex1, surf->asTexture()->getBackendTexture()));
Brian Salomonf55e8d52019-01-30 17:28:20 -0500303 }
Brian Salomon7d88f312019-02-28 10:03:03 -0500304 }
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500305
Brian Salomon0cc57542019-03-08 13:28:46 -0500306 // Invalidate the backing texture, this should invalidate the keys.
Brian Salomon7d88f312019-02-28 10:03:03 -0500307 promiseChecker.releaseTexture();
308 ctx->priv().getResourceCache()->purgeAsNeeded();
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500309
Brian Salomon7d88f312019-02-28 10:03:03 -0500310 for (const auto& key : keys) {
311 auto surf = ctx->priv().resourceProvider()->findByUniqueKey<GrSurface>(key);
312 REPORTER_ASSERT(reporter, !surf);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500313 }
Brian Salomon876a0172019-03-08 11:12:14 -0500314 alphaImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500315 ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
316 check_fulfill_and_release_cnts(reporter, promiseChecker, 2,
317 ReleaseBalanceExpectation::kUnbalancedByOne,
318 DoneBalanceExpectation::kUnbalancedByOne);
Brian Salomon876a0172019-03-08 11:12:14 -0500319 grayImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500320 ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
321 check_all_done(reporter, promiseChecker, 2);
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400322 ctx->deleteBackendTexture(backendTex1);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500323}
Brian Salomon9bc76d92019-01-24 12:18:33 -0500324
325DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
326 const int kWidth = 10;
327 const int kHeight = 10;
328
329 // Different ways of killing contexts.
330 using DeathFn = std::function<void(sk_gpu_test::GrContextFactory*, GrContext*)>;
331 DeathFn destroy = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
332 factory->destroyContexts();
333 };
334 DeathFn abandon = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
335 context->abandonContext();
336 };
337 DeathFn releaseResourcesAndAbandon = [](sk_gpu_test::GrContextFactory* factory,
338 GrContext* context) {
339 context->releaseResourcesAndAbandonContext();
340 };
341
342 for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
343 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
344 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
345 // and http://skbug.com/8275
346 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
347 if (api == GrBackendApi::kVulkan) {
348 continue;
349 }
350 DeathFn contextKillers[] = {destroy, abandon, releaseResourcesAndAbandon};
351 for (auto contextDeath : contextKillers) {
352 sk_gpu_test::GrContextFactory factory;
353 auto ctx = factory.get(contextType);
354 if (!ctx) {
355 continue;
356 }
Brian Salomon9bc76d92019-01-24 12:18:33 -0500357
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400358 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400359 kWidth, kHeight, kAlpha_8_SkColorType,
360 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500361 REPORTER_ASSERT(reporter, backendTex.isValid());
362
363 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
364 kPremul_SkAlphaType);
365 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
366 SkCanvas* canvas = surface->getCanvas();
367
368 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
369 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
370 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
Brian Salomonf55e8d52019-01-30 17:28:20 -0500371 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
372 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500373 PromiseTextureChecker::Done, &promiseChecker,
374 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500375 REPORTER_ASSERT(reporter, image);
376
377 canvas->drawImage(image, 0, 0);
378 image.reset();
379 // If the surface still holds a ref to the context then the factory will not be able
380 // to destroy the context (and instead will release-all-and-abandon).
381 surface.reset();
382
383 ctx->flush();
384 contextDeath(&factory, ctx);
385
Brian Salomon0cc57542019-03-08 13:28:46 -0500386 check_all_done(reporter, promiseChecker);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500387 }
388 }
389}
390
391DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxInfo) {
392 const int kWidth = 10;
393 const int kHeight = 10;
394
395 GrContext* ctx = ctxInfo.grContext();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500396
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400397 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400398 kWidth, kHeight, kAlpha_8_SkColorType,
399 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500400 REPORTER_ASSERT(reporter, backendTex.isValid());
401
402 SkImageInfo info =
403 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
404 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
405 SkCanvas* canvas = surface->getCanvas();
406
407 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
408 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
409 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
410 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
411 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500412 PromiseTextureChecker::Done, &promiseChecker,
413 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500414 REPORTER_ASSERT(reporter, image);
415
416 // Make the cache full. This tests that we don't preemptively purge cached textures for
417 // fulfillment due to cache pressure.
418 static constexpr int kMaxResources = 10;
419 static constexpr int kMaxBytes = 100;
420 ctx->setResourceCacheLimits(kMaxResources, kMaxBytes);
421 sk_sp<GrTexture> textures[2 * kMaxResources];
422 for (int i = 0; i < 2 * kMaxResources; ++i) {
423 GrSurfaceDesc desc;
424 desc.fConfig = kRGBA_8888_GrPixelConfig;
425 desc.fWidth = desc.fHeight = 100;
Robert Phillips9313aa72019-04-09 18:41:27 -0400426 textures[i] = ctx->priv().resourceProvider()->createTexture(
427 desc, SkBudgeted::kYes, GrResourceProvider::Flags::kNoPendingIO);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500428 REPORTER_ASSERT(reporter, textures[i]);
429 }
430
431 // Relying on the asserts in the promiseImageChecker to ensure that fulfills and releases are
432 // properly ordered.
433 canvas->drawImage(image, 0, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500434 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500435 canvas->drawImage(image, 1, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500436 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500437 canvas->drawImage(image, 2, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500438 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500439 canvas->drawImage(image, 3, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500440 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500441 canvas->drawImage(image, 4, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500442 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500443 canvas->drawImage(image, 5, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500444 surface->flush();
Brian Salomon876a0172019-03-08 11:12:14 -0500445 // Must call these to ensure that all callbacks are performed before the checker is destroyed.
446 image.reset();
447 ctx->flush();
Robert Phillips9b16f812019-05-17 10:01:21 -0400448 ctx->priv().getGpu()->testingOnly_flushGpuAndSync();
Brian Salomon876a0172019-03-08 11:12:14 -0500449
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400450 ctx->deleteBackendTexture(backendTex);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500451}
Brian Salomond538d3d2019-04-04 12:18:17 -0400452
453// Test case where promise image fulfill returns nullptr.
454DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageNullFulfill, reporter, ctxInfo) {
455 const int kWidth = 10;
456 const int kHeight = 10;
457
458 GrContext* ctx = ctxInfo.grContext();
Brian Salomond538d3d2019-04-04 12:18:17 -0400459
460 // Do all this just to get a valid backend format for the image.
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400461 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400462 kWidth, kHeight, kRGBA_8888_SkColorType,
463 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kYes);
Brian Salomond538d3d2019-04-04 12:18:17 -0400464 REPORTER_ASSERT(reporter, backendTex.isValid());
465 GrBackendFormat backendFormat = backendTex.getBackendFormat();
466 REPORTER_ASSERT(reporter, backendFormat.isValid());
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400467 ctx->deleteBackendTexture(backendTex);
Brian Salomond538d3d2019-04-04 12:18:17 -0400468
469 struct Counts {
470 int fFulfillCount = 0;
471 int fReleaseCount = 0;
472 int fDoneCount = 0;
473 } counts;
474 auto fulfill = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
475 ++static_cast<Counts*>(ctx)->fFulfillCount;
476 return sk_sp<SkPromiseImageTexture>();
477 };
478 auto release = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
479 ++static_cast<Counts*>(ctx)->fReleaseCount;
480 };
481 auto done = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
482 ++static_cast<Counts*>(ctx)->fDoneCount;
483 };
484 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
485 sk_sp<SkImage> refImg(SkImage_Gpu::MakePromiseTexture(
486 ctx, backendFormat, kWidth, kHeight, GrMipMapped::kNo, texOrigin,
487 kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, fulfill, release, done, &counts,
488 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
489
490 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
491 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
492 SkCanvas* canvas = surface->getCanvas();
493 // Draw the image a few different ways.
494 canvas->drawImage(refImg, 0, 0);
495 SkPaint paint;
Mike Reedb286bc22019-04-08 16:23:20 -0400496 paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
Brian Salomond538d3d2019-04-04 12:18:17 -0400497 canvas->drawImage(refImg, 0, 0, &paint);
498 auto shader = refImg->makeShader(SkTileMode::kClamp, SkTileMode::kClamp);
499 REPORTER_ASSERT(reporter, shader);
500 paint.setShader(std::move(shader));
501 canvas->drawRect(SkRect::MakeWH(1,1), paint);
502 paint.setShader(nullptr);
503 refImg.reset();
504 surface->flush();
505 // We should only call each callback once and we should have made all the calls by this point.
506 REPORTER_ASSERT(reporter, counts.fFulfillCount == 1);
507 REPORTER_ASSERT(reporter, counts.fReleaseCount == 1);
508 REPORTER_ASSERT(reporter, counts.fDoneCount == 1);
509}