SkBitmapProcState.cpp revision 80bacfeb4bda06541e8695bd502229727bccfeab
1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "SkBitmapProcState.h" 9#include "SkColorPriv.h" 10#include "SkFilterProc.h" 11#include "SkPaint.h" 12#include "SkShader.h" // for tilemodes 13#include "SkUtilsArm.h" 14 15#if !SK_ARM_NEON_IS_NONE 16// These are defined in src/opts/SkBitmapProcState_arm_neon.cpp 17extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[]; 18extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; 19extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*); 20extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 21extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int); 22extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*); 23extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); 24extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int); 25#endif 26 27#if !SK_ARM_NEON_IS_ALWAYS 28#define NAME_WRAP(x) x 29#include "SkBitmapProcState_filter.h" 30#include "SkBitmapProcState_procs.h" 31#endif 32 33/////////////////////////////////////////////////////////////////////////////// 34 35static bool valid_for_filtering(unsigned dimension) { 36 // for filtering, width and height must fit in 14bits, since we use steal 37 // 2 bits from each to store our 4bit subpixel data 38 return (dimension & ~0x3FFF) == 0; 39} 40 41bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { 42 if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) { 43 return false; 44 } 45 46 const SkMatrix* m; 47 bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0; 48 bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX && 49 SkShader::kClamp_TileMode == fTileModeY; 50 51 if (clamp_clamp || trivial_matrix) { 52 m = &inv; 53 } else { 54 fUnitInvMatrix = inv; 55 fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height()); 56 m = &fUnitInvMatrix; 57 } 58 59 fBitmap = &fOrigBitmap; 60 if (fOrigBitmap.hasMipMap()) { 61 int shift = fOrigBitmap.extractMipLevel(&fMipBitmap, 62 SkScalarToFixed(m->getScaleX()), 63 SkScalarToFixed(m->getSkewY())); 64 65 if (shift > 0) { 66 if (m != &fUnitInvMatrix) { 67 fUnitInvMatrix = *m; 68 m = &fUnitInvMatrix; 69 } 70 71 SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift); 72 fUnitInvMatrix.postScale(scale, scale); 73 74 // now point here instead of fOrigBitmap 75 fBitmap = &fMipBitmap; 76 } 77 } 78 79 fInvMatrix = m; 80 fInvProc = m->getMapXYProc(); 81 fInvType = m->getType(); 82 fInvSx = SkScalarToFixed(m->getScaleX()); 83 fInvSxFractionalInt = SkScalarToFractionalInt(m->getScaleX()); 84 fInvKy = SkScalarToFixed(m->getSkewY()); 85 fInvKyFractionalInt = SkScalarToFractionalInt(m->getSkewY()); 86 87 fAlphaScale = SkAlpha255To256(paint.getAlpha()); 88 89 // pick-up filtering from the paint, but only if the matrix is 90 // more complex than identity/translate (i.e. no need to pay the cost 91 // of filtering if we're not scaled etc.). 92 // note: we explicitly check inv, since m might be scaled due to unitinv 93 // trickery, but we don't want to see that for this test 94 fDoFilter = paint.isFilterBitmap() && 95 (inv.getType() > SkMatrix::kTranslate_Mask && 96 valid_for_filtering(fBitmap->width() | fBitmap->height())); 97 98 fShaderProc32 = NULL; 99 fShaderProc16 = NULL; 100 fSampleProc32 = NULL; 101 fSampleProc16 = NULL; 102 103 fMatrixProc = this->chooseMatrixProc(trivial_matrix); 104 if (NULL == fMatrixProc) { 105 return false; 106 } 107 108 /////////////////////////////////////////////////////////////////////// 109 110 int index = 0; 111 if (fAlphaScale < 256) { // note: this distinction is not used for D16 112 index |= 1; 113 } 114 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 115 index |= 2; 116 } 117 if (fDoFilter) { 118 index |= 4; 119 } 120 // bits 3,4,5 encoding the source bitmap format 121 switch (fBitmap->config()) { 122 case SkBitmap::kARGB_8888_Config: 123 index |= 0; 124 break; 125 case SkBitmap::kRGB_565_Config: 126 index |= 8; 127 break; 128 case SkBitmap::kIndex8_Config: 129 index |= 16; 130 break; 131 case SkBitmap::kARGB_4444_Config: 132 index |= 24; 133 break; 134 case SkBitmap::kA8_Config: 135 index |= 32; 136 fPaintPMColor = SkPreMultiplyColor(paint.getColor()); 137 break; 138 default: 139 return false; 140 } 141 142#if !SK_ARM_NEON_IS_ALWAYS 143 static const SampleProc32 gSkBitmapProcStateSample32[] = { 144 S32_opaque_D32_nofilter_DXDY, 145 S32_alpha_D32_nofilter_DXDY, 146 S32_opaque_D32_nofilter_DX, 147 S32_alpha_D32_nofilter_DX, 148 S32_opaque_D32_filter_DXDY, 149 S32_alpha_D32_filter_DXDY, 150 S32_opaque_D32_filter_DX, 151 S32_alpha_D32_filter_DX, 152 153 S16_opaque_D32_nofilter_DXDY, 154 S16_alpha_D32_nofilter_DXDY, 155 S16_opaque_D32_nofilter_DX, 156 S16_alpha_D32_nofilter_DX, 157 S16_opaque_D32_filter_DXDY, 158 S16_alpha_D32_filter_DXDY, 159 S16_opaque_D32_filter_DX, 160 S16_alpha_D32_filter_DX, 161 162 SI8_opaque_D32_nofilter_DXDY, 163 SI8_alpha_D32_nofilter_DXDY, 164 SI8_opaque_D32_nofilter_DX, 165 SI8_alpha_D32_nofilter_DX, 166 SI8_opaque_D32_filter_DXDY, 167 SI8_alpha_D32_filter_DXDY, 168 SI8_opaque_D32_filter_DX, 169 SI8_alpha_D32_filter_DX, 170 171 S4444_opaque_D32_nofilter_DXDY, 172 S4444_alpha_D32_nofilter_DXDY, 173 S4444_opaque_D32_nofilter_DX, 174 S4444_alpha_D32_nofilter_DX, 175 S4444_opaque_D32_filter_DXDY, 176 S4444_alpha_D32_filter_DXDY, 177 S4444_opaque_D32_filter_DX, 178 S4444_alpha_D32_filter_DX, 179 180 // A8 treats alpha/opauqe the same (equally efficient) 181 SA8_alpha_D32_nofilter_DXDY, 182 SA8_alpha_D32_nofilter_DXDY, 183 SA8_alpha_D32_nofilter_DX, 184 SA8_alpha_D32_nofilter_DX, 185 SA8_alpha_D32_filter_DXDY, 186 SA8_alpha_D32_filter_DXDY, 187 SA8_alpha_D32_filter_DX, 188 SA8_alpha_D32_filter_DX 189 }; 190 191 static const SampleProc16 gSkBitmapProcStateSample16[] = { 192 S32_D16_nofilter_DXDY, 193 S32_D16_nofilter_DX, 194 S32_D16_filter_DXDY, 195 S32_D16_filter_DX, 196 197 S16_D16_nofilter_DXDY, 198 S16_D16_nofilter_DX, 199 S16_D16_filter_DXDY, 200 S16_D16_filter_DX, 201 202 SI8_D16_nofilter_DXDY, 203 SI8_D16_nofilter_DX, 204 SI8_D16_filter_DXDY, 205 SI8_D16_filter_DX, 206 207 // Don't support 4444 -> 565 208 NULL, NULL, NULL, NULL, 209 // Don't support A8 -> 565 210 NULL, NULL, NULL, NULL 211 }; 212#endif 213 214 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index]; 215 index >>= 1; // shift away any opaque/alpha distinction 216 fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index]; 217 218 // our special-case shaderprocs 219 if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) { 220 if (clamp_clamp) { 221 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc); 222 } else if (SkShader::kRepeat_TileMode == fTileModeX && 223 SkShader::kRepeat_TileMode == fTileModeY) { 224 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc); 225 } 226 } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clamp_clamp) { 227 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc); 228 } 229 230 if (NULL == fShaderProc32) { 231 fShaderProc32 = this->chooseShaderProc32(); 232 } 233 234 // see if our platform has any accelerated overrides 235 this->platformProcs(); 236 return true; 237} 238 239static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, 240 int x, int y, 241 SkPMColor* SK_RESTRICT colors, 242 int count) { 243 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); 244 SkASSERT(s.fInvKy == 0); 245 SkASSERT(count > 0 && colors != NULL); 246 SkASSERT(!s.fDoFilter); 247 248 const int maxX = s.fBitmap->width() - 1; 249 const int maxY = s.fBitmap->height() - 1; 250 int ix = s.fFilterOneX + x; 251 int iy = SkClampMax(s.fFilterOneY + y, maxY); 252#ifdef SK_DEBUG 253 { 254 SkPoint pt; 255 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, 256 SkIntToScalar(y) + SK_ScalarHalf, &pt); 257 int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY); 258 int ix2 = SkScalarFloorToInt(pt.fX); 259 260 SkASSERT(iy == iy2); 261 SkASSERT(ix == ix2); 262 } 263#endif 264 const SkPMColor* row = s.fBitmap->getAddr32(0, iy); 265 266 // clamp to the left 267 if (ix < 0) { 268 int n = SkMin32(-ix, count); 269 sk_memset32(colors, row[0], n); 270 count -= n; 271 if (0 == count) { 272 return; 273 } 274 colors += n; 275 SkASSERT(-ix == n); 276 ix = 0; 277 } 278 // copy the middle 279 if (ix <= maxX) { 280 int n = SkMin32(maxX - ix + 1, count); 281 memcpy(colors, row + ix, n * sizeof(SkPMColor)); 282 count -= n; 283 if (0 == count) { 284 return; 285 } 286 colors += n; 287 } 288 SkASSERT(count > 0); 289 // clamp to the right 290 sk_memset32(colors, row[maxX], count); 291} 292 293SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() { 294 if (fAlphaScale < 256) { 295 return NULL; 296 } 297 if (fInvType > SkMatrix::kTranslate_Mask) { 298 return NULL; 299 } 300 if (fDoFilter) { 301 return NULL; 302 } 303 if (SkBitmap::kARGB_8888_Config != fBitmap->config()) { 304 return NULL; 305 } 306 307 if (SkShader::kClamp_TileMode == fTileModeX && SkShader::kClamp_TileMode == fTileModeY) { 308 SkPoint pt; 309 fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt); 310 // Since we know we're not filtered, we re-purpose these fields allow 311 // us to go from device -> src coordinates w/ just an integer add, 312 // rather than running through the inverse-matrix 313 fFilterOneX = SkScalarFloorToInt(pt.fX); 314 fFilterOneY = SkScalarFloorToInt(pt.fY); 315 return Clamp_S32_D32_nofilter_trans_shaderproc; 316 } 317 return NULL; 318} 319 320/////////////////////////////////////////////////////////////////////////////// 321 322#ifdef SK_DEBUG 323 324static void check_scale_nofilter(uint32_t bitmapXY[], int count, 325 unsigned mx, unsigned my) { 326 unsigned y = *bitmapXY++; 327 SkASSERT(y < my); 328 329 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY); 330 for (int i = 0; i < count; ++i) { 331 SkASSERT(xptr[i] < mx); 332 } 333} 334 335static void check_scale_filter(uint32_t bitmapXY[], int count, 336 unsigned mx, unsigned my) { 337 uint32_t YY = *bitmapXY++; 338 unsigned y0 = YY >> 18; 339 unsigned y1 = YY & 0x3FFF; 340 SkASSERT(y0 < my); 341 SkASSERT(y1 < my); 342 343 for (int i = 0; i < count; ++i) { 344 uint32_t XX = bitmapXY[i]; 345 unsigned x0 = XX >> 18; 346 unsigned x1 = XX & 0x3FFF; 347 SkASSERT(x0 < mx); 348 SkASSERT(x1 < mx); 349 } 350} 351 352static void check_affine_nofilter(uint32_t bitmapXY[], int count, 353 unsigned mx, unsigned my) { 354 for (int i = 0; i < count; ++i) { 355 uint32_t XY = bitmapXY[i]; 356 unsigned x = XY & 0xFFFF; 357 unsigned y = XY >> 16; 358 SkASSERT(x < mx); 359 SkASSERT(y < my); 360 } 361} 362 363static void check_affine_filter(uint32_t bitmapXY[], int count, 364 unsigned mx, unsigned my) { 365 for (int i = 0; i < count; ++i) { 366 uint32_t YY = *bitmapXY++; 367 unsigned y0 = YY >> 18; 368 unsigned y1 = YY & 0x3FFF; 369 SkASSERT(y0 < my); 370 SkASSERT(y1 < my); 371 372 uint32_t XX = *bitmapXY++; 373 unsigned x0 = XX >> 18; 374 unsigned x1 = XX & 0x3FFF; 375 SkASSERT(x0 < mx); 376 SkASSERT(x1 < mx); 377 } 378} 379 380void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state, 381 uint32_t bitmapXY[], int count, 382 int x, int y) { 383 SkASSERT(bitmapXY); 384 SkASSERT(count > 0); 385 386 state.fMatrixProc(state, bitmapXY, count, x, y); 387 388 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my); 389 390 // There are four formats possible: 391 // scale -vs- affine 392 // filter -vs- nofilter 393 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 394 proc = state.fDoFilter ? check_scale_filter : check_scale_nofilter; 395 } else { 396 proc = state.fDoFilter ? check_affine_filter : check_affine_nofilter; 397 } 398 proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height()); 399} 400 401SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const { 402 return DebugMatrixProc; 403} 404 405#endif 406 407/////////////////////////////////////////////////////////////////////////////// 408/* 409 The storage requirements for the different matrix procs are as follows, 410 where each X or Y is 2 bytes, and N is the number of pixels/elements: 411 412 scale/translate nofilter Y(4bytes) + N * X 413 affine/perspective nofilter N * (X Y) 414 scale/translate filter Y Y + N * (X X) 415 affine/perspective filter N * (Y Y X X) 416 */ 417int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const { 418 int32_t size = static_cast<int32_t>(bufferSize); 419 420 size &= ~3; // only care about 4-byte aligned chunks 421 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 422 size -= 4; // the shared Y (or YY) coordinate 423 if (size < 0) { 424 size = 0; 425 } 426 size >>= 1; 427 } else { 428 size >>= 2; 429 } 430 431 if (fDoFilter) { 432 size >>= 1; 433 } 434 435 return size; 436} 437 438