/// zero-terminated run-length encoding of spans of constant alpha values.
virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]);
+
/// Blit a vertical run of pixels with a constant alpha value.
virtual void blitV(int x, int y, int height, SkAlpha alpha);
/// Blit a solid rectangle one or more pixels wide.
virtual bool resetShaderContext(const SkShader::ContextRec&);
virtual SkShader::Context* getShaderContext() const;
+ /**
+ * Special methods for blitters that can blit more than one row at a time.
+ * This function returns the number of rows that this blitter could optimally
+ * process at a time. It is still required to support blitting one scanline
+ * at a time.
+ */
+ virtual int requestRowsPreserved() const { return 1; }
+
///@name non-virtual helpers
void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
void blitRectRegion(const SkIRect& rect, const SkRegion& clip);
virtual ~SuperBlitter() {
this->flush();
- sk_free(fRuns.fRuns);
+ sk_free(fRunsBuffer);
}
/// Once fRuns contains a complete supersampled row, flush() blits
virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
private:
+ // The next three variables are used to track a circular buffer that
+ // contains the values used in SkAlphaRuns. These variables should only
+ // ever be updated in advanceRuns(), and fRuns should always point to
+ // a valid SkAlphaRuns...
+ int fRunsToBuffer;
+ void* fRunsBuffer;
+ int fCurrentRun;
SkAlphaRuns fRuns;
+
+ // extra one to store the zero at the end
+ int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); }
+
+ // This function updates the fRuns variable to point to the next buffer space
+ // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun
+ // and resets fRuns to point to an empty scanline.
+ void advanceRuns() {
+ const size_t kRunsSz = this->getRunsSz();
+ fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
+ fRuns.fRuns = reinterpret_cast<int16_t*>(
+ reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz);
+ fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
+ fRuns.reset(fWidth);
+ }
+
int fOffsetX;
};
SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
const SkRegion& clip)
: BaseSuperBlitter(realBlitter, ir, clip) {
- const int width = fWidth;
+ fRunsToBuffer = realBlitter->requestRowsPreserved();
+ fRunsBuffer = sk_malloc_throw(fRunsToBuffer * this->getRunsSz());
+ fCurrentRun = -1;
- // extra one to store the zero at the end
- fRuns.fRuns = (int16_t*)sk_malloc_throw((width + 1 + (width + 2)/2) * sizeof(int16_t));
- fRuns.fAlpha = (uint8_t*)(fRuns.fRuns + width + 1);
- fRuns.reset(width);
+ this->advanceRuns();
fOffsetX = 0;
}
void SuperBlitter::flush() {
if (fCurrIY >= fTop) {
+
+ SkASSERT(fCurrentRun < fRunsToBuffer);
if (!fRuns.empty()) {
- // SkDEBUGCODE(fRuns.dump();)
+ // SkDEBUGCODE(fRuns.dump();)
fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
- fRuns.reset(fWidth);
+ this->advanceRuns();
fOffsetX = 0;
}
+
fCurrIY = fTop - 1;
SkDEBUGCODE(fCurrX = -1;)
}