templatize SkBitmapProcState_matrixProcs

Long standing TODO.

Basically a no-op, except adding an explicit `& 0xffff` to
extract_low_bits_repeat_mirror.  The NEON code does this, and I think it
may help some of the fuzzer bugs we have floating out there.

SkBitmapProcState_matrix_neon.h is a similar setup, up next.

Change-Id: I3109f20a8f1640975901d7e5be10b7d94c490dfb
Reviewed-on: https://skia-review.googlesource.com/c/176060
Auto-Submit: Mike Klein <mtklein@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
Mike Klein 2018-12-10 11:34:27 -05:00 committed by Skia Commit-Bot
parent a0160896f3
commit dbfd7664f2
3 changed files with 64 additions and 90 deletions

View File

@ -32,7 +32,6 @@ skia_core_sources = [
"$_src/core/SkBitmapDevice.h",
"$_src/core/SkBitmapProcState.cpp",
"$_src/core/SkBitmapProcState.h",
"$_src/core/SkBitmapProcState_matrix.h",
"$_src/core/SkBitmapProcState_matrixProcs.cpp",
"$_src/core/SkBitmapProcState_utils.h",
"$_src/core/SkBitmapProvider.cpp",

View File

@ -1,66 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkMath.h"
#include "SkMathPriv.h"
#define SCALE_FILTER_NAME MAKENAME(_filter_scale)
static void SCALE_FILTER_NAME(const SkBitmapProcState& s,
uint32_t xy[], int count, int x, int y) {
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
SkMatrix::kScale_Mask)) == 0);
SkASSERT(s.fInvKy == 0);
auto pack = [](SkFixed f, unsigned max, SkFixed one) {
unsigned i = TILE_PROCF(f, max);
i = (i << 4) | EXTRACT_LOW_BITS(f, max);
return (i << 14) | (TILE_PROCF((f + one), max));
};
const unsigned maxX = s.fPixmap.width() - 1;
const SkFractionalInt dx = s.fInvSxFractionalInt;
SkFractionalInt fx;
{
const SkBitmapProcStateAutoMapper mapper(s, x, y);
const SkFixed fy = mapper.fixedY();
const unsigned maxY = s.fPixmap.height() - 1;
// compute our two Y values up front
*xy++ = pack(fy, maxY, s.fFilterOneY);
// now initialize fx
fx = mapper.fractionalIntX();
}
#ifdef CHECK_FOR_DECAL
// For historical reasons we check both ends are < maxX rather than <= maxX.
// TODO: try changing this? See also can_truncate_to_fixed_for_decal().
if ((unsigned)SkFractionalIntToInt(fx ) < maxX &&
(unsigned)SkFractionalIntToInt(fx + dx*(count-1)) < maxX) {
while (count --> 0) {
SkFixed fixedFx = SkFractionalIntToFixed(fx);
SkASSERT((fixedFx >> (16 + 14)) == 0);
*xy++ = (fixedFx >> 12 << 14) | ((fixedFx >> 16) + 1);
fx += dx;
}
return;
}
#endif
while (count --> 0) {
SkFixed fixedFx = SkFractionalIntToFixed(fx);
*xy++ = pack(fixedFx, maxX, s.fFilterOneX);
fx += dx;
}
}
#undef MAKENAME
#undef TILE_PROCF
#undef EXTRACT_LOW_BITS
#ifdef CHECK_FOR_DECAL
#undef CHECK_FOR_DECAL
#endif
#undef SCALE_FILTER_NAME

View File

