blob: 4ba011b0fe65ecc1c2eee7765fe51c90fb3c8dab [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
8#include "Test.h"
9
10#if SK_SUPPORT_GPU
11
12#include "GrBackendSurface.h"
13#include "GrContextPriv.h"
14#include "GrGpu.h"
15#include "GrTest.h"
16#include "SkDeferredDisplayListRecorder.h"
17#include "SkImage_Gpu.h"
18
19using namespace sk_gpu_test;
20
21struct PromiseTextureChecker {
22 explicit PromiseTextureChecker(const GrBackendTexture& tex)
23 : fTexture(tex)
24 , fFulfillCount(0)
25 , fReleaseCount(0) {}
26 GrBackendTexture fTexture;
27 int fFulfillCount;
28 int fReleaseCount;
29 static void Fulfill(void* self, GrBackendTexture* outTexture) {
30 static_cast<PromiseTextureChecker*>(self)->fFulfillCount++;
31 *outTexture = static_cast<PromiseTextureChecker*>(self)->fTexture;
32 }
33 static void Release(void* self) {
34 static_cast<PromiseTextureChecker*>(self)->fReleaseCount++;
35 }
36};
37
38// Because Vulkan may delay when it actually calls the ReleaseProcs depending on when command
39// buffers finish their work, we need some slight wiggle room in what values we expect for fulfill
40// and release counts.
41static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseChecker,
42 bool countsMustBeEqual,
43 int expectedFulfillCnt,
44 int expectedReleaseCnt,
45 bool expectedRequired,
46 skiatest::Reporter* reporter) {
47 bool result = true;
48 int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
49 // FulfillCount should always equal ReleaseCount or be at most one higher
50 if (countDiff != 0) {
51 if (countsMustBeEqual) {
52 result = false;
53 REPORTER_ASSERT(reporter, 0 == countDiff);
54 } else if (countDiff != 1) {
55 result = false;
56 REPORTER_ASSERT(reporter, 0 == countDiff || 1 == countDiff);
57 }
58 }
59
60 int fulfillDiff = expectedFulfillCnt - promiseChecker.fFulfillCount;
61 REPORTER_ASSERT(reporter, fulfillDiff >= 0);
62 if (fulfillDiff != 0) {
63 if (expectedRequired) {
64 result = false;
65 REPORTER_ASSERT(reporter, expectedFulfillCnt == promiseChecker.fFulfillCount);
66 } else if (fulfillDiff > 1) {
67 result = false;
68 REPORTER_ASSERT(reporter, fulfillDiff <= 1);
69 }
70 }
71
72 int releaseDiff = expectedReleaseCnt - promiseChecker.fReleaseCount;
73 REPORTER_ASSERT(reporter, releaseDiff >= 0);
74 if (releaseDiff != 0) {
75 if (expectedRequired) {
76 result = false;
77 REPORTER_ASSERT(reporter, expectedReleaseCnt == promiseChecker.fReleaseCount);
78 } else if (releaseDiff > 1) {
79 result = false;
80 REPORTER_ASSERT(reporter, releaseDiff <= 1);
81 }
82 }
83
84 return result;
85}
86
87DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
88 const int kWidth = 10;
89 const int kHeight = 10;
90 std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]);
91
92 GrContext* ctx = ctxInfo.grContext();
93 GrGpu* gpu = ctx->contextPriv().getGpu();
94
95 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
96 pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo);
97 REPORTER_ASSERT(reporter, backendTex.isValid());
98
99 GrBackendFormat backendFormat = GrTest::CreateBackendFormatFromTexture(backendTex);
100 REPORTER_ASSERT(reporter, backendFormat.isValid());
101
102 PromiseTextureChecker promiseChecker(backendTex);
103 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
104 sk_sp<SkImage> refImg(
105 SkImage_Gpu::MakePromiseTexture(ctx, backendFormat, kWidth, kHeight, GrMipMapped::kNo,
106 texOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
107 nullptr,
108 PromiseTextureChecker::Fulfill,
109 PromiseTextureChecker::Release,
110 &promiseChecker));
111
112 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
113 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
114 SkCanvas* canvas = surface->getCanvas();
115
116 int expectedFulfillCnt = 0;
117 int expectedReleaseCnt = 0;
118
119 canvas->drawImage(refImg, 0, 0);
120 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
121 true,
122 expectedFulfillCnt,
123 expectedReleaseCnt,
124 true,
125 reporter));
126
127 bool isVulkan = kVulkan_GrBackend == ctx->contextPriv().getBackend();
128 canvas->flush();
129 expectedFulfillCnt++;
130 expectedReleaseCnt++;
131 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
132 !isVulkan,
133 expectedFulfillCnt,
134 expectedReleaseCnt,
135 !isVulkan,
136 reporter));
137
138 gpu->testingOnly_flushGpuAndSync();
139 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
140 true,
141 expectedFulfillCnt,
142 expectedReleaseCnt,
143 true,
144 reporter));
145
146 canvas->drawImage(refImg, 0, 0);
147 canvas->drawImage(refImg, 0, 0);
148
149 canvas->flush();
150 expectedFulfillCnt++;
151 expectedReleaseCnt++;
152
153 gpu->testingOnly_flushGpuAndSync();
154 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
155 true,
156 expectedFulfillCnt,
157 expectedReleaseCnt,
158 true,
159 reporter));
160
161 // Now test code path on Vulkan where we released the texture, but the GPU isn't done with
162 // resource yet and we do another draw. We should only call fulfill on the first draw and
163 // use the cached GrBackendTexture on the second. Release should only be called after the second
164 // draw is finished.
165 canvas->drawImage(refImg, 0, 0);
166 canvas->flush();
167 expectedFulfillCnt++;
168 expectedReleaseCnt++;
169 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
170 !isVulkan,
171 expectedFulfillCnt,
172 expectedReleaseCnt,
173 !isVulkan,
174 reporter));
175
176 canvas->drawImage(refImg, 0, 0);
177 canvas->flush();
178 expectedFulfillCnt++;
179
180 gpu->testingOnly_flushGpuAndSync();
181 expectedReleaseCnt++;
182 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
183 true,
184 expectedFulfillCnt,
185 expectedReleaseCnt,
186 !isVulkan,
187 reporter));
188 expectedFulfillCnt = promiseChecker.fFulfillCount;
189 expectedReleaseCnt = promiseChecker.fReleaseCount;
190
191 refImg.reset();
192
193 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
194 true,
195 expectedFulfillCnt,
196 expectedReleaseCnt,
197 true,
198 reporter));
199
Brian Salomoncb1bbfe2018-03-09 13:35:43 -0500200 gpu->deleteTestingOnlyBackendTexture(backendTex);
Greg Daniela8d92112018-03-09 12:05:04 -0500201}
202
203#endif