LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkConvertPixels.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 214 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 14 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13