blob: 1e109a924bc1228d8fc97f4cb67ae1353afec9dc [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"
Mike Klein33d20552017-03-22 13:47:51 -04009#include "sk_tool_utils.h"
brianosman2c4b64e2016-09-07 07:04:44 -070010
brianosman2c4b64e2016-09-07 07:04:44 -070011#include "SkGradientShader.h"
Brian Osman0d4ff6c2017-01-17 16:10:07 -050012#include "SkImagePriv.h"
brianosman2c4b64e2016-09-07 07:04:44 -070013#include "SkPM4fPriv.h"
raftias7c602de2016-10-13 10:45:44 -070014#include "SkSurface.h"
Mike Reed887cdf12017-04-03 11:11:09 -040015#include "SkVertices.h"
brianosman2c4b64e2016-09-07 07:04:44 -070016
17static const int gRectSize = 50;
18static const SkScalar gScalarSize = SkIntToScalar(gRectSize);
19static const int gTestWidth = 700;
20static const int gTestHeight = 300;
21
22struct CellRenderer {
23 virtual void draw(SkCanvas* canvas) = 0;
24 virtual const char* label() = 0;
25 virtual ~CellRenderer() {}
26};
27
28struct PaintColorCellRenderer : public CellRenderer {
29 PaintColorCellRenderer(SkColor color) : fColor(color) {}
30 void draw(SkCanvas* canvas) override {
31 canvas->drawColor(fColor);
32 }
33 const char* label() override {
34 return "Paint Color";
35 }
36protected:
37 SkColor fColor;
38};
39
40struct BitmapCellRenderer : public CellRenderer {
41 BitmapCellRenderer(SkColor color, SkFilterQuality quality, float scale = 1.0f)
42 : fQuality(quality) {
Mike Reed35ee0e02017-08-06 22:29:57 -040043 int scaledSize = sk_float_round2int(scale * gRectSize);
brianosman2c4b64e2016-09-07 07:04:44 -070044 fBitmap.allocPixels(SkImageInfo::MakeS32(scaledSize, scaledSize, kPremul_SkAlphaType));
45 fBitmap.eraseColor(color);
Greg Daniela4ead652018-02-07 10:21:48 -050046 fBitmap.setImmutable();
brianosman2c4b64e2016-09-07 07:04:44 -070047 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 }
58protected:
59 SkFilterQuality fQuality;
60 SkBitmap fBitmap;
61 SkString fLabel;
62};
63
64struct GradientCellRenderer : public CellRenderer {
brianosmand4546092016-09-22 12:31:58 -070065 GradientCellRenderer(SkColor colorOne, SkColor colorTwo, bool manyStops) {
brianosman2c4b64e2016-09-07 07:04:44 -070066 fColors[0] = colorOne;
67 fColors[1] = colorTwo;
brianosmand4546092016-09-22 12:31:58 -070068 fManyStops = manyStops;
brianosman2c4b64e2016-09-07 07:04:44 -070069 }
70 void draw(SkCanvas* canvas) override {
71 SkPoint points[2] = {
72 SkPoint::Make(0, 0),
73 SkPoint::Make(0, gScalarSize)
74 };
75 SkPaint paint;
brianosmand4546092016-09-22 12:31:58 -070076 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 }
brianosman2c4b64e2016-09-07 07:04:44 -070086 canvas->drawPaint(paint);
87 }
88 const char* label() override {
89 return "Linear Gradient";
90 }
91protected:
92 SkColor fColors[2];
brianosmand4546092016-09-22 12:31:58 -070093 bool fManyStops;
brianosman2c4b64e2016-09-07 07:04:44 -070094};
95
96struct 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 };
Mike Reed887cdf12017-04-03 11:11:09 -0400109 canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4, vertices,
110 nullptr, fColors),
111 SkBlendMode::kModulate, paint);
brianosman2c4b64e2016-09-07 07:04:44 -0700112 }
113 const char* label() override {
114 return "Vertices";
115 }
116protected:
117 SkColor fColors[4];
118};
119
Ben Wagner145dbcd2016-11-03 14:40:50 -0400120static void draw_gamut_grid(SkCanvas* canvas, SkTArray<std::unique_ptr<CellRenderer>>& renderers) {
brianosman2c4b64e2016-09-07 07:04:44 -0700121 // 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[]{
brianosmande68d6c2016-09-09 10:36:17 -0700124 0.7161046f, 0.1009296f, 0.1471858f, // -> X
125 0.2581874f, 0.7249378f, 0.0168748f, // -> Y
126 0.0000000f, 0.0517813f, 0.7734287f, // -> Z
brianosman2c4b64e2016-09-07 07:04:44 -0700127 };
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
fmalitaed387722016-09-30 06:14:49 -0700133 SkImageInfo origInfo = canvas->imageInfo();
raftias94888332016-10-18 10:02:51 -0700134 sk_sp<SkColorSpace> srgbCS;
135 sk_sp<SkColorSpace> wideCS;
fmalitaed387722016-09-30 06:14:49 -0700136 switch (origInfo.colorType()) {
brianosman2c4b64e2016-09-07 07:04:44 -0700137 case kRGBA_8888_SkColorType:
138 case kBGRA_8888_SkColorType:
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500139 srgbCS = SkColorSpace::MakeSRGB();
Brian Osman526972e2016-10-24 09:24:02 -0400140 wideCS = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
raftias94888332016-10-18 10:02:51 -0700141 wideGamutRGB_toXYZD50);
brianosman2c4b64e2016-09-07 07:04:44 -0700142 break;
143 case kRGBA_F16_SkColorType:
Mike Klein37854712018-06-26 11:43:06 -0400144 case kRGBA_F32_SkColorType:
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500145 srgbCS = SkColorSpace::MakeSRGBLinear();
Brian Osman526972e2016-10-24 09:24:02 -0400146 wideCS = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
raftias94888332016-10-18 10:02:51 -0700147 wideGamutRGB_toXYZD50);
brianosman2c4b64e2016-09-07 07:04:44 -0700148 break;
149 default:
150 return;
151 }
raftias94888332016-10-18 10:02:51 -0700152 SkASSERT(srgbCS);
153 SkASSERT(wideCS);
brianosman2c4b64e2016-09-07 07:04:44 -0700154
Brian Osman0d4ff6c2017-01-17 16:10:07 -0500155 // Make our two working surfaces (one sRGB, one Wide)
fmalitaed387722016-09-30 06:14:49 -0700156 SkImageInfo srgbGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
brianosman2c4b64e2016-09-07 07:04:44 -0700157 kPremul_SkAlphaType, srgbCS);
fmalitaed387722016-09-30 06:14:49 -0700158 SkImageInfo wideGamutInfo = SkImageInfo::Make(gRectSize, gRectSize, origInfo.colorType(),
brianosman2c4b64e2016-09-07 07:04:44 -0700159 kPremul_SkAlphaType, wideCS);
Brian Osman0d4ff6c2017-01-17 16:10:07 -0500160
brianosman2c4b64e2016-09-07 07:04:44 -0700161 sk_sp<SkSurface> srgbGamutSurface = canvas->makeSurface(srgbGamutInfo);
162 sk_sp<SkSurface> wideGamutSurface = canvas->makeSurface(wideGamutInfo);
fmalitaed387722016-09-30 06:14:49 -0700163 if (!srgbGamutSurface || !wideGamutSurface) {
164 return;
brianosman2c4b64e2016-09-07 07:04:44 -0700165 }
166 SkCanvas* srgbGamutCanvas = srgbGamutSurface->getCanvas();
167 SkCanvas* wideGamutCanvas = wideGamutSurface->getCanvas();
168
169 SkPaint textPaint;
170 textPaint.setAntiAlias(true);
171 textPaint.setColor(SK_ColorWHITE);
172 sk_tool_utils::set_portable_typeface(&textPaint);
173
174 SkScalar x = 0, y = 0;
175 SkScalar textHeight = textPaint.getFontSpacing();
176
177 for (const auto& renderer : renderers) {
178 srgbGamutCanvas->clear(SK_ColorBLACK);
179 renderer->draw(srgbGamutCanvas);
180 wideGamutCanvas->clear(SK_ColorBLACK);
181 renderer->draw(wideGamutCanvas);
182
Cary Clark2a475ea2017-04-28 15:35:12 -0400183 canvas->drawString(renderer->label(), x, y + textHeight, textPaint);
brianosman2c4b64e2016-09-07 07:04:44 -0700184
Brian Osman0d4ff6c2017-01-17 16:10:07 -0500185 // Re-interpret the off-screen images, so we can see the raw data (eg, Wide gamut squares
186 // will look desaturated, relative to sRGB).
187 auto srgbImage = srgbGamutSurface->makeImageSnapshot();
188 srgbImage = SkImageMakeRasterCopyAndAssignColorSpace(srgbImage.get(),
189 origInfo.colorSpace());
190 canvas->drawImage(srgbImage, x, y + textHeight + 5);
brianosman2c4b64e2016-09-07 07:04:44 -0700191 x += (gScalarSize + 1);
192
Brian Osman0d4ff6c2017-01-17 16:10:07 -0500193 auto wideImage = wideGamutSurface->makeImageSnapshot();
194 wideImage = SkImageMakeRasterCopyAndAssignColorSpace(wideImage.get(),
195 origInfo.colorSpace());
196 canvas->drawImage(wideImage, x, y + textHeight + 5);
brianosman2c4b64e2016-09-07 07:04:44 -0700197 x += (gScalarSize + 10);
198
199 if (x + (2 * gScalarSize + 1) > gTestWidth) {
200 x = 0;
201 y += (textHeight + gScalarSize + 10);
202 }
203 }
204}
205
206DEF_SIMPLE_GM_BG(gamut, canvas, gTestWidth, gTestHeight, SK_ColorBLACK) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400207 SkTArray<std::unique_ptr<CellRenderer>> renderers;
brianosman2c4b64e2016-09-07 07:04:44 -0700208
209 // sRGB primaries, rendered as paint color
Ben Wagner145dbcd2016-11-03 14:40:50 -0400210 renderers.emplace_back(new PaintColorCellRenderer(SK_ColorRED));
211 renderers.emplace_back(new PaintColorCellRenderer(SK_ColorGREEN));
brianosman2c4b64e2016-09-07 07:04:44 -0700212
213 // sRGB primaries, rendered as bitmaps
Ben Wagner145dbcd2016-11-03 14:40:50 -0400214 renderers.emplace_back(new BitmapCellRenderer(SK_ColorRED, kNone_SkFilterQuality));
215 renderers.emplace_back(new BitmapCellRenderer(SK_ColorGREEN, kLow_SkFilterQuality));
brianosman2c4b64e2016-09-07 07:04:44 -0700216 // Larger bitmap to trigger mipmaps
Ben Wagner145dbcd2016-11-03 14:40:50 -0400217 renderers.emplace_back(new BitmapCellRenderer(SK_ColorRED, kMedium_SkFilterQuality, 2.0f));
brianosman2c4b64e2016-09-07 07:04:44 -0700218 // Smaller bitmap to trigger bicubic
Ben Wagner145dbcd2016-11-03 14:40:50 -0400219 renderers.emplace_back(new BitmapCellRenderer(SK_ColorGREEN, kHigh_SkFilterQuality, 0.5f));
brianosman2c4b64e2016-09-07 07:04:44 -0700220
221 // Various gradients involving sRGB primaries and white/black
brianosmand4546092016-09-22 12:31:58 -0700222
223 // First with just two stops (implemented with uniforms on GPU)
Ben Wagner145dbcd2016-11-03 14:40:50 -0400224 renderers.emplace_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, false));
225 renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, false));
226 renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, false));
brianosmand4546092016-09-22 12:31:58 -0700227
228 // ... and then with four stops (implemented with textures on GPU)
Ben Wagner145dbcd2016-11-03 14:40:50 -0400229 renderers.emplace_back(new GradientCellRenderer(SK_ColorRED, SK_ColorGREEN, true));
230 renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorBLACK, true));
231 renderers.emplace_back(new GradientCellRenderer(SK_ColorGREEN, SK_ColorWHITE, true));
brianosman2c4b64e2016-09-07 07:04:44 -0700232
233 // Vertex colors
Ben Wagner145dbcd2016-11-03 14:40:50 -0400234 renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorRED));
235 renderers.emplace_back(new VerticesCellRenderer(SK_ColorRED, SK_ColorGREEN));
brianosman2c4b64e2016-09-07 07:04:44 -0700236
237 draw_gamut_grid(canvas, renderers);
238}