blob: bd2fe9bcc347c3dbee38ff995df9c5cca68449e9 [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"
Brian Osmanb1168a72017-03-20 14:21:18 -040013#include "SkColorSpaceXform.h"
14#include "SkColorSpaceXformPriv.h"
Matt Sarett909d3792016-12-22 10:52:25 -050015#include "SkHalf.h"
16#include "SkImage.h"
Matt Sarett34855f92017-01-10 17:41:53 -050017#include "SkPictureRecorder.h"
Matt Sarett909d3792016-12-22 10:52:25 -050018
19static 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
42sk_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
50static const int kWidth = 64;
51static const int kHeight = 64;
52
Brian Osmanb1168a72017-03-20 14:21:18 -040053static sk_sp<SkImage> make_raster_image(SkColorType colorType) {
Matt Sarett909d3792016-12-22 10:52:25 -050054 std::unique_ptr<SkStream> stream(GetResourceAsStream("google_chrome.ico"));
Mike Reedede7bac2017-07-23 15:30:02 -040055 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream));
Matt Sarett909d3792016-12-22 10:52:25 -050056
57 SkBitmap bitmap;
58 SkImageInfo info = codec->getInfo().makeWH(kWidth, kHeight)
59 .makeColorType(colorType)
Brian Osmanb1168a72017-03-20 14:21:18 -040060 .makeAlphaType(kPremul_SkAlphaType)
Matt Sarett909d3792016-12-22 10:52:25 -050061 .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
Matt Sarett34855f92017-01-10 17:41:53 -050068static sk_sp<SkImage> make_codec_image() {
69 sk_sp<SkData> encoded = GetResourceAsData("randPixels.png");
70 return SkImage::MakeFromEncoded(encoded);
71}
72
73static 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
Matt Sarett9df70bb2017-02-14 13:50:43 -050085static sk_sp<SkImage> make_picture_image() {
Matt Sarett34855f92017-01-10 17:41:53 -050086 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,
Matt Sarett77a7a1b2017-02-07 13:56:11 -050091 SkColorSpace::MakeSRGB());
Matt Sarett34855f92017-01-10 17:41:53 -050092}
93
Matt Sarett733340a2017-05-02 16:19:51 -040094static sk_sp<SkColorSpace> make_parametric_transfer_fn(const SkColorSpacePrimaries& primaries) {
Matt Sarett578f52c2016-12-22 13:14:30 -050095 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
Matt Sarett909d3792016-12-22 10:52:25 -050096 SkAssertResult(primaries.toXYZD50(&toXYZD50));
Matt Sarett733340a2017-05-02 16:19:51 -040097 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);
Matt Sarett909d3792016-12-22 10:52:25 -0500100}
101
102static 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;
Matt Sarett733340a2017-05-02 16:19:51 -0400113 return make_parametric_transfer_fn(primaries);
Matt Sarett909d3792016-12-22 10:52:25 -0500114}
115
116static 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;
Matt Sarett733340a2017-05-02 16:19:51 -0400126 return make_parametric_transfer_fn(primaries);
Matt Sarett909d3792016-12-22 10:52:25 -0500127}
128
129static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType,
Matt Sarett34855f92017-01-10 17:41:53 -0500130 SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace,
131 SkImage::CachingHint hint) {
Matt Sarett909d3792016-12-22 10:52:25 -0500132 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);
Brian Osman89150582017-03-20 16:54:28 -0400137 if (!image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) {
138 memset(data->writable_data(), 0, rowBytes * image->height());
139 }
Matt Sarett909d3792016-12-22 10:52:25 -0500140
Brian Osmanb1168a72017-03-20 14:21:18 -0400141 // 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
Matt Sarett909d3792016-12-22 10:52:25 -0500152 // 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(
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500157 SkColorSpace::MakeSRGB().get(), dstColorType);
Matt Sarett909d3792016-12-22 10:52:25 -0500158 sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes);
159 canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr);
160}
161
162class ReadPixelsGM : public skiagm::GM {
163public:
164 ReadPixelsGM() {}
165
166protected:
167 SkString onShortName() override {
168 return SkString("readpixels");
169 }
170
171 SkISize onISize() override {
Brian Osmanb1168a72017-03-20 14:21:18 -0400172 return SkISize::Make(6 * kWidth, 9 * kHeight);
Matt Sarett909d3792016-12-22 10:52:25 -0500173 }
174
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(),
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500192 SkColorSpace::MakeSRGB(),
Matt Sarett909d3792016-12-22 10:52:25 -0500193 make_small_gamut(),
194 };
195
196 for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
197 for (SkColorType srcColorType : colorTypes) {
Brian Osmanb1168a72017-03-20 14:21:18 -0400198 canvas->save();
199 sk_sp<SkImage> image = make_raster_image(srcColorType);
Brian Osman89150582017-03-20 16:54:28 -0400200 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 }
Matt Sarett909d3792016-12-22 10:52:25 -0500210 }
Matt Sarett909d3792016-12-22 10:52:25 -0500211 }
Brian Osmanb1168a72017-03-20 14:21:18 -0400212 canvas->restore();
213 canvas->translate(0.0f, (float) kHeight);
Matt Sarett909d3792016-12-22 10:52:25 -0500214 }
215 }
216 }
217
218private:
219 typedef skiagm::GM INHERITED;
220};
221DEF_GM( return new ReadPixelsGM; )
Matt Sarett34855f92017-01-10 17:41:53 -0500222
223class ReadPixelsCodecGM : public skiagm::GM {
224public:
225 ReadPixelsCodecGM() {}
226
227protected:
228 SkString onShortName() override {
229 return SkString("readpixelscodec");
230 }
231
232 SkISize onISize() override {
233 return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
234 }
235
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(),
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500253 SkColorSpace::MakeSRGB(),
Matt Sarett34855f92017-01-10 17:41:53 -0500254 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
278private:
279 static const int kEncodedWidth = 8;
280 static const int kEncodedHeight = 8;
281
282 typedef skiagm::GM INHERITED;
283};
284DEF_GM( return new ReadPixelsCodecGM; )
285
286class ReadPixelsPictureGM : public skiagm::GM {
287public:
288 ReadPixelsPictureGM() {}
289
290protected:
291 SkString onShortName() override {
292 return SkString("readpixelspicture");
293 }
294
295 SkISize onISize() override {
296 return SkISize::Make(3 * kWidth, 12 * kHeight);
297 }
298
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[] = {
Matt Sarett9df70bb2017-02-14 13:50:43 -0500306 make_picture_image(),
Matt Sarett34855f92017-01-10 17:41:53 -0500307 };
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(),
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500319 SkColorSpace::MakeSRGB(),
Matt Sarett34855f92017-01-10 17:41:53 -0500320 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
345private:
346
347 typedef skiagm::GM INHERITED;
348};
349DEF_GM( return new ReadPixelsPictureGM; )