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 "SkBitmapController.h"
10 #include "SkBitmapProcState.h"
11 #include "SkColorPriv.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 defined(SK_ARM_HAS_NEON)
22 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
23 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
24 #endif
25
26 extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void*, int, int, uint32_t*, int);
27
28 #define NAME_WRAP(x) x
29 #include "SkBitmapProcState_filter.h"
30 #include "SkBitmapProcState_procs.h"
31
SkBitmapProcInfo(const SkBitmapProvider & provider,SkShader::TileMode tmx,SkShader::TileMode tmy)32 SkBitmapProcInfo::SkBitmapProcInfo(const SkBitmapProvider& provider,
33 SkShader::TileMode tmx, SkShader::TileMode tmy)
34 : fProvider(provider)
35 , fTileModeX(tmx)
36 , fTileModeY(tmy)
37 , fBMState(nullptr)
38 {}
39
~SkBitmapProcInfo()40 SkBitmapProcInfo::~SkBitmapProcInfo() {
41 SkInPlaceDeleteCheck(fBMState, fBMStateStorage.get());
42 }
43
44 ///////////////////////////////////////////////////////////////////////////////
45
46 // true iff the matrix has a scale and no more than an optional translate.
matrix_only_scale_translate(const SkMatrix & m)47 static bool matrix_only_scale_translate(const SkMatrix& m) {
48 return (m.getType() & ~SkMatrix::kTranslate_Mask) == SkMatrix::kScale_Mask;
49 }
50
51 /**
52 * For the purposes of drawing bitmaps, if a matrix is "almost" translate
53 * go ahead and treat it as if it were, so that subsequent code can go fast.
54 */
just_trans_general(const SkMatrix & matrix)55 static bool just_trans_general(const SkMatrix& matrix) {
56 SkASSERT(matrix_only_scale_translate(matrix));
57
58 const SkScalar tol = SK_Scalar1 / 32768;
59
60 return SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)
61 && SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol);
62 }
63
64 /**
65 * Determine if the matrix can be treated as integral-only-translate,
66 * for the purpose of filtering.
67 */
just_trans_integral(const SkMatrix & m)68 static bool just_trans_integral(const SkMatrix& m) {
69 #ifdef SK_SUPPORT_LEGACY_BILERP
70 return false;
71 #else
72 static constexpr SkScalar tol = SK_Scalar1 / 256;
73
74 return m.getType() <= SkMatrix::kTranslate_Mask
75 && SkScalarNearlyEqual(m.getTranslateX(), SkScalarRoundToScalar(m.getTranslateX()), tol)
76 && SkScalarNearlyEqual(m.getTranslateY(), SkScalarRoundToScalar(m.getTranslateY()), tol);
77 #endif
78 }
79
valid_for_filtering(unsigned dimension)80 static bool valid_for_filtering(unsigned dimension) {
81 // for filtering, width and height must fit in 14bits, since we use steal
82 // 2 bits from each to store our 4bit subpixel data
83 return (dimension & ~0x3FFF) == 0;
84 }
85
init(const SkMatrix & inv,const SkPaint & paint)86 bool SkBitmapProcInfo::init(const SkMatrix& inv, const SkPaint& paint) {
87 SkASSERT(!inv.hasPerspective());
88
89 fPixmap.reset();
90 fInvMatrix = inv;
91 fFilterQuality = paint.getFilterQuality();
92
93 SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kNo);
94 fBMState = controller.requestBitmap(fProvider, inv, paint.getFilterQuality(),
95 fBMStateStorage.get(), fBMStateStorage.size());
96 // Note : we allow the controller to return an empty (zero-dimension) result. Should we?
97 if (nullptr == fBMState || fBMState->pixmap().info().isEmpty()) {
98 return false;
99 }
100 fPixmap = fBMState->pixmap();
101 fInvMatrix = fBMState->invMatrix();
102 fRealInvMatrix = fBMState->invMatrix();
103 fPaintColor = paint.getColor();
104 fFilterQuality = fBMState->quality();
105 SkASSERT(fPixmap.addr());
106
107 // Most of the scanline procs deal with "unit" texture coordinates, as this
108 // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate
109 // those, we divide the matrix by its dimensions here.
110 //
111 // We don't do this if we're either trivial (can ignore the matrix) or clamping
112 // in both X and Y since clamping to width,height is just as easy as to 0xFFFF.
113
114 if (fTileModeX != SkShader::kClamp_TileMode ||
115 fTileModeY != SkShader::kClamp_TileMode) {
116 fInvMatrix.postIDiv(fPixmap.width(), fPixmap.height());
117 }
118
119 // Now that all possible changes to the matrix have taken place, check
120 // to see if we're really close to a no-scale matrix. If so, explicitly
121 // set it to be so. Subsequent code may inspect this matrix to choose
122 // a faster path in this case.
123
124 // This code will only execute if the matrix has some scale component;
125 // if it's already pure translate then we won't do this inversion.
126
127 if (matrix_only_scale_translate(fInvMatrix)) {
128 SkMatrix forward;
129 if (fInvMatrix.invert(&forward) && just_trans_general(forward)) {
130 fInvMatrix.setTranslate(-forward.getTranslateX(), -forward.getTranslateY());
131 }
132 }
133
134 fInvType = fInvMatrix.getType();
135
136 if (kLow_SkFilterQuality == fFilterQuality &&
137 (!valid_for_filtering(fPixmap.width() | fPixmap.height()) ||
138 just_trans_integral(fInvMatrix))) {
139 fFilterQuality = kNone_SkFilterQuality;
140 }
141
142 return true;
143 }
144
145 /*
146 * Analyze filter-quality and matrix, and decide how to implement that.
147 *
148 * In general, we cascade down the request level [ High ... None ]
149 * - for a given level, if we can fulfill it, fine, else
150 * - else we downgrade to the next lower level and try again.
151 * We can always fulfill requests for Low and None
152 * - sometimes we will "ignore" Low and give None, but this is likely a legacy perf hack
153 * and may be removed.
154 */
chooseProcs()155 bool SkBitmapProcState::chooseProcs() {
156 fInvProc = fInvMatrix.getMapXYProc();
157 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX());
158 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
159 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY());
160 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
161
162 fAlphaScale = SkAlpha255To256(SkColorGetA(fPaintColor));
163
164 fShaderProc32 = nullptr;
165 fShaderProc16 = nullptr;
166 fSampleProc32 = nullptr;
167
168 const bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
169 const bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
170 SkShader::kClamp_TileMode == fTileModeY;
171
172 return this->chooseScanlineProcs(trivialMatrix, clampClamp);
173 }
174
chooseScanlineProcs(bool trivialMatrix,bool clampClamp)175 bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp) {
176 SkASSERT(fPixmap.colorType() == kN32_SkColorType);
177
178 fMatrixProc = this->chooseMatrixProc(trivialMatrix);
179 // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns nullptr.
180 if (nullptr == fMatrixProc) {
181 return false;
182 }
183
184 const SkAlphaType at = fPixmap.alphaType();
185 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
186 return false;
187 }
188
189 // No need to do this if we're doing HQ sampling; if filter quality is
190 // still set to HQ by the time we get here, then we must have installed
191 // the shader procs above and can skip all this.
192
193 if (fFilterQuality < kHigh_SkFilterQuality) {
194 int index = 0;
195 if (fAlphaScale < 256) { // note: this distinction is not used for D16
196 index |= 1;
197 }
198 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
199 index |= 2;
200 }
201 if (fFilterQuality > kNone_SkFilterQuality) {
202 index |= 4;
203 }
204
205 #if !defined(SK_ARM_HAS_NEON)
206 static const SampleProc32 gSkBitmapProcStateSample32[] = {
207 S32_opaque_D32_nofilter_DXDY,
208 S32_alpha_D32_nofilter_DXDY,
209 S32_opaque_D32_nofilter_DX,
210 S32_alpha_D32_nofilter_DX,
211 S32_opaque_D32_filter_DXDY,
212 S32_alpha_D32_filter_DXDY,
213 S32_opaque_D32_filter_DX,
214 S32_alpha_D32_filter_DX,
215 };
216 #endif
217
218 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
219
220 // our special-case shaderprocs
221 if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) {
222 fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc;
223 }
224
225 if (nullptr == fShaderProc32) {
226 fShaderProc32 = this->chooseShaderProc32();
227 }
228 }
229
230 // see if our platform has any accelerated overrides
231 this->platformProcs();
232
233 return true;
234 }
235
Clamp_S32_D32_nofilter_trans_shaderproc(const void * sIn,int x,int y,SkPMColor * SK_RESTRICT colors,int count)236 static void Clamp_S32_D32_nofilter_trans_shaderproc(const void* sIn,
237 int x, int y,
238 SkPMColor* SK_RESTRICT colors,
239 int count) {
240 const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
241 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
242 SkASSERT(s.fInvKy == 0);
243 SkASSERT(count > 0 && colors != nullptr);
244 SkASSERT(kNone_SkFilterQuality == s.fFilterQuality);
245
246 const int maxX = s.fPixmap.width() - 1;
247 const int maxY = s.fPixmap.height() - 1;
248 int ix = s.fFilterOneX + x;
249 int iy = SkClampMax(s.fFilterOneY + y, maxY);
250 const SkPMColor* row = s.fPixmap.addr32(0, iy);
251
252 // clamp to the left
253 if (ix < 0) {
254 int n = SkMin32(-ix, count);
255 sk_memset32(colors, row[0], n);
256 count -= n;
257 if (0 == count) {
258 return;
259 }
260 colors += n;
261 SkASSERT(-ix == n);
262 ix = 0;
263 }
264 // copy the middle
265 if (ix <= maxX) {
266 int n = SkMin32(maxX - ix + 1, count);
267 memcpy(colors, row + ix, n * sizeof(SkPMColor));
268 count -= n;
269 if (0 == count) {
270 return;
271 }
272 colors += n;
273 }
274 SkASSERT(count > 0);
275 // clamp to the right
276 sk_memset32(colors, row[maxX], count);
277 }
278
sk_int_mod(int x,int n)279 static inline int sk_int_mod(int x, int n) {
280 SkASSERT(n > 0);
281 if ((unsigned)x >= (unsigned)n) {
282 if (x < 0) {
283 x = n + ~(~x % n);
284 } else {
285 x = x % n;
286 }
287 }
288 return x;
289 }
290
sk_int_mirror(int x,int n)291 static inline int sk_int_mirror(int x, int n) {
292 x = sk_int_mod(x, 2 * n);
293 if (x >= n) {
294 x = n + ~(x - n);
295 }
296 return x;
297 }
298
Repeat_S32_D32_nofilter_trans_shaderproc(const void * sIn,int x,int y,SkPMColor * SK_RESTRICT colors,int count)299 static void Repeat_S32_D32_nofilter_trans_shaderproc(const void* sIn,
300 int x, int y,
301 SkPMColor* SK_RESTRICT colors,
302 int count) {
303 const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
304 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
305 SkASSERT(s.fInvKy == 0);
306 SkASSERT(count > 0 && colors != nullptr);
307 SkASSERT(kNone_SkFilterQuality == s.fFilterQuality);
308
309 const int stopX = s.fPixmap.width();
310 const int stopY = s.fPixmap.height();
311 int ix = s.fFilterOneX + x;
312 int iy = sk_int_mod(s.fFilterOneY + y, stopY);
313 const SkPMColor* row = s.fPixmap.addr32(0, iy);
314
315 ix = sk_int_mod(ix, stopX);
316 for (;;) {
317 int n = SkMin32(stopX - ix, count);
318 memcpy(colors, row + ix, n * sizeof(SkPMColor));
319 count -= n;
320 if (0 == count) {
321 return;
322 }
323 colors += n;
324 ix = 0;
325 }
326 }
327
S32_D32_constX_shaderproc(const void * sIn,int x,int y,SkPMColor * SK_RESTRICT colors,int count)328 static void S32_D32_constX_shaderproc(const void* sIn,
329 int x, int y,
330 SkPMColor* SK_RESTRICT colors,
331 int count) {
332 const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
333 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
334 SkASSERT(s.fInvKy == 0);
335 SkASSERT(count > 0 && colors != nullptr);
336 SkASSERT(1 == s.fPixmap.width());
337
338 int iY0;
339 int iY1 SK_INIT_TO_AVOID_WARNING;
340 int iSubY SK_INIT_TO_AVOID_WARNING;
341
342 if (kNone_SkFilterQuality != s.fFilterQuality) {
343 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
344 uint32_t xy[2];
345
346 mproc(s, xy, 1, x, y);
347
348 iY0 = xy[0] >> 18;
349 iY1 = xy[0] & 0x3FFF;
350 iSubY = (xy[0] >> 14) & 0xF;
351 } else {
352 int yTemp;
353
354 if (s.fInvType > SkMatrix::kTranslate_Mask) {
355 const SkBitmapProcStateAutoMapper mapper(s, x, y);
356
357 // When the matrix has a scale component the setup code in
358 // chooseProcs multiples the inverse matrix by the inverse of the
359 // bitmap's width and height. Since this method is going to do
360 // its own tiling and sampling we need to undo that here.
361 if (SkShader::kClamp_TileMode != s.fTileModeX ||
362 SkShader::kClamp_TileMode != s.fTileModeY) {
363 yTemp = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height());
364 } else {
365 yTemp = mapper.intY();
366 }
367 } else {
368 yTemp = s.fFilterOneY + y;
369 }
370
371 const int stopY = s.fPixmap.height();
372 switch (s.fTileModeY) {
373 case SkShader::kClamp_TileMode:
374 iY0 = SkClampMax(yTemp, stopY-1);
375 break;
376 case SkShader::kRepeat_TileMode:
377 iY0 = sk_int_mod(yTemp, stopY);
378 break;
379 case SkShader::kMirror_TileMode:
380 default:
381 iY0 = sk_int_mirror(yTemp, stopY);
382 break;
383 }
384
385 #ifdef SK_DEBUG
386 {
387 const SkBitmapProcStateAutoMapper mapper(s, x, y);
388 int iY2;
389
390 if (s.fInvType > SkMatrix::kTranslate_Mask &&
391 (SkShader::kClamp_TileMode != s.fTileModeX ||
392 SkShader::kClamp_TileMode != s.fTileModeY)) {
393 iY2 = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height());
394 } else {
395 iY2 = mapper.intY();
396 }
397
398 switch (s.fTileModeY) {
399 case SkShader::kClamp_TileMode:
400 iY2 = SkClampMax(iY2, stopY-1);
401 break;
402 case SkShader::kRepeat_TileMode:
403 iY2 = sk_int_mod(iY2, stopY);
404 break;
405 case SkShader::kMirror_TileMode:
406 default:
407 iY2 = sk_int_mirror(iY2, stopY);
408 break;
409 }
410
411 SkASSERT(iY0 == iY2);
412 }
413 #endif
414 }
415
416 const SkPMColor* row0 = s.fPixmap.addr32(0, iY0);
417 SkPMColor color;
418
419 if (kNone_SkFilterQuality != s.fFilterQuality) {
420 const SkPMColor* row1 = s.fPixmap.addr32(0, iY1);
421
422 if (s.fAlphaScale < 256) {
423 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
424 } else {
425 Filter_32_opaque(iSubY, *row0, *row1, &color);
426 }
427 } else {
428 if (s.fAlphaScale < 256) {
429 color = SkAlphaMulQ(*row0, s.fAlphaScale);
430 } else {
431 color = *row0;
432 }
433 }
434
435 sk_memset32(colors, color, count);
436 }
437
DoNothing_shaderproc(const void *,int x,int y,SkPMColor * SK_RESTRICT colors,int count)438 static void DoNothing_shaderproc(const void*, int x, int y,
439 SkPMColor* SK_RESTRICT colors, int count) {
440 // if we get called, the matrix is too tricky, so we just draw nothing
441 sk_memset32(colors, 0, count);
442 }
443
setupForTranslate()444 bool SkBitmapProcState::setupForTranslate() {
445 SkPoint pt;
446 const SkBitmapProcStateAutoMapper mapper(*this, 0, 0, &pt);
447
448 /*
449 * if the translate is larger than our ints, we can get random results, or
450 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't
451 * negate it.
452 */
453 const SkScalar too_big = SkIntToScalar(1 << 30);
454 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
455 return false;
456 }
457
458 // Since we know we're not filtered, we re-purpose these fields allow
459 // us to go from device -> src coordinates w/ just an integer add,
460 // rather than running through the inverse-matrix
461 fFilterOneX = mapper.intX();
462 fFilterOneY = mapper.intY();
463
464 return true;
465 }
466
chooseShaderProc32()467 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
468
469 if (kN32_SkColorType != fPixmap.colorType()) {
470 return nullptr;
471 }
472
473 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
474
475 if (1 == fPixmap.width() && 0 == (fInvType & ~kMask)) {
476 if (kNone_SkFilterQuality == fFilterQuality &&
477 fInvType <= SkMatrix::kTranslate_Mask &&
478 !this->setupForTranslate()) {
479 return DoNothing_shaderproc;
480 }
481 return S32_D32_constX_shaderproc;
482 }
483
484 if (fAlphaScale < 256) {
485 return nullptr;
486 }
487 if (fInvType > SkMatrix::kTranslate_Mask) {
488 return nullptr;
489 }
490 if (kNone_SkFilterQuality != fFilterQuality) {
491 return nullptr;
492 }
493
494 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
495 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
496
497 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
498 if (this->setupForTranslate()) {
499 return Clamp_S32_D32_nofilter_trans_shaderproc;
500 }
501 return DoNothing_shaderproc;
502 }
503 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
504 if (this->setupForTranslate()) {
505 return Repeat_S32_D32_nofilter_trans_shaderproc;
506 }
507 return DoNothing_shaderproc;
508 }
509 return nullptr;
510 }
511
512 ///////////////////////////////////////////////////////////////////////////////
513
514 #ifdef SK_DEBUG
515
check_scale_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)516 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
517 unsigned mx, unsigned my) {
518 unsigned y = *bitmapXY++;
519 SkASSERT(y < my);
520
521 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
522 for (int i = 0; i < count; ++i) {
523 SkASSERT(xptr[i] < mx);
524 }
525 }
526
check_scale_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)527 static void check_scale_filter(uint32_t bitmapXY[], int count,
528 unsigned mx, unsigned my) {
529 uint32_t YY = *bitmapXY++;
530 unsigned y0 = YY >> 18;
531 unsigned y1 = YY & 0x3FFF;
532 SkASSERT(y0 < my);
533 SkASSERT(y1 < my);
534
535 for (int i = 0; i < count; ++i) {
536 uint32_t XX = bitmapXY[i];
537 unsigned x0 = XX >> 18;
538 unsigned x1 = XX & 0x3FFF;
539 SkASSERT(x0 < mx);
540 SkASSERT(x1 < mx);
541 }
542 }
543
check_affine_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)544 static void check_affine_nofilter(uint32_t bitmapXY[], int count,
545 unsigned mx, unsigned my) {
546 for (int i = 0; i < count; ++i) {
547 uint32_t XY = bitmapXY[i];
548 unsigned x = XY & 0xFFFF;
549 unsigned y = XY >> 16;
550 SkASSERT(x < mx);
551 SkASSERT(y < my);
552 }
553 }
554
check_affine_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)555 static void check_affine_filter(uint32_t bitmapXY[], int count,
556 unsigned mx, unsigned my) {
557 for (int i = 0; i < count; ++i) {
558 uint32_t YY = *bitmapXY++;
559 unsigned y0 = YY >> 18;
560 unsigned y1 = YY & 0x3FFF;
561 SkASSERT(y0 < my);
562 SkASSERT(y1 < my);
563
564 uint32_t XX = *bitmapXY++;
565 unsigned x0 = XX >> 18;
566 unsigned x1 = XX & 0x3FFF;
567 SkASSERT(x0 < mx);
568 SkASSERT(x1 < mx);
569 }
570 }
571
DebugMatrixProc(const SkBitmapProcState & state,uint32_t bitmapXY[],int count,int x,int y)572 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
573 uint32_t bitmapXY[], int count,
574 int x, int y) {
575 SkASSERT(bitmapXY);
576 SkASSERT(count > 0);
577
578 state.fMatrixProc(state, bitmapXY, count, x, y);
579
580 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
581
582 // There are four formats possible:
583 // scale -vs- affine
584 // filter -vs- nofilter
585 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
586 proc = state.fFilterQuality != kNone_SkFilterQuality ?
587 check_scale_filter : check_scale_nofilter;
588 } else {
589 proc = state.fFilterQuality != kNone_SkFilterQuality ?
590 check_affine_filter : check_affine_nofilter;
591 }
592 proc(bitmapXY, count, state.fPixmap.width(), state.fPixmap.height());
593 }
594
getMatrixProc() const595 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
596 return DebugMatrixProc;
597 }
598
599 #endif
600
601 ///////////////////////////////////////////////////////////////////////////////
602 /*
603 The storage requirements for the different matrix procs are as follows,
604 where each X or Y is 2 bytes, and N is the number of pixels/elements:
605
606 scale/translate nofilter Y(4bytes) + N * X
607 affine/perspective nofilter N * (X Y)
608 scale/translate filter Y Y + N * (X X)
609 affine filter N * (Y Y X X)
610 */
maxCountForBufferSize(size_t bufferSize) const611 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
612 int32_t size = static_cast<int32_t>(bufferSize);
613
614 size &= ~3; // only care about 4-byte aligned chunks
615 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
616 size -= 4; // the shared Y (or YY) coordinate
617 if (size < 0) {
618 size = 0;
619 }
620 size >>= 1;
621 } else {
622 size >>= 2;
623 }
624
625 if (fFilterQuality != kNone_SkFilterQuality) {
626 size >>= 1;
627 }
628
629 return size;
630 }
631
632 ///////////////////////
633
Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void * sIn,int x,int y,SkPMColor * SK_RESTRICT dst,int count)634 void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void* sIn, int x, int y,
635 SkPMColor* SK_RESTRICT dst, int count) {
636 const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
637 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
638 SkMatrix::kScale_Mask)) == 0);
639
640 const unsigned maxX = s.fPixmap.width() - 1;
641 SkFractionalInt fx;
642 int dstY;
643 {
644 const SkBitmapProcStateAutoMapper mapper(s, x, y);
645 const unsigned maxY = s.fPixmap.height() - 1;
646 dstY = SkClampMax(mapper.intY(), maxY);
647 fx = mapper.fractionalIntX();
648 }
649
650 const SkPMColor* SK_RESTRICT src = s.fPixmap.addr32(0, dstY);
651 const SkFractionalInt dx = s.fInvSxFractionalInt;
652
653 // Check if we're safely inside [0...maxX] so no need to clamp each computed index.
654 //
655 if ((uint64_t)SkFractionalIntToInt(fx) <= maxX &&
656 (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX)
657 {
658 int count4 = count >> 2;
659 for (int i = 0; i < count4; ++i) {
660 SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx;
661 SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx;
662 SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx;
663 SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx;
664 dst[0] = src0;
665 dst[1] = src1;
666 dst[2] = src2;
667 dst[3] = src3;
668 dst += 4;
669 }
670 for (int i = (count4 << 2); i < count; ++i) {
671 unsigned index = SkFractionalIntToInt(fx);
672 SkASSERT(index <= maxX);
673 *dst++ = src[index];
674 fx += dx;
675 }
676 } else {
677 for (int i = 0; i < count; ++i) {
678 dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)];
679 fx += dx;
680 }
681 }
682 }
683