2 * Copyright 2016 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "sk_tool_utils.h"
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"
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;
24 virtual void draw(SkCanvas* canvas) = 0;
25 virtual const char* label() = 0;
26 virtual ~CellRenderer() {}
29 struct PaintColorCellRenderer : public CellRenderer {
30 PaintColorCellRenderer(SkColor color) : fColor(color) {}
31 void draw(SkCanvas* canvas) override {
32 canvas->drawColor(fColor);
34 const char* label() override {
41 struct BitmapCellRenderer : public CellRenderer {
42 BitmapCellRenderer(SkColor color, SkFilterQuality quality, float scale = 1.0f)
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]);
50 void draw(SkCanvas* canvas) override {
52 paint.setFilterQuality(fQuality);
53 canvas->drawBitmapRect(fBitmap, SkRect::MakeIWH(gRectSize, gRectSize), &paint);
55 const char* label() override {
56 return fLabel.c_str();
59 SkFilterQuality fQuality;
64 struct GradientCellRenderer : public CellRenderer {
65 GradientCellRenderer(SkColor colorOne, SkColor colorTwo, bool manyStops) {
66 fColors[0] = colorOne;
67 fColors[1] = colorTwo;
68 fManyStops = manyStops;
70 void draw(SkCanvas* canvas) override {
73 SkPoint::Make(0, gScalarSize)
78 fColors[0], fColors[0], fColors[1], fColors[1]
80 paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 4,
81 SkShader::kClamp_TileMode));
83 paint.setShader(SkGradientShader::MakeLinear(points, fColors, nullptr, 2,
84 SkShader::kClamp_TileMode));
86 canvas->drawPaint(paint);
88 const char* label() override {
89 return "Linear Gradient";
96 struct VerticesCellRenderer : public CellRenderer {
97 VerticesCellRenderer(SkColor colorOne, SkColor colorTwo) {
98 fColors[0] = fColors[1] = colorOne;
99 fColors[2] = fColors[3] = colorTwo;
101 void draw(SkCanvas* canvas) override {
103 SkPoint vertices[4] = {
105 SkPoint::Make(gScalarSize, 0),
106 SkPoint::Make(gScalarSize, gScalarSize),
107 SkPoint::Make(0, gScalarSize)
109 canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4, vertices,
111 SkBlendMode::kModulate, paint);
113 const char* label() override {
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
129 SkMatrix44 wideGamutRGB_toXYZD50(SkMatrix44::kUninitialized_Constructor);
130 wideGamutRGB_toXYZD50.set3x3RowMajorf(gWideGamutRGB_toXYZD50);
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);
143 case kRGBA_F16_SkColorType:
144 srgbCS = SkColorSpace::MakeSRGBLinear();
145 wideCS = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
146 wideGamutRGB_toXYZD50);
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);
160 sk_sp<SkSurface> srgbGamutSurface = canvas->makeSurface(srgbGamutInfo);
161 sk_sp<SkSurface> wideGamutSurface = canvas->makeSurface(wideGamutInfo);
162 if (!srgbGamutSurface || !wideGamutSurface) {
165 SkCanvas* srgbGamutCanvas = srgbGamutSurface->getCanvas();
166 SkCanvas* wideGamutCanvas = wideGamutSurface->getCanvas();
169 textPaint.setAntiAlias(true);
170 textPaint.setColor(SK_ColorWHITE);
171 sk_tool_utils::set_portable_typeface(&textPaint);
173 SkScalar x = 0, y = 0;
174 SkScalar textHeight = textPaint.getFontSpacing();
176 for (const auto& renderer : renderers) {
177 srgbGamutCanvas->clear(SK_ColorBLACK);
178 renderer->draw(srgbGamutCanvas);
179 wideGamutCanvas->clear(SK_ColorBLACK);
180 renderer->draw(wideGamutCanvas);
182 canvas->drawString(renderer->label(), x, y + textHeight, textPaint);
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);
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);
198 if (x + (2 * gScalarSize + 1) > gTestWidth) {
200 y += (textHeight + gScalarSize + 10);
205 DEF_SIMPLE_GM_BG(gamut, canvas, gTestWidth, gTestHeight, SK_ColorBLACK) {
206 SkTArray<std::unique_ptr<CellRenderer>> renderers;
208 // sRGB primaries, rendered as paint color
209 renderers.emplace_back(new PaintColorCellRenderer(SK_ColorRED));
210 renderers.emplace_back(new PaintColorCellRenderer(SK_ColorGREEN));
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));
220 // Various gradients involving sRGB primaries and white/black
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));
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));
233 renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorRED));
234 renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorGREEN));
236 draw_gamut_grid(canvas, renderers);