blob: 21312ce6fa64fb925023c6303c0e848ca84cc5f2 [file] [log] [blame]
brianosman2c4b64e2016-09-07 07:04:44 -07001/*
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
raftias7c602de2016-10-13 10:45:44 -070010#include "SkColorSpace_Base.h"
brianosman2c4b64e2016-09-07 07:04:44 -070011#include "SkGradientShader.h"
12#include "SkPM4fPriv.h"
raftias7c602de2016-10-13 10:45:44 -070013#include "SkSurface.h"
brianosman2c4b64e2016-09-07 07:04:44 -070014
15static const int gRectSize = 50;
16static const SkScalar gScalarSize = SkIntToScalar(gRectSize);
17static const int gTestWidth = 700;
18static const int gTestHeight = 300;
19
20struct CellRenderer {
21 virtual void draw(SkCanvas* canvas) = 0;
22 virtual const char* label() = 0;
23 virtual ~CellRenderer() {}
24};
25
26struct PaintColorCellRenderer : public CellRenderer {
27 PaintColorCellRenderer(SkColor color) : fColor(color) {}
28 void draw(SkCanvas* canvas) override {
29 canvas->drawColor(fColor);
30 }
31 const char* label() override {
32 return "Paint Color";
33 }
34protected:
35 SkColor fColor;
36};
37
38struct BitmapCellRenderer : public CellRenderer {
39 BitmapCellRenderer(SkColor color, SkFilterQuality quality, float scale = 1.0f)
40 : fQuality(quality) {
41 int scaledSize = SkFloatToIntRound(scale * gRectSize);
42 fBitmap.allocPixels(SkImageInfo::MakeS32(scaledSize, scaledSize, kPremul_SkAlphaType));
43 fBitmap.eraseColor(color);
44 const char* qualityNames[] = { "None", "Low", "Medium", "High" };
45 fLabel = SkStringPrintf("Bitmap (%s)", qualityNames[quality]);
46 }
47 void draw(SkCanvas* canvas) override {
48 SkPaint paint;
49 paint.setFilterQuality(fQuality);
50 canvas->drawBitmapRect(fBitmap, SkRect::MakeIWH(gRectSize, gRectSize), &paint);
51 }
52 const char* label() override {
53 return fLabel.c_str();
54 }
55protected:
56 SkFilterQuality fQuality;
57 SkBitmap fBitmap;
58 SkString fLabel;
59};
60
61struct GradientCellRenderer : public CellRenderer {
brianosmand4546092016-09-22 12:31:58 -070062 GradientCellRenderer(SkColor colorOne, SkColor colorTwo, bool manyStops) {
brianosman2c4b64e2016-09-07 07:04:44 -070063 fColors[0] = colorOne;
64 fColors[1] = colorTwo;
brianosmand4546092016-09-22 12:31:58 -070065 fManyStops = manyStops;
brianosman2c4b64e2016-09-07 07:04:44 -070066 }
67 void draw(SkCanvas* canvas) override {
68 SkPoint points[2] = {
69 SkPoint::Make(0, 0),
70 SkPoint::Make(0, gScalarSize)
71 };
72 SkPaint paint;
brianosmand4546092016-09-22 12:31:58 -070073 if (fManyStops) {
74 SkColor colors[4] ={
75 fColors[0], fColors[0], fColors[1], fColors[1]
76 };
77 paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
78 SkShader::kClamp_TileMode));
79 } else {
80 paint.setShader(SkGradientShader::MakeLinear(points, fColors, nullptr, 2,
81 SkShader::kClamp_TileMode));
82 }
brianosman2c4b64e2016-09-07 07:04:44 -070083 canvas->drawPaint(paint);
84 }
85 const char* label() override {
86 return "Linear Gradient";
87 }
88protected:
89 SkColor fColors[2];
brianosmand4546092016-09-22 12:31:58 -070090 bool fManyStops;
brianosman2c4b64e2016-09-07 07:04:44 -070091};
92
93struct VerticesCellRenderer : public CellRenderer {
94 VerticesCellRenderer(SkColor colorOne, SkColor colorTwo) {
95 fColors[0] = fColors[1] = colorOne;
96 fColors[2] = fColors[3] = colorTwo;
97 }
98 void draw(SkCanvas* canvas) override {
99 SkPaint paint;
100 SkPoint vertices[4] = {
101 SkPoint::Make(0, 0),
102 SkPoint::Make(gScalarSize, 0),
103 SkPoint::Make(gScalarSize, gScalarSize),
104 SkPoint::Make(0, gScalarSize)
105 };
106 canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, vertices, nullptr, fColors,
Mike Reed7d954ad2016-10-28 15:42:34 -0400107 SkBlendMode::kModulate, nullptr, 0, paint);
brianosman2c4b64e2016-09-07 07:04:44 -0700108 }
109 const char* label() override {
110 return "Vertices";
111 }
112protected:
113 SkColor fColors[4];
114};
115
Ben Wagner145dbcd2016-11-03 14:40:50 -0400116static void draw_gamut_grid(SkCanvas* canvas, SkTArray<std::unique_ptr<CellRenderer>>& renderers) {
brianosman2c4b64e2016-09-07 07:04:44 -0700117 // We want our colors in our wide gamut to be obviously visibly distorted from sRGB, so we use
118 // Wide Gamut RGB (with sRGB gamma, for HW acceleration) as the working space for this test:
119 const float gWideGamutRGB_toXYZD50[]{
brianosmande68d6c2016-09-09 10:36:17 -0700120 0.7161046f, 0.1009296f, 0.1471858f, // -> X
121 0.2581874f, 0.7249378f, 0.0168748f, // -> Y
122 0.0000000f, 0.0517813f, 0.7734287f, // -> Z
brianosman2c4b64e2016-09-07 07:04:44 -0700123 };
124
125 SkMatrix44 wideGamutRGB_toXYZD50(SkMatrix44::kUninitialized_Constructor);
126 wideGamutRGB_toXYZD50.set3x3RowMajorf(gWideGamutRGB_toXYZD50);
127
128 // Use the original canvas' color type, but account for gamma requirements
fmalitaed387722016-09-30 06:14:49 -0700129 SkImageInfo origInfo = canvas->imageInfo();
raftias94888332016-10-18 10:02:51 -0700130 sk_sp<SkColorSpace> srgbCS;
131 sk_sp<SkColorSpace> wideCS;
fmalitaed387722016-09-30 06:14:49 -0700132 switch (origInfo.colorType()) {
brianosman2c4b64e2016-09-07 07:04:44 -0700133 case kRGBA_8888_SkColorType:
134 case kBGRA_8888_SkColorType:
Brian Osman526972e2016-10-24 09:24:02 -0400135 srgbCS = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
136 wideCS = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
raftias94888332016-10-18 10:02:51 -0700137 wideGamutRGB_toXYZD50);
brianosman2c4b64e2016-09-07 07:04:44 -0700138 break;
139 case kRGBA_F16_SkColorType:
Brian Osman526972e2016-10-24 09:24:02 -0400140 srgbCS = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
141 wideCS = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
raftias94888332016-10-18 10:02:51 -0700142 wideGamutRGB_toXYZD50);
brianosman2c4b64e2016-09-07 07:04:44 -0700143 break;
144 default:
145 return;
146 }
raftias94888332016-10-18 10:02:51 -0700147 SkASSERT(srgbCS);
148 SkASSERT(wideCS);
brianosman2c4b64e2016-09-07 07:04:44 -0700149
150 // Make our two working surfaces (one sRGB, one Adobe)
fmalitaed387722016-09-30 06:14:49 -0700151 SkImageInfo srgbGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
brianosman2c4b64e2016-09-07 07:04:44 -0700152 kPremul_SkAlphaType, srgbCS);
fmalitaed387722016-09-30 06:14:49 -0700153 SkImageInfo wideGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
brianosman2c4b64e2016-09-07 07:04:44 -0700154 kPremul_SkAlphaType, wideCS);
155 // readPixels doesn't do color conversion (yet), so we can use it to see the raw (wide) data
156 SkImageInfo dstInfo = srgbGamutInfo.makeColorSpace(nullptr);
157 sk_sp<SkSurface> srgbGamutSurface = canvas->makeSurface(srgbGamutInfo);
158 sk_sp<SkSurface> wideGamutSurface = canvas->makeSurface(wideGamutInfo);
fmalitaed387722016-09-30 06:14:49 -0700159 if (!srgbGamutSurface || !wideGamutSurface) {
160 return;
brianosman2c4b64e2016-09-07 07:04:44 -0700161 }
162 SkCanvas* srgbGamutCanvas = srgbGamutSurface->getCanvas();
163 SkCanvas* wideGamutCanvas = wideGamutSurface->getCanvas();
164
165 SkPaint textPaint;
166 textPaint.setAntiAlias(true);
167 textPaint.setColor(SK_ColorWHITE);
168 sk_tool_utils::set_portable_typeface(&textPaint);
169
170 SkScalar x = 0, y = 0;
171 SkScalar textHeight = textPaint.getFontSpacing();
172
173 for (const auto& renderer : renderers) {
174 srgbGamutCanvas->clear(SK_ColorBLACK);
175 renderer->draw(srgbGamutCanvas);
176 wideGamutCanvas->clear(SK_ColorBLACK);
177 renderer->draw(wideGamutCanvas);
178
179 canvas->drawText(renderer->label(), strlen(renderer->label()), x, y + textHeight,
180 textPaint);
181
182 SkBitmap srgbBitmap;
183 srgbBitmap.setInfo(dstInfo);
184 srgbGamutCanvas->readPixels(&srgbBitmap, 0, 0);
185 canvas->drawBitmap(srgbBitmap, x, y + textHeight + 5);
186 x += (gScalarSize + 1);
187
188 SkBitmap wideBitmap;
189 wideBitmap.setInfo(dstInfo);
190 wideGamutCanvas->readPixels(&wideBitmap, 0, 0);
191 canvas->drawBitmap(wideBitmap, x, y + textHeight + 5);
192 x += (gScalarSize + 10);
193
194 if (x + (2 * gScalarSize + 1) > gTestWidth) {
195 x = 0;
196 y += (textHeight + gScalarSize + 10);
197 }
198 }
199}
200
201DEF_SIMPLE_GM_BG(gamut, canvas, gTestWidth, gTestHeight, SK_ColorBLACK) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400202 SkTArray<std::unique_ptr<CellRenderer>> renderers;
brianosman2c4b64e2016-09-07 07:04:44 -0700203
204 // sRGB primaries, rendered as paint color
Ben Wagner145dbcd2016-11-03 14:40:50 -0400205 renderers.emplace_back(new PaintColorCellRenderer(SK_ColorRED));
206 renderers.emplace_back(new PaintColorCellRenderer(SK_ColorGREEN));
brianosman2c4b64e2016-09-07 07:04:44 -0700207
208 // sRGB primaries, rendered as bitmaps
Ben Wagner145dbcd2016-11-03 14:40:50 -0400209 renderers.emplace_back(new BitmapCellRenderer(SK_ColorRED, kNone_SkFilterQuality));
210 renderers.emplace_back(new BitmapCellRenderer(SK_ColorGREEN, kLow_SkFilterQuality));
brianosman2c4b64e2016-09-07 07:04:44 -0700211 // Larger bitmap to trigger mipmaps
Ben Wagner145dbcd2016-11-03 14:40:50 -0400212 renderers.emplace_back(new BitmapCellRenderer(SK_ColorRED, kMedium_SkFilterQuality, 2.0f));
brianosman2c4b64e2016-09-07 07:04:44 -0700213 // Smaller bitmap to trigger bicubic
Ben Wagner145dbcd2016-11-03 14:40:50 -0400214 renderers.emplace_back(new BitmapCellRenderer(SK_ColorGREEN, kHigh_SkFilterQuality, 0.5f));
brianosman2c4b64e2016-09-07 07:04:44 -0700215
216 // Various gradients involving sRGB primaries and white/black
brianosmand4546092016-09-22 12:31:58 -0700217
218 // First with just two stops (implemented with uniforms on GPU)
Ben Wagner145dbcd2016-11-03 14:40:50 -0400219 renderers.emplace_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, false));
220 renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, false));
221 renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, false));
brianosmand4546092016-09-22 12:31:58 -0700222
223 // ... and then with four stops (implemented with textures on GPU)
Ben Wagner145dbcd2016-11-03 14:40:50 -0400224 renderers.emplace_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, true));
225 renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, true));
226 renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, true));
brianosman2c4b64e2016-09-07 07:04:44 -0700227
228 // Vertex colors
Ben Wagner145dbcd2016-11-03 14:40:50 -0400229 renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorRED));
230 renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorGREEN));
brianosman2c4b64e2016-09-07 07:04:44 -0700231
232 draw_gamut_grid(canvas, renderers);
233}