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