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