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