@ -86,9 +86,66 @@ static void nofilter_scale(const SkBitmapProcState& s,
}
}
// Clamp/Clamp and Repeat/Repeat have NEON or portable implementations.
// TODO: switch SkBitmapProcState_matrix.h to templates instead of #defines and multiple includes?
// Extract the high four fractional bits from fx, the lerp parameter when filtering.
static unsigned extract_low_bits_clamp(SkFixed fx, int /*max*/) {
// If we're already scaled up to by max like clamp/decal,
// just grab the high four fractional bits.
return (fx >> 12) & 0xf;
}
static unsigned extract_low_bits_repeat_mirror(SkFixed fx, int max) {
// In repeat or mirror fx is in [0,1], so scale up by max first.
// TODO: remove the +1 here and the -1 at the call sites...
return extract_low_bits_clamp((fx & 0xffff) * (max+1), max);
}
template <unsigned (*tile)(SkFixed, int), unsigned (*extract_low_bits)(SkFixed, int), bool tryDecal>
static void filter_scale(const SkBitmapProcState& s,
uint32_t xy[], int count, int x, int y) {
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
SkMatrix::kScale_Mask)) == 0);
SkASSERT(s.fInvKy == 0);
auto pack = [](SkFixed f, unsigned max, SkFixed one) {
unsigned i = tile(f, max);
i = (i << 4) | extract_low_bits(f, max);
return (i << 14) | (tile((f + one), max));
};
const unsigned maxX = s.fPixmap.width() - 1;
const SkFractionalInt dx = s.fInvSxFractionalInt;
SkFractionalInt fx;
{
const SkBitmapProcStateAutoMapper mapper(s, x, y);
const SkFixed fy = mapper.fixedY();
const unsigned maxY = s.fPixmap.height() - 1;
// compute our two Y values up front
*xy++ = pack(fy, maxY, s.fFilterOneY);
// now initialize fx
fx = mapper.fractionalIntX();
}
// For historical reasons we check both ends are < maxX rather than <= maxX.
// TODO: try changing this? See also can_truncate_to_fixed_for_decal().
if (tryDecal &&
(unsigned)SkFractionalIntToInt(fx ) < maxX &&
(unsigned)SkFractionalIntToInt(fx + dx*(count-1)) < maxX) {
while (count --> 0) {
SkFixed fixedFx = SkFractionalIntToFixed(fx);
SkASSERT((fixedFx >> (16 + 14)) == 0);
*xy++ = (fixedFx >> 12 << 14) | ((fixedFx >> 16) + 1);
fx += dx;
}
return;
}
while (count --> 0) {
SkFixed fixedFx = SkFractionalIntToFixed(fx);
*xy++ = pack(fixedFx, maxX, s.fFilterOneX);
fx += dx;
}
}
// Clamp/Clamp and Repeat/Repeat have NEON or portable implementations.
#if defined(SK_ARM_HAS_NEON)
#include <arm_neon.h>
@ -286,7 +343,7 @@ static void nofilter_scale(const SkBitmapProcState& s,
#define TILEY_PROCF_NEON8(l, h, max) sbpsm_clamp_tile8(l, h, max)
#define TILEX_PROCF_NEON4(fx, max) sbpsm_clamp_tile4(fx, max)
#define TILEY_PROCF_NEON4(fy, max) sbpsm_clamp_tile4(fy, max)
#define EXTRACT_LOW_BITS(v, max) (((v) >> 12) & 0xF)
#define EXTRACT_LOW_BITS extract_low_bits_clamp
#define EXTRACT_LOW_BITS_NEON4(v, max) sbpsm_clamp_tile4_low_bits(v)
#define CHECK_FOR_DECAL
#include "SkBitmapProcState_matrix_neon.h"
@ -298,7 +355,7 @@ static void nofilter_scale(const SkBitmapProcState& s,
#define TILEY_PROCF_NEON8(l, h, max) sbpsm_repeat_tile8(l, h, max)
#define TILEX_PROCF_NEON4(fx, max) sbpsm_repeat_tile4(fx, max)
#define TILEY_PROCF_NEON4(fy, max) sbpsm_repeat_tile4(fy, max)
#define EXTRACT_LOW_BITS(v, max) ((((v) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
#define EXTRACT_LOW_BITS extract_low_bits_repeat_mirror
#define EXTRACT_LOW_BITS_NEON4(v, max) sbpsm_repeat_tile4_low_bits(v, max)
#include "SkBitmapProcState_matrix_neon.h"
@ -307,15 +364,9 @@ static void nofilter_scale(const SkBitmapProcState& s,
return SkClampMax(fx >> 16, max);
}
#define MAKENAME(suffix) ClampX_ClampY ## suffix
#define TILE_PROCF clamp
#define EXTRACT_LOW_BITS(v, max) (((v) >> 12) & 0xF)
#define CHECK_FOR_DECAL
#include "SkBitmapProcState_matrix.h" // will create ClampX_ClampY_filter_scale.
static const SkBitmapProcState::MatrixProc ClampX_ClampY_Procs[] = {
nofilter_scale<clamp, true>,
ClampX_ClampY_filter_scale,
filter_scale<clamp, extract_low_bits_clamp, true>,
};
@ -324,14 +375,9 @@ static void nofilter_scale(const SkBitmapProcState& s,
return SK_USHIFT16((unsigned)(fx & 0xFFFF) * (max + 1));
}
#define MAKENAME(suffix) RepeatX_RepeatY ## suffix
#define TILE_PROCF repeat
#define EXTRACT_LOW_BITS(v, max) (((v * (max + 1)) >> 12) & 0xF)
#include "SkBitmapProcState_matrix.h" // will create RepeatX_RepeatY_filter_scale.
static const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs[] = {
nofilter_scale<repeat, false>,
RepeatX_RepeatY_filter_scale,
filter_scale<repeat, extract_low_bits_repeat_mirror, false>,
};
#endif
@ -344,14 +390,9 @@ static unsigned mirror(SkFixed fx, int max) {
return SK_USHIFT16( ((fx ^ s) & 0xFFFF) * (max + 1) );
}
#define MAKENAME(suffix) MirrorX_MirrorY ## suffix
#define TILE_PROCF mirror
#define EXTRACT_LOW_BITS(v, max) (((v * (max + 1)) >> 12) & 0xF)
#include "SkBitmapProcState_matrix.h" // will create MirrorX_MirrorY_filter_scale.
static const SkBitmapProcState::MatrixProc MirrorX_MirrorY_Procs[] = {
nofilter_scale<mirror, false>,
MirrorX_MirrorY_filter_scale,
filter_scale<mirror, extract_low_bits_repeat_mirror, false>,
};