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 "SkColorData.h"
      9 #include "SkColorSpacePriv.h"
     10 #include "SkColorSpaceXformSteps.h"
     11 #include "SkConvertPixels.h"
     12 #include "SkHalf.h"
     13 #include "SkImageInfoPriv.h"
     14 #include "SkOpts.h"
     15 #include "SkRasterPipeline.h"
     16 
     17 static bool rect_memcpy(const SkImageInfo& dstInfo,       void* dstPixels, size_t dstRB,
     18                         const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
     19                         const SkColorSpaceXformSteps& steps) {
     20     // We can copy the pixels when no color type, alpha type, or color space changes.
     21     if (dstInfo.colorType() != srcInfo.colorType()) {
     22         return false;
     23     }
     24     if (dstInfo.colorType() != kAlpha_8_SkColorType
     25             && steps.flags.mask() != 0b00000) {
     26         return false;
     27     }
     28 
     29     SkRectMemcpy(dstPixels, dstRB,
     30                  srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height());
     31     return true;
     32 }
     33 
     34 static bool swizzle_or_premul(const SkImageInfo& dstInfo,       void* dstPixels, size_t dstRB,
     35                               const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
     36                               const SkColorSpaceXformSteps& steps) {
     37     auto is_8888 = [](SkColorType ct) {
     38         return ct == kRGBA_8888_SkColorType || ct == kBGRA_8888_SkColorType;
     39     };
     40     if (!is_8888(dstInfo.colorType()) ||
     41         !is_8888(srcInfo.colorType()) ||
     42         steps.flags.linearize         ||
     43         steps.flags.gamut_transform   ||
     44         steps.flags.unpremul          ||
     45         steps.flags.encode) {
     46         return false;
     47     }
     48 
     49     const bool swapRB = dstInfo.colorType() != srcInfo.colorType();
     50 
     51     void (*fn)(uint32_t*, const uint32_t*, int) = nullptr;
     52 
     53     if (steps.flags.premul) {
     54         fn = swapRB ? SkOpts::RGBA_to_bgrA
     55                     : SkOpts::RGBA_to_rgbA;
     56     } else {
     57         // If we're not swizzling, we ought to have used rect_memcpy().
     58         SkASSERT(swapRB);
     59         fn = SkOpts::RGBA_to_BGRA;
     60     }
     61 
     62     for (int y = 0; y < dstInfo.height(); y++) {
     63         fn((uint32_t*)dstPixels, (const uint32_t*)srcPixels, dstInfo.width());
     64         dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
     65         srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
     66     }
     67     return true;
     68 }
     69 
     70 static bool convert_to_alpha8(const SkImageInfo& dstInfo,       void* vdst, size_t dstRB,
     71                               const SkImageInfo& srcInfo, const void*  src, size_t srcRB,
     72                               const SkColorSpaceXformSteps&) {
     73     if (dstInfo.colorType() != kAlpha_8_SkColorType) {
     74         return false;
     75     }
     76     auto dst = (uint8_t*)vdst;
     77 
     78     switch (srcInfo.colorType()) {
     79         case kUnknown_SkColorType:
     80         case kAlpha_8_SkColorType: {
     81             // Unknown should never happen.
     82             // Alpha8 should have been handled by rect_memcpy().
     83             SkASSERT(false);
     84             return false;
     85         }
     86 
     87         case kGray_8_SkColorType:
     88         case kRGB_565_SkColorType:
     89         case kRGB_888x_SkColorType:
     90         case kRGB_101010x_SkColorType: {
     91             for (int y = 0; y < srcInfo.height(); ++y) {
     92                memset(dst, 0xFF, srcInfo.width());
     93                dst = SkTAddOffset<uint8_t>(dst, dstRB);
     94             }
     95             return true;
     96         }
     97 
     98         case kARGB_4444_SkColorType: {
     99             auto src16 = (const uint16_t*) src;
    100             for (int y = 0; y < srcInfo.height(); y++) {
    101                 for (int x = 0; x < srcInfo.width(); x++) {
    102                     dst[x] = SkPacked4444ToA32(src16[x]);
    103                 }
    104                 dst = SkTAddOffset<uint8_t>(dst, dstRB);
    105                 src16 = SkTAddOffset<const uint16_t>(src16, srcRB);
    106             }
    107             return true;
    108         }
    109 
    110         case kBGRA_8888_SkColorType:
    111         case kRGBA_8888_SkColorType: {
    112             auto src32 = (const uint32_t*) src;
    113             for (int y = 0; y < srcInfo.height(); y++) {
    114                 for (int x = 0; x < srcInfo.width(); x++) {
    115                     dst[x] = src32[x] >> 24;
    116                 }
    117                 dst = SkTAddOffset<uint8_t>(dst, dstRB);
    118                 src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
    119             }
    120             return true;
    121         }
    122 
    123         case kRGBA_1010102_SkColorType: {
    124             auto src32 = (const uint32_t*) src;
    125             for (int y = 0; y < srcInfo.height(); y++) {
    126                 for (int x = 0; x < srcInfo.width(); x++) {
    127                     dst[x] = (src32[x] >> 30) * 0x55;
    128                 }
    129                 dst = SkTAddOffset<uint8_t>(dst, dstRB);
    130                 src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
    131             }
    132             return true;
    133         }
    134 
    135         case kRGBA_F16_SkColorType: {
    136             auto src64 = (const uint64_t*) src;
    137             for (int y = 0; y < srcInfo.height(); y++) {
    138                 for (int x = 0; x < srcInfo.width(); x++) {
    139                     dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48));
    140                 }
    141                 dst = SkTAddOffset<uint8_t>(dst, dstRB);
    142                 src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
    143             }
    144             return true;
    145         }
    146 
    147         case kRGBA_F32_SkColorType: {
    148             auto rgba = (const float*)src;
    149             for (int y = 0; y < srcInfo.height(); y++) {
    150                 for (int x = 0; x < srcInfo.width(); x++) {
    151                     dst[x] = (uint8_t)(255.0f * rgba[4*x+3]);
    152                 }
    153                 dst  = SkTAddOffset<uint8_t>(dst, dstRB);
    154                 rgba = SkTAddOffset<const float>(rgba, srcRB);
    155             }
    156             return true;
    157         }
    158     }
    159     return false;
    160 }
    161 
    162 // Default: Use the pipeline.
    163 static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
    164                                   const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
    165                                   const SkColorSpaceXformSteps& steps) {
    166 
    167     SkRasterPipeline_MemoryCtx src = { (void*)srcRow, (int)(srcRB / srcInfo.bytesPerPixel()) },
    168                                dst = { (void*)dstRow, (int)(dstRB / dstInfo.bytesPerPixel()) };
    169 
    170     SkRasterPipeline_<256> pipeline;
    171     pipeline.append_load(srcInfo.colorType(), &src);
    172     steps.apply(&pipeline, srcInfo.colorType());
    173 
    174     pipeline.append_gamut_clamp_if_normalized(dstInfo);
    175 
    176     // We'll dither if we're decreasing precision below 32-bit.
    177     float dither_rate = 0.0f;
    178     if (srcInfo.bytesPerPixel() > dstInfo.bytesPerPixel()) {
    179         switch (dstInfo.colorType()) {
    180             case   kRGB_565_SkColorType: dither_rate = 1/63.0f; break;
    181             case kARGB_4444_SkColorType: dither_rate = 1/15.0f; break;
    182             default:                     dither_rate =    0.0f; break;
    183         }
    184     }
    185     if (dither_rate > 0) {
    186         pipeline.append(SkRasterPipeline::dither, &dither_rate);
    187     }
    188 
    189     pipeline.append_store(dstInfo.colorType(), &dst);
    190     pipeline.run(0,0, srcInfo.width(), srcInfo.height());
    191 }
    192 
    193 void SkConvertPixels(const SkImageInfo& dstInfo,       void* dstPixels, size_t dstRB,
    194                      const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) {
    195     SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
    196     SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));
    197 
    198     SkColorSpaceXformSteps steps{srcInfo.colorSpace(), srcInfo.alphaType(),
    199                                  dstInfo.colorSpace(), dstInfo.alphaType()};
    200 
    201     for (auto fn : {rect_memcpy, swizzle_or_premul, convert_to_alpha8}) {
    202         if (fn(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, steps)) {
    203             return;
    204         }
    205     }
    206     convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, steps);
    207 }
    208