Home | History | Annotate | Download | only in core
      1 #include "SkConfig8888.h"
      2 #include "SkMathPriv.h"
      3 #include "SkUnPreMultiply.h"
      4 
      5 namespace {
      6 
      7 template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
      8 inline uint32_t pack_config8888(uint32_t a, uint32_t r,
      9                                 uint32_t g, uint32_t b) {
     10 #ifdef SK_CPU_LENDIAN
     11     return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) |
     12            (g << (G_IDX * 8)) | (b << (B_IDX * 8));
     13 #else
     14     return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) |
     15            (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8));
     16 #endif
     17 }
     18 
     19 template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
     20 inline void unpack_config8888(uint32_t color,
     21                               uint32_t* a, uint32_t* r,
     22                               uint32_t* g, uint32_t* b) {
     23 #ifdef SK_CPU_LENDIAN
     24     *a = (color >> (A_IDX * 8)) & 0xff;
     25     *r = (color >> (R_IDX * 8)) & 0xff;
     26     *g = (color >> (G_IDX * 8)) & 0xff;
     27     *b = (color >> (B_IDX * 8)) & 0xff;
     28 #else
     29     *a = (color >> ((3 - A_IDX) * 8)) & 0xff;
     30     *r = (color >> ((3 - R_IDX) * 8)) & 0xff;
     31     *g = (color >> ((3 - G_IDX) * 8)) & 0xff;
     32     *b = (color >> ((3 - B_IDX) * 8)) & 0xff;
     33 #endif
     34 }
     35 
     36 #ifdef SK_CPU_LENDIAN
     37     static const int SK_NATIVE_A_IDX = SK_A32_SHIFT / 8;
     38     static const int SK_NATIVE_R_IDX = SK_R32_SHIFT / 8;
     39     static const int SK_NATIVE_G_IDX = SK_G32_SHIFT / 8;
     40     static const int SK_NATIVE_B_IDX = SK_B32_SHIFT / 8;
     41 #else
     42     static const int SK_NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8);
     43     static const int SK_NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8);
     44     static const int SK_NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8);
     45     static const int SK_NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8);
     46 #endif
     47 
     48 /**
     49  * convert_pixel<OUT_CFG, IN_CFG converts a pixel value from one Config8888 to
     50  * another. It is implemented by first expanding OUT_CFG to r, g, b, a indices
     51  * and an is_premul bool as params to another template function. Then IN_CFG is
     52  * expanded via another function call.
     53  */
     54 
     55 template <bool OUT_PM, int OUT_A_IDX, int OUT_R_IDX, int OUT_G_IDX, int OUT_B_IDX,
     56           bool IN_PM,  int IN_A_IDX,  int IN_R_IDX,  int IN_G_IDX,  int IN_B_IDX>
     57 inline uint32_t convert_pixel(uint32_t pixel) {
     58     uint32_t a, r, g, b;
     59     unpack_config8888<IN_A_IDX, IN_R_IDX, IN_G_IDX, IN_B_IDX>(pixel, &a, &r, &g, &b);
     60     if (IN_PM && !OUT_PM) {
     61         // Using SkUnPreMultiply::ApplyScale is faster than (value * 0xff) / a.
     62         if (a) {
     63             SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(a);
     64             r = SkUnPreMultiply::ApplyScale(scale, r);
     65             g = SkUnPreMultiply::ApplyScale(scale, g);
     66             b = SkUnPreMultiply::ApplyScale(scale, b);
     67         } else {
     68             return 0;
     69         }
     70     } else if (!IN_PM && OUT_PM) {
     71         // This matches SkUnPreMultiply conversion which we are replacing.
     72         r = SkMulDiv255Round(r, a);
     73         g = SkMulDiv255Round(g, a);
     74         b = SkMulDiv255Round(b, a);
     75     }
     76     return pack_config8888<OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX>(a, r, g, b);
     77 }
     78 
     79 template <bool OUT_PM, int OUT_A_IDX, int OUT_R_IDX, int OUT_G_IDX, int OUT_B_IDX, SkCanvas::Config8888 IN_CFG>
     80 inline uint32_t convert_pixel(uint32_t pixel) {
     81     switch(IN_CFG) {
     82         case SkCanvas::kNative_Premul_Config8888:
     83             return convert_pixel<OUT_PM, OUT_A_IDX,       OUT_R_IDX,       OUT_G_IDX,       OUT_B_IDX,
     84                                  true,  SK_NATIVE_A_IDX,  SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(pixel);
     85             break;
     86         case SkCanvas::kNative_Unpremul_Config8888:
     87             return convert_pixel<OUT_PM, OUT_A_IDX,       OUT_R_IDX,       OUT_G_IDX,       OUT_B_IDX,
     88                                  false,  SK_NATIVE_A_IDX, SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(pixel);
     89             break;
     90         case SkCanvas::kBGRA_Premul_Config8888:
     91             return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX,
     92                                  true,  3,         2,         1,         0>(pixel);
     93             break;
     94         case SkCanvas::kBGRA_Unpremul_Config8888:
     95             return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX,
     96                                  false,  3,         2,         1,         0>(pixel);
     97             break;
     98         case SkCanvas::kRGBA_Premul_Config8888:
     99             return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX,
    100                                  true,  3,         0,         1,         2>(pixel);
    101             break;
    102         case SkCanvas::kRGBA_Unpremul_Config8888:
    103             return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX,
    104                                  false,  3,         0,         1,         2>(pixel);
    105             break;
    106         default:
    107             SkDEBUGFAIL("Unexpected config8888");
    108             return 0;
    109             break;
    110     }
    111 }
    112 
    113 template <SkCanvas::Config8888 OUT_CFG, SkCanvas::Config8888 IN_CFG>
    114 inline uint32_t convert_pixel(uint32_t pixel) {
    115     switch(OUT_CFG) {
    116         case SkCanvas::kNative_Premul_Config8888:
    117             return convert_pixel<true,  SK_NATIVE_A_IDX,  SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX, IN_CFG>(pixel);
    118             break;
    119         case SkCanvas::kNative_Unpremul_Config8888:
    120             return convert_pixel<false,  SK_NATIVE_A_IDX,  SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX, IN_CFG>(pixel);
    121             break;
    122         case SkCanvas::kBGRA_Premul_Config8888:
    123             return convert_pixel<true, 3, 2, 1, 0, IN_CFG>(pixel);
    124             break;
    125         case SkCanvas::kBGRA_Unpremul_Config8888:
    126             return convert_pixel<false, 3, 2, 1, 0, IN_CFG>(pixel);
    127             break;
    128         case SkCanvas::kRGBA_Premul_Config8888:
    129             return convert_pixel<true, 3, 0, 1, 2, IN_CFG>(pixel);
    130             break;
    131         case SkCanvas::kRGBA_Unpremul_Config8888:
    132             return convert_pixel<false, 3, 0, 1, 2, IN_CFG>(pixel);
    133             break;
    134         default:
    135             SkDEBUGFAIL("Unexpected config8888");
    136             return 0;
    137             break;
    138     }
    139 }
    140 
    141 /**
    142  * SkConvertConfig8888Pixels has 6 * 6 possible combinations of src and dst
    143  * configs. Each is implemented as an instantiation templated function. Two
    144  * levels of switch statements are used to select the correct instantiation, one
    145  * for the src config and one for the dst config.
    146  */
    147 
    148 template <SkCanvas::Config8888 DST_CFG, SkCanvas::Config8888 SRC_CFG>
    149 inline void convert_config8888(uint32_t* dstPixels,
    150                                size_t dstRowBytes,
    151                                const uint32_t* srcPixels,
    152                                size_t srcRowBytes,
    153                                int width,
    154                                int height) {
    155     intptr_t dstPix = reinterpret_cast<intptr_t>(dstPixels);
    156     intptr_t srcPix = reinterpret_cast<intptr_t>(srcPixels);
    157 
    158     for (int y = 0; y < height; ++y) {
    159         srcPixels = reinterpret_cast<const uint32_t*>(srcPix);
    160         dstPixels = reinterpret_cast<uint32_t*>(dstPix);
    161         for (int x = 0; x < width; ++x) {
    162             dstPixels[x] = convert_pixel<DST_CFG, SRC_CFG>(srcPixels[x]);
    163         }
    164         dstPix += dstRowBytes;
    165         srcPix += srcRowBytes;
    166     }
    167 }
    168 
    169 template <SkCanvas::Config8888 SRC_CFG>
    170 inline void convert_config8888(uint32_t* dstPixels,
    171                                size_t dstRowBytes,
    172                                SkCanvas::Config8888 dstConfig,
    173                                const uint32_t* srcPixels,
    174                                size_t srcRowBytes,
    175                                int width,
    176                                int height) {
    177     switch(dstConfig) {
    178         case SkCanvas::kNative_Premul_Config8888:
    179             convert_config8888<SkCanvas::kNative_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    180             break;
    181         case SkCanvas::kNative_Unpremul_Config8888:
    182             convert_config8888<SkCanvas::kNative_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    183             break;
    184         case SkCanvas::kBGRA_Premul_Config8888:
    185             convert_config8888<SkCanvas::kBGRA_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    186             break;
    187         case SkCanvas::kBGRA_Unpremul_Config8888:
    188             convert_config8888<SkCanvas::kBGRA_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    189             break;
    190         case SkCanvas::kRGBA_Premul_Config8888:
    191             convert_config8888<SkCanvas::kRGBA_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    192             break;
    193         case SkCanvas::kRGBA_Unpremul_Config8888:
    194             convert_config8888<SkCanvas::kRGBA_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    195             break;
    196         default:
    197             SkDEBUGFAIL("Unexpected config8888");
    198             break;
    199     }
    200 }
    201 
    202 }
    203 
    204 void SkConvertConfig8888Pixels(uint32_t* dstPixels,
    205                                size_t dstRowBytes,
    206                                SkCanvas::Config8888 dstConfig,
    207                                const uint32_t* srcPixels,
    208                                size_t srcRowBytes,
    209                                SkCanvas::Config8888 srcConfig,
    210                                int width,
    211                                int height) {
    212     if (srcConfig == dstConfig) {
    213         if (srcPixels == dstPixels) {
    214             return;
    215         }
    216         if (dstRowBytes == srcRowBytes &&
    217             4U * width == srcRowBytes) {
    218             memcpy(dstPixels, srcPixels, srcRowBytes * height);
    219             return;
    220         } else {
    221             intptr_t srcPix = reinterpret_cast<intptr_t>(srcPixels);
    222             intptr_t dstPix = reinterpret_cast<intptr_t>(dstPixels);
    223             for (int y = 0; y < height; ++y) {
    224                 srcPixels = reinterpret_cast<const uint32_t*>(srcPix);
    225                 dstPixels = reinterpret_cast<uint32_t*>(dstPix);
    226                 memcpy(dstPixels, srcPixels, 4 * width);
    227                 srcPix += srcRowBytes;
    228                 dstPix += dstRowBytes;
    229             }
    230             return;
    231         }
    232     }
    233     switch(srcConfig) {
    234         case SkCanvas::kNative_Premul_Config8888:
    235             convert_config8888<SkCanvas::kNative_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    236             break;
    237         case SkCanvas::kNative_Unpremul_Config8888:
    238             convert_config8888<SkCanvas::kNative_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    239             break;
    240         case SkCanvas::kBGRA_Premul_Config8888:
    241             convert_config8888<SkCanvas::kBGRA_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    242             break;
    243         case SkCanvas::kBGRA_Unpremul_Config8888:
    244             convert_config8888<SkCanvas::kBGRA_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    245             break;
    246         case SkCanvas::kRGBA_Premul_Config8888:
    247             convert_config8888<SkCanvas::kRGBA_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    248             break;
    249         case SkCanvas::kRGBA_Unpremul_Config8888:
    250             convert_config8888<SkCanvas::kRGBA_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    251             break;
    252         default:
    253             SkDEBUGFAIL("Unexpected config8888");
    254             break;
    255     }
    256 }
    257 
    258 uint32_t SkPackConfig8888(SkCanvas::Config8888 config,
    259                           uint32_t a,
    260                           uint32_t r,
    261                           uint32_t g,
    262                           uint32_t b) {
    263     switch (config) {
    264         case SkCanvas::kNative_Premul_Config8888:
    265         case SkCanvas::kNative_Unpremul_Config8888:
    266             return pack_config8888<SK_NATIVE_A_IDX,
    267                                    SK_NATIVE_R_IDX,
    268                                    SK_NATIVE_G_IDX,
    269                                    SK_NATIVE_B_IDX>(a, r, g, b);
    270         case SkCanvas::kBGRA_Premul_Config8888:
    271         case SkCanvas::kBGRA_Unpremul_Config8888:
    272             return pack_config8888<3, 2, 1, 0>(a, r, g, b);
    273         case SkCanvas::kRGBA_Premul_Config8888:
    274         case SkCanvas::kRGBA_Unpremul_Config8888:
    275             return pack_config8888<3, 0, 1, 2>(a, r, g, b);
    276         default:
    277             SkDEBUGFAIL("Unexpected config8888");
    278             return 0;
    279     }
    280 }
    281