• 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 "SkColorSpace_Base.h"
13 #include "SkColorSpaceXform.h"
14 #include "SkColorSpaceXformPriv.h"
15 #include "SkHalf.h"
16 #include "SkImage.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 as_CSB(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("google_chrome.ico"));
55     std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
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("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_srgb_transfer_fn(const SkColorSpacePrimaries & primaries)94 static sk_sp<SkColorSpace> make_srgb_transfer_fn(const SkColorSpacePrimaries& primaries) {
95     SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
96     SkAssertResult(primaries.toXYZD50(&toXYZD50));
97     return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
98 }
99 
make_wide_gamut()100 static sk_sp<SkColorSpace> make_wide_gamut() {
101     // ProPhoto
102     SkColorSpacePrimaries primaries;
103     primaries.fRX = 0.7347f;
104     primaries.fRY = 0.2653f;
105     primaries.fGX = 0.1596f;
106     primaries.fGY = 0.8404f;
107     primaries.fBX = 0.0366f;
108     primaries.fBY = 0.0001f;
109     primaries.fWX = 0.34567f;
110     primaries.fWY = 0.35850f;
111     return make_srgb_transfer_fn(primaries);
112 }
113 
make_small_gamut()114 static sk_sp<SkColorSpace> make_small_gamut() {
115     SkColorSpacePrimaries primaries;
116     primaries.fRX = 0.50f;
117     primaries.fRY = 0.33f;
118     primaries.fGX = 0.30f;
119     primaries.fGY = 0.50f;
120     primaries.fBX = 0.25f;
121     primaries.fBY = 0.16f;
122     primaries.fWX = 0.3127f;
123     primaries.fWY = 0.3290f;
124     return make_srgb_transfer_fn(primaries);
125 }
126 
draw_image(SkCanvas * canvas,SkImage * image,SkColorType dstColorType,SkAlphaType dstAlphaType,sk_sp<SkColorSpace> dstColorSpace,SkImage::CachingHint hint)127 static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType,
128                        SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace,
129                        SkImage::CachingHint hint) {
130     size_t rowBytes = image->width() * SkColorTypeBytesPerPixel(dstColorType);
131     sk_sp<SkData> data = SkData::MakeUninitialized(rowBytes * image->height());
132     dstColorSpace = fix_for_colortype(dstColorSpace.get(), dstColorType);
133     SkImageInfo dstInfo = SkImageInfo::Make(image->width(), image->height(), dstColorType,
134                                             dstAlphaType, dstColorSpace);
135     if (!image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) {
136         memset(data->writable_data(), 0, rowBytes * image->height());
137     }
138 
139     // SkImage must be premul, so manually premul the data if we unpremul'd during readPixels
140     if (kUnpremul_SkAlphaType == dstAlphaType) {
141         auto xform = SkColorSpaceXform::New(dstColorSpace.get(), dstColorSpace.get());
142         if (!xform->apply(select_xform_format(dstColorType), data->writable_data(),
143                           select_xform_format(dstColorType), data->data(),
144                           image->width() * image->height(), kPremul_SkAlphaType)) {
145             memset(data->writable_data(), 0, rowBytes * image->height());
146         }
147         dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType);
148     }
149 
150     // readPixels() does not always clamp F16.  The drawing code expects pixels in the 0-1 range.
151     clamp_if_necessary(dstInfo, data->writable_data());
152 
153     // Now that we have called readPixels(), dump the raw pixels into an srgb image.
154     sk_sp<SkColorSpace> srgb = fix_for_colortype(
155             SkColorSpace::MakeSRGB().get(), dstColorType);
156     sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes);
157     canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr);
158 }
159 
160 class ReadPixelsGM : public skiagm::GM {
161 public:
ReadPixelsGM()162     ReadPixelsGM() {}
163 
164 protected:
onShortName()165     SkString onShortName() override {
166         return SkString("readpixels");
167     }
168 
onISize()169     SkISize onISize() override {
170         return SkISize::Make(6 * kWidth, 9 * kHeight);
171     }
172 
onDraw(SkCanvas * canvas)173     void onDraw(SkCanvas* canvas) override {
174         if (!canvas->imageInfo().colorSpace()) {
175             // This gm is only interesting in color correct modes.
176             return;
177         }
178 
179         const SkAlphaType alphaTypes[] = {
180                 kUnpremul_SkAlphaType,
181                 kPremul_SkAlphaType,
182         };
183         const SkColorType colorTypes[] = {
184                 kRGBA_8888_SkColorType,
185                 kBGRA_8888_SkColorType,
186                 kRGBA_F16_SkColorType,
187         };
188         const sk_sp<SkColorSpace> colorSpaces[] = {
189                 make_wide_gamut(),
190                 SkColorSpace::MakeSRGB(),
191                 make_small_gamut(),
192         };
193 
194         for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
195             for (SkColorType srcColorType : colorTypes) {
196                 canvas->save();
197                 sk_sp<SkImage> image = make_raster_image(srcColorType);
198                 if (GrContext* context = canvas->getGrContext()) {
199                     image = image->makeTextureImage(context, canvas->imageInfo().colorSpace());
200                 }
201                 if (image) {
202                     for (SkColorType dstColorType : colorTypes) {
203                         for (SkAlphaType dstAlphaType : alphaTypes) {
204                             draw_image(canvas, image.get(), dstColorType, dstAlphaType,
205                                        dstColorSpace, SkImage::kAllow_CachingHint);
206                             canvas->translate((float)kWidth, 0.0f);
207                         }
208                     }
209                 }
210                 canvas->restore();
211                 canvas->translate(0.0f, (float) kHeight);
212             }
213         }
214     }
215 
216 private:
217     typedef skiagm::GM INHERITED;
218 };
219 DEF_GM( return new ReadPixelsGM; )
220 
221 class ReadPixelsCodecGM : public skiagm::GM {
222 public:
ReadPixelsCodecGM()223     ReadPixelsCodecGM() {}
224 
225 protected:
onShortName()226     SkString onShortName() override {
227         return SkString("readpixelscodec");
228     }
229 
onISize()230     SkISize onISize() override {
231         return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
232     }
233 
onDraw(SkCanvas * canvas)234     void onDraw(SkCanvas* canvas) override {
235         if (!canvas->imageInfo().colorSpace()) {
236             // This gm is only interesting in color correct modes.
237             return;
238         }
239 
240         const SkAlphaType alphaTypes[] = {
241                 kUnpremul_SkAlphaType,
242                 kPremul_SkAlphaType,
243         };
244         const SkColorType colorTypes[] = {
245                 kRGBA_8888_SkColorType,
246                 kBGRA_8888_SkColorType,
247                 kRGBA_F16_SkColorType,
248         };
249         const sk_sp<SkColorSpace> colorSpaces[] = {
250                 make_wide_gamut(),
251                 SkColorSpace::MakeSRGB(),
252                 make_small_gamut(),
253         };
254         const SkImage::CachingHint hints[] = {
255                 SkImage::kAllow_CachingHint,
256                 SkImage::kDisallow_CachingHint,
257         };
258 
259         sk_sp<SkImage> image = make_codec_image();
260         for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
261             canvas->save();
262             for (SkColorType dstColorType : colorTypes) {
263                 for (SkAlphaType dstAlphaType : alphaTypes) {
264                     for (SkImage::CachingHint hint : hints) {
265                         draw_image(canvas, image.get(), dstColorType, dstAlphaType, dstColorSpace,
266                                    hint);
267                         canvas->translate(0.0f, (float) kEncodedHeight + 1);
268                     }
269                 }
270             }
271             canvas->restore();
272             canvas->translate((float) kEncodedWidth + 1, 0.0f);
273         }
274     }
275 
276 private:
277     static const int kEncodedWidth = 8;
278     static const int kEncodedHeight = 8;
279 
280     typedef skiagm::GM INHERITED;
281 };
282 DEF_GM( return new ReadPixelsCodecGM; )
283 
284 class ReadPixelsPictureGM : public skiagm::GM {
285 public:
ReadPixelsPictureGM()286     ReadPixelsPictureGM() {}
287 
288 protected:
onShortName()289     SkString onShortName() override {
290         return SkString("readpixelspicture");
291     }
292 
onISize()293     SkISize onISize() override {
294         return SkISize::Make(3 * kWidth, 12 * kHeight);
295     }
296 
onDraw(SkCanvas * canvas)297     void onDraw(SkCanvas* canvas) override {
298         if (!canvas->imageInfo().colorSpace()) {
299             // This gm is only interesting in color correct modes.
300             return;
301         }
302 
303         const sk_sp<SkImage> images[] = {
304                 make_picture_image(),
305         };
306         const SkAlphaType alphaTypes[] = {
307                 kUnpremul_SkAlphaType,
308                 kPremul_SkAlphaType,
309         };
310         const SkColorType colorTypes[] = {
311                 kRGBA_8888_SkColorType,
312                 kBGRA_8888_SkColorType,
313                 kRGBA_F16_SkColorType,
314         };
315         const sk_sp<SkColorSpace> colorSpaces[] = {
316                 make_wide_gamut(),
317                 SkColorSpace::MakeSRGB(),
318                 make_small_gamut(),
319         };
320         const SkImage::CachingHint hints[] = {
321                 SkImage::kAllow_CachingHint,
322                 SkImage::kDisallow_CachingHint,
323         };
324 
325         for (sk_sp<SkImage> image : images) {
326             for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
327                 canvas->save();
328                 for (SkColorType dstColorType : colorTypes) {
329                     for (SkAlphaType dstAlphaType : alphaTypes) {
330                         for (SkImage::CachingHint hint : hints) {
331                             draw_image(canvas, image.get(), dstColorType, dstAlphaType,
332                                        dstColorSpace, hint);
333                             canvas->translate(0.0f, (float) kHeight);
334                         }
335                     }
336                 }
337                 canvas->restore();
338                 canvas->translate((float) kWidth, 0.0f);
339             }
340         }
341     }
342 
343 private:
344 
345     typedef skiagm::GM INHERITED;
346 };
347 DEF_GM( return new ReadPixelsPictureGM; )
348