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