blob: 26231c5e8fe954ecb067195b35d7b906d0502237 [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
10#include "SkSurface.h"
11#include "SkGradientShader.h"
12#include "SkPM4fPriv.h"
13
14static const int gRectSize = 50;
15static const SkScalar gScalarSize = SkIntToScalar(gRectSize);
16static const int gTestWidth = 700;
17static const int gTestHeight = 300;
18
19struct CellRenderer {
20 virtual void draw(SkCanvas* canvas) = 0;
21 virtual const char* label() = 0;
22 virtual ~CellRenderer() {}
23};
24
25struct PaintColorCellRenderer : public CellRenderer {
26 PaintColorCellRenderer(SkColor color) : fColor(color) {}
27 void draw(SkCanvas* canvas) override {
28 canvas->drawColor(fColor);
29 }
30 const char* label() override {
31 return "Paint Color";
32 }
33protected:
34 SkColor fColor;
35};
36
37struct BitmapCellRenderer : public CellRenderer {
38 BitmapCellRenderer(SkColor color, SkFilterQuality quality, float scale = 1.0f)
39 : fQuality(quality) {
40 int scaledSize = SkFloatToIntRound(scale * gRectSize);
41 fBitmap.allocPixels(SkImageInfo::MakeS32(scaledSize, scaledSize, kPremul_SkAlphaType));
42 fBitmap.eraseColor(color);
43 const char* qualityNames[] = { "None", "Low", "Medium", "High" };
44 fLabel = SkStringPrintf("Bitmap (%s)", qualityNames[quality]);
45 }
46 void draw(SkCanvas* canvas) override {
47 SkPaint paint;
48 paint.setFilterQuality(fQuality);
49 canvas->drawBitmapRect(fBitmap, SkRect::MakeIWH(gRectSize, gRectSize), &paint);
50 }
51 const char* label() override {
52 return fLabel.c_str();
53 }
54protected:
55 SkFilterQuality fQuality;
56 SkBitmap fBitmap;
57 SkString fLabel;
58};
59
60struct GradientCellRenderer : public CellRenderer {
brianosmand4546092016-09-22 12:31:58 -070061 GradientCellRenderer(SkColor colorOne, SkColor colorTwo, bool manyStops) {
brianosman2c4b64e2016-09-07 07:04:44 -070062 fColors[0] = colorOne;
63 fColors[1] = colorTwo;
brianosmand4546092016-09-22 12:31:58 -070064 fManyStops = manyStops;
brianosman2c4b64e2016-09-07 07:04:44 -070065 }
66 void draw(SkCanvas* canvas) override {
67 SkPoint points[2] = {
68 SkPoint::Make(0, 0),
69 SkPoint::Make(0, gScalarSize)
70 };
71 SkPaint paint;
brianosmand4546092016-09-22 12:31:58 -070072 if (fManyStops) {
73 SkColor colors[4] ={
74 fColors[0], fColors[0], fColors[1], fColors[1]
75 };
76 paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
77 SkShader::kClamp_TileMode));
78 } else {
79 paint.setShader(SkGradientShader::MakeLinear(points, fColors, nullptr, 2,
80 SkShader::kClamp_TileMode));
81 }
brianosman2c4b64e2016-09-07 07:04:44 -070082 canvas->drawPaint(paint);
83 }
84 const char* label() override {
85 return "Linear Gradient";
86 }
87protected:
88 SkColor fColors[2];
brianosmand4546092016-09-22 12:31:58 -070089 bool fManyStops;
brianosman2c4b64e2016-09-07 07:04:44 -070090};
91
92struct VerticesCellRenderer : public CellRenderer {
93 VerticesCellRenderer(SkColor colorOne, SkColor colorTwo) {
94 fColors[0] = fColors[1] = colorOne;
95 fColors[2] = fColors[3] = colorTwo;
96 }
97 void draw(SkCanvas* canvas) override {
98 SkPaint paint;
99 SkPoint vertices[4] = {
100 SkPoint::Make(0, 0),
101 SkPoint::Make(gScalarSize, 0),
102 SkPoint::Make(gScalarSize, gScalarSize),
103 SkPoint::Make(0, gScalarSize)
104 };
105 canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, vertices, nullptr, fColors,
106 nullptr, nullptr, 0, paint);
107 }
108 const char* label() override {
109 return "Vertices";
110 }
111protected:
112 SkColor fColors[4];
113};
114
115static void draw_gamut_grid(SkCanvas* canvas, SkTArray<SkAutoTDelete<CellRenderer>>& renderers) {
116 // We want our colors in our wide gamut to be obviously visibly distorted from sRGB, so we use
117 // Wide Gamut RGB (with sRGB gamma, for HW acceleration) as the working space for this test:
118 const float gWideGamutRGB_toXYZD50[]{
brianosmande68d6c2016-09-09 10:36:17 -0700119 0.7161046f, 0.1009296f, 0.1471858f, // -> X
120 0.2581874f, 0.7249378f, 0.0168748f, // -> Y
121 0.0000000f, 0.0517813f, 0.7734287f, // -> Z
brianosman2c4b64e2016-09-07 07:04:44 -0700122 };
123
124 SkMatrix44 wideGamutRGB_toXYZD50(SkMatrix44::kUninitialized_Constructor);
125 wideGamutRGB_toXYZD50.set3x3RowMajorf(gWideGamutRGB_toXYZD50);
126
127 // Use the original canvas' color type, but account for gamma requirements
fmalitaed387722016-09-30 06:14:49 -0700128 SkImageInfo origInfo = canvas->imageInfo();
brianosman2c4b64e2016-09-07 07:04:44 -0700129 auto srgbCS = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
msarett48ba2b82016-09-07 18:55:49 -0700130 auto wideCS = SkColorSpace::NewRGB(SkColorSpace::kSRGB_RenderTargetGamma,
131 wideGamutRGB_toXYZD50);
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:
135 break;
136 case kRGBA_F16_SkColorType:
137 srgbCS = srgbCS->makeLinearGamma();
138 wideCS = wideCS->makeLinearGamma();
139 break;
140 default:
141 return;
142 }
143
144 // Make our two working surfaces (one sRGB, one Adobe)
fmalitaed387722016-09-30 06:14:49 -0700145 SkImageInfo srgbGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
brianosman2c4b64e2016-09-07 07:04:44 -0700146 kPremul_SkAlphaType, srgbCS);
fmalitaed387722016-09-30 06:14:49 -0700147 SkImageInfo wideGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
brianosman2c4b64e2016-09-07 07:04:44 -0700148 kPremul_SkAlphaType, wideCS);
149 // readPixels doesn't do color conversion (yet), so we can use it to see the raw (wide) data
150 SkImageInfo dstInfo = srgbGamutInfo.makeColorSpace(nullptr);
151 sk_sp<SkSurface> srgbGamutSurface = canvas->makeSurface(srgbGamutInfo);
152 sk_sp<SkSurface> wideGamutSurface = canvas->makeSurface(wideGamutInfo);
fmalitaed387722016-09-30 06:14:49 -0700153 if (!srgbGamutSurface || !wideGamutSurface) {
154 return;
brianosman2c4b64e2016-09-07 07:04:44 -0700155 }
156 SkCanvas* srgbGamutCanvas = srgbGamutSurface->getCanvas();
157 SkCanvas* wideGamutCanvas = wideGamutSurface->getCanvas();
158
159 SkPaint textPaint;
160 textPaint.setAntiAlias(true);
161 textPaint.setColor(SK_ColorWHITE);
162 sk_tool_utils::set_portable_typeface(&textPaint);
163
164 SkScalar x = 0, y = 0;
165 SkScalar textHeight = textPaint.getFontSpacing();
166
167 for (const auto& renderer : renderers) {
168 srgbGamutCanvas->clear(SK_ColorBLACK);
169 renderer->draw(srgbGamutCanvas);
170 wideGamutCanvas->clear(SK_ColorBLACK);
171 renderer->draw(wideGamutCanvas);
172
173 canvas->drawText(renderer->label(), strlen(renderer->label()), x, y + textHeight,
174 textPaint);
175
176 SkBitmap srgbBitmap;
177 srgbBitmap.setInfo(dstInfo);
178 srgbGamutCanvas->readPixels(&srgbBitmap, 0, 0);
179 canvas->drawBitmap(srgbBitmap, x, y + textHeight + 5);
180 x += (gScalarSize + 1);
181
182 SkBitmap wideBitmap;
183 wideBitmap.setInfo(dstInfo);
184 wideGamutCanvas->readPixels(&wideBitmap, 0, 0);
185 canvas->drawBitmap(wideBitmap, x, y + textHeight + 5);
186 x += (gScalarSize + 10);
187
188 if (x + (2 * gScalarSize + 1) > gTestWidth) {
189 x = 0;
190 y += (textHeight + gScalarSize + 10);
191 }
192 }
193}
194
195DEF_SIMPLE_GM_BG(gamut, canvas, gTestWidth, gTestHeight, SK_ColorBLACK) {
196 SkTArray<SkAutoTDelete<CellRenderer>> renderers;
197
198 // sRGB primaries, rendered as paint color
199 renderers.push_back(new PaintColorCellRenderer(SK_ColorRED));
200 renderers.push_back(new PaintColorCellRenderer(SK_ColorGREEN));
201
202 // sRGB primaries, rendered as bitmaps
203 renderers.push_back(new BitmapCellRenderer(SK_ColorRED, kNone_SkFilterQuality));
204 renderers.push_back(new BitmapCellRenderer(SK_ColorGREEN, kLow_SkFilterQuality));
205 // Larger bitmap to trigger mipmaps
206 renderers.push_back(new BitmapCellRenderer(SK_ColorRED, kMedium_SkFilterQuality, 2.0f));
207 // Smaller bitmap to trigger bicubic
208 renderers.push_back(new BitmapCellRenderer(SK_ColorGREEN, kHigh_SkFilterQuality, 0.5f));
209
210 // Various gradients involving sRGB primaries and white/black
brianosmand4546092016-09-22 12:31:58 -0700211
212 // First with just two stops (implemented with uniforms on GPU)
213 renderers.push_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, false));
214 renderers.push_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, false));
215 renderers.push_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, false));
216
217 // ... and then with four stops (implemented with textures on GPU)
218 renderers.push_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, true));
219 renderers.push_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, true));
220 renderers.push_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, true));
brianosman2c4b64e2016-09-07 07:04:44 -0700221
222 // Vertex colors
223 renderers.push_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorRED));
224 renderers.push_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorGREEN));
225
226 draw_gamut_grid(canvas, renderers);
227}