Buffer four scanlines prior to blitting. We will eventually use this

to blit four scanlines in a row in order to aggressively compress alpha
masks as the information comes in. This CL is only to introduce the API
and to make sure that nothing breaks in the general case.

R=reed@google.com, robertphillips@google.com

Author: krajcevski@google.com

Review URL: https://codereview.chromium.org/387953005
This commit is contained in:
krajcevski 2014-07-16 13:31:41 -07:00 committed by Commit bot
parent b577c55a13
commit 2ec93fc1d3
2 changed files with 42 additions and 8 deletions

View File

@ -33,6 +33,7 @@ public:
/// zero-terminated run-length encoding of spans of constant alpha values. /// zero-terminated run-length encoding of spans of constant alpha values.
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]); const int16_t runs[]);
/// Blit a vertical run of pixels with a constant alpha value. /// Blit a vertical run of pixels with a constant alpha value.
virtual void blitV(int x, int y, int height, SkAlpha alpha); virtual void blitV(int x, int y, int height, SkAlpha alpha);
/// Blit a solid rectangle one or more pixels wide. /// Blit a solid rectangle one or more pixels wide.
@ -67,6 +68,14 @@ public:
virtual bool resetShaderContext(const SkShader::ContextRec&); virtual bool resetShaderContext(const SkShader::ContextRec&);
virtual SkShader::Context* getShaderContext() const; 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 ///@name non-virtual helpers
void blitMaskRegion(const SkMask& mask, const SkRegion& clip); void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
void blitRectRegion(const SkIRect& rect, const SkRegion& clip); void blitRectRegion(const SkIRect& rect, const SkRegion& clip);

View File

@ -108,7 +108,7 @@ public:
virtual ~SuperBlitter() { virtual ~SuperBlitter() {
this->flush(); this->flush();
sk_free(fRuns.fRuns); sk_free(fRunsBuffer);
} }
/// Once fRuns contains a complete supersampled row, flush() blits /// Once fRuns contains a complete supersampled row, flush() blits
@ -123,31 +123,56 @@ public:
virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE; virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
private: 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; 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; int fOffsetX;
}; };
SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
const SkRegion& clip) const SkRegion& clip)
: BaseSuperBlitter(realBlitter, ir, 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 this->advanceRuns();
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);
fOffsetX = 0; fOffsetX = 0;
} }
void SuperBlitter::flush() { void SuperBlitter::flush() {
if (fCurrIY >= fTop) { if (fCurrIY >= fTop) {
SkASSERT(fCurrentRun < fRunsToBuffer);
if (!fRuns.empty()) { if (!fRuns.empty()) {
// SkDEBUGCODE(fRuns.dump();) // SkDEBUGCODE(fRuns.dump();)
fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns); fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
fRuns.reset(fWidth); this->advanceRuns();
fOffsetX = 0; fOffsetX = 0;
} }
fCurrIY = fTop - 1; fCurrIY = fTop - 1;
SkDEBUGCODE(fCurrX = -1;) SkDEBUGCODE(fCurrX = -1;)
} }