#define SCALE (1 << SHIFT)
#define MASK (SCALE - 1)
-///////////////////////////////////////////////////////////////////////////////////////////
+//#define FORCE_SUPERMASK
+//#define FORCE_RLE
+
+///////////////////////////////////////////////////////////////////////////////
class BaseSuperBlitter : public SkBlitter {
public:
fRuns.reset(width);
}
-void SuperBlitter::flush()
-{
- if (fCurrIY >= 0)
- {
- if (!fRuns.empty())
- {
+void SuperBlitter::flush() {
+ if (fCurrIY >= 0) {
+ if (!fRuns.empty()) {
// SkDEBUGCODE(fRuns.dump();)
fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
fRuns.reset(fWidth);
}
}
-static inline int coverage_to_alpha(int aa)
-{
+static inline int coverage_to_alpha(int aa) {
aa <<= 8 - 2*SHIFT;
aa -= aa >> (8 - SHIFT - 1);
return aa;
#define SUPER_Mask ((1 << SHIFT) - 1)
-void SuperBlitter::blitH(int x, int y, int width)
-{
+void SuperBlitter::blitH(int x, int y, int width) {
int iy = y >> SHIFT;
SkASSERT(iy >= fCurrIY);
x -= fSuperLeft;
// hack, until I figure out why my cubics (I think) go beyond the bounds
- if (x < 0)
- {
+ if (x < 0) {
width += x;
x = 0;
}
fCurrY = y;
#endif
- if (iy != fCurrIY) // new scanline
- {
+ if (iy != fCurrIY) { // new scanline
this->flush();
fCurrIY = iy;
}
#if 0
SkAntiRun<SHIFT> arun;
arun.set(x, x + width);
- fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(), arun.getStopAlpha(), maxValue);
+ fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(),
+ arun.getStopAlpha(), maxValue);
#else
{
int start = x;
int fe = stop & SUPER_Mask;
int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
- if (n < 0)
- {
+ if (n < 0) {
fb = fe - fb;
n = 0;
fe = 0;
- }
- else
- {
- if (fb == 0)
+ } else {
+ if (fb == 0) {
n += 1;
- else
+ } else {
fb = (1 << SHIFT) - fb;
+ }
}
fRuns.add(x >> SHIFT, coverage_to_alpha(fb), n, coverage_to_alpha(fe),
(1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
#endif
}
-void SuperBlitter::blitRect(int x, int y, int width, int height)
-{
+void SuperBlitter::blitRect(int x, int y, int width, int height) {
for (int i = 0; i < height; ++i) {
blitH(x, y + i, width);
}
virtual void blitH(int x, int y, int width);
- static bool CanHandleRect(const SkIRect& bounds)
- {
+ static bool CanHandleRect(const SkIRect& bounds) {
+#ifdef FORCE_RLE
+ return false;
+#endif
int width = bounds.width();
int rb = SkAlign4(width);
private:
enum {
+#ifdef FORCE_SUPERMASK
+ kMAX_WIDTH = 2048,
+ kMAX_STORAGE = 1024 * 1024 * 2
+#else
kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster
kMAX_STORAGE = 1024
+#endif
};
SkMask fMask;
memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
}
-static void add_aa_span(uint8_t* alpha, U8CPU startAlpha)
-{
+static void add_aa_span(uint8_t* alpha, U8CPU startAlpha) {
/* I should be able to just add alpha[x] + startAlpha.
However, if the trailing edge of the previous span and the leading
edge of the current span round to the same super-sampled x value,
*alpha = SkToU8(tmp - (tmp >> 8));
}
-static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount, U8CPU stopAlpha, U8CPU maxValue)
-{
+static inline uint32_t quadplicate_byte(U8CPU value) {
+ uint32_t pair = (value << 8) | value;
+ return (pair << 16) | pair;
+}
+
+// minimum count before we want to setup an inner loop, adding 4-at-a-time
+#define MIN_COUNT_FOR_QUAD_LOOP 16
+
+static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount,
+ U8CPU stopAlpha, U8CPU maxValue) {
SkASSERT(middleCount >= 0);
/* I should be able to just add alpha[x] + startAlpha.
SkASSERT(tmp <= 256);
*alpha++ = SkToU8(tmp - (tmp >> 8));
- while (--middleCount >= 0)
- {
+ if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) {
+ // loop until we're quad-byte aligned
+ while (SkTCast<intptr_t>(alpha) & 0x3) {
+ alpha[0] = SkToU8(alpha[0] + maxValue);
+ alpha += 1;
+ middleCount -= 1;
+ }
+
+ int bigCount = middleCount >> 2;
+ uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha);
+ uint32_t qval = quadplicate_byte(maxValue);
+ do {
+ *qptr++ += qval;
+ } while (--bigCount > 0);
+
+ middleCount &= 3;
+ alpha = reinterpret_cast<uint8_t*> (qptr);
+ // fall through to the following while-loop
+ }
+
+ while (--middleCount >= 0) {
alpha[0] = SkToU8(alpha[0] + maxValue);
alpha += 1;
}
*alpha = SkToU8(*alpha + stopAlpha);
}
-void MaskSuperBlitter::blitH(int x, int y, int width)
-{
+void MaskSuperBlitter::blitH(int x, int y, int width) {
int iy = (y >> SHIFT);
SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
x -= (fMask.fBounds.fLeft << SHIFT);
// hack, until I figure out why my cubics (I think) go beyond the bounds
- if (x < 0)
- {
+ if (x < 0) {
width += x;
x = 0;
}
int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
- if (n < 0)
- {
+ if (n < 0) {
SkASSERT(row >= fMask.fImage);
SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1);
add_aa_span(row, coverage_to_alpha(fe - fb));
- }
- else
- {
+ } else {
fb = (1 << SHIFT) - fb;
SkASSERT(row >= fMask.fImage);
SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
SkIRect superRect, *superClipRect = NULL;
- if (clipRect)
- {
+ if (clipRect) {
superRect.set( clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
superClipRect = &superRect;
// MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
// if we're an inverse filltype
- if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir))
- {
+ if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir)) {
MaskSuperBlitter superBlit(blitter, ir, clip);
SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
- }
- else
- {
+ } else {
SuperBlitter superBlit(blitter, ir, clip);
sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
}