1 /*
2 * Copyright 2019 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 "include/core/SkCanvas.h"
9 #include "include/core/SkImage.h"
10 #include "include/core/SkSurface.h"
11 #include "include/gpu/GrDirectContext.h"
12 #include "src/core/SkAutoPixmapStorage.h"
13 #include "src/gpu/GrPixmap.h"
14
15 #include "tests/Test.h"
16 #include "tests/TestUtils.h"
17 #include "tools/ToolUtils.h"
18
19 static constexpr int kSize = 32;
20
get_trans_black_expected_color(SkColorChannelFlag channels)21 static SkColor4f get_trans_black_expected_color(SkColorChannelFlag channels) {
22 float a = 0;
23 if (!(channels & kAlpha_SkColorChannelFlag)) {
24 a = 1;
25 }
26
27 return { 0, 0, 0, a };
28 }
29
get_opaque_white_expected_color(SkColorChannelFlag channels)30 static SkColor4f get_opaque_white_expected_color(SkColorChannelFlag channels) {
31 if (channels & kGray_SkColorChannelFlag) {
32 return { 1, 1, 1, 1 };
33 }
34
35 float r = 1, g = 1, b = 1;
36 if (!(channels & kRed_SkColorChannelFlag)) {
37 r = 0;
38 }
39 if (!(channels & kGreen_SkColorChannelFlag)) {
40 g = 0;
41 }
42 if (!(channels & kBlue_SkColorChannelFlag)) {
43 b = 0;
44 }
45
46 return { r, g, b, 1.0f };
47 }
48
49 struct TestCase {
50 SkColorType fColorType;
51 SkAlphaType fAlphaType;
52 SkColorChannelFlag fChannels;
53 bool fGpuCanMakeSurfaces;
54 };
55
56 static const TestCase gTests[] = {
57 { kAlpha_8_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorChannelFlag, true },
58 { kA16_unorm_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorChannelFlag, false},
59 { kA16_float_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorChannelFlag, false},
60 { kRGB_565_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorChannelFlags, true },
61 { kARGB_4444_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true },
62 { kRGBA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true },
63 { kRGB_888x_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorChannelFlags, true },
64 { kBGRA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true },
65 { kRGBA_1010102_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true },
66 { kRGB_101010x_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorChannelFlags, true },
67 { kGray_8_SkColorType, kOpaque_SkAlphaType, kGray_SkColorChannelFlag, true },
68 { kRGBA_F16Norm_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true },
69 { kRGBA_F16_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true },
70 { kRGBA_F32_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true },
71 { kR8G8_unorm_SkColorType, kOpaque_SkAlphaType, kRG_SkColorChannelFlags, true },
72 { kR16G16_unorm_SkColorType, kOpaque_SkAlphaType, kRG_SkColorChannelFlags, false},
73 { kR16G16_float_SkColorType, kOpaque_SkAlphaType, kRG_SkColorChannelFlags, false},
74 { kR16G16B16A16_unorm_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, false},
75 };
76
raster_tests(skiatest::Reporter * reporter,const TestCase & test)77 static void raster_tests(skiatest::Reporter* reporter, const TestCase& test) {
78
79 const SkImageInfo nativeII = SkImageInfo::Make(kSize, kSize, test.fColorType, test.fAlphaType);
80 const SkImageInfo f32Unpremul = SkImageInfo::Make(kSize, kSize, kRGBA_F32_SkColorType,
81 kUnpremul_SkAlphaType);
82
83 uint32_t actualChannels = SkColorTypeChannelFlags(test.fColorType);
84 REPORTER_ASSERT(reporter, test.fChannels == actualChannels);
85
86 // all colorTypes can be drawn to
87 {
88 auto s = SkSurface::MakeRaster(nativeII);
89 REPORTER_ASSERT(reporter, SkToBool(s));
90 }
91
92 // opaque formats should make transparent black become opaque
93 {
94 SkAutoPixmapStorage pm;
95 pm.alloc(nativeII);
96 pm.erase(SkColors::kTransparent);
97 SkColor actual = pm.getColor(0, 0);
98 SkColor4f expected = get_trans_black_expected_color(test.fChannels);
99 REPORTER_ASSERT(reporter, expected.toSkColor() == actual);
100 }
101
102 // unused channels should drop out
103 {
104 SkAutoPixmapStorage pm;
105 pm.alloc(nativeII);
106 pm.erase(SkColors::kWhite);
107 SkColor actual = pm.getColor(0, 0);
108 SkColor4f expected = get_opaque_white_expected_color(test.fChannels);
109 REPORTER_ASSERT(reporter, expected.toSkColor() == actual);
110 }
111
112 // Reading back from an image to the same colorType should always work
113 {
114 SkAutoPixmapStorage srcPM;
115 srcPM.alloc(nativeII);
116 srcPM.erase(SkColors::kWhite);
117 auto i = SkImage::MakeFromRaster(srcPM, nullptr, nullptr);
118 REPORTER_ASSERT(reporter, SkToBool(i));
119
120 SkAutoPixmapStorage readbackPM;
121 readbackPM.alloc(nativeII);
122 readbackPM.erase(SkColors::kTransparent);
123
124 REPORTER_ASSERT(reporter, i->readPixels(nullptr, readbackPM, 0, 0));
125
126 SkColor expected = srcPM.getColor(0, 0);
127 SkColor actual = readbackPM.getColor(0, 0);
128 REPORTER_ASSERT(reporter, expected == actual);
129 }
130
131 // Rendering to an F32 surface should always work
132 {
133 SkAutoPixmapStorage srcPM;
134 srcPM.alloc(nativeII);
135 srcPM.erase(SkColors::kWhite);
136 auto i = SkImage::MakeFromRaster(srcPM, nullptr, nullptr);
137 REPORTER_ASSERT(reporter, SkToBool(i));
138
139 auto s = SkSurface::MakeRaster(f32Unpremul);
140 REPORTER_ASSERT(reporter, SkToBool(s));
141
142 {
143 auto c = s->getCanvas();
144 c->drawImage(i, 0, 0);
145 }
146
147 SkAutoPixmapStorage readbackPM;
148 readbackPM.alloc(f32Unpremul);
149 readbackPM.erase(SkColors::kTransparent);
150
151 REPORTER_ASSERT(reporter, i->readPixels(nullptr, readbackPM, 0, 0));
152
153 SkColor expected = srcPM.getColor(0, 0);
154 SkColor actual = readbackPM.getColor(0, 0);
155 REPORTER_ASSERT(reporter, expected == actual);
156 }
157 }
158
compare_pixmaps(skiatest::Reporter * reporter,const SkPixmap & expected,const SkPixmap & actual,SkColorType ct,const char * label)159 static void compare_pixmaps(skiatest::Reporter* reporter,
160 const SkPixmap& expected, const SkPixmap& actual,
161 SkColorType ct, const char* label) {
162 const float tols[4] = {0.0f, 0.0f, 0.0f, 0};
163
164 auto error = std::function<ComparePixmapsErrorReporter>(
165 [reporter, ct, label](int x, int y, const float diffs[4]) {
166 SkASSERT(x >= 0 && y >= 0);
167 ERRORF(reporter, "%s %s - mismatch at %d, %d (%f, %f, %f %f)",
168 ToolUtils::colortype_name(ct), label, x, y,
169 diffs[0], diffs[1], diffs[2], diffs[3]);
170 });
171
172 ComparePixels(expected, actual, tols, error);
173 }
174
gpu_tests(GrDirectContext * dContext,skiatest::Reporter * reporter,const TestCase & test)175 static void gpu_tests(GrDirectContext* dContext,
176 skiatest::Reporter* reporter,
177 const TestCase& test) {
178
179 const SkImageInfo nativeII = SkImageInfo::Make(kSize, kSize, test.fColorType, test.fAlphaType);
180 const SkImageInfo f32Unpremul = SkImageInfo::Make(kSize, kSize, kRGBA_F32_SkColorType,
181 kUnpremul_SkAlphaType);
182
183 // We had better not be able to render to prohibited colorTypes
184 if (!test.fGpuCanMakeSurfaces) {
185 auto s = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, nativeII);
186 REPORTER_ASSERT(reporter, !SkToBool(s));
187 }
188
189 if (!dContext->colorTypeSupportedAsImage(test.fColorType)) {
190 return;
191 }
192
193 SkAutoPixmapStorage nativeExpected;
194 nativeExpected.alloc(nativeII);
195 nativeExpected.erase(SkColors::kWhite);
196
197 for (bool fullInit : { false, true }) {
198 GrBackendTexture backendTex;
199
200 bool finishedBECreate = false;
201 auto markFinished = [](void* context) {
202 *(bool*)context = true;
203 };
204 if (fullInit) {
205 backendTex = dContext->createBackendTexture(nativeExpected, kTopLeft_GrSurfaceOrigin,
206 GrRenderable::kNo, GrProtected::kNo,
207 markFinished, &finishedBECreate);
208 } else {
209 backendTex = dContext->createBackendTexture(kSize, kSize, test.fColorType,
210 SkColors::kWhite, GrMipmapped::kNo,
211 GrRenderable::kNo, GrProtected::kNo,
212 markFinished, &finishedBECreate);
213 }
214 REPORTER_ASSERT(reporter, backendTex.isValid());
215 dContext->submit();
216 while (backendTex.isValid() && !finishedBECreate) {
217 dContext->checkAsyncWorkCompletion();
218 }
219
220 auto img = SkImage::MakeFromTexture(dContext, backendTex, kTopLeft_GrSurfaceOrigin,
221 test.fColorType, test.fAlphaType, nullptr);
222 REPORTER_ASSERT(reporter, SkToBool(img));
223
224 {
225 SkAutoPixmapStorage nativeActual;
226 nativeActual.alloc(nativeII);
227 nativeActual.erase(SkColors::kTransparent);
228
229 if (img->readPixels(dContext, nativeActual, 0, 0)) {
230 compare_pixmaps(reporter, nativeExpected, nativeActual,
231 test.fColorType, "SkImage::readPixels to native CT");
232 }
233
234 // SkSurface::readPixels with the same colorType as the source pixels round trips
235 // (when allowed)
236 if (dContext->colorTypeSupportedAsSurface(test.fColorType)) {
237 auto s = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, nativeII);
238 REPORTER_ASSERT(reporter, SkToBool(s));
239
240 {
241 SkCanvas* c = s->getCanvas();
242 c->drawImage(img, 0, 0);
243 }
244
245 nativeActual.erase(SkColors::kTransparent);
246 REPORTER_ASSERT(reporter, s->readPixels(nativeActual, 0, 0));
247
248 compare_pixmaps(reporter, nativeExpected, nativeActual,
249 test.fColorType, "SkSurface::readPixels to native CT");
250 }
251 }
252
253 {
254 SkAutoPixmapStorage f32Expected;
255 f32Expected.alloc(f32Unpremul);
256 f32Expected.erase(get_opaque_white_expected_color(test.fChannels));
257
258 // read back to F32 if possible
259 {
260 SkAutoPixmapStorage f32Actual;
261 f32Actual.alloc(f32Unpremul);
262 f32Actual.erase(SkColors::kTransparent);
263 if (img->readPixels(dContext, f32Actual, 0, 0)) {
264 compare_pixmaps(reporter, f32Expected, f32Actual,
265 test.fColorType, "SkImage::readPixels to F32");
266 }
267 }
268
269 // drawing a native SkImage works appropriately (as assessed by reading back from an
270 // RGBA8 surface to an F32 pixmap)
271 {
272 const SkImageInfo rgba8888Premul = SkImageInfo::Make(kSize, kSize,
273 kRGBA_8888_SkColorType,
274 kPremul_SkAlphaType);
275
276 auto s = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, rgba8888Premul);
277 REPORTER_ASSERT(reporter, SkToBool(s));
278
279 {
280 SkCanvas* c = s->getCanvas();
281 c->drawImage(img, 0, 0);
282 }
283
284 SkAutoPixmapStorage f32Actual;
285 f32Actual.alloc(f32Unpremul);
286 f32Actual.erase(SkColors::kTransparent);
287 REPORTER_ASSERT(reporter, s->readPixels(f32Actual, 0, 0));
288
289 compare_pixmaps(reporter, f32Expected, f32Actual,
290 test.fColorType, "SkSurface::drawn to RGBA8888");
291 }
292 }
293
294 img.reset();
295 dContext->flushAndSubmit();
296 dContext->deleteBackendTexture(backendTex);
297 }
298 }
299
DEF_TEST(ExtendedSkColorTypeTests_raster,reporter)300 DEF_TEST(ExtendedSkColorTypeTests_raster, reporter) {
301 for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
302 raster_tests(reporter, gTests[i]);
303 }
304 }
305
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ExtendedSkColorTypeTests_gpu,reporter,ctxInfo)306 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ExtendedSkColorTypeTests_gpu, reporter, ctxInfo) {
307 auto context = ctxInfo.directContext();
308
309 for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
310 gpu_tests(context, reporter, gTests[i]);
311 }
312 }
313