SkBitmapProcState.cpp revision a8d99307717c5fe02043969db0566c236a08c313
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 293static inline int sk_int_mod(int x, int n) { 294 SkASSERT(n > 0); 295 if ((unsigned)x >= (unsigned)n) { 296 if (x < 0) { 297 x = n + ~(~x % n); 298 } else { 299 x = x % n; 300 } 301 } 302 return x; 303} 304 305static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s, 306 int x, int y, 307 SkPMColor* SK_RESTRICT colors, 308 int count) { 309 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0); 310 SkASSERT(s.fInvKy == 0); 311 SkASSERT(count > 0 && colors != NULL); 312 SkASSERT(!s.fDoFilter); 313 314 const int stopX = s.fBitmap->width(); 315 const int stopY = s.fBitmap->height(); 316 int ix = s.fFilterOneX + x; 317 int iy = sk_int_mod(s.fFilterOneY + y, stopY); 318#ifdef SK_DEBUG 319 { 320 SkPoint pt; 321 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, 322 SkIntToScalar(y) + SK_ScalarHalf, &pt); 323 int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY); 324 int ix2 = SkScalarFloorToInt(pt.fX); 325 326 SkASSERT(iy == iy2); 327 SkASSERT(ix == ix2); 328 } 329#endif 330 const SkPMColor* row = s.fBitmap->getAddr32(0, iy); 331 332 ix = sk_int_mod(ix, stopX); 333 for (;;) { 334 int n = SkMin32(stopX - ix, count); 335 memcpy(colors, row + ix, n * sizeof(SkPMColor)); 336 count -= n; 337 if (0 == count) { 338 return; 339 } 340 colors += n; 341 ix = 0; 342 } 343} 344 345void SkBitmapProcState::setupForTranslate() { 346 SkPoint pt; 347 fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt); 348 // Since we know we're not filtered, we re-purpose these fields allow 349 // us to go from device -> src coordinates w/ just an integer add, 350 // rather than running through the inverse-matrix 351 fFilterOneX = SkScalarFloorToInt(pt.fX); 352 fFilterOneY = SkScalarFloorToInt(pt.fY); 353} 354 355SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() { 356 if (fAlphaScale < 256) { 357 return NULL; 358 } 359 if (fInvType > SkMatrix::kTranslate_Mask) { 360 return NULL; 361 } 362 if (fDoFilter) { 363 return NULL; 364 } 365 if (SkBitmap::kARGB_8888_Config != fBitmap->config()) { 366 return NULL; 367 } 368 369 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX; 370 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY; 371 372 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) { 373 this->setupForTranslate(); 374 return Clamp_S32_D32_nofilter_trans_shaderproc; 375 } 376 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) { 377 this->setupForTranslate(); 378 return Repeat_S32_D32_nofilter_trans_shaderproc; 379 } 380 return NULL; 381} 382 383/////////////////////////////////////////////////////////////////////////////// 384 385#ifdef SK_DEBUG 386 387static void check_scale_nofilter(uint32_t bitmapXY[], int count, 388 unsigned mx, unsigned my) { 389 unsigned y = *bitmapXY++; 390 SkASSERT(y < my); 391 392 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY); 393 for (int i = 0; i < count; ++i) { 394 SkASSERT(xptr[i] < mx); 395 } 396} 397 398static void check_scale_filter(uint32_t bitmapXY[], int count, 399 unsigned mx, unsigned my) { 400 uint32_t YY = *bitmapXY++; 401 unsigned y0 = YY >> 18; 402 unsigned y1 = YY & 0x3FFF; 403 SkASSERT(y0 < my); 404 SkASSERT(y1 < my); 405 406 for (int i = 0; i < count; ++i) { 407 uint32_t XX = bitmapXY[i]; 408 unsigned x0 = XX >> 18; 409 unsigned x1 = XX & 0x3FFF; 410 SkASSERT(x0 < mx); 411 SkASSERT(x1 < mx); 412 } 413} 414 415static void check_affine_nofilter(uint32_t bitmapXY[], int count, 416 unsigned mx, unsigned my) { 417 for (int i = 0; i < count; ++i) { 418 uint32_t XY = bitmapXY[i]; 419 unsigned x = XY & 0xFFFF; 420 unsigned y = XY >> 16; 421 SkASSERT(x < mx); 422 SkASSERT(y < my); 423 } 424} 425 426static void check_affine_filter(uint32_t bitmapXY[], int count, 427 unsigned mx, unsigned my) { 428 for (int i = 0; i < count; ++i) { 429 uint32_t YY = *bitmapXY++; 430 unsigned y0 = YY >> 18; 431 unsigned y1 = YY & 0x3FFF; 432 SkASSERT(y0 < my); 433 SkASSERT(y1 < my); 434 435 uint32_t XX = *bitmapXY++; 436 unsigned x0 = XX >> 18; 437 unsigned x1 = XX & 0x3FFF; 438 SkASSERT(x0 < mx); 439 SkASSERT(x1 < mx); 440 } 441} 442 443void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state, 444 uint32_t bitmapXY[], int count, 445 int x, int y) { 446 SkASSERT(bitmapXY); 447 SkASSERT(count > 0); 448 449 state.fMatrixProc(state, bitmapXY, count, x, y); 450 451 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my); 452 453 // There are four formats possible: 454 // scale -vs- affine 455 // filter -vs- nofilter 456 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 457 proc = state.fDoFilter ? check_scale_filter : check_scale_nofilter; 458 } else { 459 proc = state.fDoFilter ? check_affine_filter : check_affine_nofilter; 460 } 461 proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height()); 462} 463 464SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const { 465 return DebugMatrixProc; 466} 467 468#endif 469 470/////////////////////////////////////////////////////////////////////////////// 471/* 472 The storage requirements for the different matrix procs are as follows, 473 where each X or Y is 2 bytes, and N is the number of pixels/elements: 474 475 scale/translate nofilter Y(4bytes) + N * X 476 affine/perspective nofilter N * (X Y) 477 scale/translate filter Y Y + N * (X X) 478 affine/perspective filter N * (Y Y X X) 479 */ 480int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const { 481 int32_t size = static_cast<int32_t>(bufferSize); 482 483 size &= ~3; // only care about 4-byte aligned chunks 484 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) { 485 size -= 4; // the shared Y (or YY) coordinate 486 if (size < 0) { 487 size = 0; 488 } 489 size >>= 1; 490 } else { 491 size >>= 2; 492 } 493 494 if (fDoFilter) { 495 size >>= 1; 496 } 497 498 return size; 499} 500 501