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