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; 25 virtual ~CellRenderer() {} 26 }; 27 28 struct 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 } 36 protected: 37 SkColor fColor; 38 }; 39 40 struct BitmapCellRenderer : public CellRenderer { 41 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 fBitmap.setImmutable(); 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 } 238