blob: 7aaf84c6314babb9e710afb14200c2d1f2f09dbc [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
170 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
171 nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, true, GrMipMapped::kNo);
172 REPORTER_ASSERT(reporter, backendTex.isValid());
173
174 GrBackendFormat backendFormat = backendTex.getBackendFormat();
175 REPORTER_ASSERT(reporter, backendFormat.isValid());
176
177 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
178 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
179 sk_sp<SkImage> refImg(
180 SkImage_Gpu::MakePromiseTexture(
181 ctx, backendFormat, kWidth, kHeight,
182 GrMipMapped::kNo, texOrigin,
183 kRGBA_8888_SkColorType, kPremul_SkAlphaType,
184 nullptr,
185 PromiseTextureChecker::Fulfill,
186 PromiseTextureChecker::Release,
187 PromiseTextureChecker::Done,
Brian Salomon0cc57542019-03-08 13:28:46 -0500188 &promiseChecker,
189 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomonf55e8d52019-01-30 17:28:20 -0500190
191 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
192 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
193 SkCanvas* canvas = surface->getCanvas();
194
Brian Salomond716d442019-03-07 15:23:30 +0000195 canvas->drawImage(refImg, 0, 0);
Brian Salomon0cc57542019-03-08 13:28:46 -0500196 check_unfulfilled(promiseChecker, reporter);
Brian Salomond716d442019-03-07 15:23:30 +0000197
Robert Phillips9882dae2019-03-04 11:00:10 -0500198 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500199 // We still own the image so we should not have called Release or Done.
200 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500201
202 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500203 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500204
205 canvas->drawImage(refImg, 0, 0);
206 canvas->drawImage(refImg, 0, 0);
207
Robert Phillips9882dae2019-03-04 11:00:10 -0500208 surface->flush();
Brian Salomonf55e8d52019-01-30 17:28:20 -0500209
210 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500211 // Image should still be fulfilled from the first time we drew/flushed it.
212 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500213
214 canvas->drawImage(refImg, 0, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500215 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500216 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500217
218 canvas->drawImage(refImg, 0, 0);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500219 refImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500220 // We no longer own the image but the last draw is still unflushed.
221 check_only_fulfilled(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500222
Robert Phillips9882dae2019-03-04 11:00:10 -0500223 surface->flush();
Brian Salomon0cc57542019-03-08 13:28:46 -0500224 // Flushing should have called Release. Depending on the backend and timing it may have called
225 // done.
226 check_all_flushed_but_not_synced(reporter, promiseChecker, ctx->backend());
Brian Salomonf55e8d52019-01-30 17:28:20 -0500227 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500228 // Now Done should definitely have been called.
229 check_all_done(reporter, promiseChecker);
Brian Salomonf55e8d52019-01-30 17:28:20 -0500230
231 gpu->deleteTestingOnlyBackendTexture(backendTex);
232}
233
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500234DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureReuseDifferentConfig, reporter, ctxInfo) {
235 // Try making two promise SkImages backed by the same texture but with different configs.
236 // This will only be testable on backends where a single texture format (8bit red unorm) can
237 // be used for alpha and gray image color types.
238
239 const int kWidth = 10;
240 const int kHeight = 10;
241
242 GrContext* ctx = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500243 GrGpu* gpu = ctx->priv().getGpu();
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500244
245 GrBackendTexture backendTex1 = gpu->createTestingOnlyBackendTexture(
246 nullptr, kWidth, kHeight, GrColorType::kGray_8, false, GrMipMapped::kNo);
247 REPORTER_ASSERT(reporter, backendTex1.isValid());
248
249 GrBackendTexture backendTex2 = gpu->createTestingOnlyBackendTexture(
250 nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo);
251 REPORTER_ASSERT(reporter, backendTex2.isValid());
Brian Salomonf55e8d52019-01-30 17:28:20 -0500252 if (backendTex1.getBackendFormat() != backendTex2.getBackendFormat()) {
253 gpu->deleteTestingOnlyBackendTexture(backendTex1);
254 return;
255 }
256 // We only needed this texture to check that alpha and gray color types use the same format.
257 gpu->deleteTestingOnlyBackendTexture(backendTex2);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500258
259 SkImageInfo info =
260 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
261 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
262 SkCanvas* canvas = surface->getCanvas();
263
Brian Salomon7d88f312019-02-28 10:03:03 -0500264 PromiseTextureChecker promiseChecker(backendTex1, reporter, true);
265 sk_sp<SkImage> alphaImg(SkImage_Gpu::MakePromiseTexture(
266 ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
267 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
268 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500269 PromiseTextureChecker::Done, &promiseChecker,
270 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon7d88f312019-02-28 10:03:03 -0500271 REPORTER_ASSERT(reporter, alphaImg);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500272
Brian Salomon7d88f312019-02-28 10:03:03 -0500273 sk_sp<SkImage> grayImg(SkImage_Gpu::MakePromiseTexture(
274 ctx, backendTex1.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
275 kBottomLeft_GrSurfaceOrigin, kGray_8_SkColorType, kOpaque_SkAlphaType, nullptr,
276 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500277 PromiseTextureChecker::Done, &promiseChecker,
278 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon7d88f312019-02-28 10:03:03 -0500279 REPORTER_ASSERT(reporter, grayImg);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500280
Brian Salomon7d88f312019-02-28 10:03:03 -0500281 canvas->drawImage(alphaImg, 0, 0);
282 canvas->drawImage(grayImg, 1, 1);
Robert Phillips9882dae2019-03-04 11:00:10 -0500283 surface->flush();
Brian Salomon7d88f312019-02-28 10:03:03 -0500284 gpu->testingOnly_flushGpuAndSync();
Brian Salomon0cc57542019-03-08 13:28:46 -0500285 check_only_fulfilled(reporter, promiseChecker, 2);
Brian Salomon7d88f312019-02-28 10:03:03 -0500286
287 // Because they use different configs, each image should have created a different GrTexture
288 // and they both should still be cached.
289 ctx->priv().getResourceCache()->purgeAsNeeded();
290
291 auto keys = promiseChecker.uniqueKeys();
292 REPORTER_ASSERT(reporter, keys.count() == 2);
293 for (const auto& key : keys) {
294 auto surf = ctx->priv().resourceProvider()->findByUniqueKey<GrSurface>(key);
295 REPORTER_ASSERT(reporter, surf && surf->asTexture());
296 if (surf && surf->asTexture()) {
297 REPORTER_ASSERT(reporter,
298 !GrBackendTexture::TestingOnly_Equals(
299 backendTex1, surf->asTexture()->getBackendTexture()));
Brian Salomonf55e8d52019-01-30 17:28:20 -0500300 }
Brian Salomon7d88f312019-02-28 10:03:03 -0500301 }
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500302
Brian Salomon0cc57542019-03-08 13:28:46 -0500303 // Invalidate the backing texture, this should invalidate the keys.
Brian Salomon7d88f312019-02-28 10:03:03 -0500304 promiseChecker.releaseTexture();
305 ctx->priv().getResourceCache()->purgeAsNeeded();
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500306
Brian Salomon7d88f312019-02-28 10:03:03 -0500307 for (const auto& key : keys) {
308 auto surf = ctx->priv().resourceProvider()->findByUniqueKey<GrSurface>(key);
309 REPORTER_ASSERT(reporter, !surf);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500310 }
Brian Salomon876a0172019-03-08 11:12:14 -0500311 alphaImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500312 ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
313 check_fulfill_and_release_cnts(reporter, promiseChecker, 2,
314 ReleaseBalanceExpectation::kUnbalancedByOne,
315 DoneBalanceExpectation::kUnbalancedByOne);
Brian Salomon876a0172019-03-08 11:12:14 -0500316 grayImg.reset();
Brian Salomon0cc57542019-03-08 13:28:46 -0500317 ctx->flush(); // We do this to pick up any unref messages that are sent by unref'ing the image.
318 check_all_done(reporter, promiseChecker, 2);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500319 gpu->deleteTestingOnlyBackendTexture(backendTex1);
Brian Salomon1bf0ed82019-01-16 13:51:35 -0500320}
Brian Salomon9bc76d92019-01-24 12:18:33 -0500321
322DEF_GPUTEST(PromiseImageTextureShutdown, reporter, ctxInfo) {
323 const int kWidth = 10;
324 const int kHeight = 10;
325
326 // Different ways of killing contexts.
327 using DeathFn = std::function<void(sk_gpu_test::GrContextFactory*, GrContext*)>;
328 DeathFn destroy = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
329 factory->destroyContexts();
330 };
331 DeathFn abandon = [](sk_gpu_test::GrContextFactory* factory, GrContext* context) {
332 context->abandonContext();
333 };
334 DeathFn releaseResourcesAndAbandon = [](sk_gpu_test::GrContextFactory* factory,
335 GrContext* context) {
336 context->releaseResourcesAndAbandonContext();
337 };
338
339 for (int type = 0; type < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++type) {
340 auto contextType = static_cast<sk_gpu_test::GrContextFactory::ContextType>(type);
341 // These tests are difficult to get working with Vulkan. See http://skbug.com/8705
342 // and http://skbug.com/8275
343 GrBackendApi api = sk_gpu_test::GrContextFactory::ContextTypeBackend(contextType);
344 if (api == GrBackendApi::kVulkan) {
345 continue;
346 }
347 DeathFn contextKillers[] = {destroy, abandon, releaseResourcesAndAbandon};
348 for (auto contextDeath : contextKillers) {
349 sk_gpu_test::GrContextFactory factory;
350 auto ctx = factory.get(contextType);
351 if (!ctx) {
352 continue;
353 }
Robert Phillips9da87e02019-02-04 13:26:26 -0500354 GrGpu* gpu = ctx->priv().getGpu();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500355
356 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
357 nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo);
358 REPORTER_ASSERT(reporter, backendTex.isValid());
359
360 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType,
361 kPremul_SkAlphaType);
362 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
363 SkCanvas* canvas = surface->getCanvas();
364
365 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
366 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
367 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
Brian Salomonf55e8d52019-01-30 17:28:20 -0500368 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
369 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500370 PromiseTextureChecker::Done, &promiseChecker,
371 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500372 REPORTER_ASSERT(reporter, image);
373
374 canvas->drawImage(image, 0, 0);
375 image.reset();
376 // If the surface still holds a ref to the context then the factory will not be able
377 // to destroy the context (and instead will release-all-and-abandon).
378 surface.reset();
379
380 ctx->flush();
381 contextDeath(&factory, ctx);
382
Brian Salomon0cc57542019-03-08 13:28:46 -0500383 check_all_done(reporter, promiseChecker);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500384 }
385 }
386}
387
388DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTextureFullCache, reporter, ctxInfo) {
389 const int kWidth = 10;
390 const int kHeight = 10;
391
392 GrContext* ctx = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500393 GrGpu* gpu = ctx->priv().getGpu();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500394
395 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
396 nullptr, kWidth, kHeight, GrColorType::kAlpha_8, false, GrMipMapped::kNo);
397 REPORTER_ASSERT(reporter, backendTex.isValid());
398
399 SkImageInfo info =
400 SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
401 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
402 SkCanvas* canvas = surface->getCanvas();
403
404 PromiseTextureChecker promiseChecker(backendTex, reporter, false);
405 sk_sp<SkImage> image(SkImage_Gpu::MakePromiseTexture(
406 ctx, backendTex.getBackendFormat(), kWidth, kHeight, GrMipMapped::kNo,
407 kTopLeft_GrSurfaceOrigin, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr,
408 PromiseTextureChecker::Fulfill, PromiseTextureChecker::Release,
Brian Salomon0cc57542019-03-08 13:28:46 -0500409 PromiseTextureChecker::Done, &promiseChecker,
410 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
Brian Salomon9bc76d92019-01-24 12:18:33 -0500411 REPORTER_ASSERT(reporter, image);
412
413 // Make the cache full. This tests that we don't preemptively purge cached textures for
414 // fulfillment due to cache pressure.
415 static constexpr int kMaxResources = 10;
416 static constexpr int kMaxBytes = 100;
417 ctx->setResourceCacheLimits(kMaxResources, kMaxBytes);
418 sk_sp<GrTexture> textures[2 * kMaxResources];
419 for (int i = 0; i < 2 * kMaxResources; ++i) {
420 GrSurfaceDesc desc;
421 desc.fConfig = kRGBA_8888_GrPixelConfig;
422 desc.fWidth = desc.fHeight = 100;
Robert Phillips9313aa72019-04-09 18:41:27 -0400423 textures[i] = ctx->priv().resourceProvider()->createTexture(
424 desc, SkBudgeted::kYes, GrResourceProvider::Flags::kNoPendingIO);
Brian Salomon9bc76d92019-01-24 12:18:33 -0500425 REPORTER_ASSERT(reporter, textures[i]);
426 }
427
428 // Relying on the asserts in the promiseImageChecker to ensure that fulfills and releases are
429 // properly ordered.
430 canvas->drawImage(image, 0, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500431 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500432 canvas->drawImage(image, 1, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500433 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500434 canvas->drawImage(image, 2, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500435 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500436 canvas->drawImage(image, 3, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500437 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500438 canvas->drawImage(image, 4, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500439 surface->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500440 canvas->drawImage(image, 5, 0);
Robert Phillips9882dae2019-03-04 11:00:10 -0500441 surface->flush();
Brian Salomon876a0172019-03-08 11:12:14 -0500442 // Must call these to ensure that all callbacks are performed before the checker is destroyed.
443 image.reset();
444 ctx->flush();
Brian Salomon9bc76d92019-01-24 12:18:33 -0500445 gpu->testingOnly_flushGpuAndSync();
Brian Salomon876a0172019-03-08 11:12:14 -0500446
Brian Salomon9bc76d92019-01-24 12:18:33 -0500447 gpu->deleteTestingOnlyBackendTexture(backendTex);
448}
Brian Salomond538d3d2019-04-04 12:18:17 -0400449
450// Test case where promise image fulfill returns nullptr.
451DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageNullFulfill, reporter, ctxInfo) {
452 const int kWidth = 10;
453 const int kHeight = 10;
454
455 GrContext* ctx = ctxInfo.grContext();
456 GrGpu* gpu = ctx->priv().getGpu();
457
458 // Do all this just to get a valid backend format for the image.
459 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
460 nullptr, kWidth, kHeight, GrColorType::kRGBA_8888, true, GrMipMapped::kNo);
461 REPORTER_ASSERT(reporter, backendTex.isValid());
462 GrBackendFormat backendFormat = backendTex.getBackendFormat();
463 REPORTER_ASSERT(reporter, backendFormat.isValid());
464 gpu->deleteTestingOnlyBackendTexture(backendTex);
465
466 struct Counts {
467 int fFulfillCount = 0;
468 int fReleaseCount = 0;
469 int fDoneCount = 0;
470 } counts;
471 auto fulfill = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
472 ++static_cast<Counts*>(ctx)->fFulfillCount;
473 return sk_sp<SkPromiseImageTexture>();
474 };
475 auto release = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
476 ++static_cast<Counts*>(ctx)->fReleaseCount;
477 };
478 auto done = [](SkDeferredDisplayListRecorder::PromiseImageTextureContext ctx) {
479 ++static_cast<Counts*>(ctx)->fDoneCount;
480 };
481 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
482 sk_sp<SkImage> refImg(SkImage_Gpu::MakePromiseTexture(
483 ctx, backendFormat, kWidth, kHeight, GrMipMapped::kNo, texOrigin,
484 kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, fulfill, release, done, &counts,
485 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew));
486
487 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
488 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
489 SkCanvas* canvas = surface->getCanvas();
490 // Draw the image a few different ways.
491 canvas->drawImage(refImg, 0, 0);
492 SkPaint paint;
Mike Reedb286bc22019-04-08 16:23:20 -0400493 paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
Brian Salomond538d3d2019-04-04 12:18:17 -0400494 canvas->drawImage(refImg, 0, 0, &paint);
495 auto shader = refImg->makeShader(SkTileMode::kClamp, SkTileMode::kClamp);
496 REPORTER_ASSERT(reporter, shader);
497 paint.setShader(std::move(shader));
498 canvas->drawRect(SkRect::MakeWH(1,1), paint);
499 paint.setShader(nullptr);
500 refImg.reset();
501 surface->flush();
502 // We should only call each callback once and we should have made all the calls by this point.
503 REPORTER_ASSERT(reporter, counts.fFulfillCount == 1);
504 REPORTER_ASSERT(reporter, counts.fReleaseCount == 1);
505 REPORTER_ASSERT(reporter, counts.fDoneCount == 1);
506}