blob: 19369ff17f8ad067f9b85cd120e69bbf4e48c1d8 [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,
Mike Kleind58e01b62020-07-17 13:52:41 -050075 kPremul_SkAlphaType, kRGBA_SkColorChannelFlags, false, true},
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
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400176static void gpu_tests(GrDirectContext* dContext,
177 skiatest::Reporter* reporter,
178 const TestCase& test) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400179
180 const SkImageInfo nativeII = SkImageInfo::Make(kSize, kSize, test.fColorType, test.fAlphaType);
181 const SkImageInfo f32Unpremul = SkImageInfo::Make(kSize, kSize, kRGBA_F32_SkColorType,
182 kUnpremul_SkAlphaType);
183
184 // We had better not be able to render to prohibited colorTypes
Robert Phillips99044e12020-01-29 08:37:01 -0500185 if (!test.fGpuCanMakeSurfaces) {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400186 auto s = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, nativeII);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400187 REPORTER_ASSERT(reporter, !SkToBool(s));
188 }
189
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400190 if (!dContext->colorTypeSupportedAsImage(test.fColorType)) {
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400191 return;
192 }
193
194 SkAutoPixmapStorage nativeExpected;
195 nativeExpected.alloc(nativeII);
196 nativeExpected.erase(SkColors::kWhite);
197
198 for (bool fullInit : { false, true }) {
199 GrBackendTexture backendTex;
200
Greg Danielc1ad77c2020-05-06 11:40:03 -0400201 bool finishedBECreate = false;
202 auto markFinished = [](void* context) {
203 *(bool*)context = true;
204 };
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400205 if (fullInit) {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400206 backendTex = dContext->createBackendTexture(&nativeExpected, 1,
207 GrRenderable::kNo, GrProtected::kNo,
208 markFinished, &finishedBECreate);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400209 } else {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400210 backendTex = dContext->createBackendTexture(kSize, kSize, test.fColorType,
211 SkColors::kWhite, GrMipMapped::kNo,
212 GrRenderable::kNo, GrProtected::kNo,
213 markFinished, &finishedBECreate);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400214 }
215 REPORTER_ASSERT(reporter, backendTex.isValid());
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400216 dContext->submit();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400217 while (backendTex.isValid() && !finishedBECreate) {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400218 dContext->checkAsyncWorkCompletion();
Greg Danielc1ad77c2020-05-06 11:40:03 -0400219 }
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400220
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400221 auto img = SkImage::MakeFromTexture(dContext, backendTex, kTopLeft_GrSurfaceOrigin,
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400222 test.fColorType, test.fAlphaType, nullptr);
223 REPORTER_ASSERT(reporter, SkToBool(img));
224
225 {
226 SkAutoPixmapStorage nativeActual;
227 nativeActual.alloc(nativeII);
228 nativeActual.erase(SkColors::kTransparent);
229
230 if (img->readPixels(nativeActual, 0, 0)) {
231 compare_pixmaps(reporter, nativeExpected, nativeActual,
232 test.fColorType, "SkImage::readPixels to native CT");
233 }
234
235 // SkSurface::readPixels with the same colorType as the source pixels round trips
236 // (when allowed)
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400237 if (dContext->colorTypeSupportedAsSurface(test.fColorType)) {
238 auto s = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, nativeII);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400239 REPORTER_ASSERT(reporter, SkToBool(s));
240
241 {
242 SkCanvas* c = s->getCanvas();
243 c->drawImage(img, 0, 0);
244 }
245
246 nativeActual.erase(SkColors::kTransparent);
247 REPORTER_ASSERT(reporter, s->readPixels(nativeActual, 0, 0));
248
249 compare_pixmaps(reporter, nativeExpected, nativeActual,
250 test.fColorType, "SkSurface::readPixels to native CT");
251 }
252 }
253
254 {
255 SkAutoPixmapStorage f32Expected;
256 f32Expected.alloc(f32Unpremul);
Brian Salomon2f23ae62020-03-26 16:17:56 -0400257 f32Expected.erase(get_opaque_white_expected_color(test.fChannels));
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400258
259 // read back to F32 if possible
260 {
261 SkAutoPixmapStorage f32Actual;
262 f32Actual.alloc(f32Unpremul);
263 f32Actual.erase(SkColors::kTransparent);
264 if (img->readPixels(f32Actual, 0, 0)) {
265 compare_pixmaps(reporter, f32Expected, f32Actual,
266 test.fColorType, "SkImage::readPixels to F32");
267 }
268 }
269
270 // drawing a native SkImage works appropriately (as assessed by reading back from an
271 // RGBA8 surface to an F32 pixmap)
272 {
273 const SkImageInfo rgba8888Premul = SkImageInfo::Make(kSize, kSize,
274 kRGBA_8888_SkColorType,
275 kPremul_SkAlphaType);
276
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400277 auto s = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, rgba8888Premul);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400278 REPORTER_ASSERT(reporter, SkToBool(s));
279
280 {
281 SkCanvas* c = s->getCanvas();
282 c->drawImage(img, 0, 0);
283 }
284
285 SkAutoPixmapStorage f32Actual;
286 f32Actual.alloc(f32Unpremul);
287 f32Actual.erase(SkColors::kTransparent);
288 REPORTER_ASSERT(reporter, s->readPixels(f32Actual, 0, 0));
289
290 compare_pixmaps(reporter, f32Expected, f32Actual,
291 test.fColorType, "SkSurface::drawn to RGBA8888");
292 }
293 }
294
295 img.reset();
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400296 dContext->flushAndSubmit();
297 dContext->deleteBackendTexture(backendTex);
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400298 }
299}
300
301DEF_TEST(ExtendedSkColorTypeTests_raster, reporter) {
302 for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
303 raster_tests(reporter, gTests[i]);
304 }
305}
306
307DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ExtendedSkColorTypeTests_gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400308 auto context = ctxInfo.directContext();
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400309
310 for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
311 gpu_tests(context, reporter, gTests[i]);
312 }
313}