blob: ef4a29985051833c7f84b7acf22b2ab8c257b690 [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)
Greg Daniel7278d682018-03-16 14:57:21 -040025 , fReleaseCount(0)
26 , fDoneCount(0) {}
Greg Daniela8d92112018-03-09 12:05:04 -050027 GrBackendTexture fTexture;
28 int fFulfillCount;
29 int fReleaseCount;
Greg Daniel7278d682018-03-16 14:57:21 -040030 int fDoneCount;
Greg Daniela8d92112018-03-09 12:05:04 -050031 static void Fulfill(void* self, GrBackendTexture* outTexture) {
32 static_cast<PromiseTextureChecker*>(self)->fFulfillCount++;
33 *outTexture = static_cast<PromiseTextureChecker*>(self)->fTexture;
34 }
35 static void Release(void* self) {
36 static_cast<PromiseTextureChecker*>(self)->fReleaseCount++;
37 }
Greg Daniel7278d682018-03-16 14:57:21 -040038 static void Done(void* self) {
39 static_cast<PromiseTextureChecker*>(self)->fDoneCount++;
40 }
Greg Daniela8d92112018-03-09 12:05:04 -050041};
42
43// Because Vulkan may delay when it actually calls the ReleaseProcs depending on when command
44// buffers finish their work, we need some slight wiggle room in what values we expect for fulfill
45// and release counts.
46static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseChecker,
47 bool countsMustBeEqual,
48 int expectedFulfillCnt,
49 int expectedReleaseCnt,
50 bool expectedRequired,
Greg Daniel7278d682018-03-16 14:57:21 -040051 int expectedDoneCnt,
Greg Daniela8d92112018-03-09 12:05:04 -050052 skiatest::Reporter* reporter) {
53 bool result = true;
54 int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
55 // FulfillCount should always equal ReleaseCount or be at most one higher
56 if (countDiff != 0) {
57 if (countsMustBeEqual) {
58 result = false;
59 REPORTER_ASSERT(reporter, 0 == countDiff);
60 } else if (countDiff != 1) {
61 result = false;
62 REPORTER_ASSERT(reporter, 0 == countDiff || 1 == countDiff);
63 }
64 }
65
66 int fulfillDiff = expectedFulfillCnt - promiseChecker.fFulfillCount;
67 REPORTER_ASSERT(reporter, fulfillDiff >= 0);
68 if (fulfillDiff != 0) {
69 if (expectedRequired) {
70 result = false;
71 REPORTER_ASSERT(reporter, expectedFulfillCnt == promiseChecker.fFulfillCount);
72 } else if (fulfillDiff > 1) {
73 result = false;
74 REPORTER_ASSERT(reporter, fulfillDiff <= 1);
75 }
76 }
77
78 int releaseDiff = expectedReleaseCnt - promiseChecker.fReleaseCount;
79 REPORTER_ASSERT(reporter, releaseDiff >= 0);
80 if (releaseDiff != 0) {
81 if (expectedRequired) {
82 result = false;
83 REPORTER_ASSERT(reporter, expectedReleaseCnt == promiseChecker.fReleaseCount);
84 } else if (releaseDiff > 1) {
85 result = false;
86 REPORTER_ASSERT(reporter, releaseDiff <= 1);
87 }
88 }
89
Greg Daniel7278d682018-03-16 14:57:21 -040090 if (expectedDoneCnt != promiseChecker.fDoneCount) {
91 result = false;
92 REPORTER_ASSERT(reporter, expectedDoneCnt == promiseChecker.fDoneCount);
93 }
94
Greg Daniela8d92112018-03-09 12:05:04 -050095 return result;
96}
97
98DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
99 const int kWidth = 10;
100 const int kHeight = 10;
Greg Daniela8d92112018-03-09 12:05:04 -0500101
102 GrContext* ctx = ctxInfo.grContext();
103 GrGpu* gpu = ctx->contextPriv().getGpu();
104
Greg Daniel7278d682018-03-16 14:57:21 -0400105 for (bool releaseImageEarly : {true, false}) {
106 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
107 nullptr, kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo);
108 REPORTER_ASSERT(reporter, backendTex.isValid());
Greg Daniela8d92112018-03-09 12:05:04 -0500109
Greg Daniel7278d682018-03-16 14:57:21 -0400110 GrBackendFormat backendFormat = backendTex.format();
111 REPORTER_ASSERT(reporter, backendFormat.isValid());
Greg Daniela8d92112018-03-09 12:05:04 -0500112
Greg Daniel7278d682018-03-16 14:57:21 -0400113 PromiseTextureChecker promiseChecker(backendTex);
114 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
115 sk_sp<SkImage> refImg(
116 SkImage_Gpu::MakePromiseTexture(ctx, backendFormat, kWidth, kHeight,
117 GrMipMapped::kNo, texOrigin,
118 kRGBA_8888_SkColorType, kPremul_SkAlphaType,
119 nullptr,
120 PromiseTextureChecker::Fulfill,
121 PromiseTextureChecker::Release,
122 PromiseTextureChecker::Done,
123 &promiseChecker));
Greg Daniela8d92112018-03-09 12:05:04 -0500124
Greg Daniel7278d682018-03-16 14:57:21 -0400125 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
126 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
127 SkCanvas* canvas = surface->getCanvas();
Greg Daniela8d92112018-03-09 12:05:04 -0500128
Greg Daniel7278d682018-03-16 14:57:21 -0400129 int expectedFulfillCnt = 0;
130 int expectedReleaseCnt = 0;
131 int expectedDoneCnt = 0;
Greg Daniela8d92112018-03-09 12:05:04 -0500132
Greg Daniel7278d682018-03-16 14:57:21 -0400133 canvas->drawImage(refImg, 0, 0);
134 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
135 true,
136 expectedFulfillCnt,
137 expectedReleaseCnt,
138 true,
139 expectedDoneCnt,
140 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500141
Greg Daniel7278d682018-03-16 14:57:21 -0400142 bool isVulkan = kVulkan_GrBackend == ctx->contextPriv().getBackend();
143 canvas->flush();
144 expectedFulfillCnt++;
145 expectedReleaseCnt++;
146 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
147 !isVulkan,
148 expectedFulfillCnt,
149 expectedReleaseCnt,
150 !isVulkan,
151 expectedDoneCnt,
152 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500153
Greg Daniel7278d682018-03-16 14:57:21 -0400154 gpu->testingOnly_flushGpuAndSync();
155 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
156 true,
157 expectedFulfillCnt,
158 expectedReleaseCnt,
159 true,
160 expectedDoneCnt,
161 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500162
Greg Daniel7278d682018-03-16 14:57:21 -0400163 canvas->drawImage(refImg, 0, 0);
164 canvas->drawImage(refImg, 0, 0);
Greg Daniela8d92112018-03-09 12:05:04 -0500165
Greg Daniel7278d682018-03-16 14:57:21 -0400166 canvas->flush();
167 expectedFulfillCnt++;
168 expectedReleaseCnt++;
Greg Daniela8d92112018-03-09 12:05:04 -0500169
Greg Daniel7278d682018-03-16 14:57:21 -0400170 gpu->testingOnly_flushGpuAndSync();
171 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
172 true,
173 expectedFulfillCnt,
174 expectedReleaseCnt,
175 true,
176 expectedDoneCnt,
177 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500178
Greg Daniel7278d682018-03-16 14:57:21 -0400179 // Now test code path on Vulkan where we released the texture, but the GPU isn't done with
180 // resource yet and we do another draw. We should only call fulfill on the first draw and
181 // use the cached GrBackendTexture on the second. Release should only be called after the
182 // second draw is finished.
183 canvas->drawImage(refImg, 0, 0);
184 canvas->flush();
185 expectedFulfillCnt++;
186 expectedReleaseCnt++;
187 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
188 !isVulkan,
189 expectedFulfillCnt,
190 expectedReleaseCnt,
191 !isVulkan,
192 expectedDoneCnt,
193 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500194
Greg Daniel7278d682018-03-16 14:57:21 -0400195 canvas->drawImage(refImg, 0, 0);
Greg Daniela8d92112018-03-09 12:05:04 -0500196
Greg Daniel7278d682018-03-16 14:57:21 -0400197 if (releaseImageEarly) {
198 refImg.reset();
199 }
Greg Daniela8d92112018-03-09 12:05:04 -0500200
Greg Daniel7278d682018-03-16 14:57:21 -0400201 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
202 !isVulkan,
203 expectedFulfillCnt,
204 expectedReleaseCnt,
205 !isVulkan,
206 expectedDoneCnt,
207 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500208
Greg Daniel7278d682018-03-16 14:57:21 -0400209 canvas->flush();
210 expectedFulfillCnt++;
Greg Daniela8d92112018-03-09 12:05:04 -0500211
Greg Daniel7278d682018-03-16 14:57:21 -0400212 gpu->testingOnly_flushGpuAndSync();
213 expectedReleaseCnt++;
214 if (releaseImageEarly) {
215 expectedDoneCnt++;
216 }
217 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
218 true,
219 expectedFulfillCnt,
220 expectedReleaseCnt,
221 !isVulkan,
222 expectedDoneCnt,
223 reporter));
224 expectedFulfillCnt = promiseChecker.fFulfillCount;
225 expectedReleaseCnt = promiseChecker.fReleaseCount;
226
227 if (!releaseImageEarly) {
228 refImg.reset();
229 expectedDoneCnt++;
230 }
231
232 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
233 true,
234 expectedFulfillCnt,
235 expectedReleaseCnt,
236 true,
237 expectedDoneCnt,
238 reporter));
239
240 gpu->deleteTestingOnlyBackendTexture(backendTex);
241 }
Greg Daniela8d92112018-03-09 12:05:04 -0500242}
243
244#endif