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 #include "SkPM4fPriv.h" 15 16 DEF_SIMPLE_GM(gamma, canvas, 850, 200) { 17 SkPaint p; 18 const SkScalar sz = 50.0f; 19 const int szInt = SkScalarTruncToInt(sz); 20 const SkScalar tx = sz + 15.0f; 21 const SkRect r = SkRect::MakeXYWH(0, 0, sz, sz); 22 SkShader::TileMode rpt = SkShader::kRepeat_TileMode; 23 auto srgbColorSpace = SkColorSpace::MakeSRGB(); 24 25 SkBitmap ditherBmp; 26 ditherBmp.allocN32Pixels(2, 2); 27 SkPMColor* pixels = reinterpret_cast<SkPMColor*>(ditherBmp.getPixels()); 28 pixels[0] = pixels[3] = SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF); 29 pixels[1] = pixels[2] = SkPackARGB32(0xFF, 0, 0, 0); 30 31 SkBitmap linearGreyBmp; 32 SkImageInfo linearGreyInfo = SkImageInfo::MakeN32(szInt, szInt, kOpaque_SkAlphaType, nullptr); 33 linearGreyBmp.allocPixels(linearGreyInfo); 34 linearGreyBmp.eraseARGB(0xFF, 0x7F, 0x7F, 0x7F); 35 36 SkBitmap srgbGreyBmp; 37 SkImageInfo srgbGreyInfo = SkImageInfo::MakeN32(szInt, szInt, kOpaque_SkAlphaType, 38 srgbColorSpace); 39 srgbGreyBmp.allocPixels(srgbGreyInfo); 40 // 0xBC = 255 * linear_to_srgb(0.5f) 41 srgbGreyBmp.eraseARGB(0xFF, 0xBC, 0xBC, 0xBC); 42 43 SkBitmap mipmapBmp; 44 SkImageInfo mipmapInfo = SkImageInfo::Make(2, 2, kN32_SkColorType, kOpaque_SkAlphaType, 45 srgbColorSpace); 46 mipmapBmp.allocPixels(mipmapInfo); 47 SkPMColor* mipmapPixels = reinterpret_cast<SkPMColor*>(mipmapBmp.getPixels()); 48 unsigned s25 = 0x89; // 255 * linear_to_srgb(0.25f) 49 unsigned s75 = 0xE1; // 255 * linear_to_srgb(0.75f) 50 mipmapPixels[0] = mipmapPixels[3] = SkPackARGB32(0xFF, s25, s25, s25); 51 mipmapPixels[1] = mipmapPixels[2] = SkPackARGB32(0xFF, s75, s75, s75); 52 53 SkPaint textPaint; 54 textPaint.setAntiAlias(true); 55 textPaint.setColor(SK_ColorWHITE); 56 sk_tool_utils::set_portable_typeface(&textPaint); 57 58 // Helpers: __anon8313177e0102() 59 auto advance = [&]() { 60 canvas->translate(tx, 0); 61 p.reset(); 62 }; 63 __anon8313177e0202(const char* label, const char* label2) 64 auto nextRect = [&](const char* label, const char* label2) { 65 canvas->drawRect(r, p); 66 canvas->drawString(label, 0, sz + textPaint.getFontSpacing(), textPaint); 67 if (label2) { 68 canvas->drawString(label2, 0, sz + 2 * textPaint.getFontSpacing(), 69 textPaint); 70 } 71 advance(); 72 }; 73 __anon8313177e0302(const SkBitmap& bmp, const char* label) 74 auto nextBitmap = [&](const SkBitmap& bmp, const char* label) { 75 canvas->drawBitmap(bmp, 0, 0); 76 canvas->drawString(label, 0, sz + textPaint.getFontSpacing(), textPaint); 77 advance(); 78 }; 79 __anon8313177e0402(SkColor srcColor, SkBlendMode mode, SkColor dstColor) 80 auto nextXferRect = [&](SkColor srcColor, SkBlendMode mode, SkColor dstColor) { 81 p.setColor(dstColor); 82 canvas->drawRect(r, p); 83 p.setColor(srcColor); 84 p.setBlendMode(mode); 85 canvas->drawRect(r, p); 86 87 SkString srcText = SkStringPrintf("%08X", srcColor); 88 SkString dstText = SkStringPrintf("%08X", dstColor); 89 canvas->drawString(srcText, 0, sz + textPaint.getFontSpacing(), 90 textPaint); 91 const char* modeName = SkBlendMode_Name(mode); 92 canvas->drawString(modeName, 0, sz + 2 * textPaint.getFontSpacing(), 93 textPaint); 94 canvas->drawString(dstText, 0, sz + 3 * textPaint.getFontSpacing(), 95 textPaint); 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", 0); 131 132 // 50% grey via paint color. Paint color (SkColor) is specified to be sRGB! 133 p.setColor(0xffbcbcbc); 134 nextRect("Color", 0); 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