Home | History | Annotate | Download | only in gm
      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 "Resources.h"
     10 #include "SkCodec.h"
     11 #include "SkColorSpace.h"
     12 #include "SkColorSpaceXform.h"
     13 #include "SkColorSpaceXformPriv.h"
     14 #include "SkHalf.h"
     15 #include "SkImage.h"
     16 #include "SkImageInfoPriv.h"
     17 #include "SkPictureRecorder.h"
     18 
     19 static void clamp_if_necessary(const SkImageInfo& info, void* pixels) {
     20     if (kRGBA_F16_SkColorType != info.colorType()) {
     21         return;
     22     }
     23 
     24     for (int y = 0; y < info.height(); y++) {
     25         for (int x = 0; x < info.width(); x++) {
     26             uint64_t pixel = ((uint64_t*) pixels)[y * info.width() + x];
     27 
     28             Sk4f rgba = SkHalfToFloat_finite_ftz(pixel);
     29             if (kUnpremul_SkAlphaType == info.alphaType()) {
     30                 rgba = Sk4f::Max(0.0f, Sk4f::Min(rgba, 1.0f));
     31             } else {
     32                 SkASSERT(kPremul_SkAlphaType == info.alphaType());
     33                 rgba = Sk4f::Max(0.0f, Sk4f::Min(rgba, rgba[3]));
     34             }
     35             SkFloatToHalf_finite_ftz(rgba).store(&pixel);
     36 
     37             ((uint64_t*) pixels)[y * info.width() + x] = pixel;
     38         }
     39     }
     40 }
     41 
     42 sk_sp<SkColorSpace> fix_for_colortype(SkColorSpace* colorSpace, SkColorType colorType) {
     43     if (kRGBA_F16_SkColorType == colorType) {
     44         return colorSpace->makeLinearGamma();
     45     }
     46 
     47     return sk_ref_sp(colorSpace);
     48 }
     49 
     50 static const int kWidth = 64;
     51 static const int kHeight = 64;
     52 
     53 static sk_sp<SkImage> make_raster_image(SkColorType colorType) {
     54     std::unique_ptr<SkStream> stream(GetResourceAsStream("images/google_chrome.ico"));
     55     std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream));
     56 
     57     SkBitmap bitmap;
     58     SkImageInfo info = codec->getInfo().makeWH(kWidth, kHeight)
     59                                        .makeColorType(colorType)
     60                                        .makeAlphaType(kPremul_SkAlphaType)
     61             .makeColorSpace(fix_for_colortype(codec->getInfo().colorSpace(), colorType));
     62     bitmap.allocPixels(info);
     63     codec->getPixels(info, bitmap.getPixels(), bitmap.rowBytes());
     64     bitmap.setImmutable();
     65     return SkImage::MakeFromBitmap(bitmap);
     66 }
     67 
     68 static sk_sp<SkImage> make_codec_image() {
     69     sk_sp<SkData> encoded = GetResourceAsData("images/randPixels.png");
     70     return SkImage::MakeFromEncoded(encoded);
     71 }
     72 
     73 static void draw_contents(SkCanvas* canvas) {
     74     SkPaint paint;
     75     paint.setStyle(SkPaint::kStroke_Style);
     76     paint.setStrokeWidth(20);
     77     paint.setColor(0xFF800000);
     78     canvas->drawCircle(40, 40, 35, paint);
     79     paint.setColor(0xFF008000);
     80     canvas->drawCircle(50, 50, 35, paint);
     81     paint.setColor(0xFF000080);
     82     canvas->drawCircle(60, 60, 35, paint);
     83 }
     84 
     85 static sk_sp<SkImage> make_picture_image() {
     86     SkPictureRecorder recorder;
     87     draw_contents(recorder.beginRecording(SkRect::MakeIWH(kWidth, kHeight)));
     88     return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
     89                                     SkISize::Make(kWidth, kHeight), nullptr, nullptr,
     90                                     SkImage::BitDepth::kU8,
     91                                     SkColorSpace::MakeSRGB());
     92 }
     93 
     94 static sk_sp<SkColorSpace> make_parametric_transfer_fn(const SkColorSpacePrimaries& primaries) {
     95     SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
     96     SkAssertResult(primaries.toXYZD50(&toXYZD50));
     97     SkColorSpaceTransferFn fn;
     98     fn.fA = 1.f; fn.fB = 0.f; fn.fC = 0.f; fn.fD = 0.f; fn.fE = 0.f; fn.fF = 0.f; fn.fG = 1.8f;
     99     return SkColorSpace::MakeRGB(fn, toXYZD50);
    100 }
    101 
    102 static sk_sp<SkColorSpace> make_wide_gamut() {
    103     // ProPhoto
    104     SkColorSpacePrimaries primaries;
    105     primaries.fRX = 0.7347f;
    106     primaries.fRY = 0.2653f;
    107     primaries.fGX = 0.1596f;
    108     primaries.fGY = 0.8404f;
    109     primaries.fBX = 0.0366f;
    110     primaries.fBY = 0.0001f;
    111     primaries.fWX = 0.34567f;
    112     primaries.fWY = 0.35850f;
    113     return make_parametric_transfer_fn(primaries);
    114 }
    115 
    116 static sk_sp<SkColorSpace> make_small_gamut() {
    117     SkColorSpacePrimaries primaries;
    118     primaries.fRX = 0.50f;
    119     primaries.fRY = 0.33f;
    120     primaries.fGX = 0.30f;
    121     primaries.fGY = 0.50f;
    122     primaries.fBX = 0.25f;
    123     primaries.fBY = 0.16f;
    124     primaries.fWX = 0.3127f;
    125     primaries.fWY = 0.3290f;
    126     return make_parametric_transfer_fn(primaries);
    127 }
    128 
    129 static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType,
    130                        SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace,
    131                        SkImage::CachingHint hint) {
    132     size_t rowBytes = image->width() * SkColorTypeBytesPerPixel(dstColorType);
    133     sk_sp<SkData> data = SkData::MakeUninitialized(rowBytes * image->height());
    134     dstColorSpace = fix_for_colortype(dstColorSpace.get(), dstColorType);
    135     SkImageInfo dstInfo = SkImageInfo::Make(image->width(), image->height(), dstColorType,
    136                                             dstAlphaType, dstColorSpace);
    137     if (!image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) {
    138         memset(data->writable_data(), 0, rowBytes * image->height());
    139     }
    140 
    141     // SkImage must be premul, so manually premul the data if we unpremul'd during readPixels
    142     if (kUnpremul_SkAlphaType == dstAlphaType) {
    143         auto xform = SkColorSpaceXform::New(dstColorSpace.get(), dstColorSpace.get());
    144         if (!xform->apply(select_xform_format(dstColorType), data->writable_data(),
    145                           select_xform_format(dstColorType), data->data(),
    146                           image->width() * image->height(), kPremul_SkAlphaType)) {
    147             memset(data->writable_data(), 0, rowBytes * image->height());
    148         }
    149         dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType);
    150     }
    151 
    152     // readPixels() does not always clamp F16.  The drawing code expects pixels in the 0-1 range.
    153     clamp_if_necessary(dstInfo, data->writable_data());
    154 
    155     // Now that we have called readPixels(), dump the raw pixels into an srgb image.
    156     sk_sp<SkColorSpace> srgb = fix_for_colortype(
    157             SkColorSpace::MakeSRGB().get(), dstColorType);
    158     sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes);
    159     canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr);
    160 }
    161 
    162 class ReadPixelsGM : public skiagm::GM {
    163 public:
    164     ReadPixelsGM() {}
    165 
    166 protected:
    167     SkString onShortName() override {
    168         return SkString("readpixels");
    169     }
    170 
    171     SkISize onISize() override {
    172         return SkISize::Make(6 * kWidth, 9 * kHeight);
    173     }
    174 
    175     void onDraw(SkCanvas* canvas) override {
    176         if (!canvas->imageInfo().colorSpace()) {
    177             // This gm is only interesting in color correct modes.
    178             return;
    179         }
    180 
    181         const SkAlphaType alphaTypes[] = {
    182                 kUnpremul_SkAlphaType,
    183                 kPremul_SkAlphaType,
    184         };
    185         const SkColorType colorTypes[] = {
    186                 kRGBA_8888_SkColorType,
    187                 kBGRA_8888_SkColorType,
    188                 kRGBA_F16_SkColorType,
    189         };
    190         const sk_sp<SkColorSpace> colorSpaces[] = {
    191                 make_wide_gamut(),
    192                 SkColorSpace::MakeSRGB(),
    193                 make_small_gamut(),
    194         };
    195 
    196         for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
    197             for (SkColorType srcColorType : colorTypes) {
    198                 canvas->save();
    199                 sk_sp<SkImage> image = make_raster_image(srcColorType);
    200                 if (GrContext* context = canvas->getGrContext()) {
    201                     image = image->makeTextureImage(context, canvas->imageInfo().colorSpace());
    202                 }
    203                 if (image) {
    204                     for (SkColorType dstColorType : colorTypes) {
    205                         for (SkAlphaType dstAlphaType : alphaTypes) {
    206                             draw_image(canvas, image.get(), dstColorType, dstAlphaType,
    207                                        dstColorSpace, SkImage::kAllow_CachingHint);
    208                             canvas->translate((float)kWidth, 0.0f);
    209                         }
    210                     }
    211                 }
    212                 canvas->restore();
    213                 canvas->translate(0.0f, (float) kHeight);
    214             }
    215         }
    216     }
    217 
    218 private:
    219     typedef skiagm::GM INHERITED;
    220 };
    221 DEF_GM( return new ReadPixelsGM; )
    222 
    223 class ReadPixelsCodecGM : public skiagm::GM {
    224 public:
    225     ReadPixelsCodecGM() {}
    226 
    227 protected:
    228     SkString onShortName() override {
    229         return SkString("readpixelscodec");
    230     }
    231 
    232     SkISize onISize() override {
    233         return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
    234     }
    235 
    236     void onDraw(SkCanvas* canvas) override {
    237         if (!canvas->imageInfo().colorSpace()) {
    238             // This gm is only interesting in color correct modes.
    239             return;
    240         }
    241 
    242         const SkAlphaType alphaTypes[] = {
    243                 kUnpremul_SkAlphaType,
    244                 kPremul_SkAlphaType,
    245         };
    246         const SkColorType colorTypes[] = {
    247                 kRGBA_8888_SkColorType,
    248                 kBGRA_8888_SkColorType,
    249                 kRGBA_F16_SkColorType,
    250         };
    251         const sk_sp<SkColorSpace> colorSpaces[] = {
    252                 make_wide_gamut(),
    253                 SkColorSpace::MakeSRGB(),
    254                 make_small_gamut(),
    255         };
    256         const SkImage::CachingHint hints[] = {
    257                 SkImage::kAllow_CachingHint,
    258                 SkImage::kDisallow_CachingHint,
    259         };
    260 
    261         sk_sp<SkImage> image = make_codec_image();
    262         for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
    263             canvas->save();
    264             for (SkColorType dstColorType : colorTypes) {
    265                 for (SkAlphaType dstAlphaType : alphaTypes) {
    266                     for (SkImage::CachingHint hint : hints) {
    267                         draw_image(canvas, image.get(), dstColorType, dstAlphaType, dstColorSpace,
    268                                    hint);
    269                         canvas->translate(0.0f, (float) kEncodedHeight + 1);
    270                     }
    271                 }
    272             }
    273             canvas->restore();
    274             canvas->translate((float) kEncodedWidth + 1, 0.0f);
    275         }
    276     }
    277 
    278 private:
    279     static const int kEncodedWidth = 8;
    280     static const int kEncodedHeight = 8;
    281 
    282     typedef skiagm::GM INHERITED;
    283 };
    284 DEF_GM( return new ReadPixelsCodecGM; )
    285 
    286 class ReadPixelsPictureGM : public skiagm::GM {
    287 public:
    288     ReadPixelsPictureGM() {}
    289 
    290 protected:
    291     SkString onShortName() override {
    292         return SkString("readpixelspicture");
    293     }
    294 
    295     SkISize onISize() override {
    296         return SkISize::Make(3 * kWidth, 12 * kHeight);
    297     }
    298 
    299     void onDraw(SkCanvas* canvas) override {
    300         if (!canvas->imageInfo().colorSpace()) {
    301             // This gm is only interesting in color correct modes.
    302             return;
    303         }
    304 
    305         const sk_sp<SkImage> images[] = {
    306                 make_picture_image(),
    307         };
    308         const SkAlphaType alphaTypes[] = {
    309                 kUnpremul_SkAlphaType,
    310                 kPremul_SkAlphaType,
    311         };
    312         const SkColorType colorTypes[] = {
    313                 kRGBA_8888_SkColorType,
    314                 kBGRA_8888_SkColorType,
    315                 kRGBA_F16_SkColorType,
    316         };
    317         const sk_sp<SkColorSpace> colorSpaces[] = {
    318                 make_wide_gamut(),
    319                 SkColorSpace::MakeSRGB(),
    320                 make_small_gamut(),
    321         };
    322         const SkImage::CachingHint hints[] = {
    323                 SkImage::kAllow_CachingHint,
    324                 SkImage::kDisallow_CachingHint,
    325         };
    326 
    327         for (sk_sp<SkImage> image : images) {
    328             for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
    329                 canvas->save();
    330                 for (SkColorType dstColorType : colorTypes) {
    331                     for (SkAlphaType dstAlphaType : alphaTypes) {
    332                         for (SkImage::CachingHint hint : hints) {
    333                             draw_image(canvas, image.get(), dstColorType, dstAlphaType,
    334                                        dstColorSpace, hint);
    335                             canvas->translate(0.0f, (float) kHeight);
    336                         }
    337                     }
    338                 }
    339                 canvas->restore();
    340                 canvas->translate((float) kWidth, 0.0f);
    341             }
    342         }
    343     }
    344 
    345 private:
    346 
    347     typedef skiagm::GM INHERITED;
    348 };
    349 DEF_GM( return new ReadPixelsPictureGM; )
    350