1 /* 2 * Copyright 2015 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 "Resources.h" 12 #include "SkBlendModePriv.h" 13 #include "SkGradientShader.h" 14 15 DEF_SIMPLE_GM(gamma, canvas, 850, 200) { 16 SkPaint p; 17 const SkScalar sz = 50.0f; 18 const int szInt = SkScalarTruncToInt(sz); 19 const SkScalar tx = sz + 15.0f; 20 const SkRect r = SkRect::MakeXYWH(0, 0, sz, sz); 21 SkShader::TileMode rpt = SkShader::kRepeat_TileMode; 22 auto srgbColorSpace = SkColorSpace::MakeSRGB(); 23 24 SkBitmap ditherBmp; 25 ditherBmp.allocN32Pixels(2, 2); 26 SkPMColor* pixels = reinterpret_cast<SkPMColor*>(ditherBmp.getPixels()); 27 pixels[0] = pixels[3] = SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF); 28 pixels[1] = pixels[2] = SkPackARGB32(0xFF, 0, 0, 0); 29 30 SkBitmap linearGreyBmp; 31 SkImageInfo linearGreyInfo = SkImageInfo::MakeN32(szInt, szInt, kOpaque_SkAlphaType, nullptr); 32 linearGreyBmp.allocPixels(linearGreyInfo); 33 linearGreyBmp.eraseARGB(0xFF, 0x7F, 0x7F, 0x7F); 34 35 SkBitmap srgbGreyBmp; 36 SkImageInfo srgbGreyInfo = SkImageInfo::MakeN32(szInt, szInt, kOpaque_SkAlphaType, 37 srgbColorSpace); 38 srgbGreyBmp.allocPixels(srgbGreyInfo); 39 // 0xBC = 255 * linear_to_srgb(0.5f) 40 srgbGreyBmp.eraseARGB(0xFF, 0xBC, 0xBC, 0xBC); 41 42 SkBitmap mipmapBmp; 43 SkImageInfo mipmapInfo = SkImageInfo::Make(2, 2, kN32_SkColorType, kOpaque_SkAlphaType, 44 srgbColorSpace); 45 mipmapBmp.allocPixels(mipmapInfo); 46 SkPMColor* mipmapPixels = reinterpret_cast<SkPMColor*>(mipmapBmp.getPixels()); 47 unsigned s25 = 0x89; // 255 * linear_to_srgb(0.25f) 48 unsigned s75 = 0xE1; // 255 * linear_to_srgb(0.75f) 49 mipmapPixels[0] = mipmapPixels[3] = SkPackARGB32(0xFF, s25, s25, s25); 50 mipmapPixels[1] = mipmapPixels[2] = SkPackARGB32(0xFF, s75, s75, s75); 51 52 SkFont font(sk_tool_utils::create_portable_typeface()); 53 54 SkPaint textPaint; 55 textPaint.setAntiAlias(true); 56 textPaint.setColor(SK_ColorWHITE); 57 58 // Helpers: __anonb8714d360102() 59 auto advance = [&]() { 60 canvas->translate(tx, 0); 61 p.reset(); 62 }; 63 __anonb8714d360202(const char str[], SkScalar x, SkScalar y) 64 auto drawString = [&](const char str[], SkScalar x, SkScalar y) { 65 canvas->drawSimpleText(str, strlen(str), kUTF8_SkTextEncoding, x, y, font, textPaint); 66 }; 67 __anonb8714d360302(const char* label, const char* label2) 68 auto nextRect = [&](const char* label, const char* label2) { 69 canvas->drawRect(r, p); 70 drawString(label, 0, sz + font.getSpacing()); 71 if (label2) { 72 drawString(label2, 0, sz + 2 * font.getSpacing()); 73 } 74 advance(); 75 }; 76 __anonb8714d360402(const SkBitmap& bmp, const char* label) 77 auto nextBitmap = [&](const SkBitmap& bmp, const char* label) { 78 canvas->drawBitmap(bmp, 0, 0); 79 drawString(label, 0, sz + font.getSpacing()); 80 advance(); 81 }; 82 __anonb8714d360502(SkColor srcColor, SkBlendMode mode, SkColor dstColor) 83 auto nextXferRect = [&](SkColor srcColor, SkBlendMode mode, SkColor dstColor) { 84 p.setColor(dstColor); 85 canvas->drawRect(r, p); 86 p.setColor(srcColor); 87 p.setBlendMode(mode); 88 canvas->drawRect(r, p); 89 90 SkString srcText = SkStringPrintf("%08X", srcColor); 91 SkString dstText = SkStringPrintf("%08X", dstColor); 92 drawString(srcText.c_str(), 0, sz + font.getSpacing()); 93 const char* modeName = SkBlendMode_Name(mode); 94 drawString(modeName, 0, sz + 2 * font.getSpacing()); 95 drawString(dstText.c_str(), 0, sz + 3 * font.getSpacing()); 96 advance(); 97 }; 98 99 // Necessary for certain Xfermode tests to work (ie some of them output white @ 50% alpha): 100 canvas->clear(SK_ColorBLACK); 101 102 // *Everything* should be perceptually 50% grey. Only the first rectangle 103 // is guaranteed to draw that way, though. 104 canvas->save(); 105 106 // Black/white dither, pixel perfect. This is ground truth. 107 p.setShader(SkShader::MakeBitmapShader(ditherBmp, rpt, rpt)); 108 p.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality); 109 nextRect("Dither", "Reference"); 110 111 // Black/white dither, sampled at half-texel offset. Tests bilerp. 112 // NOTE: We need to apply a non-identity scale and/or rotation to trick 113 // the raster pipeline into *not* snapping to nearest. 114 SkMatrix offsetMatrix = SkMatrix::Concat( 115 SkMatrix::MakeScale(-1.0f), SkMatrix::MakeTrans(0.5f, 0.0f)); 116 p.setShader(SkShader::MakeBitmapShader(ditherBmp, rpt, rpt, &offsetMatrix)); 117 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality); 118 nextRect("Dither", "Bilerp"); 119 120 // Black/white dither, scaled down by 2x. Tests minification. 121 SkMatrix scaleMatrix = SkMatrix::MakeScale(0.5f); 122 p.setShader(SkShader::MakeBitmapShader(ditherBmp, rpt, rpt, &scaleMatrix)); 123 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality); 124 nextRect("Dither", "Scale"); 125 126 // 25%/75% dither, scaled down by 2x. Tests ALL aspects of minification. Specifically, are 127 // sRGB sources decoded to linear before computing mipmaps? 128 p.setShader(SkShader::MakeBitmapShader(mipmapBmp, rpt, rpt, &scaleMatrix)); 129 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality); 130 nextRect("MipMaps", nullptr); 131 132 // 50% grey via paint color. Paint color (SkColor) is specified to be sRGB! 133 p.setColor(0xffbcbcbc); 134 nextRect("Color", nullptr); 135 136 { 137 // Black -> White gradient, scaled to sample just the middle. 138 // Tests gradient interpolation. 139 SkPoint points[2] = { 140 SkPoint::Make(0 - (sz * 10), 0), 141 SkPoint::Make(sz + (sz * 10), 0) 142 }; 143 SkColor colors[2] = { SK_ColorBLACK, SK_ColorWHITE }; 144 p.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2, 145 SkShader::kClamp_TileMode)); 146 nextRect("Gradient", "Interpolation"); 147 } 148 149 { 150 // Shallow gradient around 50% (perceptual) gray. Endpoints are SkColor, so sRGB. 151 // Tests gamma-correction of gradient stops before interpolation in two-stop case 152 SkPoint points[2] = { 153 SkPoint::Make(0, 0), 154 SkPoint::Make(sz, 0) 155 }; 156 SkColor colors[2] = { 0xffbbbbbb, 0xffbdbdbd }; 157 p.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2, 158 SkShader::kClamp_TileMode)); 159 nextRect("Gradient", "Endpoints"); 160 } 161 162 { 163 // Shallow 3-stop gradient around 50% (perceptual) gray. Endpoints are SkColor, so sRGB. 164 // Tests gamma-correction of gradient stops before interpolation in three-stop case 165 SkPoint points[2] = { 166 SkPoint::Make(0, 0), 167 SkPoint::Make(sz, 0) 168 }; 169 SkColor colors[3] = { 0xffbbbbbb, 0xffbdbdbd, 0xffbbbbbb }; 170 p.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 3, 171 SkShader::kClamp_TileMode)); 172 nextRect("Gradient", "3-Stop"); 173 } 174 175 { 176 // Shallow N-stop gradient around 50% (perceptual) gray. Endpoints are SkColor, so sRGB. 177 // Tests gamma-correction of gradient stops before interpolation in texture implementation 178 SkPoint points[2] = { 179 SkPoint::Make(0, 0), 180 SkPoint::Make(sz, 0) 181 }; 182 SkColor colors[5] = { 0xffbbbbbb, 0xffbdbdbd, 0xffbbbbbb, 0xffbdbdbd, 0xffbbbbbb }; 183 p.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 5, 184 SkShader::kClamp_TileMode)); 185 nextRect("Gradient", "Texture"); 186 } 187 188 // 50% grey from linear bitmap, with drawBitmap 189 nextBitmap(linearGreyBmp, "Lnr BMP"); 190 191 // 50% grey from sRGB bitmap, with drawBitmap 192 nextBitmap(srgbGreyBmp, "sRGB BMP"); 193 194 // Bitmap wrapped in a shader (linear): 195 p.setShader(SkShader::MakeBitmapShader(linearGreyBmp, rpt, rpt)); 196 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality); 197 nextRect("Lnr BMP", "Shader"); 198 199 // Bitmap wrapped in a shader (sRGB): 200 p.setShader(SkShader::MakeBitmapShader(srgbGreyBmp, rpt, rpt)); 201 p.setFilterQuality(SkFilterQuality::kMedium_SkFilterQuality); 202 nextRect("sRGB BMP", "Shader"); 203 204 // Carriage return. 205 canvas->restore(); 206 canvas->translate(0, 2 * sz); 207 208 // Xfermode tests, all done off-screen so certain modes work... 209 210 canvas->saveLayer(nullptr, nullptr); 211 212 nextXferRect(0x7fffffff, SkBlendMode::kSrcOver, SK_ColorBLACK); 213 nextXferRect(0x7f000000, SkBlendMode::kSrcOver, SK_ColorWHITE); 214 215 nextXferRect(SK_ColorBLACK, SkBlendMode::kDstOver, 0x7fffffff); 216 nextXferRect(SK_ColorWHITE, SkBlendMode::kSrcIn, 0x7fff00ff); 217 nextXferRect(0x7fff00ff, SkBlendMode::kDstIn, SK_ColorWHITE); 218 219 // 0x89 = 255 * linear_to_srgb(0.25) 220 nextXferRect(0xff898989, SkBlendMode::kPlus, 0xff898989); 221 222 // 0xDB = 255 * linear_to_srgb(sqrt(0.5)) 223 nextXferRect(0xffdbdbdb, SkBlendMode::kModulate, 0xffdbdbdb); 224 225 canvas->restore(); 226 } 227