2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkBitmapCache.h"
9 #include "SkBitmapProcState.h"
10 #include "SkColorPriv.h"
11 #include "SkFilterProc.h"
13 #include "SkShader.h" // for tilemodes
14 #include "SkUtilsArm.h"
15 #include "SkBitmapScaler.h"
17 #include "SkPixelRef.h"
18 #include "SkImageEncoder.h"
19 #include "SkResourceCache.h"
21 #if !SK_ARM_NEON_IS_NONE
22 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
23 extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
24 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
25 extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
26 extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
27 extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
28 extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
29 extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
30 extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
33 extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState&, int, int, uint32_t*, int);
35 #define NAME_WRAP(x) x
36 #include "SkBitmapProcState_filter.h"
37 #include "SkBitmapProcState_procs.h"
39 ///////////////////////////////////////////////////////////////////////////////
41 // true iff the matrix contains, at most, scale and translate elements
42 static bool matrix_only_scale_translate(const SkMatrix& m) {
43 return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
47 * For the purposes of drawing bitmaps, if a matrix is "almost" translate
48 * go ahead and treat it as if it were, so that subsequent code can go fast.
50 static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
51 SkASSERT(matrix_only_scale_translate(matrix));
53 if (matrix.getType() & SkMatrix::kScale_Mask) {
55 bitmap.getBounds(&src);
57 // Can't call mapRect(), since that will fix up inverted rectangles,
58 // e.g. when scale is negative, and we don't want to return true for
60 matrix.mapPoints(SkTCast<SkPoint*>(&dst),
61 SkTCast<const SkPoint*>(&src),
64 // Now round all 4 edges to device space, and then compare the device
65 // width/height to the original. Note: we must map all 4 and subtract
66 // rather than map the "width" and compare, since we care about the
67 // phase (in pixel space) that any translate in the matrix might impart.
70 return idst.width() == bitmap.width() && idst.height() == bitmap.height();
72 // if we got here, we're either kTranslate_Mask or identity
76 static bool just_trans_general(const SkMatrix& matrix) {
77 SkASSERT(matrix_only_scale_translate(matrix));
79 if (matrix.getType() & SkMatrix::kScale_Mask) {
80 const SkScalar tol = SK_Scalar1 / 32768;
82 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
85 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
89 // if we got here, treat us as either kTranslate_Mask or identity
93 ///////////////////////////////////////////////////////////////////////////////
95 static bool valid_for_filtering(unsigned dimension) {
96 // for filtering, width and height must fit in 14bits, since we use steal
97 // 2 bits from each to store our 4bit subpixel data
98 return (dimension & ~0x3FFF) == 0;
101 static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) {
104 v1.fX = mat.getScaleX();
105 v1.fY = mat.getSkewY();
107 v2.fX = mat.getSkewX();
108 v2.fY = mat.getScaleY();
110 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
113 // Check to see that the size of the bitmap that would be produced by
114 // scaling by the given inverted matrix is less than the maximum allowed.
115 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
116 size_t maximumAllocation = SkResourceCache::GetSingleAllocationByteLimit();
117 if (0 == maximumAllocation) {
120 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
121 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
122 // Skip the division step:
123 return bm.info().getSafeSize(bm.info().minRowBytes())
124 < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
127 // TODO -- we may want to pass the clip into this function so we only scale
128 // the portion of the image that we're going to need. This will complicate
129 // the interface to the cache, but might be well worth it.
131 bool SkBitmapProcState::possiblyScaleImage() {
132 SkASSERT(NULL == fBitmap);
134 if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
137 // Check to see if the transformation matrix is simple, and if we're
138 // doing high quality scaling. If so, do the bitmap scale here and
139 // remove the (non-fractional) scaling component from the matrix.
141 SkScalar invScaleX = fInvMatrix.getScaleX();
142 SkScalar invScaleY = fInvMatrix.getScaleY();
144 float trueDestWidth = fOrigBitmap.width() / invScaleX;
145 float trueDestHeight = fOrigBitmap.height() / invScaleY;
147 float roundedDestWidth = SkScalarRoundToScalar(trueDestWidth);
148 float roundedDestHeight = SkScalarRoundToScalar(trueDestHeight);
150 if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
151 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
152 kN32_SkColorType == fOrigBitmap.colorType() &&
153 cache_size_okay(fOrigBitmap, fInvMatrix)) {
155 if (SkScalarNearlyEqual(invScaleX,1.0f) &&
156 SkScalarNearlyEqual(invScaleY,1.0f)) {
157 // short-circuit identity scaling; the output is supposed to
158 // be the same as the input, so we might as well go fast.
160 // Note(humper): We could also probably do this if the scales
161 // are close to -1 as well, since the flip doesn't require
162 // any fancy re-sampling...
164 // Set our filter level to low -- the only post-filtering this
165 // image might require is some interpolation if the translation
167 fFilterLevel = SkPaint::kLow_FilterLevel;
171 if (!SkBitmapCache::Find(fOrigBitmap, roundedDestWidth, roundedDestHeight, &fScaledBitmap)) {
172 // All the criteria are met; let's make a new bitmap.
174 if (!SkBitmapScaler::Resize(&fScaledBitmap,
176 SkBitmapScaler::RESIZE_BEST,
179 SkResourceCache::GetAllocator())) {
180 // we failed to create fScaledBitmap, so just return and let
181 // the scanline proc handle it.
186 SkASSERT(fScaledBitmap.getPixels());
187 fScaledBitmap.setImmutable();
188 SkBitmapCache::Add(fOrigBitmap, roundedDestWidth, roundedDestHeight, fScaledBitmap);
191 SkASSERT(fScaledBitmap.getPixels());
192 fBitmap = &fScaledBitmap;
194 // clean up the inverse matrix by incorporating the scale we just performed.
196 fInvMatrix.postScale(roundedDestWidth / fOrigBitmap.width(),
197 roundedDestHeight / fOrigBitmap.height());
199 // Set our filter level to low -- the only post-filtering this
200 // image might require is some interpolation if the translation
201 // is fractional or if there's any remaining scaling to be done.
202 fFilterLevel = SkPaint::kLow_FilterLevel;
207 * If High, then our special-case for scale-only did not take, and so we
208 * have to make a choice:
209 * 1. fall back on mipmaps + bilerp
210 * 2. fall back on scanline bicubic filter
211 * For now, we compute the "scale" value from the matrix, and have a
212 * threshold to decide when bicubic is better, and when mips are better.
213 * No doubt a fancier decision tree could be used uere.
215 * If Medium, then we just try to build a mipmap and select a level,
216 * setting the filter-level to kLow to signal that we just need bilerp
217 * to process the selected level.
220 SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
222 if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
223 // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller
224 // than this, then the mipmaps quality may be greater (certainly faster)
225 // so we only keep High quality if the scale is greater than this.
227 // Since we're dealing with the inverse, we compare against its inverse.
228 const SkScalar bicubicLimit = 4.0f;
229 const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit;
230 if (scaleSqd < bicubicLimitSqd) { // use bicubic scanline
234 // else set the filter-level to Medium, since we're scaling down and
235 // want to reqeust mipmaps
236 fFilterLevel = SkPaint::kMedium_FilterLevel;
239 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
242 * Medium quality means use a mipmap for down-scaling, and just bilper
243 * for upscaling. Since we're examining the inverse matrix, we look for
244 * a scale > 1 to indicate down scaling by the CTM.
246 if (scaleSqd > SK_Scalar1) {
247 fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap));
248 if (NULL == fCurrMip.get()) {
249 fCurrMip.reset(SkMipMapCache::AddAndRef(fOrigBitmap));
250 if (NULL == fCurrMip.get()) {
254 // diagnostic for a crasher...
255 if (NULL == fCurrMip->data()) {
259 SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd));
260 SkMipMap::Level level;
261 if (fCurrMip->extractLevel(levelScale, &level)) {
262 SkScalar invScaleFixup = level.fScale;
263 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
265 const SkImageInfo info = fOrigBitmap.info().makeWH(level.fWidth, level.fHeight);
266 // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
267 // that here, and not need to explicitly track it ourselves.
268 fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes);
269 fBitmap = &fScaledBitmap;
270 fFilterLevel = SkPaint::kLow_FilterLevel;
273 // failed to extract, so release the mipmap
274 fCurrMip.reset(NULL);
281 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) {
282 SkPixelRef* pr = src.pixelRef();
283 if (pr && pr->decodeInto(pow2, dst)) {
288 * If decodeInto() fails, it is possibe that we have an old subclass that
289 * does not, or cannot, implement that. In that case we fall back to the
290 * older protocol of having the pixelRef handle the caching for us.
294 return SkToBool(dst->getPixels());
297 bool SkBitmapProcState::lockBaseBitmap() {
298 SkPixelRef* pr = fOrigBitmap.pixelRef();
300 if (pr->isLocked() || !pr->implementsDecodeInto()) {
301 // fast-case, no need to look in our cache
302 fScaledBitmap = fOrigBitmap;
303 fScaledBitmap.lockPixels();
304 if (NULL == fScaledBitmap.getPixels()) {
308 if (!SkBitmapCache::Find(fOrigBitmap, 1, 1, &fScaledBitmap)) {
309 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) {
313 // TODO: if fScaled comes back at a different width/height than fOrig,
314 // we need to update the matrix we are using to sample from this guy.
316 SkBitmapCache::Add(fOrigBitmap, 1, 1, fScaledBitmap);
319 fBitmap = &fScaledBitmap;
323 SkBitmapProcState::~SkBitmapProcState() {
324 SkDELETE(fBitmapFilter);
327 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
328 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());
332 fFilterLevel = paint.getFilterLevel();
334 // possiblyScaleImage will look to see if it can rescale the image as a
335 // preprocess; either by scaling up to the target size, or by selecting
336 // a nearby mipmap level. If it does, it will adjust the working
337 // matrix as well as the working bitmap. It may also adjust the filter
338 // quality to avoid re-filtering an already perfectly scaled image.
339 if (!this->possiblyScaleImage()) {
340 if (!this->lockBaseBitmap()) {
344 // The above logic should have always assigned fBitmap, but in case it
345 // didn't, we check for that now...
346 // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)?
347 if (NULL == fBitmap) {
351 // If we are "still" kMedium_FilterLevel, then the request was not fulfilled by possiblyScale,
352 // so we downgrade to kLow (so the rest of the sniffing code can assume that)
353 if (SkPaint::kMedium_FilterLevel == fFilterLevel) {
354 fFilterLevel = SkPaint::kLow_FilterLevel;
357 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
358 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
359 SkShader::kClamp_TileMode == fTileModeY;
361 // Most of the scanline procs deal with "unit" texture coordinates, as this
362 // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate
363 // those, we divide the matrix by its dimensions here.
365 // We don't do this if we're either trivial (can ignore the matrix) or clamping
366 // in both X and Y since clamping to width,height is just as easy as to 0xFFFF.
368 if (!(clampClamp || trivialMatrix)) {
369 fInvMatrix.postIDiv(fBitmap->width(), fBitmap->height());
372 // Now that all possible changes to the matrix have taken place, check
373 // to see if we're really close to a no-scale matrix. If so, explicitly
374 // set it to be so. Subsequent code may inspect this matrix to choose
375 // a faster path in this case.
377 // This code will only execute if the matrix has some scale component;
378 // if it's already pure translate then we won't do this inversion.
380 if (matrix_only_scale_translate(fInvMatrix)) {
382 if (fInvMatrix.invert(&forward)) {
383 if (clampClamp ? just_trans_clamp(forward, *fBitmap)
384 : just_trans_general(forward)) {
385 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
386 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
387 fInvMatrix.setTranslate(tx, ty);
392 fInvProc = fInvMatrix.getMapXYProc();
393 fInvType = fInvMatrix.getType();
394 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX());
395 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
396 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY());
397 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
399 fAlphaScale = SkAlpha255To256(paint.getAlpha());
401 fShaderProc32 = NULL;
402 fShaderProc16 = NULL;
403 fSampleProc32 = NULL;
404 fSampleProc16 = NULL;
406 // recompute the triviality of the matrix here because we may have
409 trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
411 if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
412 // If this is still set, that means we wanted HQ sampling
413 // but couldn't do it as a preprocess. Let's try to install
414 // the scanline version of the HQ sampler. If that process fails,
415 // downgrade to bilerp.
417 // NOTE: Might need to be careful here in the future when we want
418 // to have the platform proc have a shot at this; it's possible that
419 // the chooseBitmapFilterProc will fail to install a shader but a
420 // platform-specific one might succeed, so it might be premature here
421 // to fall back to bilerp. This needs thought.
423 if (!this->setBitmapFilterProcs()) {
424 fFilterLevel = SkPaint::kLow_FilterLevel;
428 if (SkPaint::kLow_FilterLevel == fFilterLevel) {
429 // Only try bilerp if the matrix is "interesting" and
430 // the image has a suitable size.
432 if (fInvType <= SkMatrix::kTranslate_Mask ||
433 !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
434 fFilterLevel = SkPaint::kNone_FilterLevel;
438 // At this point, we know exactly what kind of sampling the per-scanline
439 // shader will perform.
441 fMatrixProc = this->chooseMatrixProc(trivialMatrix);
442 // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
443 if (NULL == fMatrixProc) {
447 ///////////////////////////////////////////////////////////////////////
449 const SkAlphaType at = fBitmap->alphaType();
451 // No need to do this if we're doing HQ sampling; if filter quality is
452 // still set to HQ by the time we get here, then we must have installed
453 // the shader procs above and can skip all this.
455 if (fFilterLevel < SkPaint::kHigh_FilterLevel) {
458 if (fAlphaScale < 256) { // note: this distinction is not used for D16
461 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
464 if (fFilterLevel > SkPaint::kNone_FilterLevel) {
467 // bits 3,4,5 encoding the source bitmap format
468 switch (fBitmap->colorType()) {
469 case kN32_SkColorType:
470 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
475 case kRGB_565_SkColorType:
478 case kIndex_8_SkColorType:
479 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
484 case kARGB_4444_SkColorType:
485 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
490 case kAlpha_8_SkColorType:
492 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
495 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
499 #if !SK_ARM_NEON_IS_ALWAYS
500 static const SampleProc32 gSkBitmapProcStateSample32[] = {
501 S32_opaque_D32_nofilter_DXDY,
502 S32_alpha_D32_nofilter_DXDY,
503 S32_opaque_D32_nofilter_DX,
504 S32_alpha_D32_nofilter_DX,
505 S32_opaque_D32_filter_DXDY,
506 S32_alpha_D32_filter_DXDY,
507 S32_opaque_D32_filter_DX,
508 S32_alpha_D32_filter_DX,
510 S16_opaque_D32_nofilter_DXDY,
511 S16_alpha_D32_nofilter_DXDY,
512 S16_opaque_D32_nofilter_DX,
513 S16_alpha_D32_nofilter_DX,
514 S16_opaque_D32_filter_DXDY,
515 S16_alpha_D32_filter_DXDY,
516 S16_opaque_D32_filter_DX,
517 S16_alpha_D32_filter_DX,
519 SI8_opaque_D32_nofilter_DXDY,
520 SI8_alpha_D32_nofilter_DXDY,
521 SI8_opaque_D32_nofilter_DX,
522 SI8_alpha_D32_nofilter_DX,
523 SI8_opaque_D32_filter_DXDY,
524 SI8_alpha_D32_filter_DXDY,
525 SI8_opaque_D32_filter_DX,
526 SI8_alpha_D32_filter_DX,
528 S4444_opaque_D32_nofilter_DXDY,
529 S4444_alpha_D32_nofilter_DXDY,
530 S4444_opaque_D32_nofilter_DX,
531 S4444_alpha_D32_nofilter_DX,
532 S4444_opaque_D32_filter_DXDY,
533 S4444_alpha_D32_filter_DXDY,
534 S4444_opaque_D32_filter_DX,
535 S4444_alpha_D32_filter_DX,
537 // A8 treats alpha/opaque the same (equally efficient)
538 SA8_alpha_D32_nofilter_DXDY,
539 SA8_alpha_D32_nofilter_DXDY,
540 SA8_alpha_D32_nofilter_DX,
541 SA8_alpha_D32_nofilter_DX,
542 SA8_alpha_D32_filter_DXDY,
543 SA8_alpha_D32_filter_DXDY,
544 SA8_alpha_D32_filter_DX,
545 SA8_alpha_D32_filter_DX
548 static const SampleProc16 gSkBitmapProcStateSample16[] = {
549 S32_D16_nofilter_DXDY,
554 S16_D16_nofilter_DXDY,
559 SI8_D16_nofilter_DXDY,
564 // Don't support 4444 -> 565
565 NULL, NULL, NULL, NULL,
566 // Don't support A8 -> 565
567 NULL, NULL, NULL, NULL
571 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
572 index >>= 1; // shift away any opaque/alpha distinction
573 fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
575 // our special-case shaderprocs
576 if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
578 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
579 } else if (SkShader::kRepeat_TileMode == fTileModeX &&
580 SkShader::kRepeat_TileMode == fTileModeY) {
581 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
583 } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
584 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
585 } else if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) {
586 fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc;
589 if (NULL == fShaderProc32) {
590 fShaderProc32 = this->chooseShaderProc32();
594 // see if our platform has any accelerated overrides
595 this->platformProcs();
600 static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
602 SkPMColor* SK_RESTRICT colors,
604 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
605 SkASSERT(s.fInvKy == 0);
606 SkASSERT(count > 0 && colors != NULL);
607 SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
609 const int maxX = s.fBitmap->width() - 1;
610 const int maxY = s.fBitmap->height() - 1;
611 int ix = s.fFilterOneX + x;
612 int iy = SkClampMax(s.fFilterOneY + y, maxY);
616 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
617 SkIntToScalar(y) + SK_ScalarHalf, &pt);
618 int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
619 int ix2 = SkScalarFloorToInt(pt.fX);
625 const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
629 int n = SkMin32(-ix, count);
630 sk_memset32(colors, row[0], n);
641 int n = SkMin32(maxX - ix + 1, count);
642 memcpy(colors, row + ix, n * sizeof(SkPMColor));
650 // clamp to the right
651 sk_memset32(colors, row[maxX], count);
654 static inline int sk_int_mod(int x, int n) {
656 if ((unsigned)x >= (unsigned)n) {
666 static inline int sk_int_mirror(int x, int n) {
667 x = sk_int_mod(x, 2 * n);
674 static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
676 SkPMColor* SK_RESTRICT colors,
678 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
679 SkASSERT(s.fInvKy == 0);
680 SkASSERT(count > 0 && colors != NULL);
681 SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
683 const int stopX = s.fBitmap->width();
684 const int stopY = s.fBitmap->height();
685 int ix = s.fFilterOneX + x;
686 int iy = sk_int_mod(s.fFilterOneY + y, stopY);
690 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
691 SkIntToScalar(y) + SK_ScalarHalf, &pt);
692 int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
693 int ix2 = SkScalarFloorToInt(pt.fX);
699 const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
701 ix = sk_int_mod(ix, stopX);
703 int n = SkMin32(stopX - ix, count);
704 memcpy(colors, row + ix, n * sizeof(SkPMColor));
714 static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
716 SkPMColor* SK_RESTRICT colors,
718 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
719 SkASSERT(s.fInvKy == 0);
720 SkASSERT(count > 0 && colors != NULL);
721 SkASSERT(1 == s.fBitmap->width());
724 int iY1 SK_INIT_TO_AVOID_WARNING;
725 int iSubY SK_INIT_TO_AVOID_WARNING;
727 if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
728 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
731 mproc(s, xy, 1, x, y);
734 iY1 = xy[0] & 0x3FFF;
735 iSubY = (xy[0] >> 14) & 0xF;
739 if (s.fInvType > SkMatrix::kTranslate_Mask) {
741 s.fInvProc(s.fInvMatrix,
742 SkIntToScalar(x) + SK_ScalarHalf,
743 SkIntToScalar(y) + SK_ScalarHalf,
745 // When the matrix has a scale component the setup code in
746 // chooseProcs multiples the inverse matrix by the inverse of the
747 // bitmap's width and height. Since this method is going to do
748 // its own tiling and sampling we need to undo that here.
749 if (SkShader::kClamp_TileMode != s.fTileModeX ||
750 SkShader::kClamp_TileMode != s.fTileModeY) {
751 yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
753 yTemp = SkScalarFloorToInt(pt.fY);
756 yTemp = s.fFilterOneY + y;
759 const int stopY = s.fBitmap->height();
760 switch (s.fTileModeY) {
761 case SkShader::kClamp_TileMode:
762 iY0 = SkClampMax(yTemp, stopY-1);
764 case SkShader::kRepeat_TileMode:
765 iY0 = sk_int_mod(yTemp, stopY);
767 case SkShader::kMirror_TileMode:
769 iY0 = sk_int_mirror(yTemp, stopY);
776 s.fInvProc(s.fInvMatrix,
777 SkIntToScalar(x) + SK_ScalarHalf,
778 SkIntToScalar(y) + SK_ScalarHalf,
780 if (s.fInvType > SkMatrix::kTranslate_Mask &&
781 (SkShader::kClamp_TileMode != s.fTileModeX ||
782 SkShader::kClamp_TileMode != s.fTileModeY)) {
783 pt.fY *= s.fBitmap->height();
787 switch (s.fTileModeY) {
788 case SkShader::kClamp_TileMode:
789 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
791 case SkShader::kRepeat_TileMode:
792 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
794 case SkShader::kMirror_TileMode:
796 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
800 SkASSERT(iY0 == iY2);
805 const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
808 if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
809 const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
811 if (s.fAlphaScale < 256) {
812 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
814 Filter_32_opaque(iSubY, *row0, *row1, &color);
817 if (s.fAlphaScale < 256) {
818 color = SkAlphaMulQ(*row0, s.fAlphaScale);
824 sk_memset32(colors, color, count);
827 static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
828 SkPMColor* SK_RESTRICT colors, int count) {
829 // if we get called, the matrix is too tricky, so we just draw nothing
830 sk_memset32(colors, 0, count);
833 bool SkBitmapProcState::setupForTranslate() {
835 fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
838 * if the translate is larger than our ints, we can get random results, or
839 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't
842 const SkScalar too_big = SkIntToScalar(1 << 30);
843 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
847 // Since we know we're not filtered, we re-purpose these fields allow
848 // us to go from device -> src coordinates w/ just an integer add,
849 // rather than running through the inverse-matrix
850 fFilterOneX = SkScalarFloorToInt(pt.fX);
851 fFilterOneY = SkScalarFloorToInt(pt.fY);
855 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
857 if (kN32_SkColorType != fBitmap->colorType()) {
861 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
863 if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
864 if (SkPaint::kNone_FilterLevel == fFilterLevel &&
865 fInvType <= SkMatrix::kTranslate_Mask &&
866 !this->setupForTranslate()) {
867 return DoNothing_shaderproc;
869 return S32_D32_constX_shaderproc;
872 if (fAlphaScale < 256) {
875 if (fInvType > SkMatrix::kTranslate_Mask) {
878 if (SkPaint::kNone_FilterLevel != fFilterLevel) {
882 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
883 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
885 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
886 if (this->setupForTranslate()) {
887 return Clamp_S32_D32_nofilter_trans_shaderproc;
889 return DoNothing_shaderproc;
891 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
892 if (this->setupForTranslate()) {
893 return Repeat_S32_D32_nofilter_trans_shaderproc;
895 return DoNothing_shaderproc;
900 ///////////////////////////////////////////////////////////////////////////////
904 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
905 unsigned mx, unsigned my) {
906 unsigned y = *bitmapXY++;
909 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
910 for (int i = 0; i < count; ++i) {
911 SkASSERT(xptr[i] < mx);
915 static void check_scale_filter(uint32_t bitmapXY[], int count,
916 unsigned mx, unsigned my) {
917 uint32_t YY = *bitmapXY++;
918 unsigned y0 = YY >> 18;
919 unsigned y1 = YY & 0x3FFF;
923 for (int i = 0; i < count; ++i) {
924 uint32_t XX = bitmapXY[i];
925 unsigned x0 = XX >> 18;
926 unsigned x1 = XX & 0x3FFF;
932 static void check_affine_nofilter(uint32_t bitmapXY[], int count,
933 unsigned mx, unsigned my) {
934 for (int i = 0; i < count; ++i) {
935 uint32_t XY = bitmapXY[i];
936 unsigned x = XY & 0xFFFF;
937 unsigned y = XY >> 16;
943 static void check_affine_filter(uint32_t bitmapXY[], int count,
944 unsigned mx, unsigned my) {
945 for (int i = 0; i < count; ++i) {
946 uint32_t YY = *bitmapXY++;
947 unsigned y0 = YY >> 18;
948 unsigned y1 = YY & 0x3FFF;
952 uint32_t XX = *bitmapXY++;
953 unsigned x0 = XX >> 18;
954 unsigned x1 = XX & 0x3FFF;
960 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
961 uint32_t bitmapXY[], int count,
966 state.fMatrixProc(state, bitmapXY, count, x, y);
968 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
970 // There are four formats possible:
972 // filter -vs- nofilter
973 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
974 proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_scale_filter : check_scale_nofilter;
976 proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter;
978 proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
981 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
982 return DebugMatrixProc;
987 ///////////////////////////////////////////////////////////////////////////////
989 The storage requirements for the different matrix procs are as follows,
990 where each X or Y is 2 bytes, and N is the number of pixels/elements:
992 scale/translate nofilter Y(4bytes) + N * X
993 affine/perspective nofilter N * (X Y)
994 scale/translate filter Y Y + N * (X X)
995 affine/perspective filter N * (Y Y X X)
997 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
998 int32_t size = static_cast<int32_t>(bufferSize);
1000 size &= ~3; // only care about 4-byte aligned chunks
1001 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
1002 size -= 4; // the shared Y (or YY) coordinate
1011 if (fFilterLevel != SkPaint::kNone_FilterLevel) {
1018 ///////////////////////
1020 void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState& s, int x, int y,
1021 SkPMColor* SK_RESTRICT dst, int count) {
1022 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
1023 SkMatrix::kScale_Mask)) == 0);
1025 const unsigned maxX = s.fBitmap->width() - 1;
1030 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf,
1032 fx = SkScalarToFractionalInt(pt.fY);
1033 const unsigned maxY = s.fBitmap->height() - 1;
1034 dstY = SkClampMax(SkFractionalIntToInt(fx), maxY);
1035 fx = SkScalarToFractionalInt(pt.fX);
1038 const SkPMColor* SK_RESTRICT src = s.fBitmap->getAddr32(0, dstY);
1039 const SkFractionalInt dx = s.fInvSxFractionalInt;
1041 // Check if we're safely inside [0...maxX] so no need to clamp each computed index.
1043 if ((uint64_t)SkFractionalIntToInt(fx) <= maxX &&
1044 (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX)
1046 int count4 = count >> 2;
1047 for (int i = 0; i < count4; ++i) {
1048 SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx;
1049 SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx;
1050 SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx;
1051 SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx;
1058 for (int i = (count4 << 2); i < count; ++i) {
1059 unsigned index = SkFractionalIntToInt(fx);
1060 SkASSERT(index <= maxX);
1061 *dst++ = src[index];
1065 for (int i = 0; i < count; ++i) {
1066 dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)];