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