Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      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 
      9 #include "SkSpriteBlitter.h"
     10 #include "SkArenaAlloc.h"
     11 #include "SkBlitRow.h"
     12 #include "SkTemplates.h"
     13 #include "SkUtils.h"
     14 #include "SkColorPriv.h"
     15 
     16 #define D16_S32A_Opaque_Pixel(dst, sc)                                        \
     17 do {                                                                          \
     18     if (sc) {                                                                 \
     19         *dst = SkSrcOver32To16(sc, *dst);                                     \
     20     }                                                                         \
     21 } while (0)
     22 
     23 static inline void D16_S32A_Blend_Pixel_helper(uint16_t* dst, SkPMColor sc,
     24                                                unsigned src_scale) {
     25     uint16_t dc = *dst;
     26     unsigned sa = SkGetPackedA32(sc);
     27     unsigned dr, dg, db;
     28 
     29     if (255 == sa) {
     30         dr = SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), src_scale);
     31         dg = SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), src_scale);
     32         db = SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), src_scale);
     33     } else {
     34         unsigned dst_scale = SkAlphaMulInv256(sa, src_scale);
     35         dr = (SkPacked32ToR16(sc) * src_scale + SkGetPackedR16(dc) * dst_scale) >> 8;
     36         dg = (SkPacked32ToG16(sc) * src_scale + SkGetPackedG16(dc) * dst_scale) >> 8;
     37         db = (SkPacked32ToB16(sc) * src_scale + SkGetPackedB16(dc) * dst_scale) >> 8;
     38     }
     39     *dst = SkPackRGB16(dr, dg, db);
     40 }
     41 
     42 #define D16_S32A_Blend_Pixel(dst, sc, src_scale) \
     43     do { if (sc) D16_S32A_Blend_Pixel_helper(dst, sc, src_scale); } while (0)
     44 
     45 
     46 ///////////////////////////////////////////////////////////////////////////////
     47 
     48 class Sprite_D16_S16_Opaque : public SkSpriteBlitter {
     49 public:
     50     Sprite_D16_S16_Opaque(const SkPixmap& source) : SkSpriteBlitter(source) {}
     51 
     52     // overrides
     53     void blitRect(int x, int y, int width, int height) override {
     54         uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y);
     55         const uint16_t* SK_RESTRICT src = fSource.addr16(x - fLeft, y - fTop);
     56         size_t dstRB = fDst.rowBytes();
     57         size_t srcRB = fSource.rowBytes();
     58 
     59         while (--height >= 0) {
     60             memcpy(dst, src, width << 1);
     61             dst = (uint16_t*)((char*)dst + dstRB);
     62             src = (const uint16_t*)((const char*)src + srcRB);
     63         }
     64     }
     65 };
     66 
     67 #define D16_S16_Blend_Pixel(dst, sc, scale)     \
     68     do {                                        \
     69         uint16_t dc = *dst;                     \
     70         *dst = SkBlendRGB16(sc, dc, scale);     \
     71     } while (0)
     72 
     73 #define SkSPRITE_CLASSNAME                  Sprite_D16_S16_Blend
     74 #define SkSPRITE_ARGS                       , uint8_t alpha
     75 #define SkSPRITE_FIELDS                     uint8_t  fSrcAlpha;
     76 #define SkSPRITE_INIT                       fSrcAlpha = alpha;
     77 #define SkSPRITE_DST_TYPE                   uint16_t
     78 #define SkSPRITE_SRC_TYPE                   uint16_t
     79 #define SkSPRITE_DST_GETADDR                writable_addr16
     80 #define SkSPRITE_SRC_GETADDR                addr16
     81 #define SkSPRITE_PREAMBLE(srcBM, x, y)      int scale = SkAlpha255To256(fSrcAlpha);
     82 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S16_Blend_Pixel(dst, src, scale)
     83 #define SkSPRITE_NEXT_ROW
     84 #define SkSPRITE_POSTAMBLE(srcBM)
     85 #include "SkSpriteBlitterTemplate.h"
     86 
     87 ///////////////////////////////////////////////////////////////////////////////
     88 
     89 #define D16_S4444_Opaque(dst, sc)           \
     90     do {                                    \
     91         uint16_t dc = *dst;                 \
     92         *dst = SkSrcOver4444To16(sc, dc);   \
     93     } while (0)
     94 
     95 #define SkSPRITE_CLASSNAME                  Sprite_D16_S4444_Opaque
     96 #define SkSPRITE_ARGS
     97 #define SkSPRITE_FIELDS
     98 #define SkSPRITE_INIT
     99 #define SkSPRITE_DST_TYPE                   uint16_t
    100 #define SkSPRITE_SRC_TYPE                   SkPMColor16
    101 #define SkSPRITE_DST_GETADDR                writable_addr16
    102 #define SkSPRITE_SRC_GETADDR                addr16
    103 #define SkSPRITE_PREAMBLE(srcBM, x, y)
    104 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S4444_Opaque(dst, src)
    105 #define SkSPRITE_NEXT_ROW
    106 #define SkSPRITE_POSTAMBLE(srcBM)
    107 #include "SkSpriteBlitterTemplate.h"
    108 
    109 #define D16_S4444_Blend(dst, sc, scale16)           \
    110     do {                                            \
    111         uint16_t dc = *dst;                         \
    112         *dst = SkBlend4444To16(sc, dc, scale16);    \
    113     } while (0)
    114 
    115 
    116 #define SkSPRITE_CLASSNAME                  Sprite_D16_S4444_Blend
    117 #define SkSPRITE_ARGS                       , uint8_t alpha
    118 #define SkSPRITE_FIELDS                     uint8_t  fSrcAlpha;
    119 #define SkSPRITE_INIT                       fSrcAlpha = alpha;
    120 #define SkSPRITE_DST_TYPE                   uint16_t
    121 #define SkSPRITE_SRC_TYPE                   uint16_t
    122 #define SkSPRITE_DST_GETADDR                writable_addr16
    123 #define SkSPRITE_SRC_GETADDR                addr16
    124 #define SkSPRITE_PREAMBLE(srcBM, x, y)      int scale = SkAlpha15To16(fSrcAlpha);
    125 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S4444_Blend(dst, src, scale)
    126 #define SkSPRITE_NEXT_ROW
    127 #define SkSPRITE_POSTAMBLE(srcBM)
    128 #include "SkSpriteBlitterTemplate.h"
    129 
    130 ///////////////////////////////////////////////////////////////////////////////
    131 
    132 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Opaque
    133 #define SkSPRITE_ARGS
    134 #define SkSPRITE_FIELDS
    135 #define SkSPRITE_INIT
    136 #define SkSPRITE_DST_TYPE                   uint16_t
    137 #define SkSPRITE_SRC_TYPE                   uint8_t
    138 #define SkSPRITE_DST_GETADDR                writable_addr16
    139 #define SkSPRITE_SRC_GETADDR                addr8
    140 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.ctable()->readColors()
    141 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Opaque_Pixel(dst, ctable[src])
    142 #define SkSPRITE_NEXT_ROW
    143 #define SkSPRITE_POSTAMBLE(srcBM)
    144 #include "SkSpriteBlitterTemplate.h"
    145 
    146 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Blend
    147 #define SkSPRITE_ARGS                       , uint8_t alpha
    148 #define SkSPRITE_FIELDS                     uint8_t fSrcAlpha;
    149 #define SkSPRITE_INIT                       fSrcAlpha = alpha;
    150 #define SkSPRITE_DST_TYPE                   uint16_t
    151 #define SkSPRITE_SRC_TYPE                   uint8_t
    152 #define SkSPRITE_DST_GETADDR                writable_addr16
    153 #define SkSPRITE_SRC_GETADDR                addr8
    154 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.ctable()->readColors(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
    155 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Blend_Pixel(dst, ctable[src], src_scale)
    156 #define SkSPRITE_NEXT_ROW
    157 #define SkSPRITE_POSTAMBLE(srcBM)
    158 #include "SkSpriteBlitterTemplate.h"
    159 
    160 ///////////////////////////////////////////////////////////////////////////////
    161 
    162 static intptr_t asint(const void* ptr) {
    163     return reinterpret_cast<const char*>(ptr) - (const char*)0;
    164 }
    165 
    166 static void blitrow_d16_si8(uint16_t* SK_RESTRICT dst,
    167                             const uint8_t* SK_RESTRICT src, int count,
    168                             const uint16_t* SK_RESTRICT ctable) {
    169     if (count <= 8) {
    170         do {
    171             *dst++ = ctable[*src++];
    172         } while (--count);
    173         return;
    174     }
    175 
    176     // eat src until we're on a 4byte boundary
    177     while (asint(src) & 3) {
    178         *dst++ = ctable[*src++];
    179         count -= 1;
    180     }
    181 
    182     int qcount = count >> 2;
    183     SkASSERT(qcount > 0);
    184     const uint32_t* qsrc = reinterpret_cast<const uint32_t*>(src);
    185     if (asint(dst) & 2) {
    186         do {
    187             uint32_t s4 = *qsrc++;
    188 #ifdef SK_CPU_LENDIAN
    189             *dst++ = ctable[s4 & 0xFF];
    190             *dst++ = ctable[(s4 >> 8) & 0xFF];
    191             *dst++ = ctable[(s4 >> 16) & 0xFF];
    192             *dst++ = ctable[s4 >> 24];
    193 #else   // BENDIAN
    194             *dst++ = ctable[s4 >> 24];
    195             *dst++ = ctable[(s4 >> 16) & 0xFF];
    196             *dst++ = ctable[(s4 >> 8) & 0xFF];
    197             *dst++ = ctable[s4 & 0xFF];
    198 #endif
    199         } while (--qcount);
    200     } else {    // dst is on a 4byte boundary
    201         uint32_t* ddst = reinterpret_cast<uint32_t*>(dst);
    202         do {
    203             uint32_t s4 = *qsrc++;
    204 #ifdef SK_CPU_LENDIAN
    205             *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
    206             *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
    207 #else   // BENDIAN
    208             *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
    209             *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
    210 #endif
    211         } while (--qcount);
    212         dst = reinterpret_cast<uint16_t*>(ddst);
    213     }
    214     src = reinterpret_cast<const uint8_t*>(qsrc);
    215     count &= 3;
    216     // catch any remaining (will be < 4)
    217     while (--count >= 0) {
    218         *dst++ = ctable[*src++];
    219     }
    220 }
    221 
    222 #define SkSPRITE_ROW_PROC(d, s, n, x, y)    blitrow_d16_si8(d, s, n, ctable)
    223 
    224 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8_Opaque
    225 #define SkSPRITE_ARGS
    226 #define SkSPRITE_FIELDS
    227 #define SkSPRITE_INIT
    228 #define SkSPRITE_DST_TYPE                   uint16_t
    229 #define SkSPRITE_SRC_TYPE                   uint8_t
    230 #define SkSPRITE_DST_GETADDR                writable_addr16
    231 #define SkSPRITE_SRC_GETADDR                addr8
    232 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const uint16_t* ctable = srcBM.ctable()->read16BitCache()
    233 #define SkSPRITE_BLIT_PIXEL(dst, src)       *dst = ctable[src]
    234 #define SkSPRITE_NEXT_ROW
    235 #define SkSPRITE_POSTAMBLE(srcBM)
    236 #include "SkSpriteBlitterTemplate.h"
    237 
    238 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8_Blend
    239 #define SkSPRITE_ARGS                       , uint8_t alpha
    240 #define SkSPRITE_FIELDS                     uint8_t fSrcAlpha;
    241 #define SkSPRITE_INIT                       fSrcAlpha = alpha;
    242 #define SkSPRITE_DST_TYPE                   uint16_t
    243 #define SkSPRITE_SRC_TYPE                   uint8_t
    244 #define SkSPRITE_DST_GETADDR                writable_addr16
    245 #define SkSPRITE_SRC_GETADDR                addr8
    246 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const uint16_t* ctable = srcBM.ctable()->read16BitCache(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
    247 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S16_Blend_Pixel(dst, ctable[src], src_scale)
    248 #define SkSPRITE_NEXT_ROW
    249 #define SkSPRITE_POSTAMBLE(srcBM)
    250 #include "SkSpriteBlitterTemplate.h"
    251 
    252 ///////////////////////////////////////////////////////////////////////////////
    253 
    254 class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter {
    255 public:
    256     Sprite_D16_S32_BlitRowProc(const SkPixmap& source) : SkSpriteBlitter(source) {}
    257 
    258     void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
    259         this->INHERITED::setup(dst, left, top, paint);
    260 
    261         unsigned flags = 0;
    262 
    263         if (paint.getAlpha() < 0xFF) {
    264             flags |= SkBlitRow::kGlobalAlpha_Flag;
    265         }
    266         if (!fSource.isOpaque()) {
    267             flags |= SkBlitRow::kSrcPixelAlpha_Flag;
    268         }
    269         if (paint.isDither()) {
    270             flags |= SkBlitRow::kDither_Flag;
    271         }
    272         fProc = SkBlitRow::Factory16(flags);
    273     }
    274 
    275     void blitRect(int x, int y, int width, int height) override {
    276         uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y);
    277         const SkPMColor* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
    278         size_t dstRB = fDst.rowBytes();
    279         size_t srcRB = fSource.rowBytes();
    280         SkBlitRow::Proc16 proc = fProc;
    281         U8CPU alpha = fPaint->getAlpha();
    282 
    283         while (--height >= 0) {
    284             proc(dst, src, width, alpha, x, y);
    285             y += 1;
    286             dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
    287             src = (const SkPMColor* SK_RESTRICT)((const char*)src + srcRB);
    288         }
    289     }
    290 
    291 private:
    292     SkBlitRow::Proc16 fProc;
    293 
    294     typedef SkSpriteBlitter INHERITED;
    295 };
    296 
    297 ///////////////////////////////////////////////////////////////////////////////
    298 
    299 SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkPixmap& source, const SkPaint& paint,
    300                                             SkArenaAlloc* allocator) {
    301 
    302     SkASSERT(allocator != nullptr);
    303 
    304     if (paint.getMaskFilter() != nullptr) { // may add cases for this
    305         return nullptr;
    306     }
    307     if (!paint.isSrcOver()) { // may add cases for this
    308         return nullptr;
    309     }
    310     if (paint.getColorFilter() != nullptr) { // may add cases for this
    311         return nullptr;
    312     }
    313 
    314     const SkAlphaType at = source.alphaType();
    315 
    316     SkSpriteBlitter* blitter = nullptr;
    317     unsigned alpha = paint.getAlpha();
    318 
    319     switch (source.colorType()) {
    320         case kN32_SkColorType: {
    321             if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
    322                 break;
    323             }
    324             blitter = allocator->make<Sprite_D16_S32_BlitRowProc>(source);
    325             break;
    326         }
    327         case kARGB_4444_SkColorType:
    328             if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
    329                 break;
    330             }
    331             if (255 == alpha) {
    332                 blitter = allocator->make<Sprite_D16_S4444_Opaque>(source);
    333             } else {
    334                 blitter = allocator->make<Sprite_D16_S4444_Blend>(source, alpha >> 4);
    335             }
    336             break;
    337         case kRGB_565_SkColorType:
    338             if (255 == alpha) {
    339                 blitter = allocator->make<Sprite_D16_S16_Opaque>(source);
    340             } else {
    341                 blitter = allocator->make<Sprite_D16_S16_Blend>(source, alpha);
    342             }
    343             break;
    344         case kIndex_8_SkColorType:
    345             if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
    346                 break;
    347             }
    348             if (paint.isDither()) {
    349                 // we don't support dither yet in these special cases
    350                 break;
    351             }
    352             if (source.isOpaque()) {
    353                 if (255 == alpha) {
    354                     blitter = allocator->make<Sprite_D16_SIndex8_Opaque>(source);
    355                 } else {
    356                     blitter = allocator->make<Sprite_D16_SIndex8_Blend>(source, alpha);
    357                 }
    358             } else {
    359                 if (255 == alpha) {
    360                     blitter = allocator->make<Sprite_D16_SIndex8A_Opaque>(source);
    361                 } else {
    362                     blitter = allocator->make<Sprite_D16_SIndex8A_Blend>(source, alpha);
    363                 }
    364             }
    365             break;
    366         default:
    367             break;
    368     }
    369     return blitter;
    370 }
    371