• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "SkBitmapScaler.h"
15 #include "SkMipMap.h"
16 #include "SkPixelRef.h"
17 #include "SkScaledImageCache.h"
18 #include "SkImageEncoder.h"
19 
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);
30 #endif
31 
32 #define   NAME_WRAP(x)  x
33 #include "SkBitmapProcState_filter.h"
34 #include "SkBitmapProcState_procs.h"
35 
36 ///////////////////////////////////////////////////////////////////////////////
37 
38 // true iff the matrix contains, at most, scale and translate elements
matrix_only_scale_translate(const SkMatrix & m)39 static bool matrix_only_scale_translate(const SkMatrix& m) {
40     return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
41 }
42 
43 /**
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.
46  */
just_trans_clamp(const SkMatrix & matrix,const SkBitmap & bitmap)47 static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
48     SkASSERT(matrix_only_scale_translate(matrix));
49 
50     if (matrix.getType() & SkMatrix::kScale_Mask) {
51         SkRect src, dst;
52         bitmap.getBounds(&src);
53 
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
56         // those.
57         matrix.mapPoints(SkTCast<SkPoint*>(&dst),
58                          SkTCast<const SkPoint*>(&src),
59                          2);
60 
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.
65         SkIRect idst;
66         dst.round(&idst);
67         return idst.width() == bitmap.width() && idst.height() == bitmap.height();
68     }
69     // if we got here, we're either kTranslate_Mask or identity
70     return true;
71 }
72 
just_trans_general(const SkMatrix & matrix)73 static bool just_trans_general(const SkMatrix& matrix) {
74     SkASSERT(matrix_only_scale_translate(matrix));
75 
76     if (matrix.getType() & SkMatrix::kScale_Mask) {
77         const SkScalar tol = SK_Scalar1 / 32768;
78 
79         if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
80             return false;
81         }
82         if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
83             return false;
84         }
85     }
86     // if we got here, treat us as either kTranslate_Mask or identity
87     return true;
88 }
89 
90 ///////////////////////////////////////////////////////////////////////////////
91 
valid_for_filtering(unsigned dimension)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;
96 }
97 
effective_matrix_scale_sqrd(const SkMatrix & mat)98 static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) {
99     SkPoint v1, v2;
100 
101     v1.fX = mat.getScaleX();
102     v1.fY = mat.getSkewY();
103 
104     v2.fX = mat.getSkewX();
105     v2.fY = mat.getScaleY();
106 
107     return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
108 }
109 
110 class AutoScaledCacheUnlocker {
111 public:
AutoScaledCacheUnlocker(SkScaledImageCache::ID ** idPtr)112     AutoScaledCacheUnlocker(SkScaledImageCache::ID** idPtr) : fIDPtr(idPtr) {}
~AutoScaledCacheUnlocker()113     ~AutoScaledCacheUnlocker() {
114         if (fIDPtr && *fIDPtr) {
115             SkScaledImageCache::Unlock(*fIDPtr);
116             *fIDPtr = NULL;
117         }
118     }
119 
120     // forgets the ID, so it won't call Unlock
release()121     void release() {
122         fIDPtr = NULL;
123     }
124 
125 private:
126     SkScaledImageCache::ID** fIDPtr;
127 };
128 #define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocker)
129 
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.
cache_size_okay(const SkBitmap & bm,const SkMatrix & invMat)132 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
133     size_t maximumAllocation
134         = SkScaledImageCache::GetSingleAllocationByteLimit();
135     if (0 == maximumAllocation) {
136         return true;
137     }
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());
143 }
144 
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.
148 
possiblyScaleImage()149 bool SkBitmapProcState::possiblyScaleImage() {
150     AutoScaledCacheUnlocker unlocker(&fScaledCacheID);
151 
152     SkASSERT(NULL == fBitmap);
153     SkASSERT(NULL == fScaledCacheID);
154 
155     if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
156         return false;
157     }
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.
161 
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)) {
166 
167         SkScalar invScaleX = fInvMatrix.getScaleX();
168         SkScalar invScaleY = fInvMatrix.getScaleY();
169 
170         fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
171                                                          invScaleX, invScaleY,
172                                                          &fScaledBitmap);
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
181             }
182         }
183 
184         if (NULL == fScaledCacheID) {
185             float dest_width  = fOrigBitmap.width() / invScaleX;
186             float dest_height = fOrigBitmap.height() / invScaleY;
187 
188             // All the criteria are met; let's make a new bitmap.
189 
190             SkConvolutionProcs simd;
191             sk_bzero(&simd, sizeof(simd));
192             this->platformConvolutionProcs(&simd);
193 
194             if (!SkBitmapScaler::Resize(&fScaledBitmap,
195                                         fOrigBitmap,
196                                         SkBitmapScaler::RESIZE_BEST,
197                                         dest_width,
198                                         dest_height,
199                                         simd,
200                                         SkScaledImageCache::GetAllocator())) {
201                 // we failed to create fScaledBitmap, so just return and let
202                 // the scanline proc handle it.
203                 return false;
204 
205             }
206 
207             SkASSERT(NULL != fScaledBitmap.getPixels());
208             fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
209                                                             invScaleX,
210                                                             invScaleY,
211                                                             fScaledBitmap);
212             if (!fScaledCacheID) {
213                 fScaledBitmap.reset();
214                 return false;
215             }
216             SkASSERT(NULL != fScaledBitmap.getPixels());
217         }
218 
219         SkASSERT(NULL != fScaledBitmap.getPixels());
220         fBitmap = &fScaledBitmap;
221 
222         // set the inv matrix type to translate-only;
223         fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScaleX(),
224                                 fInvMatrix.getTranslateY() / fInvMatrix.getScaleY());
225 
226         // no need for any further filtering; we just did it!
227         fFilterLevel = SkPaint::kNone_FilterLevel;
228         unlocker.release();
229         return true;
230     }
231 
232     /*
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.
240      *
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.
244      */
245 
246     SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
247 
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.
252         //
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
257             return false;
258         }
259 
260         // else set the filter-level to Medium, since we're scaling down and
261         // want to reqeust mipmaps
262         fFilterLevel = SkPaint::kMedium_FilterLevel;
263     }
264 
265     SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
266 
267     /**
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.
271      */
272     if (scaleSqd > SK_Scalar1) {
273         const SkMipMap* mip = NULL;
274 
275         SkASSERT(NULL == fScaledCacheID);
276         fScaledCacheID = SkScaledImageCache::FindAndLockMip(fOrigBitmap, &mip);
277         if (!fScaledCacheID) {
278             SkASSERT(NULL == mip);
279             mip = SkMipMap::Build(fOrigBitmap);
280             if (mip) {
281                 fScaledCacheID = SkScaledImageCache::AddAndLockMip(fOrigBitmap,
282                                                                    mip);
283                 SkASSERT(mip->getRefCnt() > 1);
284                 mip->unref();   // the cache took a ref
285                 SkASSERT(fScaledCacheID);
286             }
287         } else {
288             SkASSERT(mip);
289         }
290 
291         if (mip) {
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);
297 
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;
304                 unlocker.release();
305                 return true;
306             }
307         }
308     }
309 
310     return false;
311 }
312 
get_locked_pixels(const SkBitmap & src,int pow2,SkBitmap * dst)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)) {
316         return true;
317     }
318 
319     /*
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.
323      */
324     *dst = src;
325     dst->lockPixels();
326     return SkToBool(dst->getPixels());
327 }
328 
lockBaseBitmap()329 bool SkBitmapProcState::lockBaseBitmap() {
330     AutoScaledCacheUnlocker unlocker(&fScaledCacheID);
331 
332     SkPixelRef* pr = fOrigBitmap.pixelRef();
333 
334     SkASSERT(NULL == fScaledCacheID);
335 
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()) {
341             return false;
342         }
343     } else {
344         fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
345                                                          SK_Scalar1, SK_Scalar1,
346                                                          &fScaledBitmap);
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
355             }
356         }
357 
358         if (NULL == fScaledCacheID) {
359             if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) {
360                 return false;
361             }
362 
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.
365 
366             fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
367                                                             SK_Scalar1, SK_Scalar1,
368                                                             fScaledBitmap);
369             if (!fScaledCacheID) {
370                 fScaledBitmap.reset();
371                 return false;
372             }
373         }
374     }
375     fBitmap = &fScaledBitmap;
376     unlocker.release();
377     return true;
378 }
379 
~SkBitmapProcState()380 SkBitmapProcState::~SkBitmapProcState() {
381     if (fScaledCacheID) {
382         SkScaledImageCache::Unlock(fScaledCacheID);
383     }
384     SkDELETE(fBitmapFilter);
385 }
386 
chooseProcs(const SkMatrix & inv,const SkPaint & paint)387 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
388     SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());
389 
390     fBitmap = NULL;
391     fInvMatrix = inv;
392     fFilterLevel = paint.getFilterLevel();
393 
394     SkASSERT(NULL == fScaledCacheID);
395 
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()) {
403             return false;
404         }
405     }
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) {
410         return false;
411     }
412 
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;
417     }
418 
419     bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
420     bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
421                       SkShader::kClamp_TileMode == fTileModeY;
422 
423     if (!(clampClamp || trivialMatrix)) {
424         fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
425     }
426 
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.
431 
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.
434 
435     if (matrix_only_scale_translate(fInvMatrix)) {
436         SkMatrix forward;
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);
443             }
444         }
445     }
446 
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());
453 
454     fAlphaScale = SkAlpha255To256(paint.getAlpha());
455 
456     fShaderProc32 = NULL;
457     fShaderProc16 = NULL;
458     fSampleProc32 = NULL;
459     fSampleProc16 = NULL;
460 
461     // recompute the triviality of the matrix here because we may have
462     // changed it!
463 
464     trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
465 
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.
471 
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.
477 
478         if (!this->setBitmapFilterProcs()) {
479             fFilterLevel = SkPaint::kLow_FilterLevel;
480         }
481     }
482 
483     if (SkPaint::kLow_FilterLevel == fFilterLevel) {
484         // Only try bilerp if the matrix is "interesting" and
485         // the image has a suitable size.
486 
487         if (fInvType <= SkMatrix::kTranslate_Mask ||
488                 !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
489             fFilterLevel = SkPaint::kNone_FilterLevel;
490         }
491     }
492 
493     // At this point, we know exactly what kind of sampling the per-scanline
494     // shader will perform.
495 
496     fMatrixProc = this->chooseMatrixProc(trivialMatrix);
497     // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
498     if (NULL == fMatrixProc) {
499         return false;
500     }
501 
502     ///////////////////////////////////////////////////////////////////////
503 
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.
507 
508     if (fFilterLevel < SkPaint::kHigh_FilterLevel) {
509 
510         int index = 0;
511         if (fAlphaScale < 256) {  // note: this distinction is not used for D16
512             index |= 1;
513         }
514         if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
515             index |= 2;
516         }
517         if (fFilterLevel > SkPaint::kNone_FilterLevel) {
518             index |= 4;
519         }
520         // bits 3,4,5 encoding the source bitmap format
521         switch (fBitmap->colorType()) {
522             case kN32_SkColorType:
523                 index |= 0;
524                 break;
525             case kRGB_565_SkColorType:
526                 index |= 8;
527                 break;
528             case kIndex_8_SkColorType:
529                 index |= 16;
530                 break;
531             case kARGB_4444_SkColorType:
532                 index |= 24;
533                 break;
534             case kAlpha_8_SkColorType:
535                 index |= 32;
536                 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
537                 break;
538             default:
539                 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
540                 return false;
541         }
542 
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,
553 
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,
562 
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,
571 
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,
580 
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
590         };
591 
592         static const SampleProc16 gSkBitmapProcStateSample16[] = {
593             S32_D16_nofilter_DXDY,
594             S32_D16_nofilter_DX,
595             S32_D16_filter_DXDY,
596             S32_D16_filter_DX,
597 
598             S16_D16_nofilter_DXDY,
599             S16_D16_nofilter_DX,
600             S16_D16_filter_DXDY,
601             S16_D16_filter_DX,
602 
603             SI8_D16_nofilter_DXDY,
604             SI8_D16_nofilter_DX,
605             SI8_D16_filter_DXDY,
606             SI8_D16_filter_DX,
607 
608             // Don't support 4444 -> 565
609             NULL, NULL, NULL, NULL,
610             // Don't support A8 -> 565
611             NULL, NULL, NULL, NULL
612         };
613     #endif
614 
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];
618 
619         // our special-case shaderprocs
620         if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
621             if (clampClamp) {
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);
626             }
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);
629         }
630 
631         if (NULL == fShaderProc32) {
632             fShaderProc32 = this->chooseShaderProc32();
633         }
634     }
635 
636     // see if our platform has any accelerated overrides
637     this->platformProcs();
638 
639     return true;
640 }
641 
Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)642 static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
643                                                     int x, int y,
644                                                     SkPMColor* SK_RESTRICT colors,
645                                                     int count) {
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);
650 
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);
655 #ifdef SK_DEBUG
656     {
657         SkPoint pt;
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);
662 
663         SkASSERT(iy == iy2);
664         SkASSERT(ix == ix2);
665     }
666 #endif
667     const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
668 
669     // clamp to the left
670     if (ix < 0) {
671         int n = SkMin32(-ix, count);
672         sk_memset32(colors, row[0], n);
673         count -= n;
674         if (0 == count) {
675             return;
676         }
677         colors += n;
678         SkASSERT(-ix == n);
679         ix = 0;
680     }
681     // copy the middle
682     if (ix <= maxX) {
683         int n = SkMin32(maxX - ix + 1, count);
684         memcpy(colors, row + ix, n * sizeof(SkPMColor));
685         count -= n;
686         if (0 == count) {
687             return;
688         }
689         colors += n;
690     }
691     SkASSERT(count > 0);
692     // clamp to the right
693     sk_memset32(colors, row[maxX], count);
694 }
695 
sk_int_mod(int x,int n)696 static inline int sk_int_mod(int x, int n) {
697     SkASSERT(n > 0);
698     if ((unsigned)x >= (unsigned)n) {
699         if (x < 0) {
700             x = n + ~(~x % n);
701         } else {
702             x = x % n;
703         }
704     }
705     return x;
706 }
707 
sk_int_mirror(int x,int n)708 static inline int sk_int_mirror(int x, int n) {
709     x = sk_int_mod(x, 2 * n);
710     if (x >= n) {
711         x = n + ~(x - n);
712     }
713     return x;
714 }
715 
Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)716 static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
717                                                      int x, int y,
718                                                      SkPMColor* SK_RESTRICT colors,
719                                                      int count) {
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);
724 
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);
729 #ifdef SK_DEBUG
730     {
731         SkPoint pt;
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);
736 
737         SkASSERT(iy == iy2);
738         SkASSERT(ix == ix2);
739     }
740 #endif
741     const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
742 
743     ix = sk_int_mod(ix, stopX);
744     for (;;) {
745         int n = SkMin32(stopX - ix, count);
746         memcpy(colors, row + ix, n * sizeof(SkPMColor));
747         count -= n;
748         if (0 == count) {
749             return;
750         }
751         colors += n;
752         ix = 0;
753     }
754 }
755 
S32_D32_constX_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)756 static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
757                                       int x, int y,
758                                       SkPMColor* SK_RESTRICT colors,
759                                       int count) {
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());
764 
765     int iY0;
766     int iY1   SK_INIT_TO_AVOID_WARNING;
767     int iSubY SK_INIT_TO_AVOID_WARNING;
768 
769     if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
770         SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
771         uint32_t xy[2];
772 
773         mproc(s, xy, 1, x, y);
774 
775         iY0 = xy[0] >> 18;
776         iY1 = xy[0] & 0x3FFF;
777         iSubY = (xy[0] >> 14) & 0xF;
778     } else {
779         int yTemp;
780 
781         if (s.fInvType > SkMatrix::kTranslate_Mask) {
782             SkPoint pt;
783             s.fInvProc(s.fInvMatrix,
784                        SkIntToScalar(x) + SK_ScalarHalf,
785                        SkIntToScalar(y) + SK_ScalarHalf,
786                        &pt);
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());
794             } else {
795                 yTemp = SkScalarFloorToInt(pt.fY);
796             }
797         } else {
798             yTemp = s.fFilterOneY + y;
799         }
800 
801         const int stopY = s.fBitmap->height();
802         switch (s.fTileModeY) {
803             case SkShader::kClamp_TileMode:
804                 iY0 = SkClampMax(yTemp, stopY-1);
805                 break;
806             case SkShader::kRepeat_TileMode:
807                 iY0 = sk_int_mod(yTemp, stopY);
808                 break;
809             case SkShader::kMirror_TileMode:
810             default:
811                 iY0 = sk_int_mirror(yTemp, stopY);
812                 break;
813         }
814 
815 #ifdef SK_DEBUG
816         {
817             SkPoint pt;
818             s.fInvProc(s.fInvMatrix,
819                        SkIntToScalar(x) + SK_ScalarHalf,
820                        SkIntToScalar(y) + SK_ScalarHalf,
821                        &pt);
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();
826             }
827             int iY2;
828 
829             switch (s.fTileModeY) {
830             case SkShader::kClamp_TileMode:
831                 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
832                 break;
833             case SkShader::kRepeat_TileMode:
834                 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
835                 break;
836             case SkShader::kMirror_TileMode:
837             default:
838                 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
839                 break;
840             }
841 
842             SkASSERT(iY0 == iY2);
843         }
844 #endif
845     }
846 
847     const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
848     SkPMColor color;
849 
850     if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
851         const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
852 
853         if (s.fAlphaScale < 256) {
854             Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
855         } else {
856             Filter_32_opaque(iSubY, *row0, *row1, &color);
857         }
858     } else {
859         if (s.fAlphaScale < 256) {
860             color = SkAlphaMulQ(*row0, s.fAlphaScale);
861         } else {
862             color = *row0;
863         }
864     }
865 
866     sk_memset32(colors, color, count);
867 }
868 
DoNothing_shaderproc(const SkBitmapProcState &,int x,int y,SkPMColor * SK_RESTRICT colors,int 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);
873 }
874 
setupForTranslate()875 bool SkBitmapProcState::setupForTranslate() {
876     SkPoint pt;
877     fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
878 
879     /*
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
882      *  negate it.
883      */
884     const SkScalar too_big = SkIntToScalar(1 << 30);
885     if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
886         return false;
887     }
888 
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);
894     return true;
895 }
896 
chooseShaderProc32()897 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
898 
899     if (kN32_SkColorType != fBitmap->colorType()) {
900         return NULL;
901     }
902 
903     static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
904 
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;
910         }
911         return S32_D32_constX_shaderproc;
912     }
913 
914     if (fAlphaScale < 256) {
915         return NULL;
916     }
917     if (fInvType > SkMatrix::kTranslate_Mask) {
918         return NULL;
919     }
920     if (SkPaint::kNone_FilterLevel != fFilterLevel) {
921         return NULL;
922     }
923 
924     SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
925     SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
926 
927     if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
928         if (this->setupForTranslate()) {
929             return Clamp_S32_D32_nofilter_trans_shaderproc;
930         }
931         return DoNothing_shaderproc;
932     }
933     if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
934         if (this->setupForTranslate()) {
935             return Repeat_S32_D32_nofilter_trans_shaderproc;
936         }
937         return DoNothing_shaderproc;
938     }
939     return NULL;
940 }
941 
942 ///////////////////////////////////////////////////////////////////////////////
943 
944 #ifdef SK_DEBUG
945 
check_scale_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)946 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
947                                  unsigned mx, unsigned my) {
948     unsigned y = *bitmapXY++;
949     SkASSERT(y < my);
950 
951     const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
952     for (int i = 0; i < count; ++i) {
953         SkASSERT(xptr[i] < mx);
954     }
955 }
956 
check_scale_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)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;
962     SkASSERT(y0 < my);
963     SkASSERT(y1 < my);
964 
965     for (int i = 0; i < count; ++i) {
966         uint32_t XX = bitmapXY[i];
967         unsigned x0 = XX >> 18;
968         unsigned x1 = XX & 0x3FFF;
969         SkASSERT(x0 < mx);
970         SkASSERT(x1 < mx);
971     }
972 }
973 
check_affine_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)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;
980         SkASSERT(x < mx);
981         SkASSERT(y < my);
982     }
983 }
984 
check_affine_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)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;
991         SkASSERT(y0 < my);
992         SkASSERT(y1 < my);
993 
994         uint32_t XX = *bitmapXY++;
995         unsigned x0 = XX >> 18;
996         unsigned x1 = XX & 0x3FFF;
997         SkASSERT(x0 < mx);
998         SkASSERT(x1 < mx);
999     }
1000 }
1001 
DebugMatrixProc(const SkBitmapProcState & state,uint32_t bitmapXY[],int count,int x,int y)1002 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
1003                                         uint32_t bitmapXY[], int count,
1004                                         int x, int y) {
1005     SkASSERT(bitmapXY);
1006     SkASSERT(count > 0);
1007 
1008     state.fMatrixProc(state, bitmapXY, count, x, y);
1009 
1010     void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
1011 
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;
1017     } else {
1018         proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter;
1019     }
1020     proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
1021 }
1022 
getMatrixProc() const1023 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
1024     return DebugMatrixProc;
1025 }
1026 
1027 #endif
1028 
1029 ///////////////////////////////////////////////////////////////////////////////
1030 /*
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:
1033 
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)
1038  */
maxCountForBufferSize(size_t bufferSize) const1039 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
1040     int32_t size = static_cast<int32_t>(bufferSize);
1041 
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
1045         if (size < 0) {
1046             size = 0;
1047         }
1048         size >>= 1;
1049     } else {
1050         size >>= 2;
1051     }
1052 
1053     if (fFilterLevel != SkPaint::kNone_FilterLevel) {
1054         size >>= 1;
1055     }
1056 
1057     return size;
1058 }
1059