Home | History | Annotate | Download | only in gm
      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:
     59     auto advance = [&]() {
     60         canvas->translate(tx, 0);
     61         p.reset();
     62     };
     63 
     64     auto nextRect = [&](const char* label, const char* label2) {
     65         canvas->drawRect(r, p);
     66         canvas->drawText(label, strlen(label), 0, sz + textPaint.getFontSpacing(), textPaint);
     67         if (label2) {
     68             canvas->drawText(label2, strlen(label2), 0, sz + 2 * textPaint.getFontSpacing(),
     69                              textPaint);
     70         }
     71         advance();
     72     };
     73 
     74     auto nextBitmap = [&](const SkBitmap& bmp, const char* label) {
     75         canvas->drawBitmap(bmp, 0, 0);
     76         canvas->drawText(label, strlen(label), 0, sz + textPaint.getFontSpacing(), textPaint);
     77         advance();
     78     };
     79 
     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->drawText(srcText.c_str(), srcText.size(), 0, sz + textPaint.getFontSpacing(),
     90                          textPaint);
     91         const char* modeName = SkBlendMode_Name(mode);
     92         canvas->drawText(modeName, strlen(modeName), 0, sz + 2 * textPaint.getFontSpacing(),
     93                          textPaint);
     94         canvas->drawText(dstText.c_str(), dstText.size(), 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