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
D16_S32A_Blend_Pixel_helper(uint16_t * dst,SkPMColor sc,unsigned src_scale)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:
Sprite_D16_S16_Opaque(const SkBitmap & source)61 Sprite_D16_S16_Opaque(const SkBitmap& source)
62 : SkSpriteBlitter(source) {}
63
64 // overrides
blitRect(int x,int y,int width,int height)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
asint(const void * ptr)175 static intptr_t asint(const void* ptr) {
176 return reinterpret_cast<const char*>(ptr) - (const char*)0;
177 }
178
blitrow_d16_si8(SK_RESTRICT uint16_t * dst,SK_RESTRICT const uint8_t * src,int count,SK_RESTRICT const uint16_t * ctable)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:
Sprite_D16_S32_BlitRowProc(const SkBitmap & source)269 Sprite_D16_S32_BlitRowProc(const SkBitmap& source)
270 : SkSpriteBlitter(source) {}
271
272 // overrides
273
setup(const SkBitmap & device,int left,int top,const SkPaint & paint)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
blitRect(int x,int y,int width,int height)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
ChooseD16(const SkBitmap & source,const SkPaint & paint,void * storage,size_t storageSize)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