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