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