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/gm.h"
9 #include "include/codec/SkCodec.h"
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkPicture.h"
18 #include "include/core/SkPictureRecorder.h"
19 #include "include/core/SkRect.h"
20 #include "include/core/SkRefCnt.h"
21 #include "include/core/SkSize.h"
22 #include "include/core/SkStream.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTypes.h"
25 #include "include/gpu/ganesh/GrDirectContext.h"
26 #include "include/gpu/ganesh/SkImageGanesh.h"
27 #include "modules/skcms/skcms.h"
28 #include "tools/Resources.h"
29
30 #include <string.h>
31 #include <memory>
32 #include <utility>
33
34 static const int kWidth = 64;
35 static const int kHeight = 64;
36
make_raster_image(SkColorType colorType)37 static sk_sp<SkImage> make_raster_image(SkColorType colorType) {
38 std::unique_ptr<SkStream> stream(GetResourceAsStream("images/google_chrome.ico"));
39 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream));
40 if (!codec) {
41 return nullptr;
42 }
43
44 SkImageInfo info = codec->getInfo().makeWH(kWidth, kHeight)
45 .makeColorType(colorType)
46 .makeAlphaType(kPremul_SkAlphaType);
47 return std::get<0>(codec->getImage(info));
48 }
49
make_codec_image()50 static sk_sp<SkImage> make_codec_image() {
51 sk_sp<SkData> encoded = GetResourceAsData("images/randPixels.png");
52 return SkImages::DeferredFromEncodedData(encoded);
53 }
54
draw_contents(SkCanvas * canvas)55 static void draw_contents(SkCanvas* canvas) {
56 SkPaint paint;
57 paint.setStyle(SkPaint::kStroke_Style);
58 paint.setStrokeWidth(20);
59 paint.setColor(0xFF800000);
60 canvas->drawCircle(40, 40, 35, paint);
61 paint.setColor(0xFF008000);
62 canvas->drawCircle(50, 50, 35, paint);
63 paint.setColor(0xFF000080);
64 canvas->drawCircle(60, 60, 35, paint);
65 }
66
make_picture_image()67 static sk_sp<SkImage> make_picture_image() {
68 SkPictureRecorder recorder;
69 draw_contents(recorder.beginRecording(SkRect::MakeIWH(kWidth, kHeight)));
70 return SkImages::DeferredFromPicture(recorder.finishRecordingAsPicture(),
71 SkISize::Make(kWidth, kHeight),
72 nullptr,
73 nullptr,
74 SkImages::BitDepth::kU8,
75 SkColorSpace::MakeSRGB());
76 }
77
make_parametric_transfer_fn(const SkColorSpacePrimaries & primaries)78 static sk_sp<SkColorSpace> make_parametric_transfer_fn(const SkColorSpacePrimaries& primaries) {
79 skcms_Matrix3x3 toXYZD50;
80 SkAssertResult(primaries.toXYZD50(&toXYZD50));
81 skcms_TransferFunction fn = { 1.8f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f };
82 return SkColorSpace::MakeRGB(fn, toXYZD50);
83 }
84
make_wide_gamut()85 static sk_sp<SkColorSpace> make_wide_gamut() {
86 // ProPhoto
87 SkColorSpacePrimaries primaries;
88 primaries.fRX = 0.7347f;
89 primaries.fRY = 0.2653f;
90 primaries.fGX = 0.1596f;
91 primaries.fGY = 0.8404f;
92 primaries.fBX = 0.0366f;
93 primaries.fBY = 0.0001f;
94 primaries.fWX = 0.34567f;
95 primaries.fWY = 0.35850f;
96 return make_parametric_transfer_fn(primaries);
97 }
98
make_small_gamut()99 static sk_sp<SkColorSpace> make_small_gamut() {
100 SkColorSpacePrimaries primaries;
101 primaries.fRX = 0.50f;
102 primaries.fRY = 0.33f;
103 primaries.fGX = 0.30f;
104 primaries.fGY = 0.50f;
105 primaries.fBX = 0.25f;
106 primaries.fBY = 0.16f;
107 primaries.fWX = 0.3127f;
108 primaries.fWY = 0.3290f;
109 return make_parametric_transfer_fn(primaries);
110 }
111
draw_image(GrDirectContext * dContext,SkCanvas * canvas,SkImage * image,SkColorType dstColorType,SkAlphaType dstAlphaType,sk_sp<SkColorSpace> dstColorSpace,SkImage::CachingHint hint)112 static void draw_image(GrDirectContext* dContext, SkCanvas* canvas, SkImage* image,
113 SkColorType dstColorType, SkAlphaType dstAlphaType,
114 sk_sp<SkColorSpace> dstColorSpace, SkImage::CachingHint hint) {
115 size_t rowBytes = image->width() * SkColorTypeBytesPerPixel(dstColorType);
116 sk_sp<SkData> data = SkData::MakeUninitialized(rowBytes * image->height());
117 SkImageInfo dstInfo = SkImageInfo::Make(image->width(), image->height(), dstColorType,
118 dstAlphaType, dstColorSpace);
119 if (!image->readPixels(dContext, dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) {
120 memset(data->writable_data(), 0, rowBytes * image->height());
121 }
122
123 // Now that we have called readPixels(), dump the raw pixels into an srgb image.
124 sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
125 sk_sp<SkImage> raw = SkImages::RasterFromData(dstInfo.makeColorSpace(srgb), data, rowBytes);
126 canvas->drawImage(raw.get(), 0.0f, 0.0f);
127 }
128
129 class ReadPixelsGM : public skiagm::GM {
130 public:
ReadPixelsGM()131 ReadPixelsGM() {}
132
133 protected:
getName() const134 SkString getName() const override { return SkString("readpixels"); }
135
getISize()136 SkISize getISize() override { return SkISize::Make(6 * kWidth, 9 * kHeight); }
137
onDraw(SkCanvas * canvas)138 void onDraw(SkCanvas* canvas) override {
139 const SkAlphaType alphaTypes[] = {
140 kUnpremul_SkAlphaType,
141 kPremul_SkAlphaType,
142 };
143 const SkColorType colorTypes[] = {
144 kRGBA_8888_SkColorType,
145 kBGRA_8888_SkColorType,
146 kRGBA_F16_SkColorType,
147 };
148 const sk_sp<SkColorSpace> colorSpaces[] = {
149 make_wide_gamut(),
150 SkColorSpace::MakeSRGB(),
151 make_small_gamut(),
152 };
153
154 for (const sk_sp<SkColorSpace>& dstColorSpace : colorSpaces) {
155 for (SkColorType srcColorType : colorTypes) {
156 canvas->save();
157 sk_sp<SkImage> image = make_raster_image(srcColorType);
158 if (!image) {
159 continue;
160 }
161 auto dContext = GrAsDirectContext(canvas->recordingContext());
162 if (dContext) {
163 image = SkImages::TextureFromImage(dContext, image);
164 }
165 if (image) {
166 for (SkColorType dstColorType : colorTypes) {
167 for (SkAlphaType dstAlphaType : alphaTypes) {
168 draw_image(dContext, canvas, image.get(), dstColorType, dstAlphaType,
169 dstColorSpace, SkImage::kAllow_CachingHint);
170 canvas->translate((float)kWidth, 0.0f);
171 }
172 }
173 }
174 canvas->restore();
175 canvas->translate(0.0f, (float) kHeight);
176 }
177 }
178 }
179
180 private:
181 using INHERITED = skiagm::GM;
182 };
183 DEF_GM( return new ReadPixelsGM; )
184
185 class ReadPixelsCodecGM : public skiagm::GM {
186 public:
ReadPixelsCodecGM()187 ReadPixelsCodecGM() {}
188
189 protected:
getName() const190 SkString getName() const override { return SkString("readpixelscodec"); }
191
getISize()192 SkISize getISize() override {
193 return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
194 }
195
onDraw(SkCanvas * canvas,SkString * errorMsg)196 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
197 if (!canvas->imageInfo().colorSpace()) {
198 *errorMsg = "This gm is only interesting in color correct modes.";
199 return DrawResult::kSkip;
200 }
201
202 const SkAlphaType alphaTypes[] = {
203 kUnpremul_SkAlphaType,
204 kPremul_SkAlphaType,
205 };
206 const SkColorType colorTypes[] = {
207 kRGBA_8888_SkColorType,
208 kBGRA_8888_SkColorType,
209 kRGBA_F16_SkColorType,
210 };
211 const sk_sp<SkColorSpace> colorSpaces[] = {
212 make_wide_gamut(),
213 SkColorSpace::MakeSRGB(),
214 make_small_gamut(),
215 };
216 const SkImage::CachingHint hints[] = {
217 SkImage::kAllow_CachingHint,
218 SkImage::kDisallow_CachingHint,
219 };
220
221 sk_sp<SkImage> image = make_codec_image();
222 for (const sk_sp<SkColorSpace>& dstColorSpace : colorSpaces) {
223 canvas->save();
224 for (SkColorType dstColorType : colorTypes) {
225 for (SkAlphaType dstAlphaType : alphaTypes) {
226 for (SkImage::CachingHint hint : hints) {
227 draw_image(nullptr, canvas, image.get(), dstColorType, dstAlphaType,
228 dstColorSpace, hint);
229 canvas->translate(0.0f, (float) kEncodedHeight + 1);
230 }
231 }
232 }
233 canvas->restore();
234 canvas->translate((float) kEncodedWidth + 1, 0.0f);
235 }
236 return DrawResult::kOk;
237 }
238
239 private:
240 static const int kEncodedWidth = 8;
241 static const int kEncodedHeight = 8;
242
243 using INHERITED = skiagm::GM;
244 };
245 DEF_GM( return new ReadPixelsCodecGM; )
246
247 class ReadPixelsPictureGM : public skiagm::GM {
248 public:
ReadPixelsPictureGM()249 ReadPixelsPictureGM() {}
250
251 protected:
getName() const252 SkString getName() const override { return SkString("readpixelspicture"); }
253
getISize()254 SkISize getISize() override { return SkISize::Make(3 * kWidth, 12 * kHeight); }
255
onDraw(SkCanvas * canvas,SkString * errorMsg)256 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
257 if (!canvas->imageInfo().colorSpace()) {
258 *errorMsg = "This gm is only interesting in color correct modes.";
259 return DrawResult::kSkip;
260 }
261
262 const sk_sp<SkImage> images[] = {
263 make_picture_image(),
264 };
265 const SkAlphaType alphaTypes[] = {
266 kUnpremul_SkAlphaType,
267 kPremul_SkAlphaType,
268 };
269 const SkColorType colorTypes[] = {
270 kRGBA_8888_SkColorType,
271 kBGRA_8888_SkColorType,
272 kRGBA_F16_SkColorType,
273 };
274 const sk_sp<SkColorSpace> colorSpaces[] = {
275 make_wide_gamut(),
276 SkColorSpace::MakeSRGB(),
277 make_small_gamut(),
278 };
279 const SkImage::CachingHint hints[] = {
280 SkImage::kAllow_CachingHint,
281 SkImage::kDisallow_CachingHint,
282 };
283
284 for (const sk_sp<SkImage>& image : images) {
285 for (const sk_sp<SkColorSpace>& dstColorSpace : colorSpaces) {
286 canvas->save();
287 for (SkColorType dstColorType : colorTypes) {
288 for (SkAlphaType dstAlphaType : alphaTypes) {
289 for (SkImage::CachingHint hint : hints) {
290 draw_image(nullptr, canvas, image.get(), dstColorType, dstAlphaType,
291 dstColorSpace, hint);
292 canvas->translate(0.0f, (float) kHeight);
293 }
294 }
295 }
296 canvas->restore();
297 canvas->translate((float) kWidth, 0.0f);
298 }
299 }
300 return DrawResult::kOk;
301 }
302
303 private:
304
305 using INHERITED = skiagm::GM;
306 };
307 DEF_GM( return new ReadPixelsPictureGM; )
308