1/* 2 * Copyright 2011 Google Inc. 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#include "SkBlitRow.h" 9#include "SkBlitMask.h" 10#include "SkColorPriv.h" 11#include "SkUtils.h" 12 13#define UNROLL 14 15SkBlitRow::ColorRectProc PlatformColorRectProcFactory(); 16 17static void S32_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst, 18 const SkPMColor* SK_RESTRICT src, 19 int count, U8CPU alpha) { 20 SkASSERT(255 == alpha); 21 memcpy(dst, src, count * sizeof(SkPMColor)); 22} 23 24static void S32_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst, 25 const SkPMColor* SK_RESTRICT src, 26 int count, U8CPU alpha) { 27 SkASSERT(alpha <= 255); 28 if (count > 0) { 29 unsigned src_scale = SkAlpha255To256(alpha); 30 unsigned dst_scale = 256 - src_scale; 31 32#ifdef UNROLL 33 if (count & 1) { 34 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale); 35 dst += 1; 36 count -= 1; 37 } 38 39 const SkPMColor* SK_RESTRICT srcEnd = src + count; 40 while (src != srcEnd) { 41 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale); 42 dst += 1; 43 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale); 44 dst += 1; 45 } 46#else 47 do { 48 *dst = SkAlphaMulQ(*src, src_scale) + SkAlphaMulQ(*dst, dst_scale); 49 src += 1; 50 dst += 1; 51 } while (--count > 0); 52#endif 53 } 54} 55 56static void S32A_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst, 57 const SkPMColor* SK_RESTRICT src, 58 int count, U8CPU alpha) { 59 SkASSERT(255 == alpha); 60 if (count > 0) { 61#ifdef UNROLL 62 if (count & 1) { 63 *dst = SkPMSrcOver(*(src++), *dst); 64 dst += 1; 65 count -= 1; 66 } 67 68 const SkPMColor* SK_RESTRICT srcEnd = src + count; 69 while (src != srcEnd) { 70 *dst = SkPMSrcOver(*(src++), *dst); 71 dst += 1; 72 *dst = SkPMSrcOver(*(src++), *dst); 73 dst += 1; 74 } 75#else 76 do { 77 *dst = SkPMSrcOver(*src, *dst); 78 src += 1; 79 dst += 1; 80 } while (--count > 0); 81#endif 82 } 83} 84 85static void S32A_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst, 86 const SkPMColor* SK_RESTRICT src, 87 int count, U8CPU alpha) { 88 SkASSERT(alpha <= 255); 89 if (count > 0) { 90#ifdef UNROLL 91 if (count & 1) { 92 *dst = SkBlendARGB32(*(src++), *dst, alpha); 93 dst += 1; 94 count -= 1; 95 } 96 97 const SkPMColor* SK_RESTRICT srcEnd = src + count; 98 while (src != srcEnd) { 99 *dst = SkBlendARGB32(*(src++), *dst, alpha); 100 dst += 1; 101 *dst = SkBlendARGB32(*(src++), *dst, alpha); 102 dst += 1; 103 } 104#else 105 do { 106 *dst = SkBlendARGB32(*src, *dst, alpha); 107 src += 1; 108 dst += 1; 109 } while (--count > 0); 110#endif 111 } 112} 113 114/////////////////////////////////////////////////////////////////////////////// 115 116static const SkBlitRow::Proc32 gDefault_Procs32[] = { 117 S32_Opaque_BlitRow32, 118 S32_Blend_BlitRow32, 119 S32A_Opaque_BlitRow32, 120 S32A_Blend_BlitRow32 121}; 122 123SkBlitRow::Proc32 SkBlitRow::Factory32(unsigned flags) { 124 SkASSERT(flags < SK_ARRAY_COUNT(gDefault_Procs32)); 125 // just so we don't crash 126 flags &= kFlags32_Mask; 127 128 SkBlitRow::Proc32 proc = PlatformProcs32(flags); 129 if (NULL == proc) { 130 proc = gDefault_Procs32[flags]; 131 } 132 SkASSERT(proc); 133 return proc; 134} 135 136SkBlitRow::Proc32 SkBlitRow::ColorProcFactory() { 137 SkBlitRow::ColorProc proc = PlatformColorProc(); 138 if (NULL == proc) { 139 proc = Color32; 140 } 141 SkASSERT(proc); 142 return proc; 143} 144 145void SkBlitRow::Color32(SkPMColor* SK_RESTRICT dst, 146 const SkPMColor* SK_RESTRICT src, 147 int count, SkPMColor color) { 148 if (count > 0) { 149 if (0 == color) { 150 if (src != dst) { 151 memcpy(dst, src, count * sizeof(SkPMColor)); 152 } 153 return; 154 } 155 unsigned colorA = SkGetPackedA32(color); 156 if (255 == colorA) { 157 sk_memset32(dst, color, count); 158 } else { 159 unsigned scale = 256 - SkAlpha255To256(colorA); 160 do { 161 *dst = color + SkAlphaMulQ(*src, scale); 162 src += 1; 163 dst += 1; 164 } while (--count); 165 } 166 } 167} 168 169template <size_t N> void assignLoop(SkPMColor* dst, SkPMColor color) { 170 for (size_t i = 0; i < N; ++i) { 171 *dst++ = color; 172 } 173} 174 175static inline void assignLoop(SkPMColor dst[], SkPMColor color, int count) { 176 while (count >= 4) { 177 *dst++ = color; 178 *dst++ = color; 179 *dst++ = color; 180 *dst++ = color; 181 count -= 4; 182 } 183 if (count >= 2) { 184 *dst++ = color; 185 *dst++ = color; 186 count -= 2; 187 } 188 if (count > 0) { 189 *dst++ = color; 190 } 191} 192 193void SkBlitRow::ColorRect32(SkPMColor* dst, int width, int height, 194 size_t rowBytes, SkPMColor color) { 195 if (width <= 0 || height <= 0 || 0 == color) { 196 return; 197 } 198 199 // Just made up this value, since I saw it once in a SSE2 file. 200 // We should consider writing some tests to find the optimimal break-point 201 // (or query the Platform proc?) 202 static const int MIN_WIDTH_FOR_SCANLINE_PROC = 32; 203 204 bool isOpaque = (0xFF == SkGetPackedA32(color)); 205 206 if (!isOpaque || width >= MIN_WIDTH_FOR_SCANLINE_PROC) { 207 SkBlitRow::ColorProc proc = SkBlitRow::ColorProcFactory(); 208 while (--height >= 0) { 209 (*proc)(dst, dst, width, color); 210 dst = (SkPMColor*) ((char*)dst + rowBytes); 211 } 212 } else { 213 switch (width) { 214 case 1: 215 while (--height >= 0) { 216 assignLoop<1>(dst, color); 217 dst = (SkPMColor*) ((char*)dst + rowBytes); 218 } 219 break; 220 case 2: 221 while (--height >= 0) { 222 assignLoop<2>(dst, color); 223 dst = (SkPMColor*) ((char*)dst + rowBytes); 224 } 225 break; 226 case 3: 227 while (--height >= 0) { 228 assignLoop<3>(dst, color); 229 dst = (SkPMColor*) ((char*)dst + rowBytes); 230 } 231 break; 232 default: 233 while (--height >= 0) { 234 assignLoop(dst, color, width); 235 dst = (SkPMColor*) ((char*)dst + rowBytes); 236 } 237 break; 238 } 239 } 240} 241 242SkBlitRow::ColorRectProc SkBlitRow::ColorRectProcFactory() { 243 SkBlitRow::ColorRectProc proc = PlatformColorRectProcFactory(); 244 if (NULL == proc) { 245 proc = ColorRect32; 246 } 247 SkASSERT(proc); 248 return proc; 249} 250