blob: 3e47b66cbc0deef81884a85f80c3a35ca5beae25 [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,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400172 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kYes, GrProtected::kNo);
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) {
Robert Phillips62221e72019-07-24 15:07:38 -0400236 // Try making two promise SkImages backed by the same texture but with different uses/views.
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500237 // This will only be testable on backends where a single texture format (8bit red unorm) can
Robert Phillips62221e72019-07-24 15:07:38 -0400238 // be used for both alpha and gray image color types.
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500239
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 Phillips0a15cc62019-07-30 12:49:10 -0400246 GrBackendFormat gray8Format = ctx->defaultBackendFormat(kGray_8_SkColorType,
247 GrRenderable::kNo);
248 GrBackendFormat alpha8Format = ctx->defaultBackendFormat(kAlpha_8_SkColorType,
249 GrRenderable::kNo);
Robert Phillips62221e72019-07-24 15:07:38 -0400250 if (gray8Format != alpha8Format) {
251 // kGray_8 and kAlpha_8 won't share the same backend texture
Brian Salomonf55e8d52019-01-30 17:28:20 -0500252 return;
253 }
Robert Phillips62221e72019-07-24 15:07:38 -0400254
255 GrBackendTexture grayBackendTex = ctx->createBackendTexture(
256 kWidth, kHeight, gray8Format,
257 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
258 REPORTER_ASSERT(reporter, grayBackendTex.isValid());
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500259
260 SkImageInfo info =
261 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
262 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
263 SkCanvas* canvas = surface->getCanvas();
264
Robert Phillips62221e72019-07-24 15:07:38 -0400265 PromiseTextureChecker promiseChecker(grayBackendTex, reporter, true);
266
Brian Salomon7d88f312019-02-28 10:03:03 -0500267 sk_sp<SkImage> alphaImg(SkImage_Gpu::MakePromiseTexture(
Robert Phillips62221e72019-07-24 15:07:38 -0400268 ctx, alpha8Format, kWidth, kHeight, GrMipMapped::kNo,
Brian Salomon7d88f312019-02-28 10:03:03 -0500269 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
270 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500271 PromiseTextureChecker::Done, &promiseChecker,
272 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon7d88f312019-02-28 10:03:03 -0500273 REPORTER_ASSERT(reporter, alphaImg);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500274
Brian Salomon7d88f312019-02-28 10:03:03 -0500275 sk_sp<SkImage> grayImg(SkImage_Gpu::MakePromiseTexture(
Robert Phillips62221e72019-07-24 15:07:38 -0400276 ctx, gray8Format, kWidth, kHeight, GrMipMapped::kNo,
Brian Salomon7d88f312019-02-28 10:03:03 -0500277 kBottomLeft_GrSurfaceOrigin, kGray_8_SkColorType, kOpaque_SkAlphaType, nullptr,
278 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500279 PromiseTextureChecker::Done, &promiseChecker,
280 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon7d88f312019-02-28 10:03:03 -0500281 REPORTER_ASSERT(reporter, grayImg);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500282
Brian Salomon7d88f312019-02-28 10:03:03 -0500283 canvas->drawImage(alphaImg, 0, 0);
284 canvas->drawImage(grayImg, 1, 1);
Robert Phillips9882dae2019-03-04 11:00:10 -0500285 surface->flush();
Brian Salomon7d88f312019-02-28 10:03:03 -0500286 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500287 check_only_fulfilled(reporter, promiseChecker, 2);
Brian Salomon7d88f312019-02-28 10:03:03 -0500288
Robert Phillips62221e72019-07-24 15:07:38 -0400289 // Because they use different backend formats, each image should have created a different
290 // GrTexture and they both should still be cached.
Brian Salomon7d88f312019-02-28 10:03:03 -0500291 ctx->priv().getResourceCache()->purgeAsNeeded();
292
293 auto keys = promiseChecker.uniqueKeys();
294 REPORTER_ASSERT(reporter, keys.count() == 2);
295 for (const auto& key : keys) {
296 auto surf = ctx->priv().resourceProvider()->findByUniqueKey<GrSurface>(key);
297 REPORTER_ASSERT(reporter, surf && surf->asTexture());
298 if (surf && surf->asTexture()) {
Robert Phillips62221e72019-07-24 15:07:38 -0400299 GrTexture* texture = surf->asTexture();
300
301 // The backend texture should be shared between the two uses
302 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(
303 grayBackendTex, texture->getBackendTexture()));
Brian Salomonf55e8d52019-01-30 17:28:20 -0500304 }
Brian Salomon7d88f312019-02-28 10:03:03 -0500305 }
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500306
Brian Salomon0cc57542019-03-08 13:28:46 -0500307 // Invalidate the backing texture, this should invalidate the keys.
Brian Salomon7d88f312019-02-28 10:03:03 -0500308 promiseChecker.releaseTexture();
309 ctx->priv().getResourceCache()->purgeAsNeeded();
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500310
Brian Salomon7d88f312019-02-28 10:03:03 -0500311 for (const auto& key : keys) {
312 auto surf = ctx->priv().resourceProvider()->findByUniqueKey<GrSurface>(key);
313 REPORTER_ASSERT(reporter, !surf);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500314 }
Brian Salomon876a0172019-03-08 11:12:14 -0500315 alphaImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500316 ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
317 check_fulfill_and_release_cnts(reporter, promiseChecker, 2,
318 ReleaseBalanceExpectation::kUnbalancedByOne,
319 DoneBalanceExpectation::kUnbalancedByOne);
Brian Salomon876a0172019-03-08 11:12:14 -0500320 grayImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500321 ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
322 check_all_done(reporter, promiseChecker, 2);
Robert Phillips62221e72019-07-24 15:07:38 -0400323 ctx->deleteBackendTexture(grayBackendTex);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500324}
Brian Salomon9bc76d92019-01-24 12:18:33 -0500325
326DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
327 const int kWidth = 10;
328 const int kHeight = 10;
329
330 // Different ways of killing contexts.
331 using DeathFn = std::function<void(sk_gpu_test::GrContextFactory*, GrContext*)>;
332 DeathFn destroy = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
333 factory->destroyContexts();
334 };
335 DeathFn abandon = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
336 context->abandonContext();
337 };
338 DeathFn releaseResourcesAndAbandon = [](sk_gpu_test::GrContextFactory* factory,
339 GrContext* context) {
340 context->releaseResourcesAndAbandonContext();
341 };
342
343 for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
344 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
345 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
346 // and http://skbug.com/8275
347 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
348 if (api == GrBackendApi::kVulkan) {
349 continue;
350 }
351 DeathFn contextKillers[] = {destroy, abandon, releaseResourcesAndAbandon};
352 for (auto contextDeath : contextKillers) {
353 sk_gpu_test::GrContextFactory factory;
354 auto ctx = factory.get(contextType);
355 if (!ctx) {
356 continue;
357 }
Brian Salomon9bc76d92019-01-24 12:18:33 -0500358
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400359 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400360 kWidth, kHeight, kAlpha_8_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400361 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500362 REPORTER_ASSERT(reporter, backendTex.isValid());
363
364 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
365 kPremul_SkAlphaType);
366 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
367 SkCanvas* canvas = surface->getCanvas();
368
369 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
370 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
371 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
Brian Salomonf55e8d52019-01-30 17:28:20 -0500372 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
373 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500374 PromiseTextureChecker::Done, &promiseChecker,
375 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500376 REPORTER_ASSERT(reporter, image);
377
378 canvas->drawImage(image, 0, 0);
379 image.reset();
380 // If the surface still holds a ref to the context then the factory will not be able
381 // to destroy the context (and instead will release-all-and-abandon).
382 surface.reset();
383
384 ctx->flush();
385 contextDeath(&factory, ctx);
386
Brian Salomon0cc57542019-03-08 13:28:46 -0500387 check_all_done(reporter, promiseChecker);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500388 }
389 }
390}
391
392DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxInfo) {
393 const int kWidth = 10;
394 const int kHeight = 10;
395
396 GrContext* ctx = ctxInfo.grContext();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500397
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400398 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400399 kWidth, kHeight, kAlpha_8_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400400 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500401 REPORTER_ASSERT(reporter, backendTex.isValid());
402
403 SkImageInfo info =
404 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
405 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
406 SkCanvas* canvas = surface->getCanvas();
407
408 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
409 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
410 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
411 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
412 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500413 PromiseTextureChecker::Done, &promiseChecker,
414 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500415 REPORTER_ASSERT(reporter, image);
416
417 // Make the cache full. This tests that we don't preemptively purge cached textures for
418 // fulfillment due to cache pressure.
Robert Phillipscf39f372019-09-03 10:29:20 -0400419 static constexpr int kMaxBytes = 1;
420 ctx->setResourceCacheLimit(kMaxBytes);
421 SkTArray<sk_sp<GrTexture>> textures;
422 for (int i = 0; i < 5; ++i) {
Brian Salomon9bc76d92019-01-24 12:18:33 -0500423 GrSurfaceDesc desc;
Brian Salomon9bc76d92019-01-24 12:18:33 -0500424 desc.fWidth = desc.fHeight = 100;
Brian Salomon4eb38b72019-08-05 12:58:39 -0400425 auto format = ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
426 GrRenderable::kNo);
Robert Phillipscf39f372019-09-03 10:29:20 -0400427 textures.emplace_back(ctx->priv().resourceProvider()->createTexture(
Brian Salomona90382f2019-09-17 09:01:56 -0400428 desc, format, GrRenderable::kNo, 1, GrMipMapped::kNo, SkBudgeted::kYes,
429 GrProtected::kNo));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500430 REPORTER_ASSERT(reporter, textures[i]);
431 }
432
Robert Phillipscf39f372019-09-03 10:29:20 -0400433 size_t bytesUsed;
434
435 ctx->getResourceCacheUsage(nullptr, &bytesUsed);
436 REPORTER_ASSERT(reporter, bytesUsed > kMaxBytes);
437
Brian Salomon9bc76d92019-01-24 12:18:33 -0500438 // Relying on the asserts in the promiseImageChecker to ensure that fulfills and releases are
439 // properly ordered.
440 canvas->drawImage(image, 0, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500441 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500442 canvas->drawImage(image, 1, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500443 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500444 canvas->drawImage(image, 2, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500445 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500446 canvas->drawImage(image, 3, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500447 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500448 canvas->drawImage(image, 4, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500449 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500450 canvas->drawImage(image, 5, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500451 surface->flush();
Brian Salomon876a0172019-03-08 11:12:14 -0500452 // Must call these to ensure that all callbacks are performed before the checker is destroyed.
453 image.reset();
454 ctx->flush();
Robert Phillips9b16f812019-05-17 10:01:21 -0400455 ctx->priv().getGpu()->testingOnly_flushGpuAndSync();
Brian Salomon876a0172019-03-08 11:12:14 -0500456
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400457 ctx->deleteBackendTexture(backendTex);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500458}
Brian Salomond538d3d2019-04-04 12:18:17 -0400459
460// Test case where promise image fulfill returns nullptr.
461DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageNullFulfill, reporter, ctxInfo) {
462 const int kWidth = 10;
463 const int kHeight = 10;
464
465 GrContext* ctx = ctxInfo.grContext();
Brian Salomond538d3d2019-04-04 12:18:17 -0400466
467 // Do all this just to get a valid backend format for the image.
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400468 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400469 kWidth, kHeight, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400470 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kYes, GrProtected::kNo);
Brian Salomond538d3d2019-04-04 12:18:17 -0400471 REPORTER_ASSERT(reporter, backendTex.isValid());
472 GrBackendFormat backendFormat = backendTex.getBackendFormat();
473 REPORTER_ASSERT(reporter, backendFormat.isValid());
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400474 ctx->deleteBackendTexture(backendTex);
Brian Salomond538d3d2019-04-04 12:18:17 -0400475
476 struct Counts {
477 int fFulfillCount = 0;
478 int fReleaseCount = 0;
479 int fDoneCount = 0;
480 } counts;
481 auto fulfill = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
482 ++static_cast<Counts*>(ctx)->fFulfillCount;
483 return sk_sp<SkPromiseImageTexture>();
484 };
485 auto release = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
486 ++static_cast<Counts*>(ctx)->fReleaseCount;
487 };
488 auto done = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
489 ++static_cast<Counts*>(ctx)->fDoneCount;
490 };
491 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
492 sk_sp<SkImage> refImg(SkImage_Gpu::MakePromiseTexture(
493 ctx, backendFormat, kWidth, kHeight, GrMipMapped::kNo, texOrigin,
494 kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, fulfill, release, done, &counts,
495 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
496
497 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
498 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
499 SkCanvas* canvas = surface->getCanvas();
500 // Draw the image a few different ways.
501 canvas->drawImage(refImg, 0, 0);
502 SkPaint paint;
Mike Reedb286bc22019-04-08 16:23:20 -0400503 paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
Brian Salomond538d3d2019-04-04 12:18:17 -0400504 canvas->drawImage(refImg, 0, 0, &paint);
505 auto shader = refImg->makeShader(SkTileMode::kClamp, SkTileMode::kClamp);
506 REPORTER_ASSERT(reporter, shader);
507 paint.setShader(std::move(shader));
508 canvas->drawRect(SkRect::MakeWH(1,1), paint);
509 paint.setShader(nullptr);
510 refImg.reset();
511 surface->flush();
512 // We should only call each callback once and we should have made all the calls by this point.
513 REPORTER_ASSERT(reporter, counts.fFulfillCount == 1);
514 REPORTER_ASSERT(reporter, counts.fReleaseCount == 1);
515 REPORTER_ASSERT(reporter, counts.fDoneCount == 1);
516}