Add fixes & test for isConfigTexturable and isConfigRenderable
[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 #include "sk_tool_utils.h"
10
11 #include "SkColorSpace_Base.h"
12 #include "SkGradientShader.h"
13 #include "SkImagePriv.h"
14 #include "SkPM4fPriv.h"
15 #include "SkSurface.h"
16 #include "SkVertices.h"
17
18 static const int gRectSize = 50;
19 static const SkScalar gScalarSize = SkIntToScalar(gRectSize);
20 static const int gTestWidth = 700;
21 static const int gTestHeight = 300;
22
23 struct CellRenderer {
24     virtual void draw(SkCanvas* canvas) = 0;
25     virtual const char* label() = 0;
26     virtual ~CellRenderer() {}
27 };
28
29 struct PaintColorCellRenderer : public CellRenderer {
30     PaintColorCellRenderer(SkColor color) : fColor(color) {}
31     void draw(SkCanvas* canvas) override {
32         canvas->drawColor(fColor);
33     }
34     const char* label() override {
35         return "Paint Color";
36     }
37 protected:
38     SkColor fColor;
39 };
40
41 struct BitmapCellRenderer : public CellRenderer {
42     BitmapCellRenderer(SkColor color, SkFilterQuality quality, float scale = 1.0f)
43         : fQuality(quality) {
44         int scaledSize = SkFloatToIntRound(scale * gRectSize);
45         fBitmap.allocPixels(SkImageInfo::MakeS32(scaledSize, scaledSize, kPremul_SkAlphaType));
46         fBitmap.eraseColor(color);
47         const char* qualityNames[] = { "None", "Low", "Medium", "High" };
48         fLabel = SkStringPrintf("Bitmap (%s)", qualityNames[quality]);
49     }
50     void draw(SkCanvas* canvas) override {
51         SkPaint paint;
52         paint.setFilterQuality(fQuality);
53         canvas->drawBitmapRect(fBitmap, SkRect::MakeIWH(gRectSize, gRectSize), &paint);
54     }
55     const char* label() override {
56         return fLabel.c_str();
57     }
58 protected:
59     SkFilterQuality fQuality;
60     SkBitmap        fBitmap;
61     SkString        fLabel;
62 };
63
64 struct GradientCellRenderer : public CellRenderer {
65     GradientCellRenderer(SkColor colorOne, SkColor colorTwo, bool manyStops) {
66         fColors[0] = colorOne;
67         fColors[1] = colorTwo;
68         fManyStops = manyStops;
69     }
70     void draw(SkCanvas* canvas) override {
71         SkPoint points[2] = {
72             SkPoint::Make(0, 0),
73             SkPoint::Make(0, gScalarSize)
74         };
75         SkPaint paint;
76         if (fManyStops) {
77             SkColor colors[4] ={
78                 fColors[0], fColors[0], fColors[1], fColors[1]
79             };
80             paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
81                                                          SkShader::kClamp_TileMode));
82         } else {
83             paint.setShader(SkGradientShader::MakeLinear(points, fColors, nullptr, 2,
84                                                          SkShader::kClamp_TileMode));
85         }
86         canvas->drawPaint(paint);
87     }
88     const char* label() override {
89         return "Linear Gradient";
90     }
91 protected:
92     SkColor fColors[2];
93     bool fManyStops;
94 };
95
96 struct VerticesCellRenderer : public CellRenderer {
97     VerticesCellRenderer(SkColor colorOne, SkColor colorTwo) {
98         fColors[0] = fColors[1] = colorOne;
99         fColors[2] = fColors[3] = colorTwo;
100     }
101     void draw(SkCanvas* canvas) override {
102         SkPaint paint;
103         SkPoint vertices[4] = {
104             SkPoint::Make(0, 0),
105             SkPoint::Make(gScalarSize, 0),
106             SkPoint::Make(gScalarSize, gScalarSize),
107             SkPoint::Make(0, gScalarSize)
108         };
109         canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4, vertices,
110                                                   nullptr, fColors),
111                              SkBlendMode::kModulate, paint);
112     }
113     const char* label() override {
114         return "Vertices";
115     }
116 protected:
117     SkColor fColors[4];
118 };
119
120 static void draw_gamut_grid(SkCanvas* canvas, SkTArray<std::unique_ptr<CellRenderer>>& renderers) {
121     // We want our colors in our wide gamut to be obviously visibly distorted from sRGB, so we use
122     // Wide Gamut RGB (with sRGB gamma, for HW acceleration) as the working space for this test:
123     const float gWideGamutRGB_toXYZD50[]{
124         0.7161046f, 0.1009296f, 0.1471858f,  // -> X
125         0.2581874f, 0.7249378f, 0.0168748f,  // -> Y
126         0.0000000f, 0.0517813f, 0.7734287f,  // -> Z
127     };
128
129     SkMatrix44 wideGamutRGB_toXYZD50(SkMatrix44::kUninitialized_Constructor);
130     wideGamutRGB_toXYZD50.set3x3RowMajorf(gWideGamutRGB_toXYZD50);
131
132     // Use the original canvas' color type, but account for gamma requirements
133     SkImageInfo origInfo = canvas->imageInfo();
134     sk_sp<SkColorSpace> srgbCS;
135     sk_sp<SkColorSpace> wideCS;
136     switch (origInfo.colorType()) {
137         case kRGBA_8888_SkColorType:
138         case kBGRA_8888_SkColorType:
139             srgbCS = SkColorSpace::MakeSRGB();
140             wideCS = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
141                                           wideGamutRGB_toXYZD50);
142             break;
143         case kRGBA_F16_SkColorType:
144             srgbCS = SkColorSpace::MakeSRGBLinear();
145             wideCS = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
146                                           wideGamutRGB_toXYZD50);
147             break;
148         default:
149             return;
150     }
151     SkASSERT(srgbCS);
152     SkASSERT(wideCS);
153
154     // Make our two working surfaces (one sRGB, one Wide)
155     SkImageInfo srgbGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
156                                                   kPremul_SkAlphaType, srgbCS);
157     SkImageInfo wideGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
158                                                   kPremul_SkAlphaType, wideCS);
159
160     sk_sp<SkSurface> srgbGamutSurface = canvas->makeSurface(srgbGamutInfo);
161     sk_sp<SkSurface> wideGamutSurface = canvas->makeSurface(wideGamutInfo);
162     if (!srgbGamutSurface || !wideGamutSurface) {
163         return;
164     }
165     SkCanvas* srgbGamutCanvas = srgbGamutSurface->getCanvas();
166     SkCanvas* wideGamutCanvas = wideGamutSurface->getCanvas();
167
168     SkPaint textPaint;
169     textPaint.setAntiAlias(true);
170     textPaint.setColor(SK_ColorWHITE);
171     sk_tool_utils::set_portable_typeface(&textPaint);
172
173     SkScalar x = 0, y = 0;
174     SkScalar textHeight = textPaint.getFontSpacing();
175
176     for (const auto& renderer : renderers) {
177         srgbGamutCanvas->clear(SK_ColorBLACK);
178         renderer->draw(srgbGamutCanvas);
179         wideGamutCanvas->clear(SK_ColorBLACK);
180         renderer->draw(wideGamutCanvas);
181
182         canvas->drawString(renderer->label(), x, y + textHeight, textPaint);
183
184         // Re-interpret the off-screen images, so we can see the raw data (eg, Wide gamut squares
185         // will look desaturated, relative to sRGB).
186         auto srgbImage = srgbGamutSurface->makeImageSnapshot();
187         srgbImage = SkImageMakeRasterCopyAndAssignColorSpace(srgbImage.get(),
188                                                              origInfo.colorSpace());
189         canvas->drawImage(srgbImage, x, y + textHeight + 5);
190         x += (gScalarSize + 1);
191
192         auto wideImage = wideGamutSurface->makeImageSnapshot();
193         wideImage = SkImageMakeRasterCopyAndAssignColorSpace(wideImage.get(),
194                                                              origInfo.colorSpace());
195         canvas->drawImage(wideImage, x, y + textHeight + 5);
196         x += (gScalarSize + 10);
197
198         if (x + (2 * gScalarSize + 1) > gTestWidth) {
199             x = 0;
200             y += (textHeight + gScalarSize + 10);
201         }
202     }
203 }
204
205 DEF_SIMPLE_GM_BG(gamut, canvas, gTestWidth, gTestHeight, SK_ColorBLACK) {
206     SkTArray<std::unique_ptr<CellRenderer>> renderers;
207
208     // sRGB primaries, rendered as paint color
209     renderers.emplace_back(new PaintColorCellRenderer(SK_ColorRED));
210     renderers.emplace_back(new PaintColorCellRenderer(SK_ColorGREEN));
211
212     // sRGB primaries, rendered as bitmaps
213     renderers.emplace_back(new BitmapCellRenderer(SK_ColorRED, kNone_SkFilterQuality));
214     renderers.emplace_back(new BitmapCellRenderer(SK_ColorGREEN, kLow_SkFilterQuality));
215     // Larger bitmap to trigger mipmaps
216     renderers.emplace_back(new BitmapCellRenderer(SK_ColorRED, kMedium_SkFilterQuality, 2.0f));
217     // Smaller bitmap to trigger bicubic
218     renderers.emplace_back(new BitmapCellRenderer(SK_ColorGREEN, kHigh_SkFilterQuality, 0.5f));
219
220     // Various gradients involving sRGB primaries and white/black
221
222     // First with just two stops (implemented with uniforms on GPU)
223     renderers.emplace_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, false));
224     renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, false));
225     renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, false));
226
227     // ... and then with four stops (implemented with textures on GPU)
228     renderers.emplace_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, true));
229     renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, true));
230     renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, true));
231
232     // Vertex colors
233     renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorRED));
234     renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorGREEN));
235
236     draw_gamut_grid(canvas, renderers);
237 }