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