update the nearly_integral calculation to be (a) faster, and (b) to correctly

identify that the AA granularity is 1/4 of a pixel, not 1/16 (along an axis).



git-svn-id: http://skia.googlecode.com/svn/trunk@3919 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2012-05-11 20:57:25 +00:00
parent 5adf9b2e98
commit 18c464b460
2 changed files with 77 additions and 9 deletions

View File

@ -150,21 +150,27 @@ bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
return this->updateCacheAndReturnNonEmpty();
}
// return true if x is nearly integral (within 1/16) since that is the highest
// precision our aa code can have.
static bool is_integral(SkScalar x) {
int ix = SkScalarRoundToInt(x);
SkScalar sx = SkIntToScalar(ix);
return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
/**
* Our antialiasing currently has a granularity of 1/4 of a pixel along each
* axis. Thus we can treat an axis coordinate as an integer if it differs
* from its nearest int by < half of that value (1.8 in this case).
*/
static bool nearly_integral(SkScalar x) {
static const SkScalar domain = SK_Scalar1 / 4;
static const SkScalar halfDomain = domain / 2;
x += halfDomain;
return x - SkScalarFloorToScalar(x) < domain;
}
bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
AUTO_RASTERCLIP_VALIDATE(*this);
if (fIsBW && doAA) {
// check that the rect really needs aa
if (is_integral(r.fLeft) && is_integral(r.fTop) &&
is_integral(r.fRight) && is_integral(r.fBottom)) {
// check that the rect really needs aa, or is it close enought to
// integer boundaries that we can just treat it as a BW rect?
if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
doAA = false;
}
}

View File

@ -316,6 +316,67 @@ static void test_path_with_hole(skiatest::Reporter* reporter) {
}
}
#include "SkRasterClip.h"
static void copyToMask(const SkRasterClip& rc, SkMask* mask) {
if (rc.isAA()) {
rc.aaRgn().copyToMask(mask);
} else {
copyToMask(rc.bwRgn(), mask);
}
}
static bool operator==(const SkRasterClip& a, const SkRasterClip& b) {
if (a.isEmpty()) {
return b.isEmpty();
}
if (b.isEmpty()) {
return false;
}
SkMask ma, mb;
copyToMask(a, &ma);
copyToMask(b, &mb);
return ma == mb;
}
static void did_dx_affect(skiatest::Reporter* reporter, const SkScalar dx[],
size_t count, bool changed) {
SkIRect ir = { 0, 0, 10, 10 };
for (size_t i = 0; i < count; ++i) {
SkRect r;
r.set(ir);
SkRasterClip rc0(ir);
SkRasterClip rc1(ir);
SkRasterClip rc2(ir);
rc0.op(r, SkRegion::kIntersect_Op, false);
r.offset(dx[i], 0);
rc1.op(r, SkRegion::kIntersect_Op, true);
r.offset(-2*dx[i], 0);
rc2.op(r, SkRegion::kIntersect_Op, true);
REPORTER_ASSERT(reporter, changed != (rc0 == rc1));
REPORTER_ASSERT(reporter, changed != (rc0 == rc2));
}
}
static void test_nearly_integral(skiatest::Reporter* reporter) {
// All of these should generate equivalent rasterclips
static const SkScalar gSafeX[] = {
0, SK_Scalar1/1000, SK_Scalar1/100, SK_Scalar1/10,
};
did_dx_affect(reporter, gSafeX, SK_ARRAY_COUNT(gSafeX), false);
static const SkScalar gUnsafeX[] = {
SK_Scalar1/4, SK_Scalar1/3,
};
did_dx_affect(reporter, gUnsafeX, SK_ARRAY_COUNT(gUnsafeX), true);
}
static void test_regressions(skiatest::Reporter* reporter) {
// these should not assert in the debug build
// bug was introduced in rev. 3209
@ -337,6 +398,7 @@ static void TestAAClip(skiatest::Reporter* reporter) {
test_rgn(reporter);
test_path_with_hole(reporter);
test_regressions(reporter);
test_nearly_integral(reporter);
}
#include "TestClassDef.h"