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