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