[Reland] Repeating SkBitmapProcState rounding bias

1) observe the bias in repeat matrix procs also.
2) add utility for device space -> bitmap space mapping.
3) remove unneeded filter bias

This is a reland of https://codereview.chromium.org/1529833003/. The
main difference (and the fix) vs. the prev version is increased
precision: the mapper now operates with SkFractionalInts.

R=reed@google.com
BUG=skia:4680, skia:4649
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1539083002

Review URL: https://codereview.chromium.org/1539083002
This commit is contained in:
fmalita 2016-01-04 10:28:11 -08:00 committed by Commit bot
parent 0152cc3819
commit b3a835891c
4 changed files with 43 additions and 39 deletions

View File

@ -824,15 +824,10 @@ void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void* sIn, int x, int y,
SkFractionalInt fx;
int dstY;
{
SkPoint pt;
s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf,
&pt);
fx = SkScalarToFractionalInt(pt.fY)
+ bitmap_sampler_inv_bias(s.fInvMatrix.getScaleY());
const SkBitmapProcStateAutoMapper mapper(s, x, y);
const unsigned maxY = s.fPixmap.height() - 1;
dstY = SkClampMax(SkFractionalIntToInt(fx), maxY);
fx = SkScalarToFractionalInt(pt.fX)
+ bitmap_sampler_inv_bias(s.fInvMatrix.getScaleX());
dstY = SkClampMax(SkFractionalIntToInt(mapper.y()), maxY);
fx = mapper.x();
}
const SkPMColor* SK_RESTRICT src = s.fPixmap.addr32(0, dstY);

View File

@ -25,17 +25,6 @@ typedef SkFixed3232 SkFractionalInt;
#define SkFixedToFractionalInt(x) SkFixedToFixed3232(x)
#define SkFractionalIntToInt(x) SkFixed3232ToInt(x)
// Applying a fixed point (SkFixed, SkFractionalInt) epsilon bias ensures that the inverse-mapped
// bitmap coordinates are rounded consistently WRT geometry. Note that we only have to do this
// when the scale is positive - for negative scales we're already rounding in the right direction.
static inline int bitmap_sampler_inv_bias(SkScalar scale) {
#ifndef SK_SUPPORT_LEGACY_BITMAP_SAMPLER_BIAS
return -(scale > 0);
#else
return 0;
#endif
}
class SkPaint;
struct SkBitmapProcState {
@ -210,4 +199,34 @@ void S32_D16_filter_DX(const SkBitmapProcState& s,
void S32_D16_filter_DXDY(const SkBitmapProcState& s,
const uint32_t* xy, int count, uint16_t* colors);
// Helper class for mapping the middle of pixel (x, y) into SkFractionalInt bitmap space.
// TODO: filtered version which applies a fFilterOne{X,Y}/2 bias instead of epsilon?
class SkBitmapProcStateAutoMapper {
public:
SkBitmapProcStateAutoMapper(const SkBitmapProcState& s, int x, int y) {
SkPoint pt;
s.fInvProc(s.fInvMatrix,
SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &pt);
#ifndef SK_SUPPORT_LEGACY_BITMAP_SAMPLER_BIAS
// SkFixed epsilon bias to ensure inverse-mapped bitmap coordinates are rounded
// consistently WRT geometry. Note that we only need the bias for positive scales:
// for negative scales, the rounding is intrinsically correct.
// We scale it to persist SkFractionalInt -> SkFixed conversions.
fX = SkScalarToFractionalInt(pt.x()) - SkFixedToFractionalInt(s.fInvMatrix.getScaleX() > 0);
fY = SkScalarToFractionalInt(pt.y()) - SkFixedToFractionalInt(s.fInvMatrix.getScaleY() > 0);
#else
fX = SkScalarToFractionalInt(pt.x());
fY = SkScalarToFractionalInt(pt.y());
#endif
}
SkFractionalInt x() const { return fX; }
SkFractionalInt y() const { return fY; }
private:
SkFractionalInt fX, fY;
};
#endif

View File

@ -64,14 +64,12 @@ void SCALE_FILTER_NAME(const SkBitmapProcState& s,
SkPoint pt;
s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &pt);
const SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1)
+ bitmap_sampler_inv_bias(s.fInvMatrix.getScaleY());
const SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1);
const unsigned maxY = s.fPixmap.height() - 1;
// compute our two Y values up front
*xy++ = PACK_FILTER_Y_NAME(fy, maxY, s.fFilterOneY PREAMBLE_ARG_Y);
// now initialize fx
fx = SkScalarToFractionalInt(pt.fX) - (SkFixedToFractionalInt(one) >> 1)
+ bitmap_sampler_inv_bias(s.fInvMatrix.getScaleX());
fx = SkScalarToFractionalInt(pt.fX) - (SkFixedToFractionalInt(one) >> 1);
}
#ifdef CHECK_FOR_DECAL
@ -104,10 +102,8 @@ void AFFINE_FILTER_NAME(const SkBitmapProcState& s,
SkFixed oneX = s.fFilterOneX;
SkFixed oneY = s.fFilterOneY;
SkFixed fx = SkScalarToFixed(srcPt.fX) - (oneX >> 1)
+ bitmap_sampler_inv_bias(s.fInvMatrix.getScaleX());
SkFixed fy = SkScalarToFixed(srcPt.fY) - (oneY >> 1)
+ bitmap_sampler_inv_bias(s.fInvMatrix.getScaleY());
SkFixed fx = SkScalarToFixed(srcPt.fX) - (oneX >> 1);
SkFixed fy = SkScalarToFixed(srcPt.fY) - (oneY >> 1);
SkFixed dx = s.fInvSx;
SkFixed dy = s.fInvKy;
unsigned maxX = s.fPixmap.width() - 1;

View File

@ -22,13 +22,10 @@ void NoFilterProc_Scale(const SkBitmapProcState& s, uint32_t xy[],
const unsigned maxX = s.fPixmap.width() - 1;
SkFractionalInt fx;
{
SkPoint pt;
s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &pt);
fx = SkScalarToFractionalInt(pt.fY);
const SkBitmapProcStateAutoMapper mapper(s, x, y);
const unsigned maxY = s.fPixmap.height() - 1;
*xy++ = TileProc::Y(s, SkFractionalIntToFixed(fx), maxY);
fx = SkScalarToFractionalInt(pt.fX);
*xy++ = TileProc::Y(s, SkFractionalIntToFixed(mapper.y()), maxY);
fx = mapper.x();
}
if (0 == maxX) {
@ -80,13 +77,10 @@ void NoFilterProc_Affine(const SkBitmapProcState& s, uint32_t xy[],
SkMatrix::kScale_Mask |
SkMatrix::kAffine_Mask)) == 0);
SkPoint srcPt;
s.fInvProc(s.fInvMatrix,
SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
const SkBitmapProcStateAutoMapper mapper(s, x, y);
SkFractionalInt fx = SkScalarToFractionalInt(srcPt.fX);
SkFractionalInt fy = SkScalarToFractionalInt(srcPt.fY);
SkFractionalInt fx = mapper.x();
SkFractionalInt fy = mapper.y();
SkFractionalInt dx = s.fInvSxFractionalInt;
SkFractionalInt dy = s.fInvKyFractionalInt;
int maxX = s.fPixmap.width() - 1;