• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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