staticinline SkFixed quick_div(SkFDot6 a, SkFDot6 b) {
constexpr int kMinBits = 3; // abs(b) should be at least (1 << kMinBits) for quick division
constexpr int kMaxBits = 31; // Number of bits available in signed int // Given abs(b) <= (1 << kMinBits), the inverse of abs(b) is at most 1 << (22 - kMinBits) in // SkFixed format. Hence abs(a) should be less than kMaxAbsA
constexpr int kMaxAbsA = 1 << (kMaxBits - (22 - kMinBits));
SkFDot6 abs_a = SkAbs32(a);
SkFDot6 abs_b = SkAbs32(b); if (abs_b >= (1 << kMinBits) && abs_b < kInverseTableSize && abs_a < kMaxAbsA) {
SkASSERT((int64_t)a * quick_inverse(b) <= SK_MaxS32
&& (int64_t)a * quick_inverse(b) >= SK_MinS32);
SkFixed ourAnswer = (a * quick_inverse(b)) >> 6;
SkASSERT(
(SkFDot6Div(a,b) == 0 && ourAnswer == 0) ||
SkFixedDiv(SkAbs32(SkFDot6Div(a,b) - ourAnswer), SkAbs32(SkFDot6Div(a,b))) <= 1 << 10
); return ourAnswer;
} return SkFDot6Div(a, b);
}
bool SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1) { // We must set X/Y using the same way (e.g., times 4, to FDot6, then to Fixed) as Quads/Cubics. // Otherwise the order of the edge might be wrong due to precision limit.
constexpr int accuracy = kDefaultAccuracy; #ifdef SK_RASTERIZE_EVEN_ROUNDING
SkFixed x0 = SkFDot6ToFixed(SkScalarRoundToFDot6(p0.fX, accuracy)) >> accuracy;
SkFixed y0 = SnapY(SkFDot6ToFixed(SkScalarRoundToFDot6(p0.fY, accuracy)) >> accuracy);
SkFixed x1 = SkFDot6ToFixed(SkScalarRoundToFDot6(p1.fX, accuracy)) >> accuracy;
SkFixed y1 = SnapY(SkFDot6ToFixed(SkScalarRoundToFDot6(p1.fY, accuracy)) >> accuracy); #else
constexpr int multiplier = (1 << kDefaultAccuracy);
SkFixed x0 = SkFDot6ToFixed(SkScalarToFDot6(p0.fX * multiplier)) >> accuracy;
SkFixed y0 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p0.fY * multiplier)) >> accuracy);
SkFixed x1 = SkFDot6ToFixed(SkScalarToFDot6(p1.fX * multiplier)) >> accuracy;
SkFixed y1 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p1.fY * multiplier)) >> accuracy); #endif
Winding winding = Winding::kCW;
if (y0 > y1) {
using std::swap;
swap(x0, x1);
swap(y0, y1);
winding = Winding::kCCW;
}
// are we a zero-height line?
SkFDot6 dy = SkFixedToFDot6(y1 - y0); if (dy == 0) { returnfalse;
}
SkFDot6 dx = SkFixedToFDot6(x1 - x0);
SkFixed slope = quick_div(dx, dy);
SkFixed absSlope = SkAbs32(slope);
// This will become a bottleneck for small ovals rendering if we call SkFixedDiv twice here. // Therefore, we'll let the outter function compute the slope once and send in the value. // Moreover, we'll compute fDY by quickly lookup the inverse table (if possible). bool SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1, SkFixed slope) { // Since we send in the slope, we can no longer snap y inside this function. // If we don't send in the slope, or we do some more sophisticated snapping, this function // could be a performance bottleneck.
SkASSERT(fWinding == Winding::kCW || fWinding == Winding::kCCW);
SkASSERT(fCurveCount != 0);
// We don't chop at y extrema for cubics so the y is not guaranteed to be increasing for them. // In that case, we have to swap x/y and negate the winding. if (y0 > y1) {
using std::swap;
swap(x0, x1);
swap(y0, y1);
fWinding = swap_winding(fWinding);
}
/* We store 1<<shift in a (signed) byte, so its maximum value is 1<<6 == 64. Notethatthislimitsthenumberoflinesweusetoapproximateacurve. Ifweneedtoincreasethis,weneedtostorefCurveCountinsomething largerthanint8_t.
*/ #define MAX_COEFF_SHIFT 6
staticinline SkFDot6 cheap_distance(SkFDot6 dx, SkFDot6 dy)
{
dx = SkAbs32(dx);
dy = SkAbs32(dy); // return max + min/2 if (dx > dy){
dx += dy >> 1;
} else {
dx = dy + (dx >> 1);
} return dx;
}
staticinlineint diff_to_shift(SkFDot6 dx, SkFDot6 dy, int shiftAA) { // cheap calc of distance from center of p0-p2 to the center of the curve
SkFDot6 dist = cheap_distance(dx, dy);
// shift down dist (it is currently in dot6) // down by 3 should give us 1/8 pixel accuracy (assuming our dist is accurate...) // this is chosen by heuristic: make it as big as possible (to minimize segments) // ... but small enough so that our curves still look smooth // When shift > 0, we're using AA and everything is scaled up so we can // lower the accuracy.
dist = (dist + (1 << (2 + shiftAA))) >> (3 + shiftAA);
// each subdivision (shift value) cuts this dist (error) by 1/4 return (32 - SkCLZ(dist)) >> 1;
}
staticinline SkFixed SkFDot6ToFixedDiv2(SkFDot6 value) { // we want to return SkFDot6ToFixed(value >> 1), but we don't want to throw // away data in value, so just perform a modify up-shift return SkLeftShift(value, 16 - 6 - 1);
}
int top = SkFDot6Round(y0); int bot = SkFDot6Round(y2);
// are we a zero-height quad (line)? if (top == bot) { return0;
}
// compute number of steps needed (1 << shift)
{
SkFDot6 dx = (SkLeftShift(x1, 1) - x0 - x2) >> 2;
SkFDot6 dy = (SkLeftShift(y1, 1) - y0 - y2) >> 2; // This is a little confusing: // before this line, shift is the scale up factor for AA; // after this line, shift is the fCurveShift.
shift = diff_to_shift(dx, dy, shift);
SkASSERT(shift >= 0);
} // need at least 1 subdivision for our bias trick if (shift == 0) {
shift = 1;
} elseif (shift > MAX_COEFF_SHIFT) {
shift = MAX_COEFF_SHIFT;
}
fWinding = winding; //fCubicDShift only set for cubics
fEdgeType = Type::kQuad;
fCurveCount = SkToS8(1 << shift);
int top = SkFDot6Round(y0); int bot = SkFDot6Round(y3);
// are we a zero-height cubic (line)? if (top == bot) return0;
// compute number of steps needed (1 << shift)
{ // Can't use (center of curve - center of baseline), since center-of-curve // need not be the max delta from the baseline (it could even be coincident) // so we try just looking at the two off-curve points
SkFDot6 dx = cubic_delta_from_line(x0, x1, x2, x3);
SkFDot6 dy = cubic_delta_from_line(y0, y1, y2, y3); // add 1 (by observation)
shift = diff_to_shift(dx, dy, 2) + 1;
} // need at least 1 subdivision for our bias trick
SkASSERT(shift > 0); if (shift > MAX_COEFF_SHIFT) {
shift = MAX_COEFF_SHIFT;
}
/* Since our in coming data is initially shifted down by 10 (or 8 in antialias).Thatmeansthemostwecanshiftupis8.However,we computecoefficientswitha3*,sothesafestupshiftisreally6
*/ int upShift = 6; // largest safe value int downShift = shift + upShift - 10; if (downShift < 0) {
downShift = 0;
upShift = 10 - shift;
}
// we want to say SkASSERT(oldy <= newy), but our finite fixedpoint // doesn't always achieve that, so we have to explicitly pin it here. if (newy < oldy) {
newy = oldy;
}
SkFixed newSnappedY = SnapY(newy); // we want to SkASSERT(snappedNewY <= fCLastY), but our finite fixedpoint // doesn't always achieve that, so we have to explicitly pin it here. if (fCLastY < newSnappedY) {
newSnappedY = fCLastY;
count = 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.