1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkBitmapCache.h"
9 #include "SkBitmapProcState.h"
10 #include "SkColorPriv.h"
11 #include "SkFilterProc.h"
12 #include "SkPaint.h"
13 #include "SkShader.h" // for tilemodes
14 #include "SkUtilsArm.h"
15 #include "SkBitmapScaler.h"
16 #include "SkMipMap.h"
17 #include "SkPixelRef.h"
18 #include "SkImageEncoder.h"
19 #include "SkResourceCache.h"
20
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);
31 #endif
32
33 extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState&, int, int, uint32_t*, int);
34
35 #define NAME_WRAP(x) x
36 #include "SkBitmapProcState_filter.h"
37 #include "SkBitmapProcState_procs.h"
38
39 ///////////////////////////////////////////////////////////////////////////////
40
41 // true iff the matrix contains, at most, scale and translate elements
matrix_only_scale_translate(const SkMatrix & m)42 static bool matrix_only_scale_translate(const SkMatrix& m) {
43 return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
44 }
45
46 /**
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.
49 */
just_trans_clamp(const SkMatrix & matrix,const SkBitmap & bitmap)50 static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
51 SkASSERT(matrix_only_scale_translate(matrix));
52
53 if (matrix.getType() & SkMatrix::kScale_Mask) {
54 SkRect src, dst;
55 bitmap.getBounds(&src);
56
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
59 // those.
60 matrix.mapPoints(SkTCast<SkPoint*>(&dst),
61 SkTCast<const SkPoint*>(&src),
62 2);
63
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.
68 SkIRect idst;
69 dst.round(&idst);
70 return idst.width() == bitmap.width() && idst.height() == bitmap.height();
71 }
72 // if we got here, we're either kTranslate_Mask or identity
73 return true;
74 }
75
just_trans_general(const SkMatrix & matrix)76 static bool just_trans_general(const SkMatrix& matrix) {
77 SkASSERT(matrix_only_scale_translate(matrix));
78
79 if (matrix.getType() & SkMatrix::kScale_Mask) {
80 const SkScalar tol = SK_Scalar1 / 32768;
81
82 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
83 return false;
84 }
85 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
86 return false;
87 }
88 }
89 // if we got here, treat us as either kTranslate_Mask or identity
90 return true;
91 }
92
93 ///////////////////////////////////////////////////////////////////////////////
94
valid_for_filtering(unsigned dimension)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;
99 }
100
101 // Check to see that the size of the bitmap that would be produced by
102 // scaling by the given inverted matrix is less than the maximum allowed.
cache_size_okay(const SkBitmap & bm,const SkMatrix & invMat)103 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
104 size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByteLimit();
105 if (0 == maximumAllocation) {
106 return true;
107 }
108 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
109 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
110 // Skip the division step:
111 return bm.info().getSafeSize(bm.info().minRowBytes())
112 < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
113 }
114
115 /*
116 * High quality is implemented by performing up-right scale-only filtering and then
117 * using bilerp for any remaining transformations.
118 */
processHQRequest()119 void SkBitmapProcState::processHQRequest() {
120 SkASSERT(kHigh_SkFilterQuality == fFilterLevel);
121
122 // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap
123 // to a valid bitmap. If we succeed, we will set this to Low instead.
124 fFilterLevel = kMedium_SkFilterQuality;
125
126 if (kN32_SkColorType != fOrigBitmap.colorType() || !cache_size_okay(fOrigBitmap, fInvMatrix) ||
127 fInvMatrix.hasPerspective())
128 {
129 return; // can't handle the reqeust
130 }
131
132 SkScalar invScaleX = fInvMatrix.getScaleX();
133 SkScalar invScaleY = fInvMatrix.getScaleY();
134 if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
135 SkSize scale;
136 if (!fInvMatrix.decomposeScale(&scale)) {
137 return;
138 }
139 invScaleX = scale.width();
140 invScaleY = scale.height();
141 }
142 if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) {
143 return; // no need for HQ
144 }
145
146 SkScalar trueDestWidth = fOrigBitmap.width() / invScaleX;
147 SkScalar trueDestHeight = fOrigBitmap.height() / invScaleY;
148 SkScalar roundedDestWidth = SkScalarRoundToScalar(trueDestWidth);
149 SkScalar roundedDestHeight = SkScalarRoundToScalar(trueDestHeight);
150
151 if (!SkBitmapCache::Find(fOrigBitmap, roundedDestWidth, roundedDestHeight, &fScaledBitmap)) {
152 if (!SkBitmapScaler::Resize(&fScaledBitmap,
153 fOrigBitmap,
154 SkBitmapScaler::RESIZE_BEST,
155 roundedDestWidth,
156 roundedDestHeight,
157 SkResourceCache::GetAllocator())) {
158 return; // we failed to create fScaledBitmap
159 }
160
161 SkASSERT(fScaledBitmap.getPixels());
162 fScaledBitmap.setImmutable();
163 SkBitmapCache::Add(fOrigBitmap, roundedDestWidth, roundedDestHeight, fScaledBitmap);
164 }
165
166 SkASSERT(fScaledBitmap.getPixels());
167 fBitmap = &fScaledBitmap;
168
169 fInvMatrix.postScale(roundedDestWidth / fOrigBitmap.width(),
170 roundedDestHeight / fOrigBitmap.height());
171 fFilterLevel = kLow_SkFilterQuality;
172 }
173
174 /*
175 * Modulo internal errors, this should always succeed *if* the matrix is downscaling
176 * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling)
177 */
processMediumRequest()178 void SkBitmapProcState::processMediumRequest() {
179 SkASSERT(kMedium_SkFilterQuality == fFilterLevel);
180
181 // Our default return state is to downgrade the request to Low, w/ or w/o setting fBitmap
182 // to a valid bitmap.
183 fFilterLevel = kLow_SkFilterQuality;
184
185 SkSize invScaleSize;
186 if (!fInvMatrix.decomposeScale(&invScaleSize, NULL)) {
187 return;
188 }
189 SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height());
190
191 if (invScale > SK_Scalar1) {
192 fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap));
193 if (NULL == fCurrMip.get()) {
194 fCurrMip.reset(SkMipMapCache::AddAndRef(fOrigBitmap));
195 if (NULL == fCurrMip.get()) {
196 return;
197 }
198 }
199 // diagnostic for a crasher...
200 if (NULL == fCurrMip->data()) {
201 sk_throw();
202 }
203
204 SkScalar levelScale = SkScalarInvert(invScale);
205 SkMipMap::Level level;
206 if (fCurrMip->extractLevel(levelScale, &level)) {
207 SkScalar invScaleFixup = level.fScale;
208 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
209
210 const SkImageInfo info = fOrigBitmap.info().makeWH(level.fWidth, level.fHeight);
211 // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
212 // that here, and not need to explicitly track it ourselves.
213 fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes);
214 fBitmap = &fScaledBitmap;
215 } else {
216 // failed to extract, so release the mipmap
217 fCurrMip.reset(NULL);
218 }
219 }
220 }
221
lockBaseBitmap()222 bool SkBitmapProcState::lockBaseBitmap() {
223 // TODO(reed): use bitmap cache here?
224 fScaledBitmap = fOrigBitmap;
225 fScaledBitmap.lockPixels();
226 if (NULL == fScaledBitmap.getPixels()) {
227 return false;
228 }
229 fBitmap = &fScaledBitmap;
230 return true;
231 }
232
valid_for_drawing(const SkBitmap & bm)233 static bool valid_for_drawing(const SkBitmap& bm) {
234 if (0 == bm.width() || 0 == bm.height()) {
235 return false; // nothing to draw
236 }
237 if (NULL == bm.pixelRef()) {
238 return false; // no pixels to read
239 }
240 if (bm.getTexture()) {
241 // we can handle texture (ugh) since lockPixels will perform a read-back
242 return true;
243 }
244 if (kIndex_8_SkColorType == bm.colorType()) {
245 SkAutoLockPixels alp(bm); // but we need to call it before getColorTable() is safe.
246 if (!bm.getColorTable()) {
247 return false;
248 }
249 }
250 return true;
251 }
252
253 /*
254 * Analyze filter-quality and matrix, and decide how to implement that.
255 *
256 * In general, we cascade down the request level [ High ... None ]
257 * - for a given level, if we can fulfill it, fine, else
258 * - else we downgrade to the next lower level and try again.
259 * We can always fulfill requests for Low and None
260 * - sometimes we will "ignore" Low and give None, but this is likely a legacy perf hack
261 * and may be removed.
262 */
chooseProcs(const SkMatrix & inv,const SkPaint & paint)263 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
264 if (!valid_for_drawing(fOrigBitmap)) {
265 return false;
266 }
267
268 fBitmap = NULL;
269 fInvMatrix = inv;
270 fFilterLevel = paint.getFilterQuality();
271
272 if (kHigh_SkFilterQuality == fFilterLevel) {
273 this->processHQRequest();
274 }
275 SkASSERT(fFilterLevel < kHigh_SkFilterQuality);
276
277 if (kMedium_SkFilterQuality == fFilterLevel) {
278 this->processMediumRequest();
279 }
280 SkASSERT(fFilterLevel < kMedium_SkFilterQuality);
281
282 if (NULL == fBitmap) {
283 if (!this->lockBaseBitmap()) {
284 return false;
285 }
286 }
287 SkASSERT(fBitmap);
288
289 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
290 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
291 SkShader::kClamp_TileMode == fTileModeY;
292
293 // Most of the scanline procs deal with "unit" texture coordinates, as this
294 // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate
295 // those, we divide the matrix by its dimensions here.
296 //
297 // We don't do this if we're either trivial (can ignore the matrix) or clamping
298 // in both X and Y since clamping to width,height is just as easy as to 0xFFFF.
299
300 if (!(clampClamp || trivialMatrix)) {
301 fInvMatrix.postIDiv(fBitmap->width(), fBitmap->height());
302 }
303
304 // Now that all possible changes to the matrix have taken place, check
305 // to see if we're really close to a no-scale matrix. If so, explicitly
306 // set it to be so. Subsequent code may inspect this matrix to choose
307 // a faster path in this case.
308
309 // This code will only execute if the matrix has some scale component;
310 // if it's already pure translate then we won't do this inversion.
311
312 if (matrix_only_scale_translate(fInvMatrix)) {
313 SkMatrix forward;
314 if (fInvMatrix.invert(&forward)) {
315 if (clampClamp ? just_trans_clamp(forward, *fBitmap)
316 : just_trans_general(forward)) {
317 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
318 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
319 fInvMatrix.setTranslate(tx, ty);
320 }
321 }
322 }
323
324 fInvProc = fInvMatrix.getMapXYProc();
325 fInvType = fInvMatrix.getType();
326 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX());
327 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
328 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY());
329 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
330
331 fAlphaScale = SkAlpha255To256(paint.getAlpha());
332
333 fShaderProc32 = NULL;
334 fShaderProc16 = NULL;
335 fSampleProc32 = NULL;
336 fSampleProc16 = NULL;
337
338 // recompute the triviality of the matrix here because we may have
339 // changed it!
340
341 trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
342
343 if (kLow_SkFilterQuality == fFilterLevel) {
344 // Only try bilerp if the matrix is "interesting" and
345 // the image has a suitable size.
346
347 if (fInvType <= SkMatrix::kTranslate_Mask ||
348 !valid_for_filtering(fBitmap->width() | fBitmap->height()))
349 {
350 fFilterLevel = kNone_SkFilterQuality;
351 }
352 }
353
354 return this->chooseScanlineProcs(trivialMatrix, clampClamp, paint);
355 }
356
chooseScanlineProcs(bool trivialMatrix,bool clampClamp,const SkPaint & paint)357 bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp,
358 const SkPaint& paint) {
359 fMatrixProc = this->chooseMatrixProc(trivialMatrix);
360 // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
361 if (NULL == fMatrixProc) {
362 return false;
363 }
364
365 ///////////////////////////////////////////////////////////////////////
366
367 const SkAlphaType at = fBitmap->alphaType();
368
369 // No need to do this if we're doing HQ sampling; if filter quality is
370 // still set to HQ by the time we get here, then we must have installed
371 // the shader procs above and can skip all this.
372
373 if (fFilterLevel < kHigh_SkFilterQuality) {
374
375 int index = 0;
376 if (fAlphaScale < 256) { // note: this distinction is not used for D16
377 index |= 1;
378 }
379 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
380 index |= 2;
381 }
382 if (fFilterLevel > kNone_SkFilterQuality) {
383 index |= 4;
384 }
385 // bits 3,4,5 encoding the source bitmap format
386 switch (fBitmap->colorType()) {
387 case kN32_SkColorType:
388 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
389 return false;
390 }
391 index |= 0;
392 break;
393 case kRGB_565_SkColorType:
394 index |= 8;
395 break;
396 case kIndex_8_SkColorType:
397 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
398 return false;
399 }
400 index |= 16;
401 break;
402 case kARGB_4444_SkColorType:
403 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
404 return false;
405 }
406 index |= 24;
407 break;
408 case kAlpha_8_SkColorType:
409 index |= 32;
410 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
411 break;
412 case kGray_8_SkColorType:
413 index |= 40;
414 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
415 break;
416 default:
417 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
418 return false;
419 }
420
421 #if !SK_ARM_NEON_IS_ALWAYS
422 static const SampleProc32 gSkBitmapProcStateSample32[] = {
423 S32_opaque_D32_nofilter_DXDY,
424 S32_alpha_D32_nofilter_DXDY,
425 S32_opaque_D32_nofilter_DX,
426 S32_alpha_D32_nofilter_DX,
427 S32_opaque_D32_filter_DXDY,
428 S32_alpha_D32_filter_DXDY,
429 S32_opaque_D32_filter_DX,
430 S32_alpha_D32_filter_DX,
431
432 S16_opaque_D32_nofilter_DXDY,
433 S16_alpha_D32_nofilter_DXDY,
434 S16_opaque_D32_nofilter_DX,
435 S16_alpha_D32_nofilter_DX,
436 S16_opaque_D32_filter_DXDY,
437 S16_alpha_D32_filter_DXDY,
438 S16_opaque_D32_filter_DX,
439 S16_alpha_D32_filter_DX,
440
441 SI8_opaque_D32_nofilter_DXDY,
442 SI8_alpha_D32_nofilter_DXDY,
443 SI8_opaque_D32_nofilter_DX,
444 SI8_alpha_D32_nofilter_DX,
445 SI8_opaque_D32_filter_DXDY,
446 SI8_alpha_D32_filter_DXDY,
447 SI8_opaque_D32_filter_DX,
448 SI8_alpha_D32_filter_DX,
449
450 S4444_opaque_D32_nofilter_DXDY,
451 S4444_alpha_D32_nofilter_DXDY,
452 S4444_opaque_D32_nofilter_DX,
453 S4444_alpha_D32_nofilter_DX,
454 S4444_opaque_D32_filter_DXDY,
455 S4444_alpha_D32_filter_DXDY,
456 S4444_opaque_D32_filter_DX,
457 S4444_alpha_D32_filter_DX,
458
459 // A8 treats alpha/opaque the same (equally efficient)
460 SA8_alpha_D32_nofilter_DXDY,
461 SA8_alpha_D32_nofilter_DXDY,
462 SA8_alpha_D32_nofilter_DX,
463 SA8_alpha_D32_nofilter_DX,
464 SA8_alpha_D32_filter_DXDY,
465 SA8_alpha_D32_filter_DXDY,
466 SA8_alpha_D32_filter_DX,
467 SA8_alpha_D32_filter_DX,
468
469 // todo: possibly specialize on opaqueness
470 SG8_alpha_D32_nofilter_DXDY,
471 SG8_alpha_D32_nofilter_DXDY,
472 SG8_alpha_D32_nofilter_DX,
473 SG8_alpha_D32_nofilter_DX,
474 SG8_alpha_D32_filter_DXDY,
475 SG8_alpha_D32_filter_DXDY,
476 SG8_alpha_D32_filter_DX,
477 SG8_alpha_D32_filter_DX
478 };
479
480 static const SampleProc16 gSkBitmapProcStateSample16[] = {
481 S32_D16_nofilter_DXDY,
482 S32_D16_nofilter_DX,
483 S32_D16_filter_DXDY,
484 S32_D16_filter_DX,
485
486 S16_D16_nofilter_DXDY,
487 S16_D16_nofilter_DX,
488 S16_D16_filter_DXDY,
489 S16_D16_filter_DX,
490
491 SI8_D16_nofilter_DXDY,
492 SI8_D16_nofilter_DX,
493 SI8_D16_filter_DXDY,
494 SI8_D16_filter_DX,
495
496 // Don't support 4444 -> 565
497 NULL, NULL, NULL, NULL,
498 // Don't support A8 -> 565
499 NULL, NULL, NULL, NULL,
500 // Don't support G8 -> 565 (but we could)
501 NULL, NULL, NULL, NULL
502 };
503 #endif
504
505 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
506 index >>= 1; // shift away any opaque/alpha distinction
507 fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
508
509 // our special-case shaderprocs
510 if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
511 if (clampClamp) {
512 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
513 } else if (SkShader::kRepeat_TileMode == fTileModeX &&
514 SkShader::kRepeat_TileMode == fTileModeY) {
515 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
516 }
517 } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
518 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
519 } else if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) {
520 fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc;
521 }
522
523 if (NULL == fShaderProc32) {
524 fShaderProc32 = this->chooseShaderProc32();
525 }
526 }
527
528 // see if our platform has any accelerated overrides
529 this->platformProcs();
530
531 return true;
532 }
533
Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)534 static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
535 int x, int y,
536 SkPMColor* SK_RESTRICT colors,
537 int count) {
538 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
539 SkASSERT(s.fInvKy == 0);
540 SkASSERT(count > 0 && colors != NULL);
541 SkASSERT(kNone_SkFilterQuality == s.fFilterLevel);
542
543 const int maxX = s.fBitmap->width() - 1;
544 const int maxY = s.fBitmap->height() - 1;
545 int ix = s.fFilterOneX + x;
546 int iy = SkClampMax(s.fFilterOneY + y, maxY);
547 #ifdef SK_DEBUG
548 {
549 SkPoint pt;
550 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
551 SkIntToScalar(y) + SK_ScalarHalf, &pt);
552 int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
553 int ix2 = SkScalarFloorToInt(pt.fX);
554
555 SkASSERT(iy == iy2);
556 SkASSERT(ix == ix2);
557 }
558 #endif
559 const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
560
561 // clamp to the left
562 if (ix < 0) {
563 int n = SkMin32(-ix, count);
564 sk_memset32(colors, row[0], n);
565 count -= n;
566 if (0 == count) {
567 return;
568 }
569 colors += n;
570 SkASSERT(-ix == n);
571 ix = 0;
572 }
573 // copy the middle
574 if (ix <= maxX) {
575 int n = SkMin32(maxX - ix + 1, count);
576 memcpy(colors, row + ix, n * sizeof(SkPMColor));
577 count -= n;
578 if (0 == count) {
579 return;
580 }
581 colors += n;
582 }
583 SkASSERT(count > 0);
584 // clamp to the right
585 sk_memset32(colors, row[maxX], count);
586 }
587
sk_int_mod(int x,int n)588 static inline int sk_int_mod(int x, int n) {
589 SkASSERT(n > 0);
590 if ((unsigned)x >= (unsigned)n) {
591 if (x < 0) {
592 x = n + ~(~x % n);
593 } else {
594 x = x % n;
595 }
596 }
597 return x;
598 }
599
sk_int_mirror(int x,int n)600 static inline int sk_int_mirror(int x, int n) {
601 x = sk_int_mod(x, 2 * n);
602 if (x >= n) {
603 x = n + ~(x - n);
604 }
605 return x;
606 }
607
Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)608 static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
609 int x, int y,
610 SkPMColor* SK_RESTRICT colors,
611 int count) {
612 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
613 SkASSERT(s.fInvKy == 0);
614 SkASSERT(count > 0 && colors != NULL);
615 SkASSERT(kNone_SkFilterQuality == s.fFilterLevel);
616
617 const int stopX = s.fBitmap->width();
618 const int stopY = s.fBitmap->height();
619 int ix = s.fFilterOneX + x;
620 int iy = sk_int_mod(s.fFilterOneY + y, stopY);
621 #ifdef SK_DEBUG
622 {
623 SkPoint pt;
624 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
625 SkIntToScalar(y) + SK_ScalarHalf, &pt);
626 int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
627 int ix2 = SkScalarFloorToInt(pt.fX);
628
629 SkASSERT(iy == iy2);
630 SkASSERT(ix == ix2);
631 }
632 #endif
633 const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
634
635 ix = sk_int_mod(ix, stopX);
636 for (;;) {
637 int n = SkMin32(stopX - ix, count);
638 memcpy(colors, row + ix, n * sizeof(SkPMColor));
639 count -= n;
640 if (0 == count) {
641 return;
642 }
643 colors += n;
644 ix = 0;
645 }
646 }
647
S32_D32_constX_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)648 static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
649 int x, int y,
650 SkPMColor* SK_RESTRICT colors,
651 int count) {
652 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
653 SkASSERT(s.fInvKy == 0);
654 SkASSERT(count > 0 && colors != NULL);
655 SkASSERT(1 == s.fBitmap->width());
656
657 int iY0;
658 int iY1 SK_INIT_TO_AVOID_WARNING;
659 int iSubY SK_INIT_TO_AVOID_WARNING;
660
661 if (kNone_SkFilterQuality != s.fFilterLevel) {
662 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
663 uint32_t xy[2];
664
665 mproc(s, xy, 1, x, y);
666
667 iY0 = xy[0] >> 18;
668 iY1 = xy[0] & 0x3FFF;
669 iSubY = (xy[0] >> 14) & 0xF;
670 } else {
671 int yTemp;
672
673 if (s.fInvType > SkMatrix::kTranslate_Mask) {
674 SkPoint pt;
675 s.fInvProc(s.fInvMatrix,
676 SkIntToScalar(x) + SK_ScalarHalf,
677 SkIntToScalar(y) + SK_ScalarHalf,
678 &pt);
679 // When the matrix has a scale component the setup code in
680 // chooseProcs multiples the inverse matrix by the inverse of the
681 // bitmap's width and height. Since this method is going to do
682 // its own tiling and sampling we need to undo that here.
683 if (SkShader::kClamp_TileMode != s.fTileModeX ||
684 SkShader::kClamp_TileMode != s.fTileModeY) {
685 yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
686 } else {
687 yTemp = SkScalarFloorToInt(pt.fY);
688 }
689 } else {
690 yTemp = s.fFilterOneY + y;
691 }
692
693 const int stopY = s.fBitmap->height();
694 switch (s.fTileModeY) {
695 case SkShader::kClamp_TileMode:
696 iY0 = SkClampMax(yTemp, stopY-1);
697 break;
698 case SkShader::kRepeat_TileMode:
699 iY0 = sk_int_mod(yTemp, stopY);
700 break;
701 case SkShader::kMirror_TileMode:
702 default:
703 iY0 = sk_int_mirror(yTemp, stopY);
704 break;
705 }
706
707 #ifdef SK_DEBUG
708 {
709 SkPoint pt;
710 s.fInvProc(s.fInvMatrix,
711 SkIntToScalar(x) + SK_ScalarHalf,
712 SkIntToScalar(y) + SK_ScalarHalf,
713 &pt);
714 if (s.fInvType > SkMatrix::kTranslate_Mask &&
715 (SkShader::kClamp_TileMode != s.fTileModeX ||
716 SkShader::kClamp_TileMode != s.fTileModeY)) {
717 pt.fY *= s.fBitmap->height();
718 }
719 int iY2;
720
721 switch (s.fTileModeY) {
722 case SkShader::kClamp_TileMode:
723 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
724 break;
725 case SkShader::kRepeat_TileMode:
726 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
727 break;
728 case SkShader::kMirror_TileMode:
729 default:
730 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
731 break;
732 }
733
734 SkASSERT(iY0 == iY2);
735 }
736 #endif
737 }
738
739 const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
740 SkPMColor color;
741
742 if (kNone_SkFilterQuality != s.fFilterLevel) {
743 const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
744
745 if (s.fAlphaScale < 256) {
746 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
747 } else {
748 Filter_32_opaque(iSubY, *row0, *row1, &color);
749 }
750 } else {
751 if (s.fAlphaScale < 256) {
752 color = SkAlphaMulQ(*row0, s.fAlphaScale);
753 } else {
754 color = *row0;
755 }
756 }
757
758 sk_memset32(colors, color, count);
759 }
760
DoNothing_shaderproc(const SkBitmapProcState &,int x,int y,SkPMColor * SK_RESTRICT colors,int count)761 static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
762 SkPMColor* SK_RESTRICT colors, int count) {
763 // if we get called, the matrix is too tricky, so we just draw nothing
764 sk_memset32(colors, 0, count);
765 }
766
setupForTranslate()767 bool SkBitmapProcState::setupForTranslate() {
768 SkPoint pt;
769 fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
770
771 /*
772 * if the translate is larger than our ints, we can get random results, or
773 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't
774 * negate it.
775 */
776 const SkScalar too_big = SkIntToScalar(1 << 30);
777 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
778 return false;
779 }
780
781 // Since we know we're not filtered, we re-purpose these fields allow
782 // us to go from device -> src coordinates w/ just an integer add,
783 // rather than running through the inverse-matrix
784 fFilterOneX = SkScalarFloorToInt(pt.fX);
785 fFilterOneY = SkScalarFloorToInt(pt.fY);
786 return true;
787 }
788
chooseShaderProc32()789 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
790
791 if (kN32_SkColorType != fBitmap->colorType()) {
792 return NULL;
793 }
794
795 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
796
797 if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
798 if (kNone_SkFilterQuality == fFilterLevel &&
799 fInvType <= SkMatrix::kTranslate_Mask &&
800 !this->setupForTranslate()) {
801 return DoNothing_shaderproc;
802 }
803 return S32_D32_constX_shaderproc;
804 }
805
806 if (fAlphaScale < 256) {
807 return NULL;
808 }
809 if (fInvType > SkMatrix::kTranslate_Mask) {
810 return NULL;
811 }
812 if (kNone_SkFilterQuality != fFilterLevel) {
813 return NULL;
814 }
815
816 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
817 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
818
819 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
820 if (this->setupForTranslate()) {
821 return Clamp_S32_D32_nofilter_trans_shaderproc;
822 }
823 return DoNothing_shaderproc;
824 }
825 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
826 if (this->setupForTranslate()) {
827 return Repeat_S32_D32_nofilter_trans_shaderproc;
828 }
829 return DoNothing_shaderproc;
830 }
831 return NULL;
832 }
833
834 ///////////////////////////////////////////////////////////////////////////////
835
836 #ifdef SK_DEBUG
837
check_scale_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)838 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
839 unsigned mx, unsigned my) {
840 unsigned y = *bitmapXY++;
841 SkASSERT(y < my);
842
843 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
844 for (int i = 0; i < count; ++i) {
845 SkASSERT(xptr[i] < mx);
846 }
847 }
848
check_scale_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)849 static void check_scale_filter(uint32_t bitmapXY[], int count,
850 unsigned mx, unsigned my) {
851 uint32_t YY = *bitmapXY++;
852 unsigned y0 = YY >> 18;
853 unsigned y1 = YY & 0x3FFF;
854 SkASSERT(y0 < my);
855 SkASSERT(y1 < my);
856
857 for (int i = 0; i < count; ++i) {
858 uint32_t XX = bitmapXY[i];
859 unsigned x0 = XX >> 18;
860 unsigned x1 = XX & 0x3FFF;
861 SkASSERT(x0 < mx);
862 SkASSERT(x1 < mx);
863 }
864 }
865
check_affine_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)866 static void check_affine_nofilter(uint32_t bitmapXY[], int count,
867 unsigned mx, unsigned my) {
868 for (int i = 0; i < count; ++i) {
869 uint32_t XY = bitmapXY[i];
870 unsigned x = XY & 0xFFFF;
871 unsigned y = XY >> 16;
872 SkASSERT(x < mx);
873 SkASSERT(y < my);
874 }
875 }
876
check_affine_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)877 static void check_affine_filter(uint32_t bitmapXY[], int count,
878 unsigned mx, unsigned my) {
879 for (int i = 0; i < count; ++i) {
880 uint32_t YY = *bitmapXY++;
881 unsigned y0 = YY >> 18;
882 unsigned y1 = YY & 0x3FFF;
883 SkASSERT(y0 < my);
884 SkASSERT(y1 < my);
885
886 uint32_t XX = *bitmapXY++;
887 unsigned x0 = XX >> 18;
888 unsigned x1 = XX & 0x3FFF;
889 SkASSERT(x0 < mx);
890 SkASSERT(x1 < mx);
891 }
892 }
893
DebugMatrixProc(const SkBitmapProcState & state,uint32_t bitmapXY[],int count,int x,int y)894 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
895 uint32_t bitmapXY[], int count,
896 int x, int y) {
897 SkASSERT(bitmapXY);
898 SkASSERT(count > 0);
899
900 state.fMatrixProc(state, bitmapXY, count, x, y);
901
902 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
903
904 // There are four formats possible:
905 // scale -vs- affine
906 // filter -vs- nofilter
907 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
908 proc = state.fFilterLevel != kNone_SkFilterQuality ? check_scale_filter : check_scale_nofilter;
909 } else {
910 proc = state.fFilterLevel != kNone_SkFilterQuality ? check_affine_filter : check_affine_nofilter;
911 }
912 proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
913 }
914
getMatrixProc() const915 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
916 return DebugMatrixProc;
917 }
918
919 #endif
920
921 ///////////////////////////////////////////////////////////////////////////////
922 /*
923 The storage requirements for the different matrix procs are as follows,
924 where each X or Y is 2 bytes, and N is the number of pixels/elements:
925
926 scale/translate nofilter Y(4bytes) + N * X
927 affine/perspective nofilter N * (X Y)
928 scale/translate filter Y Y + N * (X X)
929 affine/perspective filter N * (Y Y X X)
930 */
maxCountForBufferSize(size_t bufferSize) const931 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
932 int32_t size = static_cast<int32_t>(bufferSize);
933
934 size &= ~3; // only care about 4-byte aligned chunks
935 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
936 size -= 4; // the shared Y (or YY) coordinate
937 if (size < 0) {
938 size = 0;
939 }
940 size >>= 1;
941 } else {
942 size >>= 2;
943 }
944
945 if (fFilterLevel != kNone_SkFilterQuality) {
946 size >>= 1;
947 }
948
949 return size;
950 }
951
952 ///////////////////////
953
Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT dst,int count)954 void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState& s, int x, int y,
955 SkPMColor* SK_RESTRICT dst, int count) {
956 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
957 SkMatrix::kScale_Mask)) == 0);
958
959 const unsigned maxX = s.fBitmap->width() - 1;
960 SkFractionalInt fx;
961 int dstY;
962 {
963 SkPoint pt;
964 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf,
965 &pt);
966 fx = SkScalarToFractionalInt(pt.fY);
967 const unsigned maxY = s.fBitmap->height() - 1;
968 dstY = SkClampMax(SkFractionalIntToInt(fx), maxY);
969 fx = SkScalarToFractionalInt(pt.fX);
970 }
971
972 const SkPMColor* SK_RESTRICT src = s.fBitmap->getAddr32(0, dstY);
973 const SkFractionalInt dx = s.fInvSxFractionalInt;
974
975 // Check if we're safely inside [0...maxX] so no need to clamp each computed index.
976 //
977 if ((uint64_t)SkFractionalIntToInt(fx) <= maxX &&
978 (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX)
979 {
980 int count4 = count >> 2;
981 for (int i = 0; i < count4; ++i) {
982 SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx;
983 SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx;
984 SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx;
985 SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx;
986 dst[0] = src0;
987 dst[1] = src1;
988 dst[2] = src2;
989 dst[3] = src3;
990 dst += 4;
991 }
992 for (int i = (count4 << 2); i < count; ++i) {
993 unsigned index = SkFractionalIntToInt(fx);
994 SkASSERT(index <= maxX);
995 *dst++ = src[index];
996 fx += dx;
997 }
998 } else {
999 for (int i = 0; i < count; ++i) {
1000 dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)];
1001 fx += dx;
1002 }
1003 }
1004 }
1005
1006