blob: f757a497b81cafab8f8f2cd0a1ad16d00dc8da9a [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"));
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)
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 Sarett909d3792016-12-22 10:52:25 -050094static sk_sp<SkColorSpace> make_srgb_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));
97 return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
98}
99
100static 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
114static 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
127static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType,
Matt Sarett34855f92017-01-10 17:41:53 -0500128 SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace,
129 SkImage::CachingHint hint) {
Matt Sarett909d3792016-12-22 10:52:25 -0500130 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);
Brian Osman89150582017-03-20 16:54:28 -0400135 if (!image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) {
136 memset(data->writable_data(), 0, rowBytes * image->height());
137 }
Matt Sarett909d3792016-12-22 10:52:25 -0500138
Brian Osmanb1168a72017-03-20 14:21:18 -0400139 // 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
Matt Sarett909d3792016-12-22 10:52:25 -0500150 // 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(
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500155 SkColorSpace::MakeSRGB().get(), dstColorType);
Matt Sarett909d3792016-12-22 10:52:25 -0500156 sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes);
157 canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr);
158}
159
160class ReadPixelsGM : public skiagm::GM {
161public:
162 ReadPixelsGM() {}
163
164protected:
165 SkString onShortName() override {
166 return SkString("readpixels");
167 }
168
169 SkISize onISize() override {
Brian Osmanb1168a72017-03-20 14:21:18 -0400170 return SkISize::Make(6 * kWidth, 9 * kHeight);
Matt Sarett909d3792016-12-22 10:52:25 -0500171 }
172
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(),
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500190 SkColorSpace::MakeSRGB(),
Matt Sarett909d3792016-12-22 10:52:25 -0500191 make_small_gamut(),
192 };
193
194 for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
195 for (SkColorType srcColorType : colorTypes) {
Brian Osmanb1168a72017-03-20 14:21:18 -0400196 canvas->save();
197 sk_sp<SkImage> image = make_raster_image(srcColorType);
Brian Osman89150582017-03-20 16:54:28 -0400198 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 }
Matt Sarett909d3792016-12-22 10:52:25 -0500208 }
Matt Sarett909d3792016-12-22 10:52:25 -0500209 }
Brian Osmanb1168a72017-03-20 14:21:18 -0400210 canvas->restore();
211 canvas->translate(0.0f, (float) kHeight);
Matt Sarett909d3792016-12-22 10:52:25 -0500212 }
213 }
214 }
215
216private:
217 typedef skiagm::GM INHERITED;
218};
219DEF_GM( return new ReadPixelsGM; )
Matt Sarett34855f92017-01-10 17:41:53 -0500220
221class ReadPixelsCodecGM : public skiagm::GM {
222public:
223 ReadPixelsCodecGM() {}
224
225protected:
226 SkString onShortName() override {
227 return SkString("readpixelscodec");
228 }
229
230 SkISize onISize() override {
231 return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
232 }
233
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(),
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500251 SkColorSpace::MakeSRGB(),
Matt Sarett34855f92017-01-10 17:41:53 -0500252 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
276private:
277 static const int kEncodedWidth = 8;
278 static const int kEncodedHeight = 8;
279
280 typedef skiagm::GM INHERITED;
281};
282DEF_GM( return new ReadPixelsCodecGM; )
283
284class ReadPixelsPictureGM : public skiagm::GM {
285public:
286 ReadPixelsPictureGM() {}
287
288protected:
289 SkString onShortName() override {
290 return SkString("readpixelspicture");
291 }
292
293 SkISize onISize() override {
294 return SkISize::Make(3 * kWidth, 12 * kHeight);
295 }
296
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[] = {
Matt Sarett9df70bb2017-02-14 13:50:43 -0500304 make_picture_image(),
Matt Sarett34855f92017-01-10 17:41:53 -0500305 };
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(),
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500317 SkColorSpace::MakeSRGB(),
Matt Sarett34855f92017-01-10 17:41:53 -0500318 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
343private:
344
345 typedef skiagm::GM INHERITED;
346};
347DEF_GM( return new ReadPixelsPictureGM; )