• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
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 "gm.h"
9 #include "Resources.h"
10 #include "SkCodec.h"
11 #include "SkColorSpace.h"
12 #include "SkColorSpaceXform.h"
13 #include "SkColorSpaceXformPriv.h"
14 #include "SkHalf.h"
15 #include "SkImage.h"
16 #include "SkPictureRecorder.h"
17 
clamp_if_necessary(const SkImageInfo & info,void * pixels)18 static void clamp_if_necessary(const SkImageInfo& info, void* pixels) {
19     if (kRGBA_F16_SkColorType != info.colorType()) {
20         return;
21     }
22 
23     for (int y = 0; y < info.height(); y++) {
24         for (int x = 0; x < info.width(); x++) {
25             uint64_t pixel = ((uint64_t*) pixels)[y * info.width() + x];
26 
27             Sk4f rgba = SkHalfToFloat_finite_ftz(pixel);
28             if (kUnpremul_SkAlphaType == info.alphaType()) {
29                 rgba = Sk4f::Max(0.0f, Sk4f::Min(rgba, 1.0f));
30             } else {
31                 SkASSERT(kPremul_SkAlphaType == info.alphaType());
32                 rgba = Sk4f::Max(0.0f, Sk4f::Min(rgba, rgba[3]));
33             }
34             SkFloatToHalf_finite_ftz(rgba).store(&pixel);
35 
36             ((uint64_t*) pixels)[y * info.width() + x] = pixel;
37         }
38     }
39 }
40 
fix_for_colortype(SkColorSpace * colorSpace,SkColorType colorType)41 sk_sp<SkColorSpace> fix_for_colortype(SkColorSpace* colorSpace, SkColorType colorType) {
42     if (kRGBA_F16_SkColorType == colorType) {
43         return colorSpace->makeLinearGamma();
44     }
45 
46     return sk_ref_sp(colorSpace);
47 }
48 
49 static const int kWidth = 64;
50 static const int kHeight = 64;
51 
make_raster_image(SkColorType colorType)52 static sk_sp<SkImage> make_raster_image(SkColorType colorType) {
53     std::unique_ptr<SkStream> stream(GetResourceAsStream("images/google_chrome.ico"));
54     std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream));
55 
56     SkBitmap bitmap;
57     SkImageInfo info = codec->getInfo().makeWH(kWidth, kHeight)
58                                        .makeColorType(colorType)
59                                        .makeAlphaType(kPremul_SkAlphaType)
60             .makeColorSpace(fix_for_colortype(codec->getInfo().colorSpace(), colorType));
61     bitmap.allocPixels(info);
62     codec->getPixels(info, bitmap.getPixels(), bitmap.rowBytes());
63     bitmap.setImmutable();
64     return SkImage::MakeFromBitmap(bitmap);
65 }
66 
make_codec_image()67 static sk_sp<SkImage> make_codec_image() {
68     sk_sp<SkData> encoded = GetResourceAsData("images/randPixels.png");
69     return SkImage::MakeFromEncoded(encoded);
70 }
71 
draw_contents(SkCanvas * canvas)72 static void draw_contents(SkCanvas* canvas) {
73     SkPaint paint;
74     paint.setStyle(SkPaint::kStroke_Style);
75     paint.setStrokeWidth(20);
76     paint.setColor(0xFF800000);
77     canvas->drawCircle(40, 40, 35, paint);
78     paint.setColor(0xFF008000);
79     canvas->drawCircle(50, 50, 35, paint);
80     paint.setColor(0xFF000080);
81     canvas->drawCircle(60, 60, 35, paint);
82 }
83 
make_picture_image()84 static sk_sp<SkImage> make_picture_image() {
85     SkPictureRecorder recorder;
86     draw_contents(recorder.beginRecording(SkRect::MakeIWH(kWidth, kHeight)));
87     return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
88                                     SkISize::Make(kWidth, kHeight), nullptr, nullptr,
89                                     SkImage::BitDepth::kU8,
90                                     SkColorSpace::MakeSRGB());
91 }
92 
make_parametric_transfer_fn(const SkColorSpacePrimaries & primaries)93 static sk_sp<SkColorSpace> make_parametric_transfer_fn(const SkColorSpacePrimaries& primaries) {
94     SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
95     SkAssertResult(primaries.toXYZD50(&toXYZD50));
96     SkColorSpaceTransferFn fn;
97     fn.fA = 1.f; fn.fB = 0.f; fn.fC = 0.f; fn.fD = 0.f; fn.fE = 0.f; fn.fF = 0.f; fn.fG = 1.8f;
98     return SkColorSpace::MakeRGB(fn, toXYZD50);
99 }
100 
make_wide_gamut()101 static sk_sp<SkColorSpace> make_wide_gamut() {
102     // ProPhoto
103     SkColorSpacePrimaries primaries;
104     primaries.fRX = 0.7347f;
105     primaries.fRY = 0.2653f;
106     primaries.fGX = 0.1596f;
107     primaries.fGY = 0.8404f;
108     primaries.fBX = 0.0366f;
109     primaries.fBY = 0.0001f;
110     primaries.fWX = 0.34567f;
111     primaries.fWY = 0.35850f;
112     return make_parametric_transfer_fn(primaries);
113 }
114 
make_small_gamut()115 static sk_sp<SkColorSpace> make_small_gamut() {
116     SkColorSpacePrimaries primaries;
117     primaries.fRX = 0.50f;
118     primaries.fRY = 0.33f;
119     primaries.fGX = 0.30f;
120     primaries.fGY = 0.50f;
121     primaries.fBX = 0.25f;
122     primaries.fBY = 0.16f;
123     primaries.fWX = 0.3127f;
124     primaries.fWY = 0.3290f;
125     return make_parametric_transfer_fn(primaries);
126 }
127 
draw_image(SkCanvas * canvas,SkImage * image,SkColorType dstColorType,SkAlphaType dstAlphaType,sk_sp<SkColorSpace> dstColorSpace,SkImage::CachingHint hint)128 static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType,
129                        SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace,
130                        SkImage::CachingHint hint) {
131     size_t rowBytes = image->width() * SkColorTypeBytesPerPixel(dstColorType);
132     sk_sp<SkData> data = SkData::MakeUninitialized(rowBytes * image->height());
133     dstColorSpace = fix_for_colortype(dstColorSpace.get(), dstColorType);
134     SkImageInfo dstInfo = SkImageInfo::Make(image->width(), image->height(), dstColorType,
135                                             dstAlphaType, dstColorSpace);
136     if (!image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) {
137         memset(data->writable_data(), 0, rowBytes * image->height());
138     }
139 
140     // SkImage must be premul, so manually premul the data if we unpremul'd during readPixels
141     if (kUnpremul_SkAlphaType == dstAlphaType) {
142         auto xform = SkColorSpaceXform::New(dstColorSpace.get(), dstColorSpace.get());
143         if (!xform->apply(select_xform_format(dstColorType), data->writable_data(),
144                           select_xform_format(dstColorType), data->data(),
145                           image->width() * image->height(), kPremul_SkAlphaType)) {
146             memset(data->writable_data(), 0, rowBytes * image->height());
147         }
148         dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType);
149     }
150 
151     // readPixels() does not always clamp F16.  The drawing code expects pixels in the 0-1 range.
152     clamp_if_necessary(dstInfo, data->writable_data());
153 
154     // Now that we have called readPixels(), dump the raw pixels into an srgb image.
155     sk_sp<SkColorSpace> srgb = fix_for_colortype(
156             SkColorSpace::MakeSRGB().get(), dstColorType);
157     sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes);
158     canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr);
159 }
160 
161 class ReadPixelsGM : public skiagm::GM {
162 public:
ReadPixelsGM()163     ReadPixelsGM() {}
164 
165 protected:
onShortName()166     SkString onShortName() override {
167         return SkString("readpixels");
168     }
169 
onISize()170     SkISize onISize() override {
171         return SkISize::Make(6 * kWidth, 9 * kHeight);
172     }
173 
onDraw(SkCanvas * canvas)174     void onDraw(SkCanvas* canvas) override {
175         if (!canvas->imageInfo().colorSpace()) {
176             // This gm is only interesting in color correct modes.
177             return;
178         }
179 
180         const SkAlphaType alphaTypes[] = {
181                 kUnpremul_SkAlphaType,
182                 kPremul_SkAlphaType,
183         };
184         const SkColorType colorTypes[] = {
185                 kRGBA_8888_SkColorType,
186                 kBGRA_8888_SkColorType,
187                 kRGBA_F16_SkColorType,
188         };
189         const sk_sp<SkColorSpace> colorSpaces[] = {
190                 make_wide_gamut(),
191                 SkColorSpace::MakeSRGB(),
192                 make_small_gamut(),
193         };
194 
195         for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
196             for (SkColorType srcColorType : colorTypes) {
197                 canvas->save();
198                 sk_sp<SkImage> image = make_raster_image(srcColorType);
199                 if (GrContext* context = canvas->getGrContext()) {
200                     image = image->makeTextureImage(context, canvas->imageInfo().colorSpace());
201                 }
202                 if (image) {
203                     for (SkColorType dstColorType : colorTypes) {
204                         for (SkAlphaType dstAlphaType : alphaTypes) {
205                             draw_image(canvas, image.get(), dstColorType, dstAlphaType,
206                                        dstColorSpace, SkImage::kAllow_CachingHint);
207                             canvas->translate((float)kWidth, 0.0f);
208                         }
209                     }
210                 }
211                 canvas->restore();
212                 canvas->translate(0.0f, (float) kHeight);
213             }
214         }
215     }
216 
217 private:
218     typedef skiagm::GM INHERITED;
219 };
220 DEF_GM( return new ReadPixelsGM; )
221 
222 class ReadPixelsCodecGM : public skiagm::GM {
223 public:
ReadPixelsCodecGM()224     ReadPixelsCodecGM() {}
225 
226 protected:
onShortName()227     SkString onShortName() override {
228         return SkString("readpixelscodec");
229     }
230 
onISize()231     SkISize onISize() override {
232         return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
233     }
234 
onDraw(SkCanvas * canvas)235     void onDraw(SkCanvas* canvas) override {
236         if (!canvas->imageInfo().colorSpace()) {
237             // This gm is only interesting in color correct modes.
238             return;
239         }
240 
241         const SkAlphaType alphaTypes[] = {
242                 kUnpremul_SkAlphaType,
243                 kPremul_SkAlphaType,
244         };
245         const SkColorType colorTypes[] = {
246                 kRGBA_8888_SkColorType,
247                 kBGRA_8888_SkColorType,
248                 kRGBA_F16_SkColorType,
249         };
250         const sk_sp<SkColorSpace> colorSpaces[] = {
251                 make_wide_gamut(),
252                 SkColorSpace::MakeSRGB(),
253                 make_small_gamut(),
254         };
255         const SkImage::CachingHint hints[] = {
256                 SkImage::kAllow_CachingHint,
257                 SkImage::kDisallow_CachingHint,
258         };
259 
260         sk_sp<SkImage> image = make_codec_image();
261         for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
262             canvas->save();
263             for (SkColorType dstColorType : colorTypes) {
264                 for (SkAlphaType dstAlphaType : alphaTypes) {
265                     for (SkImage::CachingHint hint : hints) {
266                         draw_image(canvas, image.get(), dstColorType, dstAlphaType, dstColorSpace,
267                                    hint);
268                         canvas->translate(0.0f, (float) kEncodedHeight + 1);
269                     }
270                 }
271             }
272             canvas->restore();
273             canvas->translate((float) kEncodedWidth + 1, 0.0f);
274         }
275     }
276 
277 private:
278     static const int kEncodedWidth = 8;
279     static const int kEncodedHeight = 8;
280 
281     typedef skiagm::GM INHERITED;
282 };
283 DEF_GM( return new ReadPixelsCodecGM; )
284 
285 class ReadPixelsPictureGM : public skiagm::GM {
286 public:
ReadPixelsPictureGM()287     ReadPixelsPictureGM() {}
288 
289 protected:
onShortName()290     SkString onShortName() override {
291         return SkString("readpixelspicture");
292     }
293 
onISize()294     SkISize onISize() override {
295         return SkISize::Make(3 * kWidth, 12 * kHeight);
296     }
297 
onDraw(SkCanvas * canvas)298     void onDraw(SkCanvas* canvas) override {
299         if (!canvas->imageInfo().colorSpace()) {
300             // This gm is only interesting in color correct modes.
301             return;
302         }
303 
304         const sk_sp<SkImage> images[] = {
305                 make_picture_image(),
306         };
307         const SkAlphaType alphaTypes[] = {
308                 kUnpremul_SkAlphaType,
309                 kPremul_SkAlphaType,
310         };
311         const SkColorType colorTypes[] = {
312                 kRGBA_8888_SkColorType,
313                 kBGRA_8888_SkColorType,
314                 kRGBA_F16_SkColorType,
315         };
316         const sk_sp<SkColorSpace> colorSpaces[] = {
317                 make_wide_gamut(),
318                 SkColorSpace::MakeSRGB(),
319                 make_small_gamut(),
320         };
321         const SkImage::CachingHint hints[] = {
322                 SkImage::kAllow_CachingHint,
323                 SkImage::kDisallow_CachingHint,
324         };
325 
326         for (sk_sp<SkImage> image : images) {
327             for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
328                 canvas->save();
329                 for (SkColorType dstColorType : colorTypes) {
330                     for (SkAlphaType dstAlphaType : alphaTypes) {
331                         for (SkImage::CachingHint hint : hints) {
332                             draw_image(canvas, image.get(), dstColorType, dstAlphaType,
333                                        dstColorSpace, hint);
334                             canvas->translate(0.0f, (float) kHeight);
335                         }
336                     }
337                 }
338                 canvas->restore();
339                 canvas->translate((float) kWidth, 0.0f);
340             }
341         }
342     }
343 
344 private:
345 
346     typedef skiagm::GM INHERITED;
347 };
348 DEF_GM( return new ReadPixelsPictureGM; )
349