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