Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 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 "SkColorSpaceXform_Base.h"
      9 #include "SkColorSpaceXformPriv.h"
     10 #include "SkColorSpacePriv.h"
     11 #include "SkColorTable.h"
     12 #include "SkConvertPixels.h"
     13 #include "SkHalf.h"
     14 #include "SkImageInfoPriv.h"
     15 #include "SkOpts.h"
     16 #include "SkPM4fPriv.h"
     17 #include "SkRasterPipeline.h"
     18 #include "SkUnPreMultiply.h"
     19 #include "SkUnPreMultiplyPriv.h"
     20 #include "../jumper/SkJumper.h"
     21 
     22 // Fast Path 1: The memcpy() case.
     23 static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
     24     if (dstInfo.colorType() != srcInfo.colorType()) {
     25         return false;
     26     }
     27 
     28     if (kAlpha_8_SkColorType == dstInfo.colorType()) {
     29         return true;
     30     }
     31 
     32     if (dstInfo.alphaType() != srcInfo.alphaType() &&
     33         kOpaque_SkAlphaType != dstInfo.alphaType() &&
     34         kOpaque_SkAlphaType != srcInfo.alphaType())
     35     {
     36         // We need to premultiply or unpremultiply.
     37         return false;
     38     }
     39 
     40     return !dstInfo.colorSpace() ||
     41            SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace());
     42 }
     43 
     44 // Fast Path 2: Simple swizzles and premuls.
     45 enum AlphaVerb {
     46     kNothing_AlphaVerb,
     47     kPremul_AlphaVerb,
     48     kUnpremul_AlphaVerb,
     49 };
     50 
     51 template <bool kSwapRB>
     52 static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) {
     53     SkUnpremultiplyRow<kSwapRB>(dst, (const uint32_t*) src, count);
     54 }
     55 
     56 void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
     57                           const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) {
     58     void (*proc)(uint32_t* dst, const void* src, int count);
     59     const bool swapRB = dstInfo.colorType() != srcInfo.colorType();
     60     AlphaVerb alphaVerb = kNothing_AlphaVerb;
     61     if (kPremul_SkAlphaType == dstInfo.alphaType() &&
     62         kUnpremul_SkAlphaType == srcInfo.alphaType())
     63     {
     64         alphaVerb = kPremul_AlphaVerb;
     65     } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() &&
     66                kPremul_SkAlphaType == srcInfo.alphaType()) {
     67         alphaVerb = kUnpremul_AlphaVerb;
     68     }
     69 
     70     switch (alphaVerb) {
     71         case kNothing_AlphaVerb:
     72             // If we do not need to swap or multiply, we should hit the memcpy case.
     73             SkASSERT(swapRB);
     74             proc = SkOpts::RGBA_to_BGRA;
     75             break;
     76         case kPremul_AlphaVerb:
     77             proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA;
     78             break;
     79         case kUnpremul_AlphaVerb:
     80             proc = swapRB ? wrap_unpremultiply<true> : wrap_unpremultiply<false>;
     81             break;
     82     }
     83 
     84     for (int y = 0; y < dstInfo.height(); y++) {
     85         proc((uint32_t*) dstPixels, srcPixels, dstInfo.width());
     86         dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
     87         srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
     88     }
     89 }
     90 
     91 // Fast Path 3: Color space xform.
     92 static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
     93                                          SkTransferFunctionBehavior behavior) {
     94     // Unpremultiplication is unsupported by SkColorSpaceXform.  Note that if |src| is non-linearly
     95     // premultiplied, we're always going to have to unpremultiply before doing anything.
     96     if (kPremul_SkAlphaType == srcInfo.alphaType() &&
     97             (kUnpremul_SkAlphaType == dstInfo.alphaType() ||
     98              SkTransferFunctionBehavior::kIgnore == behavior)) {
     99         return false;
    100     }
    101 
    102     switch (dstInfo.colorType()) {
    103         case kRGBA_8888_SkColorType:
    104         case kBGRA_8888_SkColorType:
    105         case kRGBA_F16_SkColorType:
    106             break;
    107         default:
    108             return false;
    109     }
    110 
    111     switch (srcInfo.colorType()) {
    112         case kRGBA_8888_SkColorType:
    113         case kBGRA_8888_SkColorType:
    114             break;
    115         default:
    116             return false;
    117     }
    118 
    119     return true;
    120 }
    121 
    122 static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
    123                                      const SkImageInfo& srcInfo, const void* srcPixels,
    124                                      size_t srcRB, SkTransferFunctionBehavior behavior) {
    125     SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType());
    126     SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType());
    127     SkAlphaType xformAlpha;
    128     switch (srcInfo.alphaType()) {
    129         case kOpaque_SkAlphaType:
    130             xformAlpha = kOpaque_SkAlphaType;
    131             break;
    132         case kPremul_SkAlphaType:
    133             SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType());
    134 
    135             // This signal means: copy the src alpha to the dst, do not premultiply (in this
    136             // case because the pixels are already premultiplied).
    137             xformAlpha = kUnpremul_SkAlphaType;
    138             break;
    139         case kUnpremul_SkAlphaType:
    140             SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType() ||
    141                      kUnpremul_SkAlphaType == dstInfo.alphaType());
    142 
    143             xformAlpha = dstInfo.alphaType();
    144             break;
    145         default:
    146             SkASSERT(false);
    147             xformAlpha = kUnpremul_SkAlphaType;
    148             break;
    149     }
    150 
    151     std::unique_ptr<SkColorSpaceXform> xform =
    152             SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior);
    153     SkASSERT(xform);
    154 
    155     for (int y = 0; y < dstInfo.height(); y++) {
    156         SkAssertResult(xform->apply(dstFormat, dstPixels, srcFormat, srcPixels, dstInfo.width(),
    157                        xformAlpha));
    158         dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
    159         srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
    160     }
    161 }
    162 
    163 // Fast Path 4: Alpha 8 dsts.
    164 static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& srcInfo,
    165                               const void* src, size_t srcRB, SkColorTable* ctable) {
    166     if (srcInfo.isOpaque()) {
    167         for (int y = 0; y < srcInfo.height(); ++y) {
    168            memset(dst, 0xFF, srcInfo.width());
    169            dst = SkTAddOffset<uint8_t>(dst, dstRB);
    170         }
    171         return;
    172     }
    173 
    174     switch (srcInfo.colorType()) {
    175         case kBGRA_8888_SkColorType:
    176         case kRGBA_8888_SkColorType: {
    177             auto src32 = (const uint32_t*) src;
    178             for (int y = 0; y < srcInfo.height(); y++) {
    179                 for (int x = 0; x < srcInfo.width(); x++) {
    180                     dst[x] = src32[x] >> 24;
    181                 }
    182                 dst = SkTAddOffset<uint8_t>(dst, dstRB);
    183                 src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
    184             }
    185             break;
    186         }
    187         case kARGB_4444_SkColorType: {
    188             auto src16 = (const uint16_t*) src;
    189             for (int y = 0; y < srcInfo.height(); y++) {
    190                 for (int x = 0; x < srcInfo.width(); x++) {
    191                     dst[x] = SkPacked4444ToA32(src16[x]);
    192                 }
    193                 dst = SkTAddOffset<uint8_t>(dst, dstRB);
    194                 src16 = SkTAddOffset<const uint16_t>(src16, srcRB);
    195             }
    196             break;
    197         }
    198         case kRGBA_F16_SkColorType: {
    199             auto src64 = (const uint64_t*) src;
    200             for (int y = 0; y < srcInfo.height(); y++) {
    201                 for (int x = 0; x < srcInfo.width(); x++) {
    202                     dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48));
    203                 }
    204                 dst = SkTAddOffset<uint8_t>(dst, dstRB);
    205                 src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
    206             }
    207             break;
    208         }
    209         default:
    210             SkASSERT(false);
    211             break;
    212     }
    213 }
    214 
    215 // Default: Use the pipeline.
    216 static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
    217                                   const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
    218                                   bool isColorAware, SkTransferFunctionBehavior behavior) {
    219 
    220     SkJumper_MemoryCtx src = { (void*)srcRow, (int)(srcRB / srcInfo.bytesPerPixel()) },
    221                        dst = { (void*)dstRow, (int)(dstRB / dstInfo.bytesPerPixel()) };
    222 
    223     SkRasterPipeline_<256> pipeline;
    224     switch (srcInfo.colorType()) {
    225         case kRGBA_8888_SkColorType:
    226             pipeline.append(SkRasterPipeline::load_8888, &src);
    227             break;
    228         case kBGRA_8888_SkColorType:
    229             pipeline.append(SkRasterPipeline::load_bgra, &src);
    230             break;
    231         case kRGB_565_SkColorType:
    232             pipeline.append(SkRasterPipeline::load_565, &src);
    233             break;
    234         case kRGBA_F16_SkColorType:
    235             pipeline.append(SkRasterPipeline::load_f16, &src);
    236             break;
    237         case kGray_8_SkColorType:
    238             pipeline.append(SkRasterPipeline::load_g8, &src);
    239             break;
    240         case kARGB_4444_SkColorType:
    241             pipeline.append(SkRasterPipeline::load_4444, &src);
    242             break;
    243         default:
    244             SkASSERT(false);
    245             break;
    246     }
    247 
    248     SkAlphaType premulState = srcInfo.alphaType();
    249     if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) {
    250         pipeline.append(SkRasterPipeline::unpremul);
    251         premulState = kUnpremul_SkAlphaType;
    252     }
    253 
    254     SkColorSpaceTransferFn srcFn;
    255     if (isColorAware && srcInfo.gammaCloseToSRGB()) {
    256         pipeline.append(SkRasterPipeline::from_srgb);
    257     } else if (isColorAware && !srcInfo.colorSpace()->gammaIsLinear()) {
    258         SkAssertResult(srcInfo.colorSpace()->isNumericalTransferFn(&srcFn));
    259         if (is_just_gamma(srcFn)) {
    260             pipeline.append(SkRasterPipeline::gamma, &srcFn.fG);
    261         } else {
    262             pipeline.append(SkRasterPipeline::parametric_r, &srcFn);
    263             pipeline.append(SkRasterPipeline::parametric_g, &srcFn);
    264             pipeline.append(SkRasterPipeline::parametric_b, &srcFn);
    265         }
    266     }
    267 
    268     float matrix[12];
    269     if (isColorAware) {
    270         append_gamut_transform(&pipeline, matrix, srcInfo.colorSpace(), dstInfo.colorSpace(),
    271                                premulState);
    272     }
    273 
    274     SkAlphaType dat = dstInfo.alphaType();
    275     if (SkTransferFunctionBehavior::kRespect == behavior) {
    276         if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) {
    277             pipeline.append(SkRasterPipeline::unpremul);
    278             premulState = kUnpremul_SkAlphaType;
    279         } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) {
    280             pipeline.append(SkRasterPipeline::premul);
    281             premulState = kPremul_SkAlphaType;
    282         }
    283     }
    284 
    285     SkColorSpaceTransferFn dstFn;
    286     if (isColorAware && dstInfo.gammaCloseToSRGB()) {
    287         pipeline.append(SkRasterPipeline::to_srgb);
    288     } else if (isColorAware && !dstInfo.colorSpace()->gammaIsLinear()) {
    289         SkAssertResult(dstInfo.colorSpace()->isNumericalTransferFn(&dstFn));
    290         dstFn = dstFn.invert();
    291         if (is_just_gamma(dstFn)) {
    292             pipeline.append(SkRasterPipeline::gamma, &dstFn.fG);
    293         } else {
    294             pipeline.append(SkRasterPipeline::parametric_r, &dstFn);
    295             pipeline.append(SkRasterPipeline::parametric_g, &dstFn);
    296             pipeline.append(SkRasterPipeline::parametric_b, &dstFn);
    297         }
    298     }
    299 
    300     if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat &&
    301         SkTransferFunctionBehavior::kIgnore == behavior)
    302     {
    303         pipeline.append(SkRasterPipeline::premul);
    304         premulState = kPremul_SkAlphaType;
    305     }
    306 
    307     // The final premul state must equal the dst alpha type.  Note that if we are "converting"
    308     // opaque to another alpha type, there's no need to worry about multiplication.
    309     SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType());
    310 
    311     // We'll dither if we're decreasing precision below 32-bit.
    312     float dither_rate = 0.0f;
    313     if (srcInfo.bytesPerPixel() > dstInfo.bytesPerPixel()) {
    314         switch (dstInfo.colorType()) {
    315             case   kRGB_565_SkColorType: dither_rate = 1/63.0f; break;
    316             case kARGB_4444_SkColorType: dither_rate = 1/15.0f; break;
    317             default:                     dither_rate =    0.0f; break;
    318         }
    319     }
    320     if (dither_rate > 0) {
    321         pipeline.append(SkRasterPipeline::dither, &dither_rate);
    322     }
    323 
    324     switch (dstInfo.colorType()) {
    325         case kRGBA_8888_SkColorType:
    326             pipeline.append(SkRasterPipeline::store_8888, &dst);
    327             break;
    328         case kBGRA_8888_SkColorType:
    329             pipeline.append(SkRasterPipeline::store_bgra, &dst);
    330             break;
    331         case kRGB_565_SkColorType:
    332             pipeline.append(SkRasterPipeline::store_565, &dst);
    333             break;
    334         case kRGBA_F16_SkColorType:
    335             pipeline.append(SkRasterPipeline::store_f16, &dst);
    336             break;
    337         case kARGB_4444_SkColorType:
    338             pipeline.append(SkRasterPipeline::store_4444, &dst);
    339             break;
    340         default:
    341             SkASSERT(false);
    342             break;
    343     }
    344 
    345     pipeline.run(0,0, srcInfo.width(), srcInfo.height());
    346 }
    347 
    348 void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
    349                      const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
    350                      SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
    351     SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
    352     SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));
    353 
    354     // Fast Path 1: The memcpy() case.
    355     if (can_memcpy(dstInfo, srcInfo)) {
    356         SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height());
    357         return;
    358     }
    359 
    360     const bool isColorAware = dstInfo.colorSpace();
    361     SkASSERT(srcInfo.colorSpace() || !isColorAware);
    362 
    363     // Fast Path 2: Simple swizzles and premuls.
    364     if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) {
    365         swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
    366         return;
    367     }
    368 
    369     // Fast Path 3: Color space xform.
    370     if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) {
    371         apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior);
    372         return;
    373     }
    374 
    375     // Fast Path 4: Alpha 8 dsts.
    376     if (kAlpha_8_SkColorType == dstInfo.colorType()) {
    377         convert_to_alpha8((uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
    378         return;
    379     }
    380 
    381     // Default: Use the pipeline.
    382     convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware,
    383                           behavior);
    384 }
    385