blob: 377f6e1bdfeda9723319b8128a4465995fa29bb2 [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
Greg Daniela8d92112018-03-09 12:05:04 -050010#include "GrBackendSurface.h"
11#include "GrContextPriv.h"
12#include "GrGpu.h"
13#include "GrTest.h"
14#include "SkDeferredDisplayListRecorder.h"
15#include "SkImage_Gpu.h"
16
17using namespace sk_gpu_test;
18
19struct PromiseTextureChecker {
20 explicit PromiseTextureChecker(const GrBackendTexture& tex)
21 : fTexture(tex)
22 , fFulfillCount(0)
Greg Daniel7278d682018-03-16 14:57:21 -040023 , fReleaseCount(0)
24 , fDoneCount(0) {}
Greg Daniela8d92112018-03-09 12:05:04 -050025 GrBackendTexture fTexture;
26 int fFulfillCount;
27 int fReleaseCount;
Greg Daniel7278d682018-03-16 14:57:21 -040028 int fDoneCount;
Greg Daniela8d92112018-03-09 12:05:04 -050029 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 }
Greg Daniel7278d682018-03-16 14:57:21 -040036 static void Done(void* self) {
37 static_cast<PromiseTextureChecker*>(self)->fDoneCount++;
38 }
Greg Daniela8d92112018-03-09 12:05:04 -050039};
40
41// Because Vulkan may delay when it actually calls the ReleaseProcs depending on when command
42// buffers finish their work, we need some slight wiggle room in what values we expect for fulfill
43// and release counts.
44static bool check_fulfill_and_release_cnts(const PromiseTextureChecker& promiseChecker,
45 bool countsMustBeEqual,
46 int expectedFulfillCnt,
47 int expectedReleaseCnt,
48 bool expectedRequired,
Greg Daniel7278d682018-03-16 14:57:21 -040049 int expectedDoneCnt,
Greg Daniela8d92112018-03-09 12:05:04 -050050 skiatest::Reporter* reporter) {
51 bool result = true;
52 int countDiff = promiseChecker.fFulfillCount - promiseChecker.fReleaseCount;
53 // FulfillCount should always equal ReleaseCount or be at most one higher
54 if (countDiff != 0) {
55 if (countsMustBeEqual) {
56 result = false;
57 REPORTER_ASSERT(reporter, 0 == countDiff);
58 } else if (countDiff != 1) {
59 result = false;
60 REPORTER_ASSERT(reporter, 0 == countDiff || 1 == countDiff);
61 }
62 }
63
64 int fulfillDiff = expectedFulfillCnt - promiseChecker.fFulfillCount;
65 REPORTER_ASSERT(reporter, fulfillDiff >= 0);
66 if (fulfillDiff != 0) {
67 if (expectedRequired) {
68 result = false;
69 REPORTER_ASSERT(reporter, expectedFulfillCnt == promiseChecker.fFulfillCount);
70 } else if (fulfillDiff > 1) {
71 result = false;
72 REPORTER_ASSERT(reporter, fulfillDiff <= 1);
73 }
74 }
75
76 int releaseDiff = expectedReleaseCnt - promiseChecker.fReleaseCount;
77 REPORTER_ASSERT(reporter, releaseDiff >= 0);
78 if (releaseDiff != 0) {
79 if (expectedRequired) {
80 result = false;
81 REPORTER_ASSERT(reporter, expectedReleaseCnt == promiseChecker.fReleaseCount);
82 } else if (releaseDiff > 1) {
83 result = false;
84 REPORTER_ASSERT(reporter, releaseDiff <= 1);
85 }
86 }
87
Greg Daniel7278d682018-03-16 14:57:21 -040088 if (expectedDoneCnt != promiseChecker.fDoneCount) {
89 result = false;
90 REPORTER_ASSERT(reporter, expectedDoneCnt == promiseChecker.fDoneCount);
91 }
92
Greg Daniela8d92112018-03-09 12:05:04 -050093 return result;
94}
95
96DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PromiseImageTest, reporter, ctxInfo) {
97 const int kWidth = 10;
98 const int kHeight = 10;
Greg Daniela8d92112018-03-09 12:05:04 -050099
100 GrContext* ctx = ctxInfo.grContext();
101 GrGpu* gpu = ctx->contextPriv().getGpu();
102
Greg Daniel7278d682018-03-16 14:57:21 -0400103 for (bool releaseImageEarly : {true, false}) {
104 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
105 nullptr, kWidth, kHeight, kRGBA_8888_GrPixelConfig, true, GrMipMapped::kNo);
106 REPORTER_ASSERT(reporter, backendTex.isValid());
Greg Daniela8d92112018-03-09 12:05:04 -0500107
Timothy Liang036fdfe2018-06-28 15:50:36 -0400108 GrBackendFormat backendFormat = gpu->caps()->createFormatFromBackendTexture(backendTex);
Greg Daniel7278d682018-03-16 14:57:21 -0400109 REPORTER_ASSERT(reporter, backendFormat.isValid());
Greg Daniela8d92112018-03-09 12:05:04 -0500110
Greg Daniel7278d682018-03-16 14:57:21 -0400111 PromiseTextureChecker promiseChecker(backendTex);
112 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
113 sk_sp<SkImage> refImg(
114 SkImage_Gpu::MakePromiseTexture(ctx, backendFormat, kWidth, kHeight,
115 GrMipMapped::kNo, texOrigin,
116 kRGBA_8888_SkColorType, kPremul_SkAlphaType,
117 nullptr,
118 PromiseTextureChecker::Fulfill,
119 PromiseTextureChecker::Release,
120 PromiseTextureChecker::Done,
121 &promiseChecker));
Greg Daniela8d92112018-03-09 12:05:04 -0500122
Greg Daniel7278d682018-03-16 14:57:21 -0400123 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
124 sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
125 SkCanvas* canvas = surface->getCanvas();
Greg Daniela8d92112018-03-09 12:05:04 -0500126
Greg Daniel7278d682018-03-16 14:57:21 -0400127 int expectedFulfillCnt = 0;
128 int expectedReleaseCnt = 0;
129 int expectedDoneCnt = 0;
Greg Daniela8d92112018-03-09 12:05:04 -0500130
Greg Daniel7278d682018-03-16 14:57:21 -0400131 canvas->drawImage(refImg, 0, 0);
132 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
133 true,
134 expectedFulfillCnt,
135 expectedReleaseCnt,
136 true,
137 expectedDoneCnt,
138 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500139
Greg Daniel7278d682018-03-16 14:57:21 -0400140 bool isVulkan = kVulkan_GrBackend == ctx->contextPriv().getBackend();
141 canvas->flush();
142 expectedFulfillCnt++;
143 expectedReleaseCnt++;
144 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
145 !isVulkan,
146 expectedFulfillCnt,
147 expectedReleaseCnt,
148 !isVulkan,
149 expectedDoneCnt,
150 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500151
Greg Daniel7278d682018-03-16 14:57:21 -0400152 gpu->testingOnly_flushGpuAndSync();
153 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
154 true,
155 expectedFulfillCnt,
156 expectedReleaseCnt,
157 true,
158 expectedDoneCnt,
159 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500160
Greg Daniel7278d682018-03-16 14:57:21 -0400161 canvas->drawImage(refImg, 0, 0);
162 canvas->drawImage(refImg, 0, 0);
Greg Daniela8d92112018-03-09 12:05:04 -0500163
Greg Daniel7278d682018-03-16 14:57:21 -0400164 canvas->flush();
165 expectedFulfillCnt++;
166 expectedReleaseCnt++;
Greg Daniela8d92112018-03-09 12:05:04 -0500167
Greg Daniel7278d682018-03-16 14:57:21 -0400168 gpu->testingOnly_flushGpuAndSync();
169 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
170 true,
171 expectedFulfillCnt,
172 expectedReleaseCnt,
173 true,
174 expectedDoneCnt,
175 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500176
Greg Daniel7278d682018-03-16 14:57:21 -0400177 // Now test code path on Vulkan where we released the texture, but the GPU isn't done with
178 // resource yet and we do another draw. We should only call fulfill on the first draw and
179 // use the cached GrBackendTexture on the second. Release should only be called after the
180 // second draw is finished.
181 canvas->drawImage(refImg, 0, 0);
182 canvas->flush();
183 expectedFulfillCnt++;
184 expectedReleaseCnt++;
185 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
186 !isVulkan,
187 expectedFulfillCnt,
188 expectedReleaseCnt,
189 !isVulkan,
190 expectedDoneCnt,
191 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500192
Greg Daniel7278d682018-03-16 14:57:21 -0400193 canvas->drawImage(refImg, 0, 0);
Greg Daniela8d92112018-03-09 12:05:04 -0500194
Greg Daniel7278d682018-03-16 14:57:21 -0400195 if (releaseImageEarly) {
196 refImg.reset();
197 }
Greg Daniela8d92112018-03-09 12:05:04 -0500198
Greg Daniel7278d682018-03-16 14:57:21 -0400199 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
200 !isVulkan,
201 expectedFulfillCnt,
202 expectedReleaseCnt,
203 !isVulkan,
204 expectedDoneCnt,
205 reporter));
Greg Daniela8d92112018-03-09 12:05:04 -0500206
Greg Daniel7278d682018-03-16 14:57:21 -0400207 canvas->flush();
208 expectedFulfillCnt++;
Greg Daniela8d92112018-03-09 12:05:04 -0500209
Greg Daniel7278d682018-03-16 14:57:21 -0400210 gpu->testingOnly_flushGpuAndSync();
211 expectedReleaseCnt++;
212 if (releaseImageEarly) {
213 expectedDoneCnt++;
214 }
215 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
216 true,
217 expectedFulfillCnt,
218 expectedReleaseCnt,
219 !isVulkan,
220 expectedDoneCnt,
221 reporter));
222 expectedFulfillCnt = promiseChecker.fFulfillCount;
223 expectedReleaseCnt = promiseChecker.fReleaseCount;
224
225 if (!releaseImageEarly) {
226 refImg.reset();
227 expectedDoneCnt++;
228 }
229
230 REPORTER_ASSERT(reporter, check_fulfill_and_release_cnts(promiseChecker,
231 true,
232 expectedFulfillCnt,
233 expectedReleaseCnt,
234 true,
235 expectedDoneCnt,
236 reporter));
237
238 gpu->deleteTestingOnlyBackendTexture(backendTex);
239 }
Greg Daniela8d92112018-03-09 12:05:04 -0500240}