1 /*
2 * Copyright 2022 Google LLC
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/SkColorSpace.h"
11 #include "include/gpu/graphite/BackendTexture.h"
12 #include "include/gpu/graphite/Context.h"
13 #include "include/gpu/graphite/Image.h"
14 #include "include/gpu/graphite/Recorder.h"
15 #include "include/gpu/graphite/Surface.h"
16 #include "src/core/SkAutoPixmapStorage.h"
17 #include "src/gpu/graphite/Caps.h"
18 #include "src/gpu/graphite/ContextPriv.h"
19 #include "src/gpu/graphite/Surface_Graphite.h"
20 #include "tests/TestUtils.h"
21 #include "tools/ToolUtils.h"
22 #include "tools/graphite/GraphiteTestContext.h"
23
24 using namespace skgpu;
25 using namespace skgpu::graphite;
26
27 namespace {
28 const SkISize kSize = { 32, 32 };
29 constexpr int kNumMipLevels = 6;
30
31 constexpr SkColor4f kColors[6] = {
32 { 1.0f, 0.0f, 0.0f, 1.0f }, // R
33 { 0.0f, 1.0f, 0.0f, 0.9f }, // G
34 { 0.0f, 0.0f, 1.0f, 0.7f }, // B
35 { 0.0f, 1.0f, 1.0f, 0.5f }, // C
36 { 1.0f, 0.0f, 1.0f, 0.3f }, // M
37 { 1.0f, 1.0f, 0.0f, 0.2f }, // Y
38 };
39
40 constexpr SkColor4f kColorsNew[6] = {
41 { 1.0f, 1.0f, 0.0f, 0.2f }, // Y
42 { 1.0f, 0.0f, 0.0f, 1.0f }, // R
43 { 0.0f, 1.0f, 0.0f, 0.9f }, // G
44 { 0.0f, 0.0f, 1.0f, 0.7f }, // B
45 { 0.0f, 1.0f, 1.0f, 0.5f }, // C
46 { 1.0f, 0.0f, 1.0f, 0.3f }, // M
47 };
48
check_solid_pixmap(skiatest::Reporter * reporter,const SkColor4f & expected,const SkPixmap & actual,SkColorType ct,const char * label)49 void check_solid_pixmap(skiatest::Reporter* reporter,
50 const SkColor4f& expected,
51 const SkPixmap& actual,
52 SkColorType ct,
53 const char* label) {
54 const float kTols[4] = { 0.01f, 0.01f, 0.01f, 0.01f };
55
56 auto error = std::function<ComparePixmapsErrorReporter>(
57 [reporter, ct, label, expected](int x, int y, const float diffs[4]) {
58 SkASSERT(x >= 0 && y >= 0);
59 ERRORF(reporter, "%s %s - mismatch at %d, %d "
60 "expected: (%.2f, %.2f, %.2f, %.2f) "
61 "- diffs: (%.2f, %.2f, %.2f, %.2f)",
62 ToolUtils::colortype_name(ct), label, x, y,
63 expected.fR, expected.fG, expected.fB, expected.fA,
64 diffs[0], diffs[1], diffs[2], diffs[3]);
65 });
66
67 CheckSolidPixels(expected, actual, kTols, error);
68 }
69
update_backend_texture(Recorder * recorder,const BackendTexture & backendTex,SkColorType ct,bool withMips,const SkColor4f colors[6],GpuFinishedProc finishedProc=nullptr,GpuFinishedContext finishedCtx=nullptr)70 void update_backend_texture(Recorder* recorder,
71 const BackendTexture& backendTex,
72 SkColorType ct,
73 bool withMips,
74 const SkColor4f colors[6],
75 GpuFinishedProc finishedProc = nullptr,
76 GpuFinishedContext finishedCtx = nullptr) {
77 SkPixmap pixmaps[6];
78 std::unique_ptr<char[]> memForPixmaps;
79
80 int numMipLevels = ToolUtils::make_pixmaps(ct, kPremul_SkAlphaType, withMips, colors, pixmaps,
81 &memForPixmaps);
82 SkASSERT(numMipLevels == 1 || numMipLevels == kNumMipLevels);
83 SkASSERT(kSize == pixmaps[0].dimensions());
84
85 recorder->updateBackendTexture(backendTex, pixmaps, numMipLevels, finishedProc, finishedCtx);
86
87 }
88
create_backend_texture(skiatest::Reporter * reporter,const Caps * caps,Recorder * recorder,SkColorType ct,bool withMips,Renderable renderable,skgpu::Protected isProtected,const SkColor4f colors[6],GpuFinishedProc finishedProc=nullptr,GpuFinishedContext finishedCtx=nullptr)89 BackendTexture create_backend_texture(skiatest::Reporter* reporter,
90 const Caps* caps,
91 Recorder* recorder,
92 SkColorType ct,
93 bool withMips,
94 Renderable renderable,
95 skgpu::Protected isProtected,
96 const SkColor4f colors[6],
97 GpuFinishedProc finishedProc = nullptr,
98 GpuFinishedContext finishedCtx = nullptr) {
99 Mipmapped mipmapped = withMips ? Mipmapped::kYes : Mipmapped::kNo;
100 TextureInfo info = caps->getDefaultSampledTextureInfo(ct,
101 mipmapped,
102 isProtected,
103 renderable);
104
105 BackendTexture backendTex = recorder->createBackendTexture(kSize, info);
106 REPORTER_ASSERT(reporter, backendTex.isValid());
107
108 update_backend_texture(recorder, backendTex, ct, withMips, colors, finishedProc, finishedCtx);
109
110 return backendTex;
111 }
112
wrap_backend_texture(skiatest::Reporter * reporter,Recorder * recorder,const skgpu::graphite::BackendTexture & backendTex,SkColorType ct,bool withMips)113 sk_sp<SkImage> wrap_backend_texture(skiatest::Reporter* reporter,
114 Recorder* recorder,
115 const skgpu::graphite::BackendTexture& backendTex,
116 SkColorType ct,
117 bool withMips) {
118 sk_sp<SkImage> image = SkImages::WrapTexture(recorder,
119 backendTex,
120 ct,
121 kPremul_SkAlphaType,
122 /* colorSpace= */ nullptr);
123 REPORTER_ASSERT(reporter, image);
124 REPORTER_ASSERT(reporter, image->hasMipmaps() == withMips);
125
126 return image;
127 }
128
check_levels(skiatest::Reporter * reporter,Context * context,Recorder * recorder,SkImage * image,bool withMips,const SkColor4f colors[6])129 void check_levels(skiatest::Reporter* reporter,
130 Context* context,
131 Recorder* recorder,
132 SkImage* image,
133 bool withMips,
134 const SkColor4f colors[6]) {
135 int numLevels = withMips ? kNumMipLevels : 1;
136
137 SkSamplingOptions sampling = withMips
138 ? SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest)
139 : SkSamplingOptions(SkFilterMode::kNearest);
140
141 SkImageInfo surfaceII = SkImageInfo::Make(kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
142 sk_sp<SkSurface> surf = SkSurfaces::RenderTarget(recorder, surfaceII, Mipmapped::kNo);
143 SkCanvas* canvas = surf->getCanvas();
144
145 for (int i = 0, drawSize = kSize.width(); i < numLevels; ++i, drawSize /= 2) {
146 if (i == 5) {
147 // TODO: Metal currently never draws the top-most mip-level (skbug.com/13792)
148 continue;
149 }
150
151 SkImageInfo readbackII = SkImageInfo::Make({drawSize, drawSize}, kRGBA_8888_SkColorType,
152 kUnpremul_SkAlphaType);
153 SkAutoPixmapStorage actual;
154 SkAssertResult(actual.tryAlloc(readbackII));
155 actual.erase(SkColors::kTransparent);
156
157 SkPaint paint;
158 paint.setBlendMode(SkBlendMode::kSrc);
159
160 canvas->clear(SkColors::kTransparent);
161
162 #if 0
163 // This option gives greater control over the tilemodes and texture scaling
164 SkMatrix lm;
165 lm.setScale(1.0f / (1 << i), 1.0f / (1 << i));
166
167 paint.setShader(image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, sampling, lm));
168 canvas->drawRect(SkRect::MakeWH(drawSize, drawSize), paint);
169 #else
170 canvas->drawImageRect(image, SkRect::MakeWH(drawSize, drawSize), sampling, &paint);
171 #endif
172
173 if (!surf->readPixels(actual, 0, 0)) {
174 ERRORF(reporter, "readPixels failed");
175 return;
176 }
177
178 SkString str;
179 str.appendf("mip-level %d", i);
180
181 check_solid_pixmap(reporter, colors[i], actual, image->colorType(), str.c_str());
182 }
183 }
184
185 } // anonymous namespace
186
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(UpdateImageBackendTextureTest,reporter,context,CtsEnforcement::kApiLevel_V)187 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(UpdateImageBackendTextureTest, reporter, context,
188 CtsEnforcement::kApiLevel_V) {
189 const Caps* caps = context->priv().caps();
190 std::unique_ptr<Recorder> recorder = context->makeRecorder();
191
192 skgpu::Protected isProtected = skgpu::Protected(caps->protectedSupport());
193
194 // TODO: test more than just RGBA8
195 for (SkColorType ct : { kRGBA_8888_SkColorType }) {
196 for (bool withMips : { true, false }) {
197 for (Renderable renderable : { Renderable::kYes, Renderable::kNo }) {
198
199 BackendTexture backendTex = create_backend_texture(reporter, caps, recorder.get(),
200 ct, withMips, renderable,
201 isProtected, kColors);
202
203 sk_sp<SkImage> image = wrap_backend_texture(reporter, recorder.get(), backendTex,
204 ct, withMips);
205 if (!image) {
206 continue;
207 }
208
209 if (isProtected == skgpu::Protected::kNo) {
210 check_levels(reporter, context, recorder.get(), image.get(), withMips, kColors);
211 }
212
213 image.reset();
214
215 update_backend_texture(recorder.get(), backendTex, ct, withMips, kColorsNew);
216
217 image = wrap_backend_texture(reporter, recorder.get(), backendTex, ct, withMips);
218 if (!image) {
219 continue;
220 }
221
222 if (isProtected == skgpu::Protected::kNo) {
223 check_levels(reporter, context, recorder.get(), image.get(), withMips,
224 kColorsNew);
225 }
226
227 image.reset();
228
229 recorder->deleteBackendTexture(backendTex);
230 }
231 }
232 }
233 }
234
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(UpdateBackendTextureFinishedProcTest,reporter,context,testContext,true,CtsEnforcement::kNextRelease)235 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(UpdateBackendTextureFinishedProcTest,
236 reporter,
237 context,
238 testContext,
239 true,
240 CtsEnforcement::kNextRelease) {
241 const Caps* caps = context->priv().caps();
242 std::unique_ptr<Recorder> recorder = context->makeRecorder();
243
244 skgpu::Protected isProtected = skgpu::Protected(caps->protectedSupport());
245
246 struct FinishContext {
247 bool fFinishedUpdate = false;
248 skiatest::Reporter* fReporter = nullptr;
249 };
250 FinishContext finishCtx;
251 finishCtx.fReporter = reporter;
252
253 auto finishedProc = [](void* ctx, CallbackResult) {
254 FinishContext* finishedCtx = (FinishContext*) ctx;
255 REPORTER_ASSERT(finishedCtx->fReporter, !(finishedCtx->fFinishedUpdate));
256 finishedCtx->fFinishedUpdate = true;
257 };
258
259 BackendTexture backendTex = create_backend_texture(reporter,
260 caps,
261 recorder.get(),
262 kRGBA_8888_SkColorType,
263 /*withMips=*/false,
264 Renderable::kNo,
265 isProtected,
266 kColors,
267 finishedProc,
268 &finishCtx);
269
270 REPORTER_ASSERT(reporter, !finishCtx.fFinishedUpdate);
271
272 std::unique_ptr<Recording> recording = recorder->snap();
273 if (!recording) {
274 ERRORF(reporter, "Failed to make recording");
275 return;
276 }
277 InsertRecordingInfo insertInfo;
278 insertInfo.fRecording = recording.get();
279 context->insertRecording(insertInfo);
280
281 REPORTER_ASSERT(reporter, !finishCtx.fFinishedUpdate);
282
283 testContext->syncedSubmit(context);
284 REPORTER_ASSERT(reporter, finishCtx.fFinishedUpdate);
285
286 recorder->deleteBackendTexture(backendTex);
287 }
288