3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
8 #include "SkBitmapProcState.h"
9 #include "SkColorPriv.h"
10 #include "SkFilterProc.h"
12 #include "SkShader.h" // for tilemodes
13 #include "SkUtilsArm.h"
14 #include "SkBitmapScaler.h"
16 #include "SkPixelRef.h"
17 #include "SkScaledImageCache.h"
18 #include "SkImageEncoder.h"
20 #if !SK_ARM_NEON_IS_NONE
21 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
22 extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
23 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
24 extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
25 extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
26 extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
27 extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
28 extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
29 extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
32 #define NAME_WRAP(x) x
33 #include "SkBitmapProcState_filter.h"
34 #include "SkBitmapProcState_procs.h"
36 ///////////////////////////////////////////////////////////////////////////////
38 // true iff the matrix contains, at most, scale and translate elements
39 static bool matrix_only_scale_translate(const SkMatrix& m) {
40 return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
44 * For the purposes of drawing bitmaps, if a matrix is "almost" translate
45 * go ahead and treat it as if it were, so that subsequent code can go fast.
47 static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
48 SkASSERT(matrix_only_scale_translate(matrix));
50 if (matrix.getType() & SkMatrix::kScale_Mask) {
52 bitmap.getBounds(&src);
54 // Can't call mapRect(), since that will fix up inverted rectangles,
55 // e.g. when scale is negative, and we don't want to return true for
57 matrix.mapPoints(SkTCast<SkPoint*>(&dst),
58 SkTCast<const SkPoint*>(&src),
61 // Now round all 4 edges to device space, and then compare the device
62 // width/height to the original. Note: we must map all 4 and subtract
63 // rather than map the "width" and compare, since we care about the
64 // phase (in pixel space) that any translate in the matrix might impart.
67 return idst.width() == bitmap.width() && idst.height() == bitmap.height();
69 // if we got here, we're either kTranslate_Mask or identity
73 static bool just_trans_general(const SkMatrix& matrix) {
74 SkASSERT(matrix_only_scale_translate(matrix));
76 if (matrix.getType() & SkMatrix::kScale_Mask) {
77 const SkScalar tol = SK_Scalar1 / 32768;
79 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
82 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
86 // if we got here, treat us as either kTranslate_Mask or identity
90 ///////////////////////////////////////////////////////////////////////////////
92 static bool valid_for_filtering(unsigned dimension) {
93 // for filtering, width and height must fit in 14bits, since we use steal
94 // 2 bits from each to store our 4bit subpixel data
95 return (dimension & ~0x3FFF) == 0;
98 static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) {
101 v1.fX = mat.getScaleX();
102 v1.fY = mat.getSkewY();
104 v2.fX = mat.getSkewX();
105 v2.fY = mat.getScaleY();
107 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
110 class AutoScaledCacheUnlocker {
112 AutoScaledCacheUnlocker(SkScaledImageCache::ID** idPtr) : fIDPtr(idPtr) {}
113 ~AutoScaledCacheUnlocker() {
114 if (fIDPtr && *fIDPtr) {
115 SkScaledImageCache::Unlock(*fIDPtr);
120 // forgets the ID, so it won't call Unlock
126 SkScaledImageCache::ID** fIDPtr;
128 #define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocker)
130 // Check to see that the size of the bitmap that would be produced by
131 // scaling by the given inverted matrix is less than the maximum allowed.
132 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
133 size_t maximumAllocation
134 = SkScaledImageCache::GetSingleAllocationByteLimit();
135 if (0 == maximumAllocation) {
138 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
139 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
140 // Skip the division step:
141 return bm.info().getSafeSize(bm.info().minRowBytes())
142 < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
145 // TODO -- we may want to pass the clip into this function so we only scale
146 // the portion of the image that we're going to need. This will complicate
147 // the interface to the cache, but might be well worth it.
149 bool SkBitmapProcState::possiblyScaleImage() {
150 AutoScaledCacheUnlocker unlocker(&fScaledCacheID);
152 SkASSERT(NULL == fBitmap);
153 SkASSERT(NULL == fScaledCacheID);
155 if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
158 // Check to see if the transformation matrix is simple, and if we're
159 // doing high quality scaling. If so, do the bitmap scale here and
160 // remove the scaling component from the matrix.
162 if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
163 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
164 kN32_SkColorType == fOrigBitmap.colorType() &&
165 cache_size_okay(fOrigBitmap, fInvMatrix)) {
167 SkScalar invScaleX = fInvMatrix.getScaleX();
168 SkScalar invScaleY = fInvMatrix.getScaleY();
170 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
171 invScaleX, invScaleY,
173 if (fScaledCacheID) {
174 fScaledBitmap.lockPixels();
175 if (!fScaledBitmap.getPixels()) {
176 fScaledBitmap.unlockPixels();
177 // found a purged entry (discardablememory?), release it
178 SkScaledImageCache::Unlock(fScaledCacheID);
179 fScaledCacheID = NULL;
180 // fall through to rebuild
184 if (NULL == fScaledCacheID) {
185 float dest_width = fOrigBitmap.width() / invScaleX;
186 float dest_height = fOrigBitmap.height() / invScaleY;
188 // All the criteria are met; let's make a new bitmap.
190 SkConvolutionProcs simd;
191 sk_bzero(&simd, sizeof(simd));
192 this->platformConvolutionProcs(&simd);
194 if (!SkBitmapScaler::Resize(&fScaledBitmap,
196 SkBitmapScaler::RESIZE_BEST,
200 SkScaledImageCache::GetAllocator())) {
201 // we failed to create fScaledBitmap, so just return and let
202 // the scanline proc handle it.
207 SkASSERT(NULL != fScaledBitmap.getPixels());
208 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
212 if (!fScaledCacheID) {
213 fScaledBitmap.reset();
216 SkASSERT(NULL != fScaledBitmap.getPixels());
219 SkASSERT(NULL != fScaledBitmap.getPixels());
220 fBitmap = &fScaledBitmap;
222 // set the inv matrix type to translate-only;
223 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScaleX(),
224 fInvMatrix.getTranslateY() / fInvMatrix.getScaleY());
226 // no need for any further filtering; we just did it!
227 fFilterLevel = SkPaint::kNone_FilterLevel;
233 * If High, then our special-case for scale-only did not take, and so we
234 * have to make a choice:
235 * 1. fall back on mipmaps + bilerp
236 * 2. fall back on scanline bicubic filter
237 * For now, we compute the "scale" value from the matrix, and have a
238 * threshold to decide when bicubic is better, and when mips are better.
239 * No doubt a fancier decision tree could be used uere.
241 * If Medium, then we just try to build a mipmap and select a level,
242 * setting the filter-level to kLow to signal that we just need bilerp
243 * to process the selected level.
246 SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
248 if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
249 // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller
250 // than this, then the mipmaps quality may be greater (certainly faster)
251 // so we only keep High quality if the scale is greater than this.
253 // Since we're dealing with the inverse, we compare against its inverse.
254 const SkScalar bicubicLimit = 4.0f;
255 const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit;
256 if (scaleSqd < bicubicLimitSqd) { // use bicubic scanline
260 // else set the filter-level to Medium, since we're scaling down and
261 // want to reqeust mipmaps
262 fFilterLevel = SkPaint::kMedium_FilterLevel;
265 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
268 * Medium quality means use a mipmap for down-scaling, and just bilper
269 * for upscaling. Since we're examining the inverse matrix, we look for
270 * a scale > 1 to indicate down scaling by the CTM.
272 if (scaleSqd > SK_Scalar1) {
273 const SkMipMap* mip = NULL;
275 SkASSERT(NULL == fScaledCacheID);
276 fScaledCacheID = SkScaledImageCache::FindAndLockMip(fOrigBitmap, &mip);
277 if (!fScaledCacheID) {
278 SkASSERT(NULL == mip);
279 mip = SkMipMap::Build(fOrigBitmap);
281 fScaledCacheID = SkScaledImageCache::AddAndLockMip(fOrigBitmap,
283 SkASSERT(mip->getRefCnt() > 1);
284 mip->unref(); // the cache took a ref
285 SkASSERT(fScaledCacheID);
292 SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd));
293 SkMipMap::Level level;
294 if (mip->extractLevel(levelScale, &level)) {
295 SkScalar invScaleFixup = level.fScale;
296 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
298 SkImageInfo info = fOrigBitmap.info();
299 info.fWidth = level.fWidth;
300 info.fHeight = level.fHeight;
301 fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes);
302 fBitmap = &fScaledBitmap;
303 fFilterLevel = SkPaint::kLow_FilterLevel;
313 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) {
314 SkPixelRef* pr = src.pixelRef();
315 if (pr && pr->decodeInto(pow2, dst)) {
320 * If decodeInto() fails, it is possibe that we have an old subclass that
321 * does not, or cannot, implement that. In that case we fall back to the
322 * older protocol of having the pixelRef handle the caching for us.
326 return SkToBool(dst->getPixels());
329 bool SkBitmapProcState::lockBaseBitmap() {
330 AutoScaledCacheUnlocker unlocker(&fScaledCacheID);
332 SkPixelRef* pr = fOrigBitmap.pixelRef();
334 SkASSERT(NULL == fScaledCacheID);
336 if (pr->isLocked() || !pr->implementsDecodeInto()) {
337 // fast-case, no need to look in our cache
338 fScaledBitmap = fOrigBitmap;
339 fScaledBitmap.lockPixels();
340 if (NULL == fScaledBitmap.getPixels()) {
344 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
345 SK_Scalar1, SK_Scalar1,
347 if (fScaledCacheID) {
348 fScaledBitmap.lockPixels();
349 if (!fScaledBitmap.getPixels()) {
350 fScaledBitmap.unlockPixels();
351 // found a purged entry (discardablememory?), release it
352 SkScaledImageCache::Unlock(fScaledCacheID);
353 fScaledCacheID = NULL;
354 // fall through to rebuild
358 if (NULL == fScaledCacheID) {
359 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) {
363 // TODO: if fScaled comes back at a different width/height than fOrig,
364 // we need to update the matrix we are using to sample from this guy.
366 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
367 SK_Scalar1, SK_Scalar1,
369 if (!fScaledCacheID) {
370 fScaledBitmap.reset();
375 fBitmap = &fScaledBitmap;
380 SkBitmapProcState::~SkBitmapProcState() {
381 if (fScaledCacheID) {
382 SkScaledImageCache::Unlock(fScaledCacheID);
384 SkDELETE(fBitmapFilter);
387 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
388 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());
392 fFilterLevel = paint.getFilterLevel();
394 SkASSERT(NULL == fScaledCacheID);
396 // possiblyScaleImage will look to see if it can rescale the image as a
397 // preprocess; either by scaling up to the target size, or by selecting
398 // a nearby mipmap level. If it does, it will adjust the working
399 // matrix as well as the working bitmap. It may also adjust the filter
400 // quality to avoid re-filtering an already perfectly scaled image.
401 if (!this->possiblyScaleImage()) {
402 if (!this->lockBaseBitmap()) {
406 // The above logic should have always assigned fBitmap, but in case it
407 // didn't, we check for that now...
408 // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)?
409 if (NULL == fBitmap) {
413 // If we are "still" kMedium_FilterLevel, then the request was not fulfilled by possiblyScale,
414 // so we downgrade to kLow (so the rest of the sniffing code can assume that)
415 if (SkPaint::kMedium_FilterLevel == fFilterLevel) {
416 fFilterLevel = SkPaint::kLow_FilterLevel;
419 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
420 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
421 SkShader::kClamp_TileMode == fTileModeY;
423 if (!(clampClamp || trivialMatrix)) {
424 fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
427 // Now that all possible changes to the matrix have taken place, check
428 // to see if we're really close to a no-scale matrix. If so, explicitly
429 // set it to be so. Subsequent code may inspect this matrix to choose
430 // a faster path in this case.
432 // This code will only execute if the matrix has some scale component;
433 // if it's already pure translate then we won't do this inversion.
435 if (matrix_only_scale_translate(fInvMatrix)) {
437 if (fInvMatrix.invert(&forward)) {
438 if (clampClamp ? just_trans_clamp(forward, *fBitmap)
439 : just_trans_general(forward)) {
440 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
441 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
442 fInvMatrix.setTranslate(tx, ty);
447 fInvProc = fInvMatrix.getMapXYProc();
448 fInvType = fInvMatrix.getType();
449 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX());
450 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
451 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY());
452 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
454 fAlphaScale = SkAlpha255To256(paint.getAlpha());
456 fShaderProc32 = NULL;
457 fShaderProc16 = NULL;
458 fSampleProc32 = NULL;
459 fSampleProc16 = NULL;
461 // recompute the triviality of the matrix here because we may have
464 trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
466 if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
467 // If this is still set, that means we wanted HQ sampling
468 // but couldn't do it as a preprocess. Let's try to install
469 // the scanline version of the HQ sampler. If that process fails,
470 // downgrade to bilerp.
472 // NOTE: Might need to be careful here in the future when we want
473 // to have the platform proc have a shot at this; it's possible that
474 // the chooseBitmapFilterProc will fail to install a shader but a
475 // platform-specific one might succeed, so it might be premature here
476 // to fall back to bilerp. This needs thought.
478 if (!this->setBitmapFilterProcs()) {
479 fFilterLevel = SkPaint::kLow_FilterLevel;
483 if (SkPaint::kLow_FilterLevel == fFilterLevel) {
484 // Only try bilerp if the matrix is "interesting" and
485 // the image has a suitable size.
487 if (fInvType <= SkMatrix::kTranslate_Mask ||
488 !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
489 fFilterLevel = SkPaint::kNone_FilterLevel;
493 // At this point, we know exactly what kind of sampling the per-scanline
494 // shader will perform.
496 fMatrixProc = this->chooseMatrixProc(trivialMatrix);
497 // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
498 if (NULL == fMatrixProc) {
502 ///////////////////////////////////////////////////////////////////////
504 // No need to do this if we're doing HQ sampling; if filter quality is
505 // still set to HQ by the time we get here, then we must have installed
506 // the shader procs above and can skip all this.
508 if (fFilterLevel < SkPaint::kHigh_FilterLevel) {
511 if (fAlphaScale < 256) { // note: this distinction is not used for D16
514 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
517 if (fFilterLevel > SkPaint::kNone_FilterLevel) {
520 // bits 3,4,5 encoding the source bitmap format
521 switch (fBitmap->colorType()) {
522 case kN32_SkColorType:
525 case kRGB_565_SkColorType:
528 case kIndex_8_SkColorType:
531 case kARGB_4444_SkColorType:
534 case kAlpha_8_SkColorType:
536 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
539 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
543 #if !SK_ARM_NEON_IS_ALWAYS
544 static const SampleProc32 gSkBitmapProcStateSample32[] = {
545 S32_opaque_D32_nofilter_DXDY,
546 S32_alpha_D32_nofilter_DXDY,
547 S32_opaque_D32_nofilter_DX,
548 S32_alpha_D32_nofilter_DX,
549 S32_opaque_D32_filter_DXDY,
550 S32_alpha_D32_filter_DXDY,
551 S32_opaque_D32_filter_DX,
552 S32_alpha_D32_filter_DX,
554 S16_opaque_D32_nofilter_DXDY,
555 S16_alpha_D32_nofilter_DXDY,
556 S16_opaque_D32_nofilter_DX,
557 S16_alpha_D32_nofilter_DX,
558 S16_opaque_D32_filter_DXDY,
559 S16_alpha_D32_filter_DXDY,
560 S16_opaque_D32_filter_DX,
561 S16_alpha_D32_filter_DX,
563 SI8_opaque_D32_nofilter_DXDY,
564 SI8_alpha_D32_nofilter_DXDY,
565 SI8_opaque_D32_nofilter_DX,
566 SI8_alpha_D32_nofilter_DX,
567 SI8_opaque_D32_filter_DXDY,
568 SI8_alpha_D32_filter_DXDY,
569 SI8_opaque_D32_filter_DX,
570 SI8_alpha_D32_filter_DX,
572 S4444_opaque_D32_nofilter_DXDY,
573 S4444_alpha_D32_nofilter_DXDY,
574 S4444_opaque_D32_nofilter_DX,
575 S4444_alpha_D32_nofilter_DX,
576 S4444_opaque_D32_filter_DXDY,
577 S4444_alpha_D32_filter_DXDY,
578 S4444_opaque_D32_filter_DX,
579 S4444_alpha_D32_filter_DX,
581 // A8 treats alpha/opaque the same (equally efficient)
582 SA8_alpha_D32_nofilter_DXDY,
583 SA8_alpha_D32_nofilter_DXDY,
584 SA8_alpha_D32_nofilter_DX,
585 SA8_alpha_D32_nofilter_DX,
586 SA8_alpha_D32_filter_DXDY,
587 SA8_alpha_D32_filter_DXDY,
588 SA8_alpha_D32_filter_DX,
589 SA8_alpha_D32_filter_DX
592 static const SampleProc16 gSkBitmapProcStateSample16[] = {
593 S32_D16_nofilter_DXDY,
598 S16_D16_nofilter_DXDY,
603 SI8_D16_nofilter_DXDY,
608 // Don't support 4444 -> 565
609 NULL, NULL, NULL, NULL,
610 // Don't support A8 -> 565
611 NULL, NULL, NULL, NULL
615 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
616 index >>= 1; // shift away any opaque/alpha distinction
617 fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
619 // our special-case shaderprocs
620 if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
622 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
623 } else if (SkShader::kRepeat_TileMode == fTileModeX &&
624 SkShader::kRepeat_TileMode == fTileModeY) {
625 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
627 } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
628 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
631 if (NULL == fShaderProc32) {
632 fShaderProc32 = this->chooseShaderProc32();
636 // see if our platform has any accelerated overrides
637 this->platformProcs();
642 static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
644 SkPMColor* SK_RESTRICT colors,
646 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
647 SkASSERT(s.fInvKy == 0);
648 SkASSERT(count > 0 && colors != NULL);
649 SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
651 const int maxX = s.fBitmap->width() - 1;
652 const int maxY = s.fBitmap->height() - 1;
653 int ix = s.fFilterOneX + x;
654 int iy = SkClampMax(s.fFilterOneY + y, maxY);
658 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
659 SkIntToScalar(y) + SK_ScalarHalf, &pt);
660 int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
661 int ix2 = SkScalarFloorToInt(pt.fX);
667 const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
671 int n = SkMin32(-ix, count);
672 sk_memset32(colors, row[0], n);
683 int n = SkMin32(maxX - ix + 1, count);
684 memcpy(colors, row + ix, n * sizeof(SkPMColor));
692 // clamp to the right
693 sk_memset32(colors, row[maxX], count);
696 static inline int sk_int_mod(int x, int n) {
698 if ((unsigned)x >= (unsigned)n) {
708 static inline int sk_int_mirror(int x, int n) {
709 x = sk_int_mod(x, 2 * n);
716 static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
718 SkPMColor* SK_RESTRICT colors,
720 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
721 SkASSERT(s.fInvKy == 0);
722 SkASSERT(count > 0 && colors != NULL);
723 SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
725 const int stopX = s.fBitmap->width();
726 const int stopY = s.fBitmap->height();
727 int ix = s.fFilterOneX + x;
728 int iy = sk_int_mod(s.fFilterOneY + y, stopY);
732 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
733 SkIntToScalar(y) + SK_ScalarHalf, &pt);
734 int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
735 int ix2 = SkScalarFloorToInt(pt.fX);
741 const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
743 ix = sk_int_mod(ix, stopX);
745 int n = SkMin32(stopX - ix, count);
746 memcpy(colors, row + ix, n * sizeof(SkPMColor));
756 static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
758 SkPMColor* SK_RESTRICT colors,
760 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
761 SkASSERT(s.fInvKy == 0);
762 SkASSERT(count > 0 && colors != NULL);
763 SkASSERT(1 == s.fBitmap->width());
766 int iY1 SK_INIT_TO_AVOID_WARNING;
767 int iSubY SK_INIT_TO_AVOID_WARNING;
769 if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
770 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
773 mproc(s, xy, 1, x, y);
776 iY1 = xy[0] & 0x3FFF;
777 iSubY = (xy[0] >> 14) & 0xF;
781 if (s.fInvType > SkMatrix::kTranslate_Mask) {
783 s.fInvProc(s.fInvMatrix,
784 SkIntToScalar(x) + SK_ScalarHalf,
785 SkIntToScalar(y) + SK_ScalarHalf,
787 // When the matrix has a scale component the setup code in
788 // chooseProcs multiples the inverse matrix by the inverse of the
789 // bitmap's width and height. Since this method is going to do
790 // its own tiling and sampling we need to undo that here.
791 if (SkShader::kClamp_TileMode != s.fTileModeX ||
792 SkShader::kClamp_TileMode != s.fTileModeY) {
793 yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
795 yTemp = SkScalarFloorToInt(pt.fY);
798 yTemp = s.fFilterOneY + y;
801 const int stopY = s.fBitmap->height();
802 switch (s.fTileModeY) {
803 case SkShader::kClamp_TileMode:
804 iY0 = SkClampMax(yTemp, stopY-1);
806 case SkShader::kRepeat_TileMode:
807 iY0 = sk_int_mod(yTemp, stopY);
809 case SkShader::kMirror_TileMode:
811 iY0 = sk_int_mirror(yTemp, stopY);
818 s.fInvProc(s.fInvMatrix,
819 SkIntToScalar(x) + SK_ScalarHalf,
820 SkIntToScalar(y) + SK_ScalarHalf,
822 if (s.fInvType > SkMatrix::kTranslate_Mask &&
823 (SkShader::kClamp_TileMode != s.fTileModeX ||
824 SkShader::kClamp_TileMode != s.fTileModeY)) {
825 pt.fY *= s.fBitmap->height();
829 switch (s.fTileModeY) {
830 case SkShader::kClamp_TileMode:
831 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
833 case SkShader::kRepeat_TileMode:
834 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
836 case SkShader::kMirror_TileMode:
838 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
842 SkASSERT(iY0 == iY2);
847 const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
850 if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
851 const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
853 if (s.fAlphaScale < 256) {
854 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
856 Filter_32_opaque(iSubY, *row0, *row1, &color);
859 if (s.fAlphaScale < 256) {
860 color = SkAlphaMulQ(*row0, s.fAlphaScale);
866 sk_memset32(colors, color, count);
869 static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
870 SkPMColor* SK_RESTRICT colors, int count) {
871 // if we get called, the matrix is too tricky, so we just draw nothing
872 sk_memset32(colors, 0, count);
875 bool SkBitmapProcState::setupForTranslate() {
877 fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
880 * if the translate is larger than our ints, we can get random results, or
881 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't
884 const SkScalar too_big = SkIntToScalar(1 << 30);
885 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
889 // Since we know we're not filtered, we re-purpose these fields allow
890 // us to go from device -> src coordinates w/ just an integer add,
891 // rather than running through the inverse-matrix
892 fFilterOneX = SkScalarFloorToInt(pt.fX);
893 fFilterOneY = SkScalarFloorToInt(pt.fY);
897 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
899 if (kN32_SkColorType != fBitmap->colorType()) {
903 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
905 if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
906 if (SkPaint::kNone_FilterLevel == fFilterLevel &&
907 fInvType <= SkMatrix::kTranslate_Mask &&
908 !this->setupForTranslate()) {
909 return DoNothing_shaderproc;
911 return S32_D32_constX_shaderproc;
914 if (fAlphaScale < 256) {
917 if (fInvType > SkMatrix::kTranslate_Mask) {
920 if (SkPaint::kNone_FilterLevel != fFilterLevel) {
924 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
925 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
927 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
928 if (this->setupForTranslate()) {
929 return Clamp_S32_D32_nofilter_trans_shaderproc;
931 return DoNothing_shaderproc;
933 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
934 if (this->setupForTranslate()) {
935 return Repeat_S32_D32_nofilter_trans_shaderproc;
937 return DoNothing_shaderproc;
942 ///////////////////////////////////////////////////////////////////////////////
946 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
947 unsigned mx, unsigned my) {
948 unsigned y = *bitmapXY++;
951 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
952 for (int i = 0; i < count; ++i) {
953 SkASSERT(xptr[i] < mx);
957 static void check_scale_filter(uint32_t bitmapXY[], int count,
958 unsigned mx, unsigned my) {
959 uint32_t YY = *bitmapXY++;
960 unsigned y0 = YY >> 18;
961 unsigned y1 = YY & 0x3FFF;
965 for (int i = 0; i < count; ++i) {
966 uint32_t XX = bitmapXY[i];
967 unsigned x0 = XX >> 18;
968 unsigned x1 = XX & 0x3FFF;
974 static void check_affine_nofilter(uint32_t bitmapXY[], int count,
975 unsigned mx, unsigned my) {
976 for (int i = 0; i < count; ++i) {
977 uint32_t XY = bitmapXY[i];
978 unsigned x = XY & 0xFFFF;
979 unsigned y = XY >> 16;
985 static void check_affine_filter(uint32_t bitmapXY[], int count,
986 unsigned mx, unsigned my) {
987 for (int i = 0; i < count; ++i) {
988 uint32_t YY = *bitmapXY++;
989 unsigned y0 = YY >> 18;
990 unsigned y1 = YY & 0x3FFF;
994 uint32_t XX = *bitmapXY++;
995 unsigned x0 = XX >> 18;
996 unsigned x1 = XX & 0x3FFF;
1002 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
1003 uint32_t bitmapXY[], int count,
1006 SkASSERT(count > 0);
1008 state.fMatrixProc(state, bitmapXY, count, x, y);
1010 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
1012 // There are four formats possible:
1013 // scale -vs- affine
1014 // filter -vs- nofilter
1015 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
1016 proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_scale_filter : check_scale_nofilter;
1018 proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter;
1020 proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
1023 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
1024 return DebugMatrixProc;
1029 ///////////////////////////////////////////////////////////////////////////////
1031 The storage requirements for the different matrix procs are as follows,
1032 where each X or Y is 2 bytes, and N is the number of pixels/elements:
1034 scale/translate nofilter Y(4bytes) + N * X
1035 affine/perspective nofilter N * (X Y)
1036 scale/translate filter Y Y + N * (X X)
1037 affine/perspective filter N * (Y Y X X)
1039 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
1040 int32_t size = static_cast<int32_t>(bufferSize);
1042 size &= ~3; // only care about 4-byte aligned chunks
1043 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
1044 size -= 4; // the shared Y (or YY) coordinate
1053 if (fFilterLevel != SkPaint::kNone_FilterLevel) {