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)                                        \
25do {                                                                          \
26    if (sc) {                                                                 \
27        *dst = SkSrcOver32To16(sc, *dst);                                     \
28    }                                                                         \
29} while (0)
30
31static 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
59class Sprite_D16_S16_Opaque : public SkSpriteBlitter {
60public:
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
175static intptr_t asint(const void* ptr) {
176    return reinterpret_cast<const char*>(ptr) - (const char*)0;
177}
178
179static 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
267class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter {
268public:
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
309private:
310    SkBlitRow::Proc fProc;
311
312    typedef SkSpriteBlitter INHERITED;
313};
314
315///////////////////////////////////////////////////////////////////////////////
316
317#include "SkTemplatesPriv.h"
318
319SkSpriteBlitter* 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