blob: 5981f4ddc4a359d4f256796b54acea9e9f53b9bb [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()));
304
305 // but the view of them from the GrTexture should've been transmuted into the
306 // specific pixel configs
307 REPORTER_ASSERT(reporter, texture->config() == kAlpha_8_as_Red_GrPixelConfig ||
308 texture->config() == kGray_8_as_Red_GrPixelConfig);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500309 }
Brian Salomon7d88f312019-02-28 10:03:03 -0500310 }
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500311
Brian Salomon0cc57542019-03-08 13:28:46 -0500312 // Invalidate the backing texture, this should invalidate the keys.
Brian Salomon7d88f312019-02-28 10:03:03 -0500313 promiseChecker.releaseTexture();
314 ctx->priv().getResourceCache()->purgeAsNeeded();
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500315
Brian Salomon7d88f312019-02-28 10:03:03 -0500316 for (const auto& key : keys) {
317 auto surf = ctx->priv().resourceProvider()->findByUniqueKey<GrSurface>(key);
318 REPORTER_ASSERT(reporter, !surf);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500319 }
Brian Salomon876a0172019-03-08 11:12:14 -0500320 alphaImg.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_fulfill_and_release_cnts(reporter, promiseChecker, 2,
323 ReleaseBalanceExpectation::kUnbalancedByOne,
324 DoneBalanceExpectation::kUnbalancedByOne);
Brian Salomon876a0172019-03-08 11:12:14 -0500325 grayImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500326 ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
327 check_all_done(reporter, promiseChecker, 2);
Robert Phillips62221e72019-07-24 15:07:38 -0400328 ctx->deleteBackendTexture(grayBackendTex);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500329}
Brian Salomon9bc76d92019-01-24 12:18:33 -0500330
331DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
332 const int kWidth = 10;
333 const int kHeight = 10;
334
335 // Different ways of killing contexts.
336 using DeathFn = std::function<void(sk_gpu_test::GrContextFactory*, GrContext*)>;
337 DeathFn destroy = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
338 factory->destroyContexts();
339 };
340 DeathFn abandon = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
341 context->abandonContext();
342 };
343 DeathFn releaseResourcesAndAbandon = [](sk_gpu_test::GrContextFactory* factory,
344 GrContext* context) {
345 context->releaseResourcesAndAbandonContext();
346 };
347
348 for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
349 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
350 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
351 // and http://skbug.com/8275
352 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
353 if (api == GrBackendApi::kVulkan) {
354 continue;
355 }
356 DeathFn contextKillers[] = {destroy, abandon, releaseResourcesAndAbandon};
357 for (auto contextDeath : contextKillers) {
358 sk_gpu_test::GrContextFactory factory;
359 auto ctx = factory.get(contextType);
360 if (!ctx) {
361 continue;
362 }
Brian Salomon9bc76d92019-01-24 12:18:33 -0500363
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400364 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400365 kWidth, kHeight, kAlpha_8_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400366 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500367 REPORTER_ASSERT(reporter, backendTex.isValid());
368
369 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
370 kPremul_SkAlphaType);
371 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
372 SkCanvas* canvas = surface->getCanvas();
373
374 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
375 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
376 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
Brian Salomonf55e8d52019-01-30 17:28:20 -0500377 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
378 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500379 PromiseTextureChecker::Done, &promiseChecker,
380 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500381 REPORTER_ASSERT(reporter, image);
382
383 canvas->drawImage(image, 0, 0);
384 image.reset();
385 // If the surface still holds a ref to the context then the factory will not be able
386 // to destroy the context (and instead will release-all-and-abandon).
387 surface.reset();
388
389 ctx->flush();
390 contextDeath(&factory, ctx);
391
Brian Salomon0cc57542019-03-08 13:28:46 -0500392 check_all_done(reporter, promiseChecker);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500393 }
394 }
395}
396
397DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxInfo) {
398 const int kWidth = 10;
399 const int kHeight = 10;
400
401 GrContext* ctx = ctxInfo.grContext();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500402
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400403 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400404 kWidth, kHeight, kAlpha_8_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400405 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500406 REPORTER_ASSERT(reporter, backendTex.isValid());
407
408 SkImageInfo info =
409 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
410 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
411 SkCanvas* canvas = surface->getCanvas();
412
413 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
414 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
415 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
416 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
417 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500418 PromiseTextureChecker::Done, &promiseChecker,
419 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500420 REPORTER_ASSERT(reporter, image);
421
422 // Make the cache full. This tests that we don't preemptively purge cached textures for
423 // fulfillment due to cache pressure.
Robert Phillipscf39f372019-09-03 10:29:20 -0400424 static constexpr int kMaxBytes = 1;
425 ctx->setResourceCacheLimit(kMaxBytes);
426 SkTArray<sk_sp<GrTexture>> textures;
427 for (int i = 0; i < 5; ++i) {
Brian Salomon9bc76d92019-01-24 12:18:33 -0500428 GrSurfaceDesc desc;
429 desc.fConfig = kRGBA_8888_GrPixelConfig;
430 desc.fWidth = desc.fHeight = 100;
Brian Salomon4eb38b72019-08-05 12:58:39 -0400431 auto format = ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
432 GrRenderable::kNo);
Robert Phillipscf39f372019-09-03 10:29:20 -0400433 textures.emplace_back(ctx->priv().resourceProvider()->createTexture(
Brian Salomona90382f2019-09-17 09:01:56 -0400434 desc, format, GrRenderable::kNo, 1, GrMipMapped::kNo, SkBudgeted::kYes,
435 GrProtected::kNo));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500436 REPORTER_ASSERT(reporter, textures[i]);
437 }
438
Robert Phillipscf39f372019-09-03 10:29:20 -0400439 size_t bytesUsed;
440
441 ctx->getResourceCacheUsage(nullptr, &bytesUsed);
442 REPORTER_ASSERT(reporter, bytesUsed > kMaxBytes);
443
Brian Salomon9bc76d92019-01-24 12:18:33 -0500444 // Relying on the asserts in the promiseImageChecker to ensure that fulfills and releases are
445 // properly ordered.
446 canvas->drawImage(image, 0, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500447 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500448 canvas->drawImage(image, 1, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500449 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500450 canvas->drawImage(image, 2, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500451 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500452 canvas->drawImage(image, 3, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500453 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500454 canvas->drawImage(image, 4, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500455 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500456 canvas->drawImage(image, 5, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500457 surface->flush();
Brian Salomon876a0172019-03-08 11:12:14 -0500458 // Must call these to ensure that all callbacks are performed before the checker is destroyed.
459 image.reset();
460 ctx->flush();
Robert Phillips9b16f812019-05-17 10:01:21 -0400461 ctx->priv().getGpu()->testingOnly_flushGpuAndSync();
Brian Salomon876a0172019-03-08 11:12:14 -0500462
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400463 ctx->deleteBackendTexture(backendTex);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500464}
Brian Salomond538d3d2019-04-04 12:18:17 -0400465
466// Test case where promise image fulfill returns nullptr.
467DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageNullFulfill, reporter, ctxInfo) {
468 const int kWidth = 10;
469 const int kHeight = 10;
470
471 GrContext* ctx = ctxInfo.grContext();
Brian Salomond538d3d2019-04-04 12:18:17 -0400472
473 // Do all this just to get a valid backend format for the image.
Robert Phillips4bdd36f2019-06-04 11:03:06 -0400474 GrBackendTexture backendTex = ctx->createBackendTexture(
Robert Phillips80626792019-06-04 07:16:10 -0400475 kWidth, kHeight, kRGBA_8888_SkColorType,
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400476 SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kYes, GrProtected::kNo);
Brian Salomond538d3d2019-04-04 12:18:17 -0400477 REPORTER_ASSERT(reporter, backendTex.isValid());
478 GrBackendFormat backendFormat = backendTex.getBackendFormat();
479 REPORTER_ASSERT(reporter, backendFormat.isValid());
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400480 ctx->deleteBackendTexture(backendTex);
Brian Salomond538d3d2019-04-04 12:18:17 -0400481
482 struct Counts {
483 int fFulfillCount = 0;
484 int fReleaseCount = 0;
485 int fDoneCount = 0;
486 } counts;
487 auto fulfill = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
488 ++static_cast<Counts*>(ctx)->fFulfillCount;
489 return sk_sp<SkPromiseImageTexture>();
490 };
491 auto release = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
492 ++static_cast<Counts*>(ctx)->fReleaseCount;
493 };
494 auto done = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
495 ++static_cast<Counts*>(ctx)->fDoneCount;
496 };
497 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
498 sk_sp<SkImage> refImg(SkImage_Gpu::MakePromiseTexture(
499 ctx, backendFormat, kWidth, kHeight, GrMipMapped::kNo, texOrigin,
500 kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, fulfill, release, done, &counts,
501 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
502
503 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
504 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
505 SkCanvas* canvas = surface->getCanvas();
506 // Draw the image a few different ways.
507 canvas->drawImage(refImg, 0, 0);
508 SkPaint paint;
Mike Reedb286bc22019-04-08 16:23:20 -0400509 paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
Brian Salomond538d3d2019-04-04 12:18:17 -0400510 canvas->drawImage(refImg, 0, 0, &paint);
511 auto shader = refImg->makeShader(SkTileMode::kClamp, SkTileMode::kClamp);
512 REPORTER_ASSERT(reporter, shader);
513 paint.setShader(std::move(shader));
514 canvas->drawRect(SkRect::MakeWH(1,1), paint);
515 paint.setShader(nullptr);
516 refImg.reset();
517 surface->flush();
518 // We should only call each callback once and we should have made all the calls by this point.
519 REPORTER_ASSERT(reporter, counts.fFulfillCount == 1);
520 REPORTER_ASSERT(reporter, counts.fReleaseCount == 1);
521 REPORTER_ASSERT(reporter, counts.fDoneCount == 1);
522}