blob: a6cc599617d546142eaeabc7a820bde1a44581fa [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
Brian Osman01e6d172020-03-30 15:57:14 -04008#include "include/core/SkCanvas.h"
Robert Phillipsd470e1b2019-09-04 15:05:35 -04009#include "include/core/SkImage.h"
10#include "include/core/SkSurface.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040011#include "include/gpu/GrDirectContext.h"
Robert Phillipsd470e1b2019-09-04 15:05:35 -040012#include "src/core/SkAutoPixmapStorage.h"
Robert Phillipsd470e1b2019-09-04 15:05:35 -040013
14#include "tests/Test.h"
15#include "tests/TestUtils.h"
Robert Phillipse3b6fe42019-09-11 11:26:46 -040016#include "tools/ToolUtils.h"
Robert Phillipsd470e1b2019-09-04 15:05:35 -040017
18static constexpr int kSize = 32;
19
Brian Salomon2f23ae62020-03-26 16:17:56 -040020static SkColor4f get_trans_black_expected_color(SkColorChannelFlag channels) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -040021 float a = 0;
Brian Salomon2f23ae62020-03-26 16:17:56 -040022 if (!(channels & kAlpha_SkColorChannelFlag)) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -040023 a = 1;
24 }
25
26 return { 0, 0, 0, a };
27}
28
Brian Salomon2f23ae62020-03-26 16:17:56 -040029static SkColor4f get_opaque_white_expected_color(SkColorChannelFlag channels) {
30 if (channels & kGray_SkColorChannelFlag) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -040031 return { 1, 1, 1, 1 };
32 }
33
34 float r = 1, g = 1, b = 1;
Brian Salomon2f23ae62020-03-26 16:17:56 -040035 if (!(channels & kRed_SkColorChannelFlag)) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -040036 r = 0;
37 }
Brian Salomon2f23ae62020-03-26 16:17:56 -040038 if (!(channels & kGreen_SkColorChannelFlag)) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -040039 g = 0;
40 }
Brian Salomon2f23ae62020-03-26 16:17:56 -040041 if (!(channels & kBlue_SkColorChannelFlag)) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -040042 b = 0;
43 }
44
45 return { r, g, b, 1.0f };
46}
47
48struct TestCase {
Brian Salomon2f23ae62020-03-26 16:17:56 -040049 SkColorType fColorType;
50 SkAlphaType fAlphaType;
51 SkColorChannelFlag fChannels;
52 bool fGpuCanMakeSurfaces;
53 bool fCpuCanMakeSurfaces;
Robert Phillipsd470e1b2019-09-04 15:05:35 -040054};
55
56static const TestCase gTests[] = {
Brian Salomon2f23ae62020-03-26 16:17:56 -040057 { kAlpha_8_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorChannelFlag, true, true },
58 { kA16_unorm_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorChannelFlag, false, false},
59 { kA16_float_SkColorType, kPremul_SkAlphaType, kAlpha_SkColorChannelFlag, false, false},
60 { kRGB_565_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorChannelFlags, true, true },
61 { kARGB_4444_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true, true },
62 { kRGBA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true, true },
63 { kRGB_888x_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorChannelFlags, true, true },
64 { kBGRA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true, true },
65 { kRGBA_1010102_SkColorType,kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true, true },
66 { kRGB_101010x_SkColorType, kOpaque_SkAlphaType, kRGB_SkColorChannelFlags, true, true },
67 { kGray_8_SkColorType, kOpaque_SkAlphaType, kGray_SkColorChannelFlag, true, true },
68 { kRGBA_F16Norm_SkColorType,kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true, true },
69 { kRGBA_F16_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true, true },
70 { kRGBA_F32_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, true, true },
71 { kR8G8_unorm_SkColorType, kOpaque_SkAlphaType, kRG_SkColorChannelFlags, true, false},
72 { kR16G16_unorm_SkColorType,kOpaque_SkAlphaType, kRG_SkColorChannelFlags, false, false},
73 { kR16G16_float_SkColorType,kOpaque_SkAlphaType, kRG_SkColorChannelFlags, false, false},
Robert Phillips99044e12020-01-29 08:37:01 -050074 { kR16G16B16A16_unorm_SkColorType,
Brian Salomon2f23ae62020-03-26 16:17:56 -040075 kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, false, false},
Robert Phillipsd470e1b2019-09-04 15:05:35 -040076};
77
78static void raster_tests(skiatest::Reporter* reporter, const TestCase& test) {
79
80 const SkImageInfo nativeII = SkImageInfo::Make(kSize, kSize, test.fColorType, test.fAlphaType);
81 const SkImageInfo f32Unpremul = SkImageInfo::Make(kSize, kSize, kRGBA_F32_SkColorType,
82 kUnpremul_SkAlphaType);
83
Brian Salomon2f23ae62020-03-26 16:17:56 -040084 uint32_t actualChannels = SkColorTypeChannelFlags(test.fColorType);
85 REPORTER_ASSERT(reporter, test.fChannels == actualChannels);
Robert Phillipsd470e1b2019-09-04 15:05:35 -040086
87 // Not all colorTypes can be drawn to
88 {
89 auto s = SkSurface::MakeRaster(nativeII);
Robert Phillips99044e12020-01-29 08:37:01 -050090 REPORTER_ASSERT(reporter, SkToBool(s) == test.fCpuCanMakeSurfaces);
Robert Phillipsd470e1b2019-09-04 15:05:35 -040091 }
92
93 // opaque formats should make transparent black become opaque
94 {
95 SkAutoPixmapStorage pm;
96 pm.alloc(nativeII);
97 pm.erase(SkColors::kTransparent);
98 SkColor actual = pm.getColor(0, 0);
Brian Salomon2f23ae62020-03-26 16:17:56 -040099 SkColor4f expected = get_trans_black_expected_color(test.fChannels);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400100 REPORTER_ASSERT(reporter, expected.toSkColor() == actual);
101 }
102
103 // unused channels should drop out
104 {
105 SkAutoPixmapStorage pm;
106 pm.alloc(nativeII);
107 pm.erase(SkColors::kWhite);
108 SkColor actual = pm.getColor(0, 0);
Brian Salomon2f23ae62020-03-26 16:17:56 -0400109 SkColor4f expected = get_opaque_white_expected_color(test.fChannels);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400110 REPORTER_ASSERT(reporter, expected.toSkColor() == actual);
111 }
112
113 // Reading back from an image to the same colorType should always work
114 {
115 SkAutoPixmapStorage srcPM;
116 srcPM.alloc(nativeII);
117 srcPM.erase(SkColors::kWhite);
118 auto i = SkImage::MakeFromRaster(srcPM, nullptr, nullptr);
119 REPORTER_ASSERT(reporter, SkToBool(i));
120
121 SkAutoPixmapStorage readbackPM;
122 readbackPM.alloc(nativeII);
123 readbackPM.erase(SkColors::kTransparent);
124
125 REPORTER_ASSERT(reporter, i->readPixels(readbackPM, 0, 0));
126
127 SkColor expected = srcPM.getColor(0, 0);
128 SkColor actual = readbackPM.getColor(0, 0);
129 REPORTER_ASSERT(reporter, expected == actual);
130 }
131
132 // Rendering to an F32 surface should always work
133 {
134 SkAutoPixmapStorage srcPM;
135 srcPM.alloc(nativeII);
136 srcPM.erase(SkColors::kWhite);
137 auto i = SkImage::MakeFromRaster(srcPM, nullptr, nullptr);
138 REPORTER_ASSERT(reporter, SkToBool(i));
139
140 auto s = SkSurface::MakeRaster(f32Unpremul);
141 REPORTER_ASSERT(reporter, SkToBool(s));
142
143 {
144 auto c = s->getCanvas();
145 c->drawImage(i, 0, 0);
146 }
147
148 SkAutoPixmapStorage readbackPM;
149 readbackPM.alloc(f32Unpremul);
150 readbackPM.erase(SkColors::kTransparent);
151
152 REPORTER_ASSERT(reporter, i->readPixels(readbackPM, 0, 0));
153
154 SkColor expected = srcPM.getColor(0, 0);
155 SkColor actual = readbackPM.getColor(0, 0);
156 REPORTER_ASSERT(reporter, expected == actual);
157 }
158}
159
160static void compare_pixmaps(skiatest::Reporter* reporter,
161 const SkPixmap& expected, const SkPixmap& actual,
Robert Phillipse3b6fe42019-09-11 11:26:46 -0400162 SkColorType ct, const char* label) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400163 const float tols[4] = {0.0f, 0.0f, 0.0f, 0};
164
165 auto error = std::function<ComparePixmapsErrorReporter>(
Robert Phillipse3b6fe42019-09-11 11:26:46 -0400166 [reporter, ct, label](int x, int y, const float diffs[4]) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400167 SkASSERT(x >= 0 && y >= 0);
Robert Phillipse3b6fe42019-09-11 11:26:46 -0400168 ERRORF(reporter, "%s %s - mismatch at %d, %d (%f, %f, %f %f)",
169 ToolUtils::colortype_name(ct), label, x, y,
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400170 diffs[0], diffs[1], diffs[2], diffs[3]);
171 });
172
Brian Salomon28a8f282019-10-24 20:07:39 -0400173 ComparePixels(expected, actual, tols, error);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400174}
175
176static void gpu_tests(GrContext* context, skiatest::Reporter* reporter, const TestCase& test) {
177
178 const SkImageInfo nativeII = SkImageInfo::Make(kSize, kSize, test.fColorType, test.fAlphaType);
179 const SkImageInfo f32Unpremul = SkImageInfo::Make(kSize, kSize, kRGBA_F32_SkColorType,
180 kUnpremul_SkAlphaType);
181
182 // We had better not be able to render to prohibited colorTypes
Robert Phillips99044e12020-01-29 08:37:01 -0500183 if (!test.fGpuCanMakeSurfaces) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400184 auto s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, nativeII);
185 REPORTER_ASSERT(reporter, !SkToBool(s));
186 }
187
188 if (!context->colorTypeSupportedAsImage(test.fColorType)) {
189 return;
190 }
191
192 SkAutoPixmapStorage nativeExpected;
193 nativeExpected.alloc(nativeII);
194 nativeExpected.erase(SkColors::kWhite);
195
196 for (bool fullInit : { false, true }) {
197 GrBackendTexture backendTex;
198
Greg Danielc1ad77c2020-05-06 11:40:03 -0400199 bool finishedBECreate = false;
200 auto markFinished = [](void* context) {
201 *(bool*)context = true;
202 };
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400203 if (fullInit) {
Robert Phillips66944402019-09-30 13:21:25 -0400204 backendTex = context->createBackendTexture(&nativeExpected, 1,
Greg Danielc1ad77c2020-05-06 11:40:03 -0400205 GrRenderable::kNo, GrProtected::kNo,
206 markFinished, &finishedBECreate);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400207 } else {
208 backendTex = context->createBackendTexture(kSize, kSize, test.fColorType,
209 SkColors::kWhite, GrMipMapped::kNo,
Greg Danielc1ad77c2020-05-06 11:40:03 -0400210 GrRenderable::kNo, GrProtected::kNo,
211 markFinished, &finishedBECreate);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400212 }
213 REPORTER_ASSERT(reporter, backendTex.isValid());
Greg Danielb5776552020-06-19 20:21:08 -0400214 context->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400215 while (backendTex.isValid() && !finishedBECreate) {
216 context->checkAsyncWorkCompletion();
217 }
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400218
219 auto img = SkImage::MakeFromTexture(context, backendTex, kTopLeft_GrSurfaceOrigin,
220 test.fColorType, test.fAlphaType, nullptr);
221 REPORTER_ASSERT(reporter, SkToBool(img));
222
223 {
224 SkAutoPixmapStorage nativeActual;
225 nativeActual.alloc(nativeII);
226 nativeActual.erase(SkColors::kTransparent);
227
228 if (img->readPixels(nativeActual, 0, 0)) {
229 compare_pixmaps(reporter, nativeExpected, nativeActual,
230 test.fColorType, "SkImage::readPixels to native CT");
231 }
232
233 // SkSurface::readPixels with the same colorType as the source pixels round trips
234 // (when allowed)
235 if (context->colorTypeSupportedAsSurface(test.fColorType)) {
236 auto s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, nativeII);
237 REPORTER_ASSERT(reporter, SkToBool(s));
238
239 {
240 SkCanvas* c = s->getCanvas();
241 c->drawImage(img, 0, 0);
242 }
243
244 nativeActual.erase(SkColors::kTransparent);
245 REPORTER_ASSERT(reporter, s->readPixels(nativeActual, 0, 0));
246
247 compare_pixmaps(reporter, nativeExpected, nativeActual,
248 test.fColorType, "SkSurface::readPixels to native CT");
249 }
250 }
251
252 {
253 SkAutoPixmapStorage f32Expected;
254 f32Expected.alloc(f32Unpremul);
Brian Salomon2f23ae62020-03-26 16:17:56 -0400255 f32Expected.erase(get_opaque_white_expected_color(test.fChannels));
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400256
257 // read back to F32 if possible
258 {
259 SkAutoPixmapStorage f32Actual;
260 f32Actual.alloc(f32Unpremul);
261 f32Actual.erase(SkColors::kTransparent);
262 if (img->readPixels(f32Actual, 0, 0)) {
263 compare_pixmaps(reporter, f32Expected, f32Actual,
264 test.fColorType, "SkImage::readPixels to F32");
265 }
266 }
267
268 // drawing a native SkImage works appropriately (as assessed by reading back from an
269 // RGBA8 surface to an F32 pixmap)
270 {
271 const SkImageInfo rgba8888Premul = SkImageInfo::Make(kSize, kSize,
272 kRGBA_8888_SkColorType,
273 kPremul_SkAlphaType);
274
275 auto s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, rgba8888Premul);
276 REPORTER_ASSERT(reporter, SkToBool(s));
277
278 {
279 SkCanvas* c = s->getCanvas();
280 c->drawImage(img, 0, 0);
281 }
282
283 SkAutoPixmapStorage f32Actual;
284 f32Actual.alloc(f32Unpremul);
285 f32Actual.erase(SkColors::kTransparent);
286 REPORTER_ASSERT(reporter, s->readPixels(f32Actual, 0, 0));
287
288 compare_pixmaps(reporter, f32Expected, f32Actual,
289 test.fColorType, "SkSurface::drawn to RGBA8888");
290 }
291 }
292
293 img.reset();
Greg Daniel0a2464f2020-05-14 15:45:44 -0400294 context->flushAndSubmit();
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400295 context->deleteBackendTexture(backendTex);
296 }
297}
298
299DEF_TEST(ExtendedSkColorTypeTests_raster, reporter) {
300 for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
301 raster_tests(reporter, gTests[i]);
302 }
303}
304
305DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ExtendedSkColorTypeTests_gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400306 auto context = ctxInfo.directContext();
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400307
308 for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
309 gpu_tests(context, reporter, gTests[i]);
310 }
311}