a54214ef35ac15c35669f26c975cc8f398e7199c
[platform/upstream/libSkiaSharp.git] / gm / gamut.cpp
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.h"
9
10 #include "SkColorSpace_Base.h"
11 #include "SkGradientShader.h"
12 #include "SkPM4fPriv.h"
13 #include "SkSurface.h"
14
15 static const int gRectSize = 50;
16 static const SkScalar gScalarSize = SkIntToScalar(gRectSize);
17 static const int gTestWidth = 700;
18 static const int gTestHeight = 300;
19
20 struct CellRenderer {
21     virtual void draw(SkCanvas* canvas) = 0;
22     virtual const char* label() = 0;
23     virtual ~CellRenderer() {}
24 };
25
26 struct 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     }
34 protected:
35     SkColor fColor;
36 };
37
38 struct 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     }
55 protected:
56     SkFilterQuality fQuality;
57     SkBitmap        fBitmap;
58     SkString        fLabel;
59 };
60
61 struct GradientCellRenderer : public CellRenderer {
62     GradientCellRenderer(SkColor colorOne, SkColor colorTwo, bool manyStops) {
63         fColors[0] = colorOne;
64         fColors[1] = colorTwo;
65         fManyStops = manyStops;
66     }
67     void draw(SkCanvas* canvas) override {
68         SkPoint points[2] = {
69             SkPoint::Make(0, 0),
70             SkPoint::Make(0, gScalarSize)
71         };
72         SkPaint paint;
73         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         }
83         canvas->drawPaint(paint);
84     }
85     const char* label() override {
86         return "Linear Gradient";
87     }
88 protected:
89     SkColor fColors[2];
90     bool fManyStops;
91 };
92
93 struct 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,
107                              nullptr, nullptr, 0, paint);
108     }
109     const char* label() override {
110         return "Vertices";
111     }
112 protected:
113     SkColor fColors[4];
114 };
115
116 static void draw_gamut_grid(SkCanvas* canvas, SkTArray<SkAutoTDelete<CellRenderer>>& renderers) {
117     // 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[]{
120         0.7161046f, 0.1009296f, 0.1471858f,  // -> X
121         0.2581874f, 0.7249378f, 0.0168748f,  // -> Y
122         0.0000000f, 0.0517813f, 0.7734287f,  // -> Z
123     };
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
129     SkImageInfo origInfo = canvas->imageInfo();
130     sk_sp<SkColorSpace> srgbCS;
131     sk_sp<SkColorSpace> wideCS;
132     switch (origInfo.colorType()) {
133         case kRGBA_8888_SkColorType:
134         case kBGRA_8888_SkColorType:
135             srgbCS = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
136             wideCS = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
137                                           wideGamutRGB_toXYZD50);
138             break;
139         case kRGBA_F16_SkColorType:
140             srgbCS = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
141             wideCS = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
142                                           wideGamutRGB_toXYZD50);
143             break;
144         default:
145             return;
146     }
147     SkASSERT(srgbCS);
148     SkASSERT(wideCS);
149
150     // Make our two working surfaces (one sRGB, one Adobe)
151     SkImageInfo srgbGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
152                                                   kPremul_SkAlphaType, srgbCS);
153     SkImageInfo wideGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
154                                                   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);
159     if (!srgbGamutSurface || !wideGamutSurface) {
160         return;
161     }
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
201 DEF_SIMPLE_GM_BG(gamut, canvas, gTestWidth, gTestHeight, SK_ColorBLACK) {
202     SkTArray<SkAutoTDelete<CellRenderer>> renderers;
203
204     // sRGB primaries, rendered as paint color
205     renderers.push_back(new PaintColorCellRenderer(SK_ColorRED));
206     renderers.push_back(new PaintColorCellRenderer(SK_ColorGREEN));
207
208     // sRGB primaries, rendered as bitmaps
209     renderers.push_back(new BitmapCellRenderer(SK_ColorRED, kNone_SkFilterQuality));
210     renderers.push_back(new BitmapCellRenderer(SK_ColorGREEN, kLow_SkFilterQuality));
211     // Larger bitmap to trigger mipmaps
212     renderers.push_back(new BitmapCellRenderer(SK_ColorRED, kMedium_SkFilterQuality, 2.0f));
213     // Smaller bitmap to trigger bicubic
214     renderers.push_back(new BitmapCellRenderer(SK_ColorGREEN, kHigh_SkFilterQuality, 0.5f));
215
216     // Various gradients involving sRGB primaries and white/black
217
218     // First with just two stops (implemented with uniforms on GPU)
219     renderers.push_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, false));
220     renderers.push_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, false));
221     renderers.push_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, false));
222
223     // ... and then with four stops (implemented with textures on GPU)
224     renderers.push_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, true));
225     renderers.push_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, true));
226     renderers.push_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, true));
227
228     // Vertex colors
229     renderers.push_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorRED));
230     renderers.push_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorGREEN));
231
232     draw_gamut_grid(canvas, renderers);
233 }