blob: df7fb0751a6305ba1418d8fa714cc8814ff1fccc [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
83static sk_sp<SkImage> make_tagged_picture_image() {
84 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,
89 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
90}
91
92static sk_sp<SkImage> make_untagged_picture_image() {
93 SkPictureRecorder recorder;
94 draw_contents(recorder.beginRecording(SkRect::MakeIWH(kWidth, kHeight)));
95 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
96 SkISize::Make(kWidth, kHeight), nullptr, nullptr);
97}
98
Matt Sarett909d3792016-12-22 10:52:25 -050099static sk_sp<SkColorSpace> make_srgb_transfer_fn(const SkColorSpacePrimaries& primaries) {
Matt Sarett578f52c2016-12-22 13:14:30 -0500100 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
Matt Sarett909d3792016-12-22 10:52:25 -0500101 SkAssertResult(primaries.toXYZD50(&toXYZD50));
102 return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
103}
104
105static sk_sp<SkColorSpace> make_wide_gamut() {
106 // ProPhoto
107 SkColorSpacePrimaries primaries;
108 primaries.fRX = 0.7347f;
109 primaries.fRY = 0.2653f;
110 primaries.fGX = 0.1596f;
111 primaries.fGY = 0.8404f;
112 primaries.fBX = 0.0366f;
113 primaries.fBY = 0.0001f;
114 primaries.fWX = 0.34567f;
115 primaries.fWY = 0.35850f;
116 return make_srgb_transfer_fn(primaries);
117}
118
119static sk_sp<SkColorSpace> make_small_gamut() {
120 SkColorSpacePrimaries primaries;
121 primaries.fRX = 0.50f;
122 primaries.fRY = 0.33f;
123 primaries.fGX = 0.30f;
124 primaries.fGY = 0.50f;
125 primaries.fBX = 0.25f;
126 primaries.fBY = 0.16f;
127 primaries.fWX = 0.3127f;
128 primaries.fWY = 0.3290f;
129 return make_srgb_transfer_fn(primaries);
130}
131
132static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType,
Matt Sarett34855f92017-01-10 17:41:53 -0500133 SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace,
134 SkImage::CachingHint hint) {
Matt Sarett909d3792016-12-22 10:52:25 -0500135 size_t rowBytes = image->width() * SkColorTypeBytesPerPixel(dstColorType);
136 sk_sp<SkData> data = SkData::MakeUninitialized(rowBytes * image->height());
137 dstColorSpace = fix_for_colortype(dstColorSpace.get(), dstColorType);
138 SkImageInfo dstInfo = SkImageInfo::Make(image->width(), image->height(), dstColorType,
139 dstAlphaType, dstColorSpace);
Matt Sarett34855f92017-01-10 17:41:53 -0500140 image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint);
Matt Sarett909d3792016-12-22 10:52:25 -0500141
142 // readPixels() does not always clamp F16. The drawing code expects pixels in the 0-1 range.
143 clamp_if_necessary(dstInfo, data->writable_data());
144
145 // Now that we have called readPixels(), dump the raw pixels into an srgb image.
146 sk_sp<SkColorSpace> srgb = fix_for_colortype(
147 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get(), dstColorType);
148 sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes);
149 canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr);
150}
151
152class ReadPixelsGM : public skiagm::GM {
153public:
154 ReadPixelsGM() {}
155
156protected:
157 SkString onShortName() override {
158 return SkString("readpixels");
159 }
160
161 SkISize onISize() override {
162 return SkISize::Make(6 * kWidth, 18 * kHeight);
163 }
164
165 void onDraw(SkCanvas* canvas) override {
166 if (!canvas->imageInfo().colorSpace()) {
167 // This gm is only interesting in color correct modes.
168 return;
169 }
170
171 const SkAlphaType alphaTypes[] = {
172 kUnpremul_SkAlphaType,
173 kPremul_SkAlphaType,
174 };
175 const SkColorType colorTypes[] = {
176 kRGBA_8888_SkColorType,
177 kBGRA_8888_SkColorType,
178 kRGBA_F16_SkColorType,
179 };
180 const sk_sp<SkColorSpace> colorSpaces[] = {
181 make_wide_gamut(),
182 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named),
183 make_small_gamut(),
184 };
185
186 for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
187 for (SkColorType srcColorType : colorTypes) {
188 for (SkAlphaType srcAlphaType : alphaTypes) {
189 canvas->save();
190 sk_sp<SkImage> image = make_raster_image(srcColorType, srcAlphaType);
191 for (SkColorType dstColorType : colorTypes) {
192 for (SkAlphaType dstAlphaType : alphaTypes) {
193 draw_image(canvas, image.get(), dstColorType, dstAlphaType,
Matt Sarett34855f92017-01-10 17:41:53 -0500194 dstColorSpace, SkImage::kAllow_CachingHint);
Matt Sarett909d3792016-12-22 10:52:25 -0500195 canvas->translate((float) kWidth, 0.0f);
196 }
197 }
198 canvas->restore();
199 canvas->translate(0.0f, (float) kHeight);
200 }
201 }
202 }
203 }
204
205private:
206 typedef skiagm::GM INHERITED;
207};
208DEF_GM( return new ReadPixelsGM; )
Matt Sarett34855f92017-01-10 17:41:53 -0500209
210class ReadPixelsCodecGM : public skiagm::GM {
211public:
212 ReadPixelsCodecGM() {}
213
214protected:
215 SkString onShortName() override {
216 return SkString("readpixelscodec");
217 }
218
219 SkISize onISize() override {
220 return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
221 }
222
223 void onDraw(SkCanvas* canvas) override {
224 if (!canvas->imageInfo().colorSpace()) {
225 // This gm is only interesting in color correct modes.
226 return;
227 }
228
229 const SkAlphaType alphaTypes[] = {
230 kUnpremul_SkAlphaType,
231 kPremul_SkAlphaType,
232 };
233 const SkColorType colorTypes[] = {
234 kRGBA_8888_SkColorType,
235 kBGRA_8888_SkColorType,
236 kRGBA_F16_SkColorType,
237 };
238 const sk_sp<SkColorSpace> colorSpaces[] = {
239 make_wide_gamut(),
240 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named),
241 make_small_gamut(),
242 };
243 const SkImage::CachingHint hints[] = {
244 SkImage::kAllow_CachingHint,
245 SkImage::kDisallow_CachingHint,
246 };
247
248 sk_sp<SkImage> image = make_codec_image();
249 for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
250 canvas->save();
251 for (SkColorType dstColorType : colorTypes) {
252 for (SkAlphaType dstAlphaType : alphaTypes) {
253 for (SkImage::CachingHint hint : hints) {
254 draw_image(canvas, image.get(), dstColorType, dstAlphaType, dstColorSpace,
255 hint);
256 canvas->translate(0.0f, (float) kEncodedHeight + 1);
257 }
258 }
259 }
260 canvas->restore();
261 canvas->translate((float) kEncodedWidth + 1, 0.0f);
262 }
263 }
264
265private:
266 static const int kEncodedWidth = 8;
267 static const int kEncodedHeight = 8;
268
269 typedef skiagm::GM INHERITED;
270};
271DEF_GM( return new ReadPixelsCodecGM; )
272
273class ReadPixelsPictureGM : public skiagm::GM {
274public:
275 ReadPixelsPictureGM() {}
276
277protected:
278 SkString onShortName() override {
279 return SkString("readpixelspicture");
280 }
281
282 SkISize onISize() override {
283 return SkISize::Make(3 * kWidth, 12 * kHeight);
284 }
285
286 void onDraw(SkCanvas* canvas) override {
287 if (!canvas->imageInfo().colorSpace()) {
288 // This gm is only interesting in color correct modes.
289 return;
290 }
291
292 const sk_sp<SkImage> images[] = {
293 make_tagged_picture_image(),
294 make_untagged_picture_image(),
295 };
296 const SkAlphaType alphaTypes[] = {
297 kUnpremul_SkAlphaType,
298 kPremul_SkAlphaType,
299 };
300 const SkColorType colorTypes[] = {
301 kRGBA_8888_SkColorType,
302 kBGRA_8888_SkColorType,
303 kRGBA_F16_SkColorType,
304 };
305 const sk_sp<SkColorSpace> colorSpaces[] = {
306 make_wide_gamut(),
307 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named),
308 make_small_gamut(),
309 };
310 const SkImage::CachingHint hints[] = {
311 SkImage::kAllow_CachingHint,
312 SkImage::kDisallow_CachingHint,
313 };
314
315 for (sk_sp<SkImage> image : images) {
316 for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
317 canvas->save();
318 for (SkColorType dstColorType : colorTypes) {
319 for (SkAlphaType dstAlphaType : alphaTypes) {
320 for (SkImage::CachingHint hint : hints) {
321 draw_image(canvas, image.get(), dstColorType, dstAlphaType,
322 dstColorSpace, hint);
323 canvas->translate(0.0f, (float) kHeight);
324 }
325 }
326 }
327 canvas->restore();
328 canvas->translate((float) kWidth, 0.0f);
329 }
330 }
331 }
332
333private:
334
335 typedef skiagm::GM INHERITED;
336};
337DEF_GM( return new ReadPixelsPictureGM; )