diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-04-16 10:16:39 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-04-16 10:16:39 +0000 |
commit | 001f4ed2fb62ecdc98ce2884d925de11b7516d23 (patch) | |
tree | 1acb3cdef582b7a33a97e6c6631c62320ca39331 | |
parent | d1061e254af7fa8267dc1a5ed444d1c4b1743b6d (diff) |
Extract most of the mutable state of SkShader into a separate Context object.
SkShader currently stores some state during draw calls via setContext(...).
Move that mutable state into a separate SkShader::Context class that is
constructed on demand for the duration of the draw.
Calls to setContext() are replaced with createContext() which returns a context
corresponding to the shader object or NULL if the parameters to createContext
are invalid.
TEST=out/Debug/dm
BUG=skia:1976
R=scroggo@google.com, skyostil@chromium.org, tomhudson@chromium.org, senorblanco@chromium.org, reed@google.com, bungeman@google.com
Author: dominikg@chromium.org
Review URL: https://codereview.chromium.org/207683004
git-svn-id: http://skia.googlecode.com/svn/trunk@14216 2bbb7eff-a529-9590-31e7-b0007b416f81
38 files changed, 1669 insertions, 997 deletions
diff --git a/include/core/SkColorShader.h b/include/core/SkColorShader.h index 975156c0eb..56e5add4a3 100644 --- a/include/core/SkColorShader.h +++ b/include/core/SkColorShader.h @@ -30,16 +30,35 @@ public: */ SkColorShader(SkColor c); - virtual ~SkColorShader(); - - virtual uint32_t getFlags() SK_OVERRIDE; - virtual uint8_t getSpan16Alpha() const SK_OVERRIDE; virtual bool isOpaque() const SK_OVERRIDE; - virtual bool setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix) SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE; - virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE; + + virtual SkShader::Context* createContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + void* storage) const SK_OVERRIDE; + + virtual size_t contextSize() const SK_OVERRIDE { + return sizeof(ColorShaderContext); + } + + class ColorShaderContext : public SkShader::Context { + public: + ColorShaderContext(const SkColorShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); + + virtual uint32_t getFlags() const SK_OVERRIDE; + virtual uint8_t getSpan16Alpha() const SK_OVERRIDE; + virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE; + virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE; + + private: + SkPMColor fPMColor; + uint32_t fFlags; + uint16_t fColor16; + + typedef SkShader::Context INHERITED; + }; // we return false for this, use asAGradient virtual BitmapType asABitmap(SkBitmap* outTexture, @@ -56,11 +75,7 @@ protected: virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; private: - SkColor fColor; // ignored if fInheritColor is true - SkPMColor fPMColor; // cached after setContext() - uint32_t fFlags; // cached after setContext() - uint16_t fColor16; // cached after setContext() SkBool8 fInheritColor; typedef SkShader INHERITED; diff --git a/include/core/SkComposeShader.h b/include/core/SkComposeShader.h index b54e5efa97..9833a9f4ad 100644 --- a/include/core/SkComposeShader.h +++ b/include/core/SkComposeShader.h @@ -34,10 +34,38 @@ public: SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode = NULL); virtual ~SkComposeShader(); - virtual bool setContext(const SkBitmap&, const SkPaint&, - const SkMatrix&) SK_OVERRIDE; - virtual void endContext() SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; + virtual bool validContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE; + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, void*) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + + class ComposeShaderContext : public SkShader::Context { + public: + // When this object gets destroyed, it will call contextA and contextB's destructor + // but it will NOT free the memory. + ComposeShaderContext(const SkComposeShader&, const SkBitmap&, + const SkPaint&, const SkMatrix&, + SkShader::Context* contextA, SkShader::Context* contextB); + + SkShader::Context* getShaderContextA() const { return fShaderContextA; } + SkShader::Context* getShaderContextB() const { return fShaderContextB; } + + virtual ~ComposeShaderContext(); + + virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; + + private: + SkShader::Context* fShaderContextA; + SkShader::Context* fShaderContextB; + + typedef SkShader::Context INHERITED; + }; + +#if SK_DEBUG + SkShader* getShaderA() { return fShaderA; } + SkShader* getShaderB() { return fShaderB; } +#endif SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeShader) @@ -47,7 +75,6 @@ protected: virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; private: - SkShader* fShaderA; SkShader* fShaderB; SkXfermode* fMode; diff --git a/include/core/SkEmptyShader.h b/include/core/SkEmptyShader.h index d2ebb61221..7494eff3d0 100644 --- a/include/core/SkEmptyShader.h +++ b/include/core/SkEmptyShader.h @@ -15,20 +15,28 @@ /** * \class SkEmptyShader - * A Shader that always draws nothing. Its setContext always returns false, - * so it never expects that its shadeSpan() methods will get called. + * A Shader that always draws nothing. Its createContext always returns NULL. */ class SK_API SkEmptyShader : public SkShader { public: SkEmptyShader() {} - virtual uint32_t getFlags() SK_OVERRIDE; - virtual uint8_t getSpan16Alpha() const SK_OVERRIDE; - virtual bool setContext(const SkBitmap&, const SkPaint&, - const SkMatrix&) SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE; - virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE { + // Even though createContext returns NULL we have to return a value of at least + // sizeof(SkShader::Context) to satisfy SkSmallAllocator. + return sizeof(SkShader::Context); + } + + virtual bool validContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE { + return false; + } + + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, void*) const SK_OVERRIDE { + // validContext returns false. + return NULL; + } SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkEmptyShader) diff --git a/include/core/SkShader.h b/include/core/SkShader.h index 076ecf5460..58e5a6ad2e 100644 --- a/include/core/SkShader.h +++ b/include/core/SkShader.h @@ -38,7 +38,7 @@ public: virtual ~SkShader(); /** - * Returns true if the local matrix is not an identity matrix. + * Returns true if the local matrix is not an identity matrix. */ bool hasLocalMatrix() const { return !fLocalMatrix.isIdentity(); } @@ -96,7 +96,7 @@ public: */ kIntrinsicly16_Flag = 0x04, - /** set (after setContext) if the spans only vary in X (const in Y). + /** set if the spans only vary in X (const in Y). e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient that varies from left-to-right. This flag specifies this for shadeSpan(). @@ -112,84 +112,111 @@ public: }; /** - * Called sometimes before drawing with this shader. Return the type of - * alpha your shader will return. The default implementation returns 0. - * Your subclass should override if it can (even sometimes) report a - * non-zero value, since that will enable various blitters to perform - * faster. - */ - virtual uint32_t getFlags() { return 0; } - - /** * Returns true if the shader is guaranteed to produce only opaque * colors, subject to the SkPaint using the shader to apply an opaque * alpha value. Subclasses should override this to allow some - * optimizations. isOpaque() can be called at any time, unlike getFlags, - * which only works properly when the context is set. + * optimizations. */ virtual bool isOpaque() const { return false; } - /** - * Return the alpha associated with the data returned by shadeSpan16(). If - * kHasSpan16_Flag is not set, this value is meaningless. - */ - virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; } + class Context : public ::SkNoncopyable { + public: + Context(const SkShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); - /** - * Called once before drawing, with the current paint and device matrix. - * Return true if your shader supports these parameters, or false if not. - * If false is returned, nothing will be drawn. If true is returned, then - * a balancing call to endContext() will be made before the next call to - * setContext. - * - * Subclasses should be sure to call their INHERITED::setContext() if they - * override this method. - */ - virtual bool setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix); + virtual ~Context(); - /** - * Assuming setContext returned true, endContext() will be called when - * the draw using the shader has completed. It is an error for setContext - * to be called twice w/o an intervening call to endContext(). - * - * Subclasses should be sure to call their INHERITED::endContext() if they - * override this method. - */ - virtual void endContext(); + /** + * Called sometimes before drawing with this shader. Return the type of + * alpha your shader will return. The default implementation returns 0. + * Your subclass should override if it can (even sometimes) report a + * non-zero value, since that will enable various blitters to perform + * faster. + */ + virtual uint32_t getFlags() const { return 0; } - SkDEBUGCODE(bool setContextHasBeenCalled() const { return SkToBool(fInSetContext); }) + /** + * Return the alpha associated with the data returned by shadeSpan16(). If + * kHasSpan16_Flag is not set, this value is meaningless. + */ + virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; } - /** - * Called for each span of the object being drawn. Your subclass should - * set the appropriate colors (with premultiplied alpha) that correspond - * to the specified device coordinates. - */ - virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0; + /** + * Called for each span of the object being drawn. Your subclass should + * set the appropriate colors (with premultiplied alpha) that correspond + * to the specified device coordinates. + */ + virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0; + + typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count); + virtual ShadeProc asAShadeProc(void** ctx); + + /** + * Called only for 16bit devices when getFlags() returns + * kOpaqueAlphaFlag | kHasSpan16_Flag + */ + virtual void shadeSpan16(int x, int y, uint16_t[], int count); + + /** + * Similar to shadeSpan, but only returns the alpha-channel for a span. + * The default implementation calls shadeSpan() and then extracts the alpha + * values from the returned colors. + */ + virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count); - typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count); - virtual ShadeProc asAShadeProc(void** ctx); + /** + * Helper function that returns true if this shader's shadeSpan16() method + * can be called. + */ + bool canCallShadeSpan16() { + return SkShader::CanCallShadeSpan16(this->getFlags()); + } + + protected: + // Reference to shader, so we don't have to dupe information. + const SkShader& fShader; + + enum MatrixClass { + kLinear_MatrixClass, // no perspective + kFixedStepInX_MatrixClass, // fast perspective, need to call fixedStepInX() each + // scanline + kPerspective_MatrixClass // slow perspective, need to mappoints each pixel + }; + static MatrixClass ComputeMatrixClass(const SkMatrix&); + + uint8_t getPaintAlpha() const { return fPaintAlpha; } + const SkMatrix& getTotalInverse() const { return fTotalInverse; } + MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; } + + private: + SkMatrix fTotalInverse; + uint8_t fPaintAlpha; + uint8_t fTotalInverseClass; + + typedef SkNoncopyable INHERITED; + }; /** - * Called only for 16bit devices when getFlags() returns - * kOpaqueAlphaFlag | kHasSpan16_Flag + * Subclasses should be sure to call their INHERITED::validContext() if + * they override this method. */ - virtual void shadeSpan16(int x, int y, uint16_t[], int count); + virtual bool validContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const; /** - * Similar to shadeSpan, but only returns the alpha-channel for a span. - * The default implementation calls shadeSpan() and then extracts the alpha - * values from the returned colors. + * Create the actual object that does the shading. + * Returns NULL if validContext() returns false. + * Size of storage must be >= contextSize. */ - virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count); + virtual Context* createContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + void* storage) const = 0; /** - * Helper function that returns true if this shader's shadeSpan16() method - * can be called. + * Return the size of a Context returned by createContext. */ - bool canCallShadeSpan16() { - return SkShader::CanCallShadeSpan16(this->getFlags()); - } + virtual size_t contextSize() const = 0; /** * Helper to check the flags to know if it is legal to call shadeSpan16() @@ -322,7 +349,7 @@ public: * The incoming color to the effect has r=g=b=a all extracted from the SkPaint's alpha. * The output color should be the computed SkShader premul color modulated by the incoming * color. The GrContext may be used by the effect to create textures. The GPU device does not - * call setContext. Instead we pass the SkPaint here in case the shader needs paint info. + * call createContext. Instead we pass the SkPaint here in case the shader needs paint info. */ virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint& paint) const; @@ -360,26 +387,14 @@ public: SK_DEFINE_FLATTENABLE_TYPE(SkShader) protected: - enum MatrixClass { - kLinear_MatrixClass, // no perspective - kFixedStepInX_MatrixClass, // fast perspective, need to call fixedStepInX() each scanline - kPerspective_MatrixClass // slow perspective, need to mappoints each pixel - }; - static MatrixClass ComputeMatrixClass(const SkMatrix&); - - // These can be called by your subclass after setContext() has been called - uint8_t getPaintAlpha() const { return fPaintAlpha; } - const SkMatrix& getTotalInverse() const { return fTotalInverse; } - MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; } SkShader(SkReadBuffer& ); virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; + private: SkMatrix fLocalMatrix; - SkMatrix fTotalInverse; - uint8_t fPaintAlpha; - uint8_t fTotalInverseClass; - SkDEBUGCODE(SkBool8 fInSetContext;) + + bool computeTotalInverse(const SkMatrix& matrix, SkMatrix* totalInverse) const; typedef SkFlattenable INHERITED; }; diff --git a/include/effects/SkPerlinNoiseShader.h b/include/effects/SkPerlinNoiseShader.h index dfd5a8c1e7..5b270293b1 100644 --- a/include/effects/SkPerlinNoiseShader.h +++ b/include/effects/SkPerlinNoiseShader.h @@ -72,10 +72,32 @@ public: } - virtual bool setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix); - virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE; + virtual SkShader::Context* createContext( + const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + + class PerlinNoiseShaderContext : public SkShader::Context { + public: + PerlinNoiseShaderContext(const SkPerlinNoiseShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); + virtual ~PerlinNoiseShaderContext() {} + + virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE; + + private: + SkPMColor shade(const SkPoint& point, StitchData& stitchData) const; + SkScalar calculateTurbulenceValueForPoint( + int channel, const PaintingData& paintingData, + StitchData& stitchData, const SkPoint& point) const; + SkScalar noise2D(int channel, const PaintingData& paintingData, + const StitchData& stitchData, const SkPoint& noiseVector) const; + + SkMatrix fMatrix; + + typedef SkShader::Context INHERITED; + }; virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint&) const SK_OVERRIDE; @@ -92,14 +114,6 @@ private: const SkISize* tileSize); virtual ~SkPerlinNoiseShader(); - SkScalar noise2D(int channel, const PaintingData& paintingData, - const StitchData& stitchData, const SkPoint& noiseVector) const; - - SkScalar calculateTurbulenceValueForPoint(int channel, const PaintingData& paintingData, - StitchData& stitchData, const SkPoint& point) const; - - SkPMColor shade(const SkPoint& point, StitchData& stitchData) const; - // TODO (scroggo): Once all SkShaders are created from a factory, and we have removed the // constructor that creates SkPerlinNoiseShader from an SkReadBuffer, several fields can // be made constant. @@ -110,8 +124,6 @@ private: /*const*/ SkScalar fSeed; /*const*/ SkISize fTileSize; /*const*/ bool fStitchTiles; - // TODO (scroggo): Once setContext creates a new object, place this on that object. - SkMatrix fMatrix; PaintingData* fPaintingData; diff --git a/include/effects/SkTransparentShader.h b/include/effects/SkTransparentShader.h index 7428d442e3..790e5ae9fd 100644 --- a/include/effects/SkTransparentShader.h +++ b/include/effects/SkTransparentShader.h @@ -14,21 +14,31 @@ class SK_API SkTransparentShader : public SkShader { public: SkTransparentShader() {} - virtual uint32_t getFlags() SK_OVERRIDE; - virtual bool setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE; + virtual SkShader::Context* createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const + SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + + class TransparentShaderContext : public SkShader::Context { + public: + TransparentShaderContext(const SkTransparentShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); + virtual ~TransparentShaderContext(); + + virtual uint32_t getFlags() const SK_OVERRIDE; + virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE; + + private: + const SkBitmap* fDevice; + + typedef SkShader::Context INHERITED; + }; SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTransparentShader) private: - // these are a cache from the call to setContext() - const SkBitmap* fDevice; - uint8_t fAlpha; - SkTransparentShader(SkReadBuffer& buffer) : INHERITED(buffer) {} typedef SkShader INHERITED; diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp index a397b78439..5f5eb1866e 100644 --- a/src/core/SkBitmapProcShader.cpp +++ b/src/core/SkBitmapProcShader.cpp @@ -34,18 +34,16 @@ bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy) { fRawBitmap = src; - fState.fTileModeX = (uint8_t)tmx; - fState.fTileModeY = (uint8_t)tmy; - fFlags = 0; // computed in setContext + fTileModeX = (uint8_t)tmx; + fTileModeY = (uint8_t)tmy; } SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer) : INHERITED(buffer) { buffer.readBitmap(&fRawBitmap); fRawBitmap.setImmutable(); - fState.fTileModeX = buffer.readUInt(); - fState.fTileModeY = buffer.readUInt(); - fFlags = 0; // computed in setContext + fTileModeX = buffer.readUInt(); + fTileModeY = buffer.readUInt(); } SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, @@ -58,8 +56,8 @@ SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, texM->reset(); } if (xy) { - xy[0] = (TileMode)fState.fTileModeX; - xy[1] = (TileMode)fState.fTileModeY; + xy[0] = (TileMode)fTileModeX; + xy[1] = (TileMode)fTileModeY; } return kDefault_BitmapType; } @@ -68,8 +66,8 @@ void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); buffer.writeBitmap(fRawBitmap); - buffer.writeUInt(fState.fTileModeX); - buffer.writeUInt(fState.fTileModeY); + buffer.writeUInt(fTileModeX); + buffer.writeUInt(fTileModeY); } static bool only_scale_and_translate(const SkMatrix& matrix) { @@ -98,25 +96,67 @@ static bool valid_for_drawing(const SkBitmap& bm) { return true; } -bool SkBitmapProcShader::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { +bool SkBitmapProcShader::validInternal(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + SkMatrix* totalInverse, + SkBitmapProcState* state) const { if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) { return false; } - // do this first, so we have a correct inverse matrix - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; + // Make sure we can use totalInverse as a cache. + SkMatrix totalInverseLocal; + if (NULL == totalInverse) { + totalInverse = &totalInverseLocal; } - fState.fOrigBitmap = fRawBitmap; - if (!fState.chooseProcs(this->getTotalInverse(), paint)) { - this->INHERITED::endContext(); + // Do this first, so we know the matrix can be inverted. + if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) { return false; } - const SkBitmap& bitmap = *fState.fBitmap; + SkASSERT(state); + state->fTileModeX = fTileModeX; + state->fTileModeY = fTileModeY; + state->fOrigBitmap = fRawBitmap; + return state->chooseProcs(*totalInverse, paint); +} + +bool SkBitmapProcShader::validContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + SkMatrix* totalInverse) const { + SkBitmapProcState state; + return this->validInternal(device, paint, matrix, totalInverse, &state); +} + +SkShader::Context* SkBitmapProcShader::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext); + SkBitmapProcState* state = SkNEW_PLACEMENT(stateStorage, SkBitmapProcState); + if (!this->validInternal(device, paint, matrix, NULL, state)) { + state->~SkBitmapProcState(); + return NULL; + } + + return SkNEW_PLACEMENT_ARGS(storage, BitmapProcShaderContext, + (*this, device, paint, matrix, state)); +} + +size_t SkBitmapProcShader::contextSize() const { + // The SkBitmapProcState is stored outside of the context object, with the context holding + // a pointer to it. + return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState); +} + +SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext( + const SkBitmapProcShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix, SkBitmapProcState* state) + : INHERITED(shader, device, paint, matrix) + , fState(state) +{ + const SkBitmap& bitmap = *fState->fBitmap; bool bitmapIsOpaque = bitmap.isOpaque(); // update fFlags @@ -157,12 +197,12 @@ bool SkBitmapProcShader::setContext(const SkBitmap& device, } fFlags = flags; - return true; } -void SkBitmapProcShader::endContext() { - fState.endContext(); - this->INHERITED::endContext(); +SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() { + // The bitmap proc state has been created outside of the context on memory that will be freed + // elsewhere. Only call the destructor but leave the freeing of the memory to the caller. + fState->~SkBitmapProcState(); } #define BUF_MAX 128 @@ -176,8 +216,9 @@ void SkBitmapProcShader::endContext() { #define TEST_BUFFER_EXTRA 0 #endif -void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { - const SkBitmapProcState& state = fState; +void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], + int count) { + const SkBitmapProcState& state = *fState; if (state.getShaderProc32()) { state.getShaderProc32()(state, x, y, dstC, count); return; @@ -186,7 +227,7 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA]; SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32(); - int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); + int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX); SkASSERT(state.fBitmap->getPixels()); SkASSERT(state.fBitmap->pixelRef() == NULL || @@ -220,16 +261,17 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { } } -SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) { - if (fState.getShaderProc32()) { - *ctx = &fState; - return (ShadeProc)fState.getShaderProc32(); +SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) { + if (fState->getShaderProc32()) { + *ctx = fState; + return (ShadeProc)fState->getShaderProc32(); } return NULL; } -void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { - const SkBitmapProcState& state = fState; +void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], + int count) { + const SkBitmapProcState& state = *fState; if (state.getShaderProc16()) { state.getShaderProc16()(state, x, y, dstC, count); return; @@ -238,7 +280,7 @@ void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { uint32_t buffer[BUF_MAX]; SkBitmapProcState::MatrixProc mproc = state.getMatrixProc(); SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16(); - int max = fState.maxCountForBufferSize(sizeof(buffer)); + int max = state.maxCountForBufferSize(sizeof(buffer)); SkASSERT(state.fBitmap->getPixels()); SkASSERT(state.fBitmap->pixelRef() == NULL || @@ -342,8 +384,8 @@ void SkBitmapProcShader::toString(SkString* str) const { str->append("BitmapShader: ("); str->appendf("(%s, %s)", - gTileModeName[fState.fTileModeX], - gTileModeName[fState.fTileModeY]); + gTileModeName[fTileModeX], + gTileModeName[fTileModeY]); str->append(" "); fRawBitmap.toString(str); @@ -384,8 +426,8 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& matrix.preConcat(lmInverse); SkShader::TileMode tm[] = { - (TileMode)fState.fTileModeX, - (TileMode)fState.fTileModeY, + (TileMode)fTileModeX, + (TileMode)fTileModeY, }; // Must set wrap and filter on the sampler before requesting a texture. In two places below diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h index 8e225a5e98..e0c78b8e45 100644 --- a/src/core/SkBitmapProcShader.h +++ b/src/core/SkBitmapProcShader.h @@ -20,14 +20,16 @@ public: // overrides from SkShader virtual bool isOpaque() const SK_OVERRIDE; - virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE; - virtual void endContext() SK_OVERRIDE; - virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; } - virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; - virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*) const SK_OVERRIDE; + virtual bool validContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + SkMatrix* totalInverse = NULL) const SK_OVERRIDE; + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, void* storage) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + static bool CanDo(const SkBitmap&, TileMode tx, TileMode ty); SK_TO_STRING_OVERRIDE() @@ -37,22 +39,54 @@ public: GrEffectRef* asNewEffect(GrContext*, const SkPaint&) const SK_OVERRIDE; #endif + class BitmapProcShaderContext : public SkShader::Context { + public: + // The context takes ownership of the state. It will call its destructor + // but will NOT free the memory. + BitmapProcShaderContext(const SkBitmapProcShader& shader, + const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + SkBitmapProcState* state); + virtual ~BitmapProcShaderContext(); + + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; + + virtual uint32_t getFlags() const SK_OVERRIDE { return fFlags; } + + private: + SkBitmapProcState* fState; + uint32_t fFlags; + + typedef SkShader::Context INHERITED; + }; + protected: SkBitmapProcShader(SkReadBuffer& ); virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; - SkBitmap fRawBitmap; // experimental for RLE encoding - SkBitmapProcState fState; - uint32_t fFlags; + SkBitmap fRawBitmap; // experimental for RLE encoding + uint8_t fTileModeX, fTileModeY; private: + bool validInternal(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse, + SkBitmapProcState* state) const; + typedef SkShader INHERITED; }; -// Commonly used allocator. It currently is only used to allocate up to 2 objects. The total -// bytes requested is calculated using one of our large shaders plus the size of an Sk3DBlitter -// in SkDraw.cpp -typedef SkSmallAllocator<2, sizeof(SkBitmapProcShader) + sizeof(void*) * 2> SkTBlitterAllocator; +// Commonly used allocator. It currently is only used to allocate up to 3 objects. The total +// bytes requested is calculated using one of our large shaders, its context size plus the size of +// an Sk3DBlitter in SkDraw.cpp +// Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not +// yet found a situation where the size below isn't big enough. +typedef SkSmallAllocator<3, sizeof(SkBitmapProcShader) + + sizeof(SkBitmapProcShader::BitmapProcShaderContext) + + sizeof(SkBitmapProcState) + + sizeof(void*) * 2> SkTBlitterAllocator; // If alloc is non-NULL, it will be used to allocate the returned SkShader, and MUST outlive // the SkShader. diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index cdc582bfee..8874e7b445 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -398,6 +398,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { } // The above logic should have always assigned fBitmap, but in case it // didn't, we check for that now... + // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)? if (NULL == fBitmap) { return false; } @@ -480,6 +481,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { // shader will perform. fMatrixProc = this->chooseMatrixProc(trivialMatrix); + // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL. if (NULL == fMatrixProc) { return false; } @@ -521,6 +523,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { fPaintPMColor = SkPreMultiplyColor(paint.getColor()); break; default: + // TODO(dominikg): Should we ever get here? SkASSERT(false) instead? return false; } diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index 52a05eded8..ad51874271 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -26,6 +26,15 @@ SkBlitter::~SkBlitter() {} bool SkBlitter::isNullBlitter() const { return false; } +bool SkBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix) { + return true; +} + +SkShader::Context* SkBlitter::getShaderContext() const { + return NULL; +} + const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) { return NULL; } @@ -568,102 +577,149 @@ class Sk3DShader : public SkShader { public: Sk3DShader(SkShader* proxy) : fProxy(proxy) { SkSafeRef(proxy); - fMask = NULL; } virtual ~Sk3DShader() { SkSafeUnref(fProxy); } - void setMask(const SkMask* mask) { fMask = mask; } + virtual size_t contextSize() const SK_OVERRIDE { + size_t size = sizeof(Sk3DShaderContext); + if (fProxy) { + size += fProxy->contextSize(); + } + return size; + } - virtual bool setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix) SK_OVERRIDE { - if (!this->INHERITED::setContext(device, paint, matrix)) { + virtual bool validContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const + SK_OVERRIDE + { + if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) { return false; } if (fProxy) { - if (!fProxy->setContext(device, paint, matrix)) { - // must keep our set/end context calls balanced - this->INHERITED::endContext(); - return false; - } - } else { - fPMColor = SkPreMultiplyColor(paint.getColor()); + return fProxy->validContext(device, paint, matrix); } return true; } - virtual void endContext() SK_OVERRIDE { + virtual SkShader::Context* createContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + void* storage) const SK_OVERRIDE + { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + SkShader::Context* proxyContext; if (fProxy) { - fProxy->endContext(); + char* proxyContextStorage = (char*) storage + sizeof(Sk3DShaderContext); + proxyContext = fProxy->createContext(device, paint, matrix, proxyContextStorage); + SkASSERT(proxyContext); + } else { + proxyContext = NULL; } - this->INHERITED::endContext(); + return SkNEW_PLACEMENT_ARGS(storage, Sk3DShaderContext, (*this, device, paint, matrix, + proxyContext)); } - virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE { - if (fProxy) { - fProxy->shadeSpan(x, y, span, count); + class Sk3DShaderContext : public SkShader::Context { + public: + // Calls proxyContext's destructor but will NOT free its memory. + Sk3DShaderContext(const Sk3DShader& shader, const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkShader::Context* proxyContext) + : INHERITED(shader, device, paint, matrix) + , fMask(NULL) + , fProxyContext(proxyContext) + { + if (!fProxyContext) { + fPMColor = SkPreMultiplyColor(paint.getColor()); + } } - if (fMask == NULL) { - if (fProxy == NULL) { - sk_memset32(span, fPMColor, count); + virtual ~Sk3DShaderContext() { + if (fProxyContext) { + fProxyContext->SkShader::Context::~Context(); } - return; } - SkASSERT(fMask->fBounds.contains(x, y)); - SkASSERT(fMask->fBounds.contains(x + count - 1, y)); + void setMask(const SkMask* mask) { fMask = mask; } - size_t size = fMask->computeImageSize(); - const uint8_t* alpha = fMask->getAddr8(x, y); - const uint8_t* mulp = alpha + size; - const uint8_t* addp = mulp + size; + virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE { + if (fProxyContext) { + fProxyContext->shadeSpan(x, y, span, count); + } - if (fProxy) { - for (int i = 0; i < count; i++) { - if (alpha[i]) { - SkPMColor c = span[i]; - if (c) { - unsigned a = SkGetPackedA32(c); - unsigned r = SkGetPackedR32(c); - unsigned g = SkGetPackedG32(c); - unsigned b = SkGetPackedB32(c); + if (fMask == NULL) { + if (fProxyContext == NULL) { + sk_memset32(span, fPMColor, count); + } + return; + } + SkASSERT(fMask->fBounds.contains(x, y)); + SkASSERT(fMask->fBounds.contains(x + count - 1, y)); + + size_t size = fMask->computeImageSize(); + const uint8_t* alpha = fMask->getAddr8(x, y); + const uint8_t* mulp = alpha + size; + const uint8_t* addp = mulp + size; + + if (fProxyContext) { + for (int i = 0; i < count; i++) { + if (alpha[i]) { + SkPMColor c = span[i]; + if (c) { + unsigned a = SkGetPackedA32(c); + unsigned r = SkGetPackedR32(c); + unsigned g = SkGetPackedG32(c); + unsigned b = SkGetPackedB32(c); + + unsigned mul = SkAlpha255To256(mulp[i]); + unsigned add = addp[i]; + + r = SkFastMin32(SkAlphaMul(r, mul) + add, a); + g = SkFastMin32(SkAlphaMul(g, mul) + add, a); + b = SkFastMin32(SkAlphaMul(b, mul) + add, a); + + span[i] = SkPackARGB32(a, r, g, b); + } + } else { + span[i] = 0; + } + } + } else { // color + unsigned a = SkGetPackedA32(fPMColor); + unsigned r = SkGetPackedR32(fPMColor); + unsigned g = SkGetPackedG32(fPMColor); + unsigned b = SkGetPackedB32(fPMColor); + for (int i = 0; i < count; i++) { + if (alpha[i]) { unsigned mul = SkAlpha255To256(mulp[i]); unsigned add = addp[i]; - r = SkFastMin32(SkAlphaMul(r, mul) + add, a); - g = SkFastMin32(SkAlphaMul(g, mul) + add, a); - b = SkFastMin32(SkAlphaMul(b, mul) + add, a); - - span[i] = SkPackARGB32(a, r, g, b); + span[i] = SkPackARGB32( a, + SkFastMin32(SkAlphaMul(r, mul) + add, a), + SkFastMin32(SkAlphaMul(g, mul) + add, a), + SkFastMin32(SkAlphaMul(b, mul) + add, a)); + } else { + span[i] = 0; } - } else { - span[i] = 0; - } - } - } else { // color - unsigned a = SkGetPackedA32(fPMColor); - unsigned r = SkGetPackedR32(fPMColor); - unsigned g = SkGetPackedG32(fPMColor); - unsigned b = SkGetPackedB32(fPMColor); - for (int i = 0; i < count; i++) { - if (alpha[i]) { - unsigned mul = SkAlpha255To256(mulp[i]); - unsigned add = addp[i]; - - span[i] = SkPackARGB32( a, - SkFastMin32(SkAlphaMul(r, mul) + add, a), - SkFastMin32(SkAlphaMul(g, mul) + add, a), - SkFastMin32(SkAlphaMul(b, mul) + add, a)); - } else { - span[i] = 0; } } } - } + + private: + // Unowned. + const SkMask* fMask; + // Memory is unowned, but we need to call the destructor. + SkShader::Context* fProxyContext; + SkPMColor fPMColor; + + typedef SkShader::Context INHERITED; + }; #ifndef SK_IGNORE_TO_STRING virtual void toString(SkString* str) const SK_OVERRIDE { @@ -685,29 +741,30 @@ public: protected: Sk3DShader(SkReadBuffer& buffer) : INHERITED(buffer) { fProxy = buffer.readShader(); - fPMColor = buffer.readColor(); - fMask = NULL; + // Leaving this here until we bump the picture version, though this + // shader should never be recorded. + buffer.readColor(); } virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE { this->INHERITED::flatten(buffer); buffer.writeFlattenable(fProxy); - buffer.writeColor(fPMColor); + // Leaving this here until we bump the picture version, though this + // shader should never be recorded. + buffer.writeColor(SkColor()); } private: SkShader* fProxy; - SkPMColor fPMColor; - const SkMask* fMask; typedef SkShader INHERITED; }; class Sk3DBlitter : public SkBlitter { public: - Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader) + Sk3DBlitter(SkBlitter* proxy, Sk3DShader::Sk3DShaderContext* shaderContext) : fProxy(proxy) - , f3DShader(SkRef(shader)) + , f3DShaderContext(shaderContext) {} virtual void blitH(int x, int y, int width) { @@ -729,22 +786,22 @@ public: virtual void blitMask(const SkMask& mask, const SkIRect& clip) { if (mask.fFormat == SkMask::k3D_Format) { - f3DShader->setMask(&mask); + f3DShaderContext->setMask(&mask); ((SkMask*)&mask)->fFormat = SkMask::kA8_Format; fProxy->blitMask(mask, clip); ((SkMask*)&mask)->fFormat = SkMask::k3D_Format; - f3DShader->setMask(NULL); + f3DShaderContext->setMask(NULL); } else { fProxy->blitMask(mask, clip); } } private: - // fProxy is unowned. It will be deleted by SkSmallAllocator. - SkBlitter* fProxy; - SkAutoTUnref<Sk3DShader> f3DShader; + // Both pointers are unowned. They will be deleted by SkSmallAllocator. + SkBlitter* fProxy; + Sk3DShader::Sk3DShaderContext* f3DShaderContext; }; /////////////////////////////////////////////////////////////////////////////// @@ -754,8 +811,7 @@ private: static bool just_solid_color(const SkPaint& paint) { if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) { SkShader* shader = paint.getShader(); - if (NULL == shader || - (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { + if (NULL == shader) { return true; } } @@ -893,16 +949,22 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, } /* - * We need to have balanced calls to the shader: - * setContext - * endContext - * We make the first call here, in case it fails we can abort the draw. - * The endContext() call is made by the blitter (assuming setContext did - * not fail) in its destructor. + * We create a SkShader::Context object, and store it on the blitter. */ - if (shader && !shader->setContext(device, *paint, matrix)) { - blitter = allocator->createT<SkNullBlitter>(); - return blitter; + SkShader::Context* shaderContext; + if (shader) { + // Try to create the ShaderContext + void* storage = allocator->reserveT<SkShader::Context>(shader->contextSize()); + shaderContext = shader->createContext(device, *paint, matrix, storage); + if (!shaderContext) { + allocator->freeLast(); + blitter = allocator->createT<SkNullBlitter>(); + return blitter; + } + SkASSERT(shaderContext); + SkASSERT((void*) shaderContext == storage); + } else { + shaderContext = NULL; } @@ -913,19 +975,20 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, SkASSERT(NULL == paint->getXfermode()); blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint); } else if (shader) { - blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint); + blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint, shaderContext); } else { blitter = allocator->createT<SkA8_Blitter>(device, *paint); } break; case kRGB_565_SkColorType: - blitter = SkBlitter_ChooseD565(device, *paint, allocator); + blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, allocator); break; case kN32_SkColorType: if (shader) { - blitter = allocator->createT<SkARGB32_Shader_Blitter>(device, *paint); + blitter = allocator->createT<SkARGB32_Shader_Blitter>( + device, *paint, shaderContext); } else if (paint->getColor() == SK_ColorBLACK) { blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint); } else if (paint->getAlpha() == 0xFF) { @@ -944,7 +1007,9 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, if (shader3D) { SkBlitter* innerBlitter = blitter; // innerBlitter was allocated by allocator, which will delete it. - blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shader3D); + // We know shaderContext is of type Sk3DShaderContext because it belongs to shader3D. + blitter = allocator->createT<Sk3DBlitter>(innerBlitter, + static_cast<Sk3DShader::Sk3DShaderContext*>(shaderContext)); } return blitter; } @@ -956,18 +1021,36 @@ const uint32_t gMask_00FF00FF = 0xFF00FF; /////////////////////////////////////////////////////////////////////////////// -SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint) - : INHERITED(device) { - fShader = paint.getShader(); +SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext) + : INHERITED(device) + , fShader(paint.getShader()) + , fShaderContext(shaderContext) { SkASSERT(fShader); - SkASSERT(fShader->setContextHasBeenCalled()); + SkASSERT(fShaderContext); fShader->ref(); - fShaderFlags = fShader->getFlags(); + fShaderFlags = fShaderContext->getFlags(); } SkShaderBlitter::~SkShaderBlitter() { - SkASSERT(fShader->setContextHasBeenCalled()); - fShader->endContext(); fShader->unref(); } + +bool SkShaderBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix) { + if (!fShader->validContext(device, paint, matrix)) { + return false; + } + + // Only destroy the old context if we have a new one. We need to ensure to have a + // live context in fShaderContext because the storage is owned by an SkSmallAllocator + // outside of this class. + // The new context will be of the same size as the old one because we use the same + // shader to create it. It is therefore safe to re-use the storage. + fShaderContext->SkShader::Context::~Context(); + fShaderContext = fShader->createContext(device, paint, matrix, (void*)fShaderContext); + SkASSERT(fShaderContext); + + return true; +} diff --git a/src/core/SkBlitter.h b/src/core/SkBlitter.h index d19a34badc..f76839e8b6 100644 --- a/src/core/SkBlitter.h +++ b/src/core/SkBlitter.h @@ -61,6 +61,13 @@ public: */ virtual bool isNullBlitter() const; + /** + * Special methods for SkShaderBlitter. On all other classes this is a no-op. + */ + virtual bool resetShaderContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix); + virtual SkShader::Context* getShaderContext() const; + ///@name non-virtual helpers void blitMaskRegion(const SkMask& mask, const SkRegion& clip); void blitRectRegion(const SkIRect& rect, const SkRegion& clip); diff --git a/src/core/SkBlitter_A8.cpp b/src/core/SkBlitter_A8.cpp index 983a226e34..11f425903b 100644 --- a/src/core/SkBlitter_A8.cpp +++ b/src/core/SkBlitter_A8.cpp @@ -228,11 +228,12 @@ void SkA8_Blitter::blitRect(int x, int y, int width, int height) { /////////////////////////////////////////////////////////////////////// -SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) - : INHERITED(device, paint) { +SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext) + : INHERITED(device, paint, shaderContext) { if ((fXfermode = paint.getXfermode()) != NULL) { fXfermode->ref(); - SkASSERT(fShader); + SkASSERT(fShaderContext); } int width = device.width(); @@ -250,13 +251,14 @@ void SkA8_Shader_Blitter::blitH(int x, int y, int width) { (unsigned)(x + width) <= (unsigned)fDevice.width()); uint8_t* device = fDevice.getAddr8(x, y); + SkShader::Context* shaderContext = fShaderContext; - if ((fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) && !fXfermode) { + if ((shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) && !fXfermode) { memset(device, 0xFF, width); } else { SkPMColor* span = fBuffer; - fShader->shadeSpan(x, y, span, width); + shaderContext->shadeSpan(x, y, span, width); if (fXfermode) { fXfermode->xferA8(device, span, width, NULL); } else { @@ -282,12 +284,12 @@ static inline uint8_t aa_blend8(SkPMColor src, U8CPU da, int aa) { void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { - SkShader* shader = fShader; - SkXfermode* mode = fXfermode; - uint8_t* aaExpand = fAAExpand; - SkPMColor* span = fBuffer; - uint8_t* device = fDevice.getAddr8(x, y); - int opaque = fShader->getFlags() & SkShader::kOpaqueAlpha_Flag; + SkShader::Context* shaderContext = fShaderContext; + SkXfermode* mode = fXfermode; + uint8_t* aaExpand = fAAExpand; + SkPMColor* span = fBuffer; + uint8_t* device = fDevice.getAddr8(x, y); + int opaque = shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag; for (;;) { int count = *runs; @@ -299,7 +301,7 @@ void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], if (opaque && aa == 255 && mode == NULL) { memset(device, 0xFF, count); } else { - shader->shadeSpan(x, y, span, count); + shaderContext->shadeSpan(x, y, span, count); if (mode) { memset(aaExpand, aa, count); mode->xferA8(device, span, count, aaExpand); @@ -329,11 +331,12 @@ void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { int height = clip.height(); uint8_t* device = fDevice.getAddr8(x, y); const uint8_t* alpha = mask.getAddr8(x, y); + SkShader::Context* shaderContext = fShaderContext; SkPMColor* span = fBuffer; while (--height >= 0) { - fShader->shadeSpan(x, y, span, width); + shaderContext->shadeSpan(x, y, span, width); if (fXfermode) { fXfermode->xferA8(device, span, width, alpha); } else { diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp index d4bec1bc08..118a1d12f3 100644 --- a/src/core/SkBlitter_ARGB32.cpp +++ b/src/core/SkBlitter_ARGB32.cpp @@ -275,14 +275,16 @@ static void blend_srcmode(SkPMColor* SK_RESTRICT device, } SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device, - const SkPaint& paint) : INHERITED(device, paint) { + const SkPaint& paint, SkShader::Context* shaderContext) + : INHERITED(device, paint, shaderContext) +{ fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor))); fXfermode = paint.getXfermode(); SkSafeRef(fXfermode); int flags = 0; - if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { + if (!(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) { flags |= SkBlitRow::kSrcPixelAlpha_Flag32; } // we call this on the output from the shader @@ -292,7 +294,7 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device, fShadeDirectlyIntoDevice = false; if (fXfermode == NULL) { - if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) { + if (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) { fShadeDirectlyIntoDevice = true; } } else { @@ -305,7 +307,7 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device, } } - fConstInY = SkToBool(fShader->getFlags() & SkShader::kConstInY32_Flag); + fConstInY = SkToBool(shaderContext->getFlags() & SkShader::kConstInY32_Flag); } SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() { @@ -319,10 +321,10 @@ void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) { uint32_t* device = fDevice.getAddr32(x, y); if (fShadeDirectlyIntoDevice) { - fShader->shadeSpan(x, y, device, width); + fShaderContext->shadeSpan(x, y, device, width); } else { SkPMColor* span = fBuffer; - fShader->shadeSpan(x, y, span, width); + fShaderContext->shadeSpan(x, y, span, width); if (fXfermode) { fXfermode->xfer32(device, span, width, NULL); } else { @@ -335,22 +337,22 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) { SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height()); - uint32_t* device = fDevice.getAddr32(x, y); - size_t deviceRB = fDevice.rowBytes(); - SkShader* shader = fShader; - SkPMColor* span = fBuffer; + uint32_t* device = fDevice.getAddr32(x, y); + size_t deviceRB = fDevice.rowBytes(); + SkShader::Context* shaderContext = fShaderContext; + SkPMColor* span = fBuffer; if (fConstInY) { if (fShadeDirectlyIntoDevice) { // shade the first row directly into the device - fShader->shadeSpan(x, y, device, width); + shaderContext->shadeSpan(x, y, device, width); span = device; while (--height > 0) { device = (uint32_t*)((char*)device + deviceRB); memcpy(device, span, width << 2); } } else { - fShader->shadeSpan(x, y, span, width); + shaderContext->shadeSpan(x, y, span, width); SkXfermode* xfer = fXfermode; if (xfer) { do { @@ -372,7 +374,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) { if (fShadeDirectlyIntoDevice) { void* ctx; - SkShader::ShadeProc shadeProc = fShader->asAShadeProc(&ctx); + SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx); if (shadeProc) { do { shadeProc(ctx, x, y, device, width); @@ -381,7 +383,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) { } while (--height > 0); } else { do { - shader->shadeSpan(x, y, device, width); + shaderContext->shadeSpan(x, y, device, width); y += 1; device = (uint32_t*)((char*)device + deviceRB); } while (--height > 0); @@ -390,7 +392,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) { SkXfermode* xfer = fXfermode; if (xfer) { do { - shader->shadeSpan(x, y, span, width); + shaderContext->shadeSpan(x, y, span, width); xfer->xfer32(device, span, width, NULL); y += 1; device = (uint32_t*)((char*)device + deviceRB); @@ -398,7 +400,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) { } else { SkBlitRow::Proc32 proc = fProc32; do { - shader->shadeSpan(x, y, span, width); + shaderContext->shadeSpan(x, y, span, width); proc(device, span, width, 255); y += 1; device = (uint32_t*)((char*)device + deviceRB); @@ -409,9 +411,9 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) { void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { - SkPMColor* span = fBuffer; - uint32_t* device = fDevice.getAddr32(x, y); - SkShader* shader = fShader; + SkPMColor* span = fBuffer; + uint32_t* device = fDevice.getAddr32(x, y); + SkShader::Context* shaderContext = fShaderContext; if (fXfermode && !fShadeDirectlyIntoDevice) { for (;;) { @@ -422,7 +424,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], break; int aa = *antialias; if (aa) { - shader->shadeSpan(x, y, span, count); + shaderContext->shadeSpan(x, y, span, count); if (aa == 255) { xfer->xfer32(device, span, count, NULL); } else { @@ -438,7 +440,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], x += count; } } else if (fShadeDirectlyIntoDevice || - (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { + (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) { for (;;) { int count = *runs; if (count <= 0) { @@ -448,9 +450,9 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], if (aa) { if (aa == 255) { // cool, have the shader draw right into the device - shader->shadeSpan(x, y, device, count); + shaderContext->shadeSpan(x, y, device, count); } else { - shader->shadeSpan(x, y, span, count); + shaderContext->shadeSpan(x, y, span, count); fProc32Blend(device, span, count, aa); } } @@ -467,7 +469,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], } int aa = *antialias; if (aa) { - fShader->shadeSpan(x, y, span, count); + shaderContext->shadeSpan(x, y, span, count); if (aa == 255) { fProc32(device, span, count, 255); } else { @@ -491,10 +493,11 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) SkASSERT(mask.fBounds.contains(clip)); + SkShader::Context* shaderContext = fShaderContext; SkBlitMask::RowProc proc = NULL; if (!fXfermode) { unsigned flags = 0; - if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) { + if (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) { flags |= SkBlitMask::kSrcIsOpaque_RowFlag; } proc = SkBlitMask::RowFactory(SkBitmap::kARGB_8888_Config, mask.fFormat, @@ -515,14 +518,13 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y); const size_t maskRB = mask.fRowBytes; - SkShader* shader = fShader; SkPMColor* span = fBuffer; if (fXfermode) { SkASSERT(SkMask::kA8_Format == mask.fFormat); SkXfermode* xfer = fXfermode; do { - shader->shadeSpan(x, y, span, width); + shaderContext->shadeSpan(x, y, span, width); xfer->xfer32((SkPMColor*)dstRow, span, width, maskRow); dstRow += dstRB; maskRow += maskRB; @@ -530,7 +532,7 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) } while (--height > 0); } else { do { - shader->shadeSpan(x, y, span, width); + shaderContext->shadeSpan(x, y, span, width); proc(dstRow, maskRow, span, width); dstRow += dstRB; maskRow += maskRB; @@ -542,13 +544,13 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height()); - uint32_t* device = fDevice.getAddr32(x, y); - size_t deviceRB = fDevice.rowBytes(); - SkShader* shader = fShader; + uint32_t* device = fDevice.getAddr32(x, y); + size_t deviceRB = fDevice.rowBytes(); + SkShader::Context* shaderContext = fShaderContext; if (fConstInY) { SkPMColor c; - fShader->shadeSpan(x, y, &c, 1); + shaderContext->shadeSpan(x, y, &c, 1); if (fShadeDirectlyIntoDevice) { if (255 == alpha) { @@ -582,7 +584,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { if (fShadeDirectlyIntoDevice) { void* ctx; - SkShader::ShadeProc shadeProc = fShader->asAShadeProc(&ctx); + SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx); if (255 == alpha) { if (shadeProc) { do { @@ -592,7 +594,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { } while (--height > 0); } else { do { - shader->shadeSpan(x, y, device, 1); + shaderContext->shadeSpan(x, y, device, 1); y += 1; device = (uint32_t*)((char*)device + deviceRB); } while (--height > 0); @@ -608,7 +610,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { } while (--height > 0); } else { do { - shader->shadeSpan(x, y, &c, 1); + shaderContext->shadeSpan(x, y, &c, 1); *device = SkFourByteInterp(c, *device, alpha); y += 1; device = (uint32_t*)((char*)device + deviceRB); @@ -620,7 +622,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { SkXfermode* xfer = fXfermode; if (xfer) { do { - shader->shadeSpan(x, y, span, 1); + shaderContext->shadeSpan(x, y, span, 1); xfer->xfer32(device, span, 1, &alpha); y += 1; device = (uint32_t*)((char*)device + deviceRB); @@ -628,7 +630,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { } else { SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend; do { - shader->shadeSpan(x, y, span, 1); + shaderContext->shadeSpan(x, y, span, 1); proc(device, span, 1, alpha); y += 1; device = (uint32_t*)((char*)device + deviceRB); diff --git a/src/core/SkBlitter_RGB16.cpp b/src/core/SkBlitter_RGB16.cpp index 21b5a16e3c..e22aac4eda 100644 --- a/src/core/SkBlitter_RGB16.cpp +++ b/src/core/SkBlitter_RGB16.cpp @@ -107,7 +107,8 @@ private: class SkRGB16_Shader_Blitter : public SkShaderBlitter { public: - SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint); + SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext); virtual ~SkRGB16_Shader_Blitter(); virtual void blitH(int x, int y, int width); virtual void blitAntiH(int x, int y, const SkAlpha* antialias, @@ -129,7 +130,8 @@ private: // used only if the shader can perform shadSpan16 class SkRGB16_Shader16_Blitter : public SkRGB16_Shader_Blitter { public: - SkRGB16_Shader16_Blitter(const SkBitmap& device, const SkPaint& paint); + SkRGB16_Shader16_Blitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext); virtual void blitH(int x, int y, int width); virtual void blitAntiH(int x, int y, const SkAlpha* antialias, const int16_t* runs); @@ -141,7 +143,8 @@ private: class SkRGB16_Shader_Xfermode_Blitter : public SkShaderBlitter { public: - SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint); + SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext); virtual ~SkRGB16_Shader_Xfermode_Blitter(); virtual void blitH(int x, int y, int width); virtual void blitAntiH(int x, int y, const SkAlpha* antialias, @@ -679,8 +682,9 @@ void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) { /////////////////////////////////////////////////////////////////////////////// SkRGB16_Shader16_Blitter::SkRGB16_Shader16_Blitter(const SkBitmap& device, - const SkPaint& paint) - : SkRGB16_Shader_Blitter(device, paint) { + const SkPaint& paint, + SkShader::Context* shaderContext) + : SkRGB16_Shader_Blitter(device, paint, shaderContext) { SkASSERT(SkShader::CanCallShadeSpan16(fShaderFlags)); } @@ -688,28 +692,28 @@ void SkRGB16_Shader16_Blitter::blitH(int x, int y, int width) { SkASSERT(x + width <= fDevice.width()); uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y); - SkShader* shader = fShader; + SkShader::Context* shaderContext = fShaderContext; - int alpha = shader->getSpan16Alpha(); + int alpha = shaderContext->getSpan16Alpha(); if (0xFF == alpha) { - shader->shadeSpan16(x, y, device, width); + shaderContext->shadeSpan16(x, y, device, width); } else { uint16_t* span16 = (uint16_t*)fBuffer; - shader->shadeSpan16(x, y, span16, width); + shaderContext->shadeSpan16(x, y, span16, width); SkBlendRGB16(span16, device, SkAlpha255To256(alpha), width); } } void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) { - SkShader* shader = fShader; - uint16_t* dst = fDevice.getAddr16(x, y); - size_t dstRB = fDevice.rowBytes(); - int alpha = shader->getSpan16Alpha(); + SkShader::Context* shaderContext = fShaderContext; + uint16_t* dst = fDevice.getAddr16(x, y); + size_t dstRB = fDevice.rowBytes(); + int alpha = shaderContext->getSpan16Alpha(); if (0xFF == alpha) { if (fShaderFlags & SkShader::kConstInY16_Flag) { // have the shader blit directly into the device the first time - shader->shadeSpan16(x, y, dst, width); + shaderContext->shadeSpan16(x, y, dst, width); // and now just memcpy that line on the subsequent lines if (--height > 0) { const uint16_t* orig = dst; @@ -720,7 +724,7 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) { } } else { // need to call shadeSpan16 for every line do { - shader->shadeSpan16(x, y, dst, width); + shaderContext->shadeSpan16(x, y, dst, width); y += 1; dst = (uint16_t*)((char*)dst + dstRB); } while (--height); @@ -729,14 +733,14 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) { int scale = SkAlpha255To256(alpha); uint16_t* span16 = (uint16_t*)fBuffer; if (fShaderFlags & SkShader::kConstInY16_Flag) { - shader->shadeSpan16(x, y, span16, width); + shaderContext->shadeSpan16(x, y, span16, width); do { SkBlendRGB16(span16, dst, scale, width); dst = (uint16_t*)((char*)dst + dstRB); } while (--height); } else { do { - shader->shadeSpan16(x, y, span16, width); + shaderContext->shadeSpan16(x, y, span16, width); SkBlendRGB16(span16, dst, scale, width); y += 1; dst = (uint16_t*)((char*)dst + dstRB); @@ -748,11 +752,11 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) { void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y, const SkAlpha* SK_RESTRICT antialias, const int16_t* SK_RESTRICT runs) { - SkShader* shader = fShader; + SkShader::Context* shaderContext = fShaderContext; SkPMColor* SK_RESTRICT span = fBuffer; - uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y); + uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y); - int alpha = shader->getSpan16Alpha(); + int alpha = shaderContext->getSpan16Alpha(); uint16_t* span16 = (uint16_t*)span; if (0xFF == alpha) { @@ -766,9 +770,9 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y, int aa = *antialias; if (aa == 255) { // go direct to the device! - shader->shadeSpan16(x, y, device, count); + shaderContext->shadeSpan16(x, y, device, count); } else if (aa) { - shader->shadeSpan16(x, y, span16, count); + shaderContext->shadeSpan16(x, y, span16, count); SkBlendRGB16(span16, device, SkAlpha255To256(aa), count); } device += count; @@ -787,7 +791,7 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y, int aa = SkAlphaMul(*antialias, alpha); if (aa) { - shader->shadeSpan16(x, y, span16, count); + shaderContext->shadeSpan16(x, y, span16, count); SkBlendRGB16(span16, device, SkAlpha255To256(aa), count); } @@ -802,8 +806,9 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y, /////////////////////////////////////////////////////////////////////////////// SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkBitmap& device, - const SkPaint& paint) -: INHERITED(device, paint) { + const SkPaint& paint, + SkShader::Context* shaderContext) +: INHERITED(device, paint, shaderContext) { SkASSERT(paint.getXfermode() == NULL); fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor)); @@ -834,20 +839,20 @@ SkRGB16_Shader_Blitter::~SkRGB16_Shader_Blitter() { void SkRGB16_Shader_Blitter::blitH(int x, int y, int width) { SkASSERT(x + width <= fDevice.width()); - fShader->shadeSpan(x, y, fBuffer, width); + fShaderContext->shadeSpan(x, y, fBuffer, width); // shaders take care of global alpha, so we pass 0xFF (should be ignored) fOpaqueProc(fDevice.getAddr16(x, y), fBuffer, width, 0xFF, x, y); } void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) { - SkShader* shader = fShader; - SkBlitRow::Proc proc = fOpaqueProc; - SkPMColor* buffer = fBuffer; - uint16_t* dst = fDevice.getAddr16(x, y); - size_t dstRB = fDevice.rowBytes(); + SkShader::Context* shaderContext = fShaderContext; + SkBlitRow::Proc proc = fOpaqueProc; + SkPMColor* buffer = fBuffer; + uint16_t* dst = fDevice.getAddr16(x, y); + size_t dstRB = fDevice.rowBytes(); if (fShaderFlags & SkShader::kConstInY32_Flag) { - shader->shadeSpan(x, y, buffer, width); + shaderContext->shadeSpan(x, y, buffer, width); do { proc(dst, buffer, width, 0xFF, x, y); y += 1; @@ -855,7 +860,7 @@ void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) { } while (--height); } else { do { - shader->shadeSpan(x, y, buffer, width); + shaderContext->shadeSpan(x, y, buffer, width); proc(dst, buffer, width, 0xFF, x, y); y += 1; dst = (uint16_t*)((char*)dst + dstRB); @@ -880,9 +885,9 @@ static inline int count_nonzero_span(const int16_t runs[], const SkAlpha aa[]) { void SkRGB16_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha* SK_RESTRICT antialias, const int16_t* SK_RESTRICT runs) { - SkShader* shader = fShader; + SkShader::Context* shaderContext = fShaderContext; SkPMColor* SK_RESTRICT span = fBuffer; - uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y); + uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y); for (;;) { int count = *runs; @@ -901,7 +906,7 @@ void SkRGB16_Shader_Blitter::blitAntiH(int x, int y, int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count); SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer - shader->shadeSpan(x, y, span, nonZeroCount); + shaderContext->shadeSpan(x, y, span, nonZeroCount); SkPMColor* localSpan = span; for (;;) { @@ -928,8 +933,9 @@ void SkRGB16_Shader_Blitter::blitAntiH(int x, int y, /////////////////////////////////////////////////////////////////////// SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter( - const SkBitmap& device, const SkPaint& paint) -: INHERITED(device, paint) { + const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext) +: INHERITED(device, paint, shaderContext) { fXfermode = paint.getXfermode(); SkASSERT(fXfermode); fXfermode->ref(); @@ -950,18 +956,18 @@ void SkRGB16_Shader_Xfermode_Blitter::blitH(int x, int y, int width) { uint16_t* device = fDevice.getAddr16(x, y); SkPMColor* span = fBuffer; - fShader->shadeSpan(x, y, span, width); + fShaderContext->shadeSpan(x, y, span, width); fXfermode->xfer16(device, span, width, NULL); } void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y, const SkAlpha* SK_RESTRICT antialias, const int16_t* SK_RESTRICT runs) { - SkShader* shader = fShader; - SkXfermode* mode = fXfermode; + SkShader::Context* shaderContext = fShaderContext; + SkXfermode* mode = fXfermode; SkPMColor* SK_RESTRICT span = fBuffer; - uint8_t* SK_RESTRICT aaExpand = fAAExpand; - uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y); + uint8_t* SK_RESTRICT aaExpand = fAAExpand; + uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y); for (;;) { int count = *runs; @@ -981,7 +987,7 @@ void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y, antialias + count); SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer - shader->shadeSpan(x, y, span, nonZeroCount); + shaderContext->shadeSpan(x, y, span, nonZeroCount); x += nonZeroCount; SkPMColor* localSpan = span; @@ -1012,6 +1018,7 @@ void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y, /////////////////////////////////////////////////////////////////////////////// SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext, SkTBlitterAllocator* allocator) { SkASSERT(allocator != NULL); @@ -1023,12 +1030,14 @@ SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint, SkASSERT(NULL == mode || NULL != shader); if (shader) { + SkASSERT(shaderContext != NULL); if (mode) { - blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint); - } else if (shader->canCallShadeSpan16()) { - blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint); + blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint, + shaderContext); + } else if (shaderContext->canCallShadeSpan16()) { + blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint, shaderContext); } else { - blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint); + blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint, shaderContext); } } else { // no shader, no xfermode, (and we always ignore colorfilter) diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 569e9e59ba..c1d2726d8c 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -91,32 +91,10 @@ private: }; #endif -class AutoCheckNoSetContext { -public: - AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) { - this->assertNoSetContext(fPaint); - } - ~AutoCheckNoSetContext() { - this->assertNoSetContext(fPaint); - } - -private: - const SkPaint& fPaint; - - void assertNoSetContext(const SkPaint& paint) { - SkShader* s = paint.getShader(); - if (s) { - SkASSERT(!s->setContextHasBeenCalled()); - } - } -}; - #define CHECK_LOCKCOUNT_BALANCE(bitmap) AutoCheckLockCountBalance clcb(bitmap) -#define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext cshsc(paint) #else #define CHECK_LOCKCOUNT_BALANCE(bitmap) - #define CHECK_SHADER_NOSETCONTEXT(paint) #endif typedef SkTLazy<SkPaint> SkLazyPaint; @@ -1935,8 +1913,6 @@ void SkCanvas::drawPaint(const SkPaint& paint) { } void SkCanvas::internalDrawPaint(const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL) while (iter.next()) { @@ -1952,8 +1928,6 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], return; } - CHECK_SHADER_NOSETCONTEXT(paint); - SkRect r, storage; const SkRect* bounds = NULL; if (paint.canComputeFastBounds()) { @@ -1981,8 +1955,6 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], } void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - SkRect storage; const SkRect* bounds = NULL; if (paint.canComputeFastBounds()) { @@ -2002,8 +1974,6 @@ void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { } void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - SkRect storage; const SkRect* bounds = NULL; if (paint.canComputeFastBounds()) { @@ -2023,8 +1993,6 @@ void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { } void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - SkRect storage; const SkRect* bounds = NULL; if (paint.canComputeFastBounds()) { @@ -2055,8 +2023,6 @@ void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - SkRect storage; const SkRect* bounds = NULL; if (paint.canComputeFastBounds()) { @@ -2076,8 +2042,6 @@ void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, } void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - if (!path.isFinite()) { return; } @@ -2353,8 +2317,6 @@ void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) while (iter.next()) { @@ -2369,8 +2331,6 @@ void SkCanvas::drawText(const void* text, size_t byteLength, void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) while (iter.next()) { @@ -2385,8 +2345,6 @@ void SkCanvas::drawPosText(const void* text, size_t byteLength, void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) while (iter.next()) { @@ -2401,8 +2359,6 @@ void SkCanvas::drawPosTextH(const void* text, size_t byteLength, void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) while (iter.next()) { @@ -2418,8 +2374,6 @@ void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkColor colors[], SkXfermode* xmode, const uint16_t indices[], int indexCount, const SkPaint& paint) { - CHECK_SHADER_NOSETCONTEXT(paint); - LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) while (iter.next()) { diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp index f53eedf876..68c4646cf6 100644 --- a/src/core/SkComposeShader.cpp +++ b/src/core/SkComposeShader.cpp @@ -45,6 +45,10 @@ SkComposeShader::~SkComposeShader() { fShaderA->unref(); } +size_t SkComposeShader::contextSize() const { + return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->contextSize(); +} + class SkAutoAlphaRestore { public: SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) { @@ -69,17 +73,16 @@ void SkComposeShader::flatten(SkWriteBuffer& buffer) const { buffer.writeFlattenable(fMode); } -/* We call setContext on our two worker shaders. However, we - always let them see opaque alpha, and if the paint really - is translucent, then we apply that after the fact. +/* We call validContext/createContext on our two worker shaders. + However, we always let them see opaque alpha, and if the paint + really is translucent, then we apply that after the fact. - We need to keep the calls to setContext/endContext balanced, since if we - return false, our endContext() will not be called. */ -bool SkComposeShader::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { - if (!this->INHERITED::setContext(device, paint, matrix)) { +bool SkComposeShader::validContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + SkMatrix* totalInverse) const { + if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) { return false; } @@ -90,38 +93,62 @@ bool SkComposeShader::setContext(const SkBitmap& device, tmpM.setConcat(matrix, this->getLocalMatrix()); - SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); + return fShaderA->validContext(device, paint, tmpM) && + fShaderB->validContext(device, paint, tmpM); +} - bool setContextA = fShaderA->setContext(device, paint, tmpM); - bool setContextB = fShaderB->setContext(device, paint, tmpM); - if (!setContextA || !setContextB) { - if (setContextB) { - fShaderB->endContext(); - } - else if (setContextA) { - fShaderA->endContext(); - } - this->INHERITED::endContext(); - return false; +SkShader::Context* SkComposeShader::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; } - return true; + + // we preconcat our localMatrix (if any) with the device matrix + // before calling our sub-shaders + + SkMatrix tmpM; + + tmpM.setConcat(matrix, this->getLocalMatrix()); + + SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF); + + char* aStorage = (char*) storage + sizeof(ComposeShaderContext); + char* bStorage = aStorage + fShaderA->contextSize(); + + SkShader::Context* contextA = fShaderA->createContext(device, paint, tmpM, aStorage); + SkShader::Context* contextB = fShaderB->createContext(device, paint, tmpM, bStorage); + + // Both functions must succeed; otherwise validContext should have returned + // false. + SkASSERT(contextA); + SkASSERT(contextB); + + return SkNEW_PLACEMENT_ARGS(storage, ComposeShaderContext, + (*this, device, paint, matrix, contextA, contextB)); } -void SkComposeShader::endContext() { - fShaderB->endContext(); - fShaderA->endContext(); - this->INHERITED::endContext(); +SkComposeShader::ComposeShaderContext::ComposeShaderContext( + const SkComposeShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix, + SkShader::Context* contextA, SkShader::Context* contextB) + : INHERITED(shader, device, paint, matrix) + , fShaderContextA(contextA) + , fShaderContextB(contextB) {} + +SkComposeShader::ComposeShaderContext::~ComposeShaderContext() { + fShaderContextA->SkShader::Context::~Context(); + fShaderContextB->SkShader::Context::~Context(); } // larger is better (fewer times we have to loop), but we shouldn't // take up too much stack-space (each element is 4 bytes) #define TMP_COLOR_COUNT 64 -void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { - SkShader* shaderA = fShaderA; - SkShader* shaderB = fShaderB; - SkXfermode* mode = fMode; - unsigned scale = SkAlpha255To256(this->getPaintAlpha()); +void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { + SkShader::Context* shaderContextA = fShaderContextA; + SkShader::Context* shaderContextB = fShaderContextB; + SkXfermode* mode = static_cast<const SkComposeShader&>(fShader).fMode; + unsigned scale = SkAlpha255To256(this->getPaintAlpha()); SkPMColor tmp[TMP_COLOR_COUNT]; @@ -134,8 +161,8 @@ void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { n = TMP_COLOR_COUNT; } - shaderA->shadeSpan(x, y, result, n); - shaderB->shadeSpan(x, y, tmp, n); + shaderContextA->shadeSpan(x, y, result, n); + shaderContextB->shadeSpan(x, y, tmp, n); if (256 == scale) { for (int i = 0; i < n; i++) { @@ -159,8 +186,8 @@ void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) { n = TMP_COLOR_COUNT; } - shaderA->shadeSpan(x, y, result, n); - shaderB->shadeSpan(x, y, tmp, n); + shaderContextA->shadeSpan(x, y, result, n); + shaderContextB->shadeSpan(x, y, tmp, n); mode->xfer32(result, tmp, n, NULL); if (256 == scale) { diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h index 285184050b..2d22d38e78 100644 --- a/src/core/SkCoreBlitters.h +++ b/src/core/SkCoreBlitters.h @@ -27,12 +27,29 @@ private: class SkShaderBlitter : public SkRasterBlitter { public: - SkShaderBlitter(const SkBitmap& device, const SkPaint& paint); + /** + * The storage for shaderContext is owned by the caller, but the object itself is not. + * The blitter only ensures that the storage always holds a live object, but it may + * exchange that object. + */ + SkShaderBlitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext); virtual ~SkShaderBlitter(); + /** + * Create a new shader context and uses it instead of the old one if successful. + * Will create the context at the same location as the old one (this is safe + * because the shader itself is unchanged). + */ + virtual bool resetShaderContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix) SK_OVERRIDE; + + virtual SkShader::Context* getShaderContext() const SK_OVERRIDE { return fShaderContext; } + protected: - uint32_t fShaderFlags; - SkShader* fShader; + uint32_t fShaderFlags; + const SkShader* fShader; + SkShader::Context* fShaderContext; private: // illegal @@ -75,7 +92,8 @@ private: class SkA8_Shader_Blitter : public SkShaderBlitter { public: - SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint); + SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext); virtual ~SkA8_Shader_Blitter(); virtual void blitH(int x, int y, int width); virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]); @@ -141,7 +159,8 @@ private: class SkARGB32_Shader_Blitter : public SkShaderBlitter { public: - SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint); + SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext); virtual ~SkARGB32_Shader_Blitter(); virtual void blitH(int x, int y, int width) SK_OVERRIDE; virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE; @@ -179,6 +198,7 @@ private: */ SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext, SkTBlitterAllocator* allocator); #endif diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 7eb0be6b6b..6ddd0d274f 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -2354,9 +2354,26 @@ class SkTriColorShader : public SkShader { public: SkTriColorShader() {} - bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); + virtual SkShader::Context* createContext( + const SkBitmap&, const SkPaint&, const SkMatrix&, void*) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + class TriColorShaderContext : public SkShader::Context { + public: + TriColorShaderContext(const SkTriColorShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); + virtual ~TriColorShaderContext(); + + bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); + + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + + private: + SkMatrix fDstToUnit; + SkPMColor fColors[3]; + + typedef SkShader::Context INHERITED; + }; SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader) @@ -2365,14 +2382,20 @@ protected: SkTriColorShader(SkReadBuffer& buffer) : SkShader(buffer) {} private: - SkMatrix fDstToUnit; - SkPMColor fColors[3]; - typedef SkShader INHERITED; }; -bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[], - int index0, int index1, int index2) { +SkShader::Context* SkTriColorShader::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + return SkNEW_PLACEMENT_ARGS(storage, TriColorShaderContext, (*this, device, paint, matrix)); +} + +bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[], + int index0, int index1, int index2) { fColors[0] = SkPreMultiplyColor(colors[index0]); fColors[1] = SkPreMultiplyColor(colors[index1]); @@ -2407,7 +2430,18 @@ static int ScalarTo256(SkScalar v) { return SkAlpha255To256(scale); } -void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { + +SkTriColorShader::TriColorShaderContext::TriColorShaderContext( + const SkTriColorShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) {} + +SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {} + +size_t SkTriColorShader::contextSize() const { + return sizeof(TriColorShaderContext); +} +void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) { SkPoint src; for (int i = 0; i < count; i++) { @@ -2492,6 +2526,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, } // setup the custom shader (if needed) + SkAutoTUnref<SkComposeShader> composeShader; if (NULL != colors) { if (NULL == textures) { // just colors (no texture) @@ -2504,9 +2539,8 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, xmode = SkXfermode::Create(SkXfermode::kModulate_Mode); releaseMode = true; } - SkShader* compose = SkNEW_ARGS(SkComposeShader, - (&triShader, shader, xmode)); - p.setShader(compose)->unref(); + composeShader.reset(SkNEW_ARGS(SkComposeShader, (&triShader, shader, xmode))); + p.setShader(composeShader); if (releaseMode) { xmode->unref(); } @@ -2514,9 +2548,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, } SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p); - // important that we abort early, as below we may manipulate the shader - // and that is only valid if the shader returned true from setContext. - // If it returned false, then our blitter will be the NullBlitter. + // Abort early if we failed to create a shader context. if (blitter->isNullBlitter()) { return; } @@ -2532,30 +2564,38 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, savedLocalM = shader->getLocalMatrix(); } - // setContext has already been called and verified to return true - // by the constructor of SkAutoBlitterChoose - bool prevContextSuccess = true; while (vertProc(&state)) { if (NULL != textures) { if (texture_to_matrix(state, vertices, textures, &tempM)) { tempM.postConcat(savedLocalM); shader->setLocalMatrix(tempM); - // Need to recall setContext since we changed the local matrix. - // However, we also need to balance the calls this with a - // call to endContext which requires tracking the result of - // the previous call to setContext. - if (prevContextSuccess) { - shader->endContext(); - } - prevContextSuccess = shader->setContext(*fBitmap, p, *fMatrix); - if (!prevContextSuccess) { + if (!blitter->resetShaderContext(*fBitmap, p, *fMatrix)) { continue; } } } if (NULL != colors) { - if (!triShader.setup(vertices, colors, - state.f0, state.f1, state.f2)) { + // Find the context for triShader. + SkTriColorShader::TriColorShaderContext* triColorShaderContext; + + SkShader::Context* shaderContext = blitter->getShaderContext(); + SkASSERT(shaderContext); + if (p.getShader() == &triShader) { + triColorShaderContext = + static_cast<SkTriColorShader::TriColorShaderContext*>(shaderContext); + } else { + // The shader is a compose shader and triShader is its first shader. + SkASSERT(p.getShader() == composeShader); + SkASSERT(composeShader->getShaderA() == &triShader); + SkComposeShader::ComposeShaderContext* composeShaderContext = + static_cast<SkComposeShader::ComposeShaderContext*>(shaderContext); + SkShader::Context* shaderContextA = composeShaderContext->getShaderContextA(); + triColorShaderContext = + static_cast<SkTriColorShader::TriColorShaderContext*>(shaderContextA); + } + + if (!triColorShaderContext->setup(vertices, colors, + state.f0, state.f1, state.f2)) { continue; } } @@ -2570,13 +2610,6 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, if (NULL != shader) { shader->setLocalMatrix(savedLocalM); } - - // If the final call to setContext fails we must make it suceed so that the - // call to endContext in the destructor for SkAutoBlitterChoose is balanced. - if (!prevContextSuccess) { - prevContextSuccess = shader->setContext(*fBitmap, paint, SkMatrix::I()); - SkASSERT(prevContextSuccess); - } } else { // no colors[] and no texture HairProc hairProc = ChooseHairProc(paint.isAntiAlias()); diff --git a/src/core/SkFilterShader.cpp b/src/core/SkFilterShader.cpp index 58961913c8..1a0255157d 100644 --- a/src/core/SkFilterShader.cpp +++ b/src/core/SkFilterShader.cpp @@ -38,9 +38,11 @@ void SkFilterShader::flatten(SkWriteBuffer& buffer) const { buffer.writeFlattenable(fFilter); } -uint32_t SkFilterShader::getFlags() { - uint32_t shaderF = fShader->getFlags(); - uint32_t filterF = fFilter->getFlags(); +uint32_t SkFilterShader::FilterShaderContext::getFlags() const { + const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader); + + uint32_t shaderF = fShaderContext->getFlags(); + uint32_t filterF = filterShader.fFilter->getFlags(); // if the filter doesn't support 16bit, clear the matching bit in the shader if (!(filterF & SkColorFilter::kHasFilter16_Flag)) { @@ -53,38 +55,62 @@ uint32_t SkFilterShader::getFlags() { return shaderF; } -bool SkFilterShader::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { - // we need to keep the setContext/endContext calls balanced. If we return - // false, our endContext() will not be called. - - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; - } - if (!fShader->setContext(device, paint, matrix)) { - this->INHERITED::endContext(); - return false; +SkShader::Context* SkFilterShader::createContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; } - return true; + + char* shaderContextStorage = (char*)storage + sizeof(FilterShaderContext); + SkShader::Context* shaderContext = fShader->createContext(device, paint, matrix, + shaderContextStorage); + SkASSERT(shaderContext); + + return SkNEW_PLACEMENT_ARGS(storage, FilterShaderContext, + (*this, shaderContext, device, paint, matrix)); +} + +size_t SkFilterShader::contextSize() const { + return sizeof(FilterShaderContext) + fShader->contextSize(); +} + +bool SkFilterShader::validContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + SkMatrix* totalInverse) const { + return this->INHERITED::validContext(device, paint, matrix, totalInverse) && + fShader->validContext(device, paint, matrix); } -void SkFilterShader::endContext() { - fShader->endContext(); - this->INHERITED::endContext(); +SkFilterShader::FilterShaderContext::FilterShaderContext(const SkFilterShader& filterShader, + SkShader::Context* shaderContext, + const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix) + : INHERITED(filterShader, device, paint, matrix) + , fShaderContext(shaderContext) {} + +SkFilterShader::FilterShaderContext::~FilterShaderContext() { + fShaderContext->SkShader::Context::~Context(); } -void SkFilterShader::shadeSpan(int x, int y, SkPMColor result[], int count) { - fShader->shadeSpan(x, y, result, count); - fFilter->filterSpan(result, count, result); +void SkFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { + const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader); + + fShaderContext->shadeSpan(x, y, result, count); + filterShader.fFilter->filterSpan(result, count, result); } -void SkFilterShader::shadeSpan16(int x, int y, uint16_t result[], int count) { - SkASSERT(fShader->getFlags() & SkShader::kHasSpan16_Flag); - SkASSERT(fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag); +void SkFilterShader::FilterShaderContext::shadeSpan16(int x, int y, uint16_t result[], int count) { + const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader); + + SkASSERT(fShaderContext->getFlags() & SkShader::kHasSpan16_Flag); + SkASSERT(filterShader.fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag); - fShader->shadeSpan16(x, y, result, count); - fFilter->filterSpan16(result, count, result); + fShaderContext->shadeSpan16(x, y, result, count); + filterShader.fFilter->filterSpan16(result, count, result); } #ifndef SK_IGNORE_TO_STRING diff --git a/src/core/SkFilterShader.h b/src/core/SkFilterShader.h index 11add0cf17..4ef4577248 100644 --- a/src/core/SkFilterShader.h +++ b/src/core/SkFilterShader.h @@ -17,12 +17,29 @@ public: SkFilterShader(SkShader* shader, SkColorFilter* filter); virtual ~SkFilterShader(); - virtual uint32_t getFlags() SK_OVERRIDE; - virtual bool setContext(const SkBitmap&, const SkPaint&, - const SkMatrix&) SK_OVERRIDE; - virtual void endContext() SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE; + virtual bool validContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE; + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, void* storage) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + + class FilterShaderContext : public SkShader::Context { + public: + // Takes ownership of shaderContext and calls its destructor. + FilterShaderContext(const SkFilterShader& filterShader, SkShader::Context* shaderContext, + const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix); + virtual ~FilterShaderContext(); + + virtual uint32_t getFlags() const SK_OVERRIDE; + + virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE; + + private: + SkShader::Context* fShaderContext; + + typedef SkShader::Context INHERITED; + }; SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkFilterShader) diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp index 15df3a37a5..1e9507190c 100644 --- a/src/core/SkPictureShader.cpp +++ b/src/core/SkPictureShader.cpp @@ -55,9 +55,9 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const { } } -bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { +SkShader* SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { if (!fPicture || (0 == fPicture->width() && 0 == fPicture->height())) { - return false; + return NULL; } SkMatrix m; @@ -78,17 +78,20 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { SkISize tileSize = scaledSize.toRound(); if (tileSize.isEmpty()) { - return false; + return NULL; } // The actual scale, compensating for rounding. SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(), SkIntToScalar(tileSize.height()) / fPicture->height()); - if (!fCachedShader || tileScale != fCachedTileScale) { + SkAutoMutexAcquire ama(fCachedBitmapShaderMutex); + + if (!fCachedBitmapShader || tileScale != fCachedTileScale || + this->getLocalMatrix() != fCachedLocalMatrix) { SkBitmap bm; if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) { - return false; + return NULL; } bm.eraseColor(SK_ColorTRANSPARENT); @@ -96,66 +99,96 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { canvas.scale(tileScale.width(), tileScale.height()); canvas.drawPicture(*fPicture); - fCachedShader.reset(CreateBitmapShader(bm, fTmx, fTmy)); + fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy)); fCachedTileScale = tileScale; - } + fCachedLocalMatrix = this->getLocalMatrix(); - SkMatrix shaderMatrix = this->getLocalMatrix(); - shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); - fCachedShader->setLocalMatrix(shaderMatrix); + SkMatrix shaderMatrix = this->getLocalMatrix(); + shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); + fCachedBitmapShader->setLocalMatrix(shaderMatrix); + } - return true; + // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. + // Otherwise, the pointer may have been overwritten on a different thread before the object's + // ref count was incremented. + fCachedBitmapShader.get()->ref(); + return fCachedBitmapShader; } -bool SkPictureShader::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { - if (!this->buildBitmapShader(matrix)) { - return false; +SkShader* SkPictureShader::validInternal(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse) const { + if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) { + return NULL; } - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; + SkShader* bitmapShader = this->buildBitmapShader(matrix); + if (!bitmapShader) { + return NULL; } - SkASSERT(fCachedShader); - if (!fCachedShader->setContext(device, paint, matrix)) { - this->INHERITED::endContext(); - return false; + if (!bitmapShader->validContext(device, paint, matrix)) { + bitmapShader->unref(); + return NULL; } - return true; + return bitmapShader; } -void SkPictureShader::endContext() { - SkASSERT(fCachedShader); - fCachedShader->endContext(); - - this->INHERITED::endContext(); +bool SkPictureShader::validContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse) const { + SkAutoTUnref<SkShader> shader(this->validInternal(device, paint, matrix, totalInverse)); + return shader != NULL; } -uint32_t SkPictureShader::getFlags() { - if (NULL != fCachedShader) { - return fCachedShader->getFlags(); +SkShader::Context* SkPictureShader::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + SkShader* bitmapShader = this->validInternal(device, paint, matrix, NULL); + if (!bitmapShader) { + return NULL; } - return 0; + + return SkNEW_PLACEMENT_ARGS(storage, PictureShaderContext, + (*this, device, paint, matrix, bitmapShader)); } -SkShader::ShadeProc SkPictureShader::asAShadeProc(void** ctx) { - if (fCachedShader) { - return fCachedShader->asAShadeProc(ctx); - } - return NULL; +size_t SkPictureShader::contextSize() const { + return sizeof(PictureShaderContext); +} + +SkPictureShader::PictureShaderContext::PictureShaderContext( + const SkPictureShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix, SkShader* bitmapShader) + : INHERITED(shader, device, paint, matrix) + , fBitmapShader(bitmapShader) +{ + SkASSERT(fBitmapShader); + fBitmapShaderContextStorage = sk_malloc_throw(fBitmapShader->contextSize()); + fBitmapShaderContext = fBitmapShader->createContext( + device, paint, matrix, fBitmapShaderContextStorage); + SkASSERT(fBitmapShaderContext); +} + +SkPictureShader::PictureShaderContext::~PictureShaderContext() { + fBitmapShaderContext->SkShader::Context::~Context(); + sk_free(fBitmapShaderContextStorage); +} + +uint32_t SkPictureShader::PictureShaderContext::getFlags() const { + return fBitmapShaderContext->getFlags(); +} + +SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) { + return fBitmapShaderContext->asAShadeProc(ctx); } -void SkPictureShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { - SkASSERT(fCachedShader); - fCachedShader->shadeSpan(x, y, dstC, count); +void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) { + SkASSERT(fBitmapShaderContext); + fBitmapShaderContext->shadeSpan(x, y, dstC, count); } -void SkPictureShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { - SkASSERT(fCachedShader); - fCachedShader->shadeSpan16(x, y, dstC, count); +void SkPictureShader::PictureShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], int count) { + SkASSERT(fBitmapShaderContext); + fBitmapShaderContext->shadeSpan16(x, y, dstC, count); } #ifndef SK_IGNORE_TO_STRING @@ -176,10 +209,10 @@ void SkPictureShader::toString(SkString* str) const { #if SK_SUPPORT_GPU GrEffectRef* SkPictureShader::asNewEffect(GrContext* context, const SkPaint& paint) const { - if (!this->buildBitmapShader(context->getMatrix())) { + SkAutoTUnref<SkShader> bitmapShader(this->buildBitmapShader(context->getMatrix())); + if (!bitmapShader) { return NULL; } - SkASSERT(fCachedShader); - return fCachedShader->asNewEffect(context, paint); + return bitmapShader->asNewEffect(context, paint); } #endif diff --git a/src/core/SkPictureShader.h b/src/core/SkPictureShader.h index ea74b56d73..a0a377d0cd 100644 --- a/src/core/SkPictureShader.h +++ b/src/core/SkPictureShader.h @@ -24,13 +24,33 @@ public: static SkPictureShader* Create(SkPicture*, TileMode, TileMode); virtual ~SkPictureShader(); - virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE; - virtual void endContext() SK_OVERRIDE; - virtual uint32_t getFlags() SK_OVERRIDE; + virtual bool validContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE; + virtual SkShader::Context* createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const + SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; - virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; + class PictureShaderContext : public SkShader::Context { + public: + PictureShaderContext(const SkPictureShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix, + SkShader* bitmapShader); + virtual ~PictureShaderContext(); + + virtual uint32_t getFlags() const SK_OVERRIDE; + + virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE; + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; + + private: + SkAutoTUnref<SkShader> fBitmapShader; + SkShader::Context* fBitmapShaderContext; + void* fBitmapShaderContextStorage; + + typedef SkShader::Context INHERITED; + }; SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPictureShader) @@ -46,13 +66,18 @@ protected: private: SkPictureShader(SkPicture*, TileMode, TileMode); - bool buildBitmapShader(const SkMatrix&) const; + SkShader* validInternal(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse) const; + + SkShader* buildBitmapShader(const SkMatrix&) const; SkPicture* fPicture; TileMode fTmx, fTmy; - mutable SkAutoTUnref<SkShader> fCachedShader; + mutable SkMutex fCachedBitmapShaderMutex; + mutable SkAutoTUnref<SkShader> fCachedBitmapShader; mutable SkSize fCachedTileScale; + mutable SkMatrix fCachedLocalMatrix; typedef SkShader INHERITED; }; diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp index e337b7d906..40e52a05cb 100644 --- a/src/core/SkShader.cpp +++ b/src/core/SkShader.cpp @@ -17,7 +17,6 @@ SkShader::SkShader() { fLocalMatrix.reset(); - SkDEBUGCODE(fInSetContext = false;) } SkShader::SkShader(SkReadBuffer& buffer) @@ -27,12 +26,9 @@ SkShader::SkShader(SkReadBuffer& buffer) } else { fLocalMatrix.reset(); } - - SkDEBUGCODE(fInSetContext = false;) } SkShader::~SkShader() { - SkASSERT(!fInSetContext); } void SkShader::flatten(SkWriteBuffer& buffer) const { @@ -44,39 +40,48 @@ void SkShader::flatten(SkWriteBuffer& buffer) const { } } -bool SkShader::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { - SkASSERT(!this->setContextHasBeenCalled()); - +bool SkShader::computeTotalInverse(const SkMatrix& matrix, SkMatrix* totalInverse) const { const SkMatrix* m = &matrix; SkMatrix total; - fPaintAlpha = paint.getAlpha(); if (this->hasLocalMatrix()) { total.setConcat(matrix, this->getLocalMatrix()); m = &total; } - if (m->invert(&fTotalInverse)) { - fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse); - SkDEBUGCODE(fInSetContext = true;) - return true; - } - return false; + + return m->invert(totalInverse); +} + +bool SkShader::validContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + SkMatrix* totalInverse) const { + return this->computeTotalInverse(matrix, totalInverse); } -void SkShader::endContext() { - SkASSERT(fInSetContext); - SkDEBUGCODE(fInSetContext = false;) +SkShader::Context::Context(const SkShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : fShader(shader) +{ + SkASSERT(fShader.validContext(device, paint, matrix)); + + // Because the context parameters must be valid at this point, we know that the matrix is + // invertible. + SkAssertResult(fShader.computeTotalInverse(matrix, &fTotalInverse)); + fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse); + + fPaintAlpha = paint.getAlpha(); } -SkShader::ShadeProc SkShader::asAShadeProc(void** ctx) { +SkShader::Context::~Context() {} + +SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) { return NULL; } #include "SkColorPriv.h" -void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) { +void SkShader::Context::shadeSpan16(int x, int y, uint16_t span16[], int count) { SkASSERT(span16); SkASSERT(count > 0); SkASSERT(this->canCallShadeSpan16()); @@ -94,7 +99,7 @@ void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) { #define SkU32BitShiftToByteOffset(shift) ((shift) >> 3) #endif -void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { +void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { SkASSERT(count > 0); SkPMColor colors[kTempColorCount]; @@ -148,7 +153,7 @@ void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { #endif } -SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) { +SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) { MatrixClass mc = kLinear_MatrixClass; if (mat.hasPerspective()) { @@ -163,8 +168,7 @@ SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) { ////////////////////////////////////////////////////////////////////////////// -SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, - TileMode*) const { +SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) const { return kNone_BitmapType; } @@ -199,19 +203,16 @@ void SkShader::toString(SkString* str) const { #include "SkColorShader.h" #include "SkUtils.h" -SkColorShader::SkColorShader() { - fFlags = 0; - fInheritColor = true; +SkColorShader::SkColorShader() + : fColor() + , fInheritColor(true) { } -SkColorShader::SkColorShader(SkColor c) { - fFlags = 0; - fColor = c; - fInheritColor = false; +SkColorShader::SkColorShader(SkColor c) + : fColor(c) + , fInheritColor(false) { } -SkColorShader::~SkColorShader() {} - bool SkColorShader::isOpaque() const { if (fInheritColor) { return true; // using paint's alpha @@ -220,8 +221,6 @@ bool SkColorShader::isOpaque() const { } SkColorShader::SkColorShader(SkReadBuffer& b) : INHERITED(b) { - fFlags = 0; // computed in setContext - fInheritColor = b.readBool(); if (fInheritColor) { return; @@ -238,32 +237,43 @@ void SkColorShader::flatten(SkWriteBuffer& buffer) const { buffer.writeColor(fColor); } -uint32_t SkColorShader::getFlags() { +uint32_t SkColorShader::ColorShaderContext::getFlags() const { return fFlags; } -uint8_t SkColorShader::getSpan16Alpha() const { +uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const { return SkGetPackedA32(fPMColor); } -bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix) { - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; +SkShader::Context* SkColorShader::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; } + return SkNEW_PLACEMENT_ARGS(storage, ColorShaderContext, (*this, device, paint, matrix)); +} + +SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader, + const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) +{ unsigned a; - if (fInheritColor) { - fColor = paint.getColor(); - a = SkColorGetA(fColor); + SkColor color; + if (shader.fInheritColor) { + color = paint.getColor(); + a = SkColorGetA(color); } else { - a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha())); + color = shader.fColor; + a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(paint.getAlpha())); } - unsigned r = SkColorGetR(fColor); - unsigned g = SkColorGetG(fColor); - unsigned b = SkColorGetB(fColor); + unsigned r = SkColorGetR(color); + unsigned g = SkColorGetG(color); + unsigned b = SkColorGetB(color); // we want this before we apply any alpha fColor16 = SkPack888ToRGB16(r, g, b); @@ -282,19 +292,17 @@ bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint, fFlags |= kHasSpan16_Flag; } } - - return true; } -void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) { +void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) { sk_memset32(span, fPMColor, count); } -void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) { +void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) { sk_memset16(span, fColor16, count); } -void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { +void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { memset(alpha, SkGetPackedA32(fPMColor), count); } @@ -334,27 +342,9 @@ void SkColorShader::toString(SkString* str) const { /////////////////////////////////////////////////////////////////////////////// +#ifndef SK_IGNORE_TO_STRING #include "SkEmptyShader.h" -uint32_t SkEmptyShader::getFlags() { return 0; } -uint8_t SkEmptyShader::getSpan16Alpha() const { return 0; } - -bool SkEmptyShader::setContext(const SkBitmap&, const SkPaint&, - const SkMatrix&) { return false; } - -void SkEmptyShader::shadeSpan(int x, int y, SkPMColor span[], int count) { - SkDEBUGFAIL("should never get called, since setContext() returned false"); -} - -void SkEmptyShader::shadeSpan16(int x, int y, uint16_t span[], int count) { - SkDEBUGFAIL("should never get called, since setContext() returned false"); -} - -void SkEmptyShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { - SkDEBUGFAIL("should never get called, since setContext() returned false"); -} - -#ifndef SK_IGNORE_TO_STRING void SkEmptyShader::toString(SkString* str) const { str->append("SkEmptyShader: ("); diff --git a/src/core/SkSmallAllocator.h b/src/core/SkSmallAllocator.h index 655008b706..8d4b53a707 100644 --- a/src/core/SkSmallAllocator.h +++ b/src/core/SkSmallAllocator.h @@ -117,10 +117,12 @@ public: // but we're not sure we can catch all callers, so handle it but // assert false in debug mode. SkASSERT(false); + rec->fStorageSize = 0; rec->fHeapStorage = sk_malloc_throw(storageRequired); rec->fObj = static_cast<void*>(rec->fHeapStorage); } else { // There is space in fStorage. + rec->fStorageSize = storageRequired; rec->fHeapStorage = NULL; SkASSERT(SkIsAlign4(fStorageUsed)); rec->fObj = static_cast<void*>(fStorage + (fStorageUsed / 4)); @@ -131,11 +133,26 @@ public: return rec->fObj; } + /* + * Free the memory reserved last without calling the destructor. + * Can be used in a nested way, i.e. after reserving A and B, calling + * freeLast once will free B and calling it again will free A. + */ + void freeLast() { + SkASSERT(fNumObjects > 0); + Rec* rec = &fRecs[fNumObjects - 1]; + sk_free(rec->fHeapStorage); + fStorageUsed -= rec->fStorageSize; + + fNumObjects--; + } + private: struct Rec { - void* fObj; - void* fHeapStorage; - void (*fKillProc)(void*); + size_t fStorageSize; // 0 if allocated on heap + void* fObj; + void* fHeapStorage; + void (*fKillProc)(void*); }; // Number of bytes used so far. diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp index ed63fafae1..5adb582506 100644 --- a/src/effects/SkPerlinNoiseShader.cpp +++ b/src/effects/SkPerlinNoiseShader.cpp @@ -278,7 +278,6 @@ SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, , fStitchTiles(!fTileSize.isEmpty()) { SkASSERT(numOctaves >= 0 && numOctaves < 256); - fMatrix.reset(); fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY)); } @@ -293,7 +292,6 @@ SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) fStitchTiles = buffer.readBool(); fTileSize.fWidth = buffer.readInt(); fTileSize.fHeight = buffer.readInt(); - fMatrix.reset(); fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY)); buffer.validate(perlin_noise_type_is_valid(fType) && (fNumOctaves >= 0) && (fNumOctaves <= 255) && @@ -317,9 +315,9 @@ void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const { buffer.writeInt(fTileSize.fHeight); } -SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingData, - const StitchData& stitchData, - const SkPoint& noiseVector) const { +SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D( + int channel, const PaintingData& paintingData, + const StitchData& stitchData, const SkPoint& noiseVector) const { struct Noise { int noisePositionIntegerValue; SkScalar noisePositionFractionValue; @@ -333,8 +331,9 @@ SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingD Noise noiseX(noiseVector.x()); Noise noiseY(noiseVector.y()); SkScalar u, v; + const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader); // If stitching, adjust lattice points accordingly. - if (fStitchTiles) { + if (perlinNoiseShader.fStitchTiles) { noiseX.noisePositionIntegerValue = checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth); noiseY.noisePositionIntegerValue = @@ -365,11 +364,11 @@ SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingD return SkScalarInterp(a, b, sy); } -SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel, - const PaintingData& paintingData, - StitchData& stitchData, - const SkPoint& point) const { - if (fStitchTiles) { +SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint( + int channel, const PaintingData& paintingData, + StitchData& stitchData, const SkPoint& point) const { + const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader); + if (perlinNoiseShader.fStitchTiles) { // Set up TurbulenceInitial stitch values. stitchData = paintingData.fStitchDataInit; } @@ -377,14 +376,14 @@ SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel, SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), paintingData.fBaseFrequency.fX), SkScalarMul(point.y(), paintingData.fBaseFrequency.fY))); SkScalar ratio = SK_Scalar1; - for (int octave = 0; octave < fNumOctaves; ++octave) { + for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) { SkScalar noise = noise2D(channel, paintingData, stitchData, noiseVector); turbulenceFunctionResult += SkScalarDiv( - (fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio); + (perlinNoiseShader.fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio); noiseVector.fX *= 2; noiseVector.fY *= 2; ratio *= 2; - if (fStitchTiles) { + if (perlinNoiseShader.fStitchTiles) { // Update stitch values stitchData.fWidth *= 2; stitchData.fWrapX = stitchData.fWidth + kPerlinNoise; @@ -395,7 +394,7 @@ SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel, // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 // by fractalNoise and (turbulenceFunctionResult) by turbulence. - if (fType == kFractalNoise_Type) { + if (perlinNoiseShader.fType == kFractalNoise_Type) { turbulenceFunctionResult = SkScalarMul(turbulenceFunctionResult, SK_ScalarHalf) + SK_ScalarHalf; } @@ -409,7 +408,9 @@ SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel, return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1); } -SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchData) const { +SkPMColor SkPerlinNoiseShader::PerlinNoiseShaderContext::shade( + const SkPoint& point, StitchData& stitchData) const { + const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader); SkPoint newPoint; fMatrix.mapPoints(&newPoint, &point, 1); newPoint.fX = SkScalarRoundToScalar(newPoint.fX); @@ -418,15 +419,32 @@ SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchDat U8CPU rgba[4]; for (int channel = 3; channel >= 0; --channel) { rgba[channel] = SkScalarFloorToInt(255 * - calculateTurbulenceValueForPoint(channel, *fPaintingData, stitchData, newPoint)); + calculateTurbulenceValueForPoint(channel, *perlinNoiseShader.fPaintingData, + stitchData, newPoint)); } return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]); } -bool SkPerlinNoiseShader::setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix) { +SkShader::Context* SkPerlinNoiseShader::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + return SkNEW_PLACEMENT_ARGS(storage, PerlinNoiseShaderContext, (*this, device, paint, matrix)); +} + +size_t SkPerlinNoiseShader::contextSize() const { + return sizeof(PerlinNoiseShaderContext); +} + +SkPerlinNoiseShader::PerlinNoiseShaderContext::PerlinNoiseShaderContext( + const SkPerlinNoiseShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) +{ SkMatrix newMatrix = matrix; - newMatrix.postConcat(getLocalMatrix()); + newMatrix.postConcat(shader.getLocalMatrix()); SkMatrix invMatrix; if (!newMatrix.invert(&invMatrix)) { invMatrix.reset(); @@ -437,10 +455,10 @@ bool SkPerlinNoiseShader::setContext(const SkBitmap& device, const SkPaint& pain newMatrix.postConcat(invMatrix); newMatrix.postConcat(invMatrix); fMatrix = newMatrix; - return INHERITED::setContext(device, paint, matrix); } -void SkPerlinNoiseShader::shadeSpan(int x, int y, SkPMColor result[], int count) { +void SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan( + int x, int y, SkPMColor result[], int count) { SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y)); StitchData stitchData; for (int i = 0; i < count; ++i) { @@ -449,7 +467,8 @@ void SkPerlinNoiseShader::shadeSpan(int x, int y, SkPMColor result[], int count) } } -void SkPerlinNoiseShader::shadeSpan16(int x, int y, uint16_t result[], int count) { +void SkPerlinNoiseShader::PerlinNoiseShaderContext::shadeSpan16( + int x, int y, uint16_t result[], int count) { SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y)); StitchData stitchData; DITHER_565_SCAN(y); diff --git a/src/effects/SkTransparentShader.cpp b/src/effects/SkTransparentShader.cpp index bd8b99a3c0..0997e62013 100644 --- a/src/effects/SkTransparentShader.cpp +++ b/src/effects/SkTransparentShader.cpp @@ -11,26 +11,40 @@ #include "SkColorPriv.h" #include "SkString.h" -bool SkTransparentShader::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { - fDevice = &device; - fAlpha = paint.getAlpha(); +SkShader::Context* SkTransparentShader::createContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + return SkNEW_PLACEMENT_ARGS(storage, TransparentShaderContext, (*this, device, paint, matrix)); +} - return this->INHERITED::setContext(device, paint, matrix); +size_t SkTransparentShader::contextSize() const { + return sizeof(TransparentShaderContext); } -uint32_t SkTransparentShader::getFlags() { +SkTransparentShader::TransparentShaderContext::TransparentShaderContext( + const SkTransparentShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) + , fDevice(&device) {} + +SkTransparentShader::TransparentShaderContext::~TransparentShaderContext() {} + +uint32_t SkTransparentShader::TransparentShaderContext::getFlags() const { uint32_t flags = this->INHERITED::getFlags(); switch (fDevice->colorType()) { case kRGB_565_SkColorType: flags |= kHasSpan16_Flag; - if (fAlpha == 255) + if (this->getPaintAlpha() == 255) flags |= kOpaqueAlpha_Flag; break; case kN32_SkColorType: - if (fAlpha == 255 && fDevice->isOpaque()) + if (this->getPaintAlpha() == 255 && fDevice->isOpaque()) flags |= kOpaqueAlpha_Flag; break; default: @@ -39,8 +53,9 @@ uint32_t SkTransparentShader::getFlags() { return flags; } -void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) { - unsigned scale = SkAlpha255To256(fAlpha); +void SkTransparentShader::TransparentShaderContext::shadeSpan(int x, int y, SkPMColor span[], + int count) { + unsigned scale = SkAlpha255To256(this->getPaintAlpha()); switch (fDevice->colorType()) { case kN32_SkColorType: @@ -63,7 +78,7 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) { span[i] = SkPixel16ToPixel32(src[i]); } } else { - unsigned alpha = fAlpha; + unsigned alpha = this->getPaintAlpha(); for (int i = count - 1; i >= 0; --i) { uint16_t c = src[i]; unsigned r = SkPacked16ToR32(c); @@ -97,7 +112,8 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) { } } -void SkTransparentShader::shadeSpan16(int x, int y, uint16_t span[], int count) { +void SkTransparentShader::TransparentShaderContext::shadeSpan16(int x, int y, uint16_t span[], + int count) { SkASSERT(fDevice->colorType() == kRGB_565_SkColorType); uint16_t* src = fDevice->getAddr16(x, y); diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp index 2ebb9c71d9..666204e0ae 100644 --- a/src/effects/gradients/SkGradientShader.cpp +++ b/src/effects/gradients/SkGradientShader.cpp @@ -15,8 +15,6 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) { SkASSERT(desc.fCount > 1); - fCacheAlpha = 256; // init to a value that paint.getAlpha() can't return - fMapper = desc.fMapper; SkSafeRef(fMapper); fGradFlags = SkToU8(desc.fFlags); @@ -26,10 +24,6 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) { fTileMode = desc.fTileMode; fTileProc = gTileProcs[desc.fTileMode]; - fCache16 = fCache16Storage = NULL; - fCache32 = NULL; - fCache32PixelRef = NULL; - /* Note: we let the caller skip the first and/or last position. i.e. pos[0] = 0.3, pos[1] = 0.7 In these cases, we insert dummy entries to ensure that the final data @@ -144,14 +138,8 @@ static uint32_t unpack_flags(uint32_t packed) { } SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buffer) { - fCacheAlpha = 256; - fMapper = buffer.readUnitMapper(); - fCache16 = fCache16Storage = NULL; - fCache32 = NULL; - fCache32PixelRef = NULL; - int colorCount = fColorCount = buffer.getArrayCount(); if (colorCount > kColorStorageCount) { size_t allocSize = (sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount; @@ -186,10 +174,6 @@ SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buf } SkGradientShaderBase::~SkGradientShaderBase() { - if (fCache16Storage) { - sk_free(fCache16Storage); - } - SkSafeUnref(fCache32PixelRef); if (fOrigColors != fStorage) { sk_free(fOrigColors); } @@ -197,7 +181,6 @@ SkGradientShaderBase::~SkGradientShaderBase() { } void SkGradientShaderBase::initCommon() { - fFlags = 0; unsigned colorAlpha = 0xFF; for (int i = 0; i < fColorCount; i++) { colorAlpha &= SkColorGetA(fOrigColors[i]); @@ -224,49 +207,50 @@ bool SkGradientShaderBase::isOpaque() const { return fColorsAreOpaque; } -bool SkGradientShaderBase::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; - } - +SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext( + const SkGradientShaderBase& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) + , fCache(shader.getCache(getPaintAlpha())) +{ const SkMatrix& inverse = this->getTotalInverse(); - fDstToIndex.setConcat(fPtsToUnit, inverse); + fDstToIndex.setConcat(shader.fPtsToUnit, inverse); + fDstToIndexProc = fDstToIndex.getMapXYProc(); - fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex); + fDstToIndexClass = (uint8_t)SkShader::Context::ComputeMatrixClass(fDstToIndex); // now convert our colors in to PMColors unsigned paintAlpha = this->getPaintAlpha(); fFlags = this->INHERITED::getFlags(); - if (fColorsAreOpaque && paintAlpha == 0xFF) { + if (shader.fColorsAreOpaque && paintAlpha == 0xFF) { fFlags |= kOpaqueAlpha_Flag; } // we can do span16 as long as our individual colors are opaque, // regardless of the paint's alpha - if (fColorsAreOpaque) { + if (shader.fColorsAreOpaque) { fFlags |= kHasSpan16_Flag; } +} - this->setCacheAlpha(paintAlpha); - return true; +SkGradientShaderBase::GradientShaderCache::GradientShaderCache( + U8CPU alpha, const SkGradientShaderBase& shader) + : fCacheAlpha(alpha) + , fShader(shader) + , fCache16Inited(false) + , fCache32Inited(false) +{ + // Only initialize the cache in getCache16/32. + fCache16 = NULL; + fCache32 = NULL; + fCache16Storage = NULL; + fCache32PixelRef = NULL; } -void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const { - // if the new alpha differs from the previous time we were called, inval our cache - // this will trigger the cache to be rebuilt. - // we don't care about the first time, since the cache ptrs will already be NULL - if (fCacheAlpha != alpha) { - fCache16 = NULL; // inval the cache - fCache32 = NULL; // inval the cache - fCacheAlpha = alpha; // record the new alpha - // inform our subclasses - if (fCache32PixelRef) { - fCache32PixelRef->notifyPixelsChanged(); - } - } +SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() { + sk_free(fCache16Storage); + SkSafeUnref(fCache32PixelRef); } #define Fixed_To_Dot8(x) (((x) + 0x80) >> 8) @@ -275,8 +259,8 @@ void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const { build a 16bit table as long as the original colors are opaque, even if the paint specifies a non-opaque alpha. */ -void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1, - int count) { +void SkGradientShaderBase::GradientShaderCache::Build16bitCache( + uint16_t cache[], SkColor c0, SkColor c1, int count) { SkASSERT(count > 1); SkASSERT(SkColorGetA(c0) == 0xFF); SkASSERT(SkColorGetA(c1) == 0xFF); @@ -324,8 +308,9 @@ void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor */ typedef uint32_t SkUFixed; -void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1, - int count, U8CPU paintAlpha, uint32_t gradFlags) { +void SkGradientShaderBase::GradientShaderCache::Build32bitCache( + SkPMColor cache[], SkColor c0, SkColor c1, + int count, U8CPU paintAlpha, uint32_t gradFlags) { SkASSERT(count > 1); // need to apply paintAlpha to our two endpoints @@ -468,97 +453,121 @@ static inline U16CPU bitsTo16(unsigned x, const unsigned bits) { return 0; } -const uint16_t* SkGradientShaderBase::getCache16() const { - if (fCache16 == NULL) { - // double the count for dither entries - const int entryCount = kCache16Count * 2; - const size_t allocSize = sizeof(uint16_t) * entryCount; +const uint16_t* SkGradientShaderBase::GradientShaderCache::getCache16() { + SkOnce(&fCache16Inited, &fCache16Mutex, SkGradientShaderBase::GradientShaderCache::initCache16, + this); + SkASSERT(fCache16); + return fCache16; +} - if (fCache16Storage == NULL) { // set the storage and our working ptr - fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); - } - fCache16 = fCache16Storage; - if (fColorCount == 2) { - Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1], - kCache16Count); - } else { - Rec* rec = fRecs; - int prevIndex = 0; - for (int i = 1; i < fColorCount; i++) { - int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift; - SkASSERT(nextIndex < kCache16Count); - - if (nextIndex > prevIndex) - Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1); - prevIndex = nextIndex; - } +void SkGradientShaderBase::GradientShaderCache::initCache16(GradientShaderCache* cache) { + // double the count for dither entries + const int entryCount = kCache16Count * 2; + const size_t allocSize = sizeof(uint16_t) * entryCount; + + SkASSERT(NULL == cache->fCache16Storage); + cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); + cache->fCache16 = cache->fCache16Storage; + if (cache->fShader.fColorCount == 2) { + Build16bitCache(cache->fCache16, cache->fShader.fOrigColors[0], + cache->fShader.fOrigColors[1], kCache16Count); + } else { + Rec* rec = cache->fShader.fRecs; + int prevIndex = 0; + for (int i = 1; i < cache->fShader.fColorCount; i++) { + int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift; + SkASSERT(nextIndex < kCache16Count); + + if (nextIndex > prevIndex) + Build16bitCache(cache->fCache16 + prevIndex, cache->fShader.fOrigColors[i-1], + cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1); + prevIndex = nextIndex; } + } - if (fMapper) { - fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); - uint16_t* linear = fCache16; // just computed linear data - uint16_t* mapped = fCache16Storage; // storage for mapped data - SkUnitMapper* map = fMapper; - for (int i = 0; i < kCache16Count; i++) { - int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift; - mapped[i] = linear[index]; - mapped[i + kCache16Count] = linear[index + kCache16Count]; - } - sk_free(fCache16); - fCache16 = fCache16Storage; + if (cache->fShader.fMapper) { + cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); + uint16_t* linear = cache->fCache16; // just computed linear data + uint16_t* mapped = cache->fCache16Storage; // storage for mapped data + SkUnitMapper* map = cache->fShader.fMapper; + for (int i = 0; i < kCache16Count; i++) { + int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift; + mapped[i] = linear[index]; + mapped[i + kCache16Count] = linear[index + kCache16Count]; } + sk_free(cache->fCache16); + cache->fCache16 = cache->fCache16Storage; } - return fCache16; } -const SkPMColor* SkGradientShaderBase::getCache32() const { - if (fCache32 == NULL) { - SkImageInfo info; - info.fWidth = kCache32Count; - info.fHeight = 4; // for our 4 dither rows - info.fAlphaType = kPremul_SkAlphaType; - info.fColorType = kN32_SkColorType; +const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() { + SkOnce(&fCache32Inited, &fCache32Mutex, SkGradientShaderBase::GradientShaderCache::initCache32, + this); + SkASSERT(fCache32); + return fCache32; +} - if (NULL == fCache32PixelRef) { - fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL); - } - fCache32 = (SkPMColor*)fCache32PixelRef->getAddr(); - if (fColorCount == 2) { - Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1], - kCache32Count, fCacheAlpha, fGradFlags); - } else { - Rec* rec = fRecs; - int prevIndex = 0; - for (int i = 1; i < fColorCount; i++) { - int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift; - SkASSERT(nextIndex < kCache32Count); - - if (nextIndex > prevIndex) - Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1], - fOrigColors[i], nextIndex - prevIndex + 1, - fCacheAlpha, fGradFlags); - prevIndex = nextIndex; - } +void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) { + SkImageInfo info; + info.fWidth = kCache32Count; + info.fHeight = 4; // for our 4 dither rows + info.fAlphaType = kPremul_SkAlphaType; + info.fColorType = kN32_SkColorType; + + SkASSERT(NULL == cache->fCache32PixelRef); + cache->fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL); + cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->getAddr(); + if (cache->fShader.fColorCount == 2) { + Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0], + cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha, + cache->fShader.fGradFlags); + } else { + Rec* rec = cache->fShader.fRecs; + int prevIndex = 0; + for (int i = 1; i < cache->fShader.fColorCount; i++) { + int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift; + SkASSERT(nextIndex < kCache32Count); + + if (nextIndex > prevIndex) + Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1], + cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1, + cache->fCacheAlpha, cache->fShader.fGradFlags); + prevIndex = nextIndex; } + } - if (fMapper) { - SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL); - SkPMColor* linear = fCache32; // just computed linear data - SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data - SkUnitMapper* map = fMapper; - for (int i = 0; i < kCache32Count; i++) { - int index = map->mapUnit16((i << 8) | i) >> 8; - mapped[i + kCache32Count*0] = linear[index + kCache32Count*0]; - mapped[i + kCache32Count*1] = linear[index + kCache32Count*1]; - mapped[i + kCache32Count*2] = linear[index + kCache32Count*2]; - mapped[i + kCache32Count*3] = linear[index + kCache32Count*3]; - } - fCache32PixelRef->unref(); - fCache32PixelRef = newPR; - fCache32 = (SkPMColor*)newPR->getAddr(); + if (cache->fShader.fMapper) { + SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL); + SkPMColor* linear = cache->fCache32; // just computed linear data + SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data + SkUnitMapper* map = cache->fShader.fMapper; + for (int i = 0; i < kCache32Count; i++) { + int index = map->mapUnit16((i << 8) | i) >> 8; + mapped[i + kCache32Count*0] = linear[index + kCache32Count*0]; + mapped[i + kCache32Count*1] = linear[index + kCache32Count*1]; + mapped[i + kCache32Count*2] = linear[index + kCache32Count*2]; + mapped[i + kCache32Count*3] = linear[index + kCache32Count*3]; } + cache->fCache32PixelRef->unref(); + cache->fCache32PixelRef = newPR; + cache->fCache32 = (SkPMColor*)newPR->getAddr(); } - return fCache32; +} + +/* + * The gradient holds a cache for the most recent value of alpha. Successive + * callers with the same alpha value will share the same cache. + */ +SkGradientShaderBase::GradientShaderCache* SkGradientShaderBase::getCache(U8CPU alpha) const { + SkAutoMutexAcquire ama(fCacheMutex); + if (!fCache || fCache->getAlpha() != alpha) { + fCache.reset(SkNEW_ARGS(GradientShaderCache, (alpha, *this))); + } + // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. + // Otherwise, the pointer may have been overwritten on a different thread before the object's + // ref count was incremented. + fCache.get()->ref(); + return fCache; } /* @@ -572,14 +581,14 @@ const SkPMColor* SkGradientShaderBase::getCache32() const { void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const { // our caller assumes no external alpha, so we ensure that our cache is // built with 0xFF - this->setCacheAlpha(0xFF); + GradientShaderCache* cache = this->getCache(0xFF); // don't have a way to put the mapper into our cache-key yet if (fMapper) { - // force our cahce32pixelref to be built - (void)this->getCache32(); + // force our cache32pixelref to be built + (void)cache->getCache32(); bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1)); - bitmap->setPixelRef(fCache32PixelRef); + bitmap->setPixelRef(cache->getCache32PixelRef()); return; } @@ -618,9 +627,9 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const { if (!gCache->find(storage.get(), size, bitmap)) { // force our cahce32pixelref to be built - (void)this->getCache32(); + (void)cache->getCache32(); bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1)); - bitmap->setPixelRef(fCache32PixelRef); + bitmap->setPixelRef(cache->getCache32PixelRef()); gCache->add(storage.get(), size, *bitmap); } diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h index 83e0789853..e01609462b 100644 --- a/src/effects/gradients/SkGradientShaderPriv.h +++ b/src/effects/gradients/SkGradientShaderPriv.h @@ -19,6 +19,7 @@ #include "SkTemplates.h" #include "SkBitmapCache.h" #include "SkShader.h" +#include "SkOnce.h" static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1, int count) { @@ -101,8 +102,64 @@ public: SkGradientShaderBase(const Descriptor& desc); virtual ~SkGradientShaderBase(); - virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE; - virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; } + // The cache is initialized on-demand when getCache16/32 is called. + class GradientShaderCache : public SkRefCnt { + public: + GradientShaderCache(U8CPU alpha, const SkGradientShaderBase& shader); + ~GradientShaderCache(); + + const uint16_t* getCache16(); + const SkPMColor* getCache32(); + + SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; } + + unsigned getAlpha() const { return fCacheAlpha; } + + private: + // Working pointers. If either is NULL, we need to recompute the corresponding cache values. + uint16_t* fCache16; + SkPMColor* fCache32; + + uint16_t* fCache16Storage; // Storage for fCache16, allocated on demand. + SkMallocPixelRef* fCache32PixelRef; + const unsigned fCacheAlpha; // The alpha value we used when we computed the cache. + // Larger than 8bits so we can store uninitialized + // value. + + const SkGradientShaderBase& fShader; + + // Make sure we only initialize the caches once. + bool fCache16Inited, fCache32Inited; + SkMutex fCache16Mutex, fCache32Mutex; + + static void initCache16(GradientShaderCache* cache); + static void initCache32(GradientShaderCache* cache); + + static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count); + static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count, + U8CPU alpha, uint32_t gradFlags); + }; + + class GradientShaderBaseContext : public SkShader::Context { + public: + GradientShaderBaseContext(const SkGradientShaderBase& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); + ~GradientShaderBaseContext() {} + + virtual uint32_t getFlags() const SK_OVERRIDE { return fFlags; } + + protected: + SkMatrix fDstToIndex; + SkMatrix::MapXYProc fDstToIndexProc; + uint8_t fDstToIndexClass; + uint8_t fFlags; + + SkAutoTUnref<GradientShaderCache> fCache; + + private: + typedef SkShader::Context INHERITED; + }; + virtual bool isOpaque() const SK_OVERRIDE; void getGradientTableBitmap(SkBitmap*) const; @@ -128,7 +185,6 @@ public: kDitherStride16 = kCache16Count, }; - protected: SkGradientShaderBase(SkReadBuffer& ); virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; @@ -136,13 +192,9 @@ protected: SkUnitMapper* fMapper; SkMatrix fPtsToUnit; // set by subclass - SkMatrix fDstToIndex; - SkMatrix::MapXYProc fDstToIndexProc; TileMode fTileMode; TileProc fTileProc; int fColorCount; - uint8_t fDstToIndexClass; - uint8_t fFlags; uint8_t fGradFlags; struct Rec { @@ -151,9 +203,6 @@ protected: }; Rec* fRecs; - const uint16_t* getCache16() const; - const SkPMColor* getCache32() const; - void commonAsAGradient(GradientInfo*) const; private: @@ -163,20 +212,13 @@ private: kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec)) }; SkColor fStorage[(kStorageSize + 3) >> 2]; - SkColor* fOrigColors; // original colors, before modulation by paint in setContext + SkColor* fOrigColors; // original colors, before modulation by paint in context. bool fColorsAreOpaque; - mutable uint16_t* fCache16; // working ptr. If this is NULL, we need to recompute the cache values - mutable SkPMColor* fCache32; // working ptr. If this is NULL, we need to recompute the cache values - - mutable uint16_t* fCache16Storage; // storage for fCache16, allocated on demand - mutable SkMallocPixelRef* fCache32PixelRef; - mutable unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value + GradientShaderCache* getCache(U8CPU alpha) const; + mutable SkMutex fCacheMutex; + mutable SkAutoTUnref<GradientShaderCache> fCache; - static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count); - static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count, - U8CPU alpha, uint32_t gradFlags); - void setCacheAlpha(U8CPU alpha) const; void initCommon(); typedef SkShader INHERITED; diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp index b24a6349c7..e660d7cd2d 100644 --- a/src/effects/gradients/SkLinearGradient.cpp +++ b/src/effects/gradients/SkLinearGradient.cpp @@ -71,12 +71,24 @@ void SkLinearGradient::flatten(SkWriteBuffer& buffer) const { buffer.writePoint(fEnd); } -bool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix) { - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; +size_t SkLinearGradient::contextSize() const { + return sizeof(LinearGradientContext); +} + +SkShader::Context* SkLinearGradient::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; } + return SkNEW_PLACEMENT_ARGS(storage, LinearGradientContext, (*this, device, paint, matrix)); +} + +SkLinearGradient::LinearGradientContext::LinearGradientContext( + const SkLinearGradient& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) +{ unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; if ((fDstToIndex.getType() & ~mask) == 0) { // when we dither, we are (usually) not const-in-Y @@ -87,7 +99,6 @@ bool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint, fFlags |= SkShader::kConstInY16_Flag; } } - return true; } #define NO_CHECK_ITER \ @@ -196,14 +207,16 @@ void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx, } -void SkLinearGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, - int count) { +void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, + int count) { SkASSERT(count > 0); + const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader); + SkPoint srcPt; SkMatrix::MapXYProc dstProc = fDstToIndexProc; - TileProc proc = fTileProc; - const SkPMColor* SK_RESTRICT cache = this->getCache32(); + TileProc proc = linearGradient.fTileProc; + const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); int toggle = init_dither_toggle(x, y); if (fDstToIndexClass != kPerspective_MatrixClass) { @@ -223,12 +236,12 @@ void SkLinearGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, LinearShadeProc shadeProc = shadeSpan_linear_repeat; if (0 == dx) { shadeProc = shadeSpan_linear_vertical_lerp; - } else if (SkShader::kClamp_TileMode == fTileMode) { + } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { shadeProc = shadeSpan_linear_clamp; - } else if (SkShader::kMirror_TileMode == fTileMode) { + } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { shadeProc = shadeSpan_linear_mirror; } else { - SkASSERT(SkShader::kRepeat_TileMode == fTileMode); + SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); } (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); } else { @@ -381,14 +394,16 @@ static bool fixed_nearly_zero(SkFixed x) { return SkAbs32(x) < (SK_Fixed1 >> 12); } -void SkLinearGradient::shadeSpan16(int x, int y, - uint16_t* SK_RESTRICT dstC, int count) { +void SkLinearGradient::LinearGradientContext::shadeSpan16(int x, int y, + uint16_t* SK_RESTRICT dstC, int count) { SkASSERT(count > 0); + const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader); + SkPoint srcPt; SkMatrix::MapXYProc dstProc = fDstToIndexProc; - TileProc proc = fTileProc; - const uint16_t* SK_RESTRICT cache = this->getCache16(); + TileProc proc = linearGradient.fTileProc; + const uint16_t* SK_RESTRICT cache = fCache->getCache16(); int toggle = init_dither_toggle16(x, y); if (fDstToIndexClass != kPerspective_MatrixClass) { @@ -408,12 +423,12 @@ void SkLinearGradient::shadeSpan16(int x, int y, LinearShade16Proc shadeProc = shadeSpan16_linear_repeat; if (fixed_nearly_zero(dx)) { shadeProc = shadeSpan16_linear_vertical; - } else if (SkShader::kClamp_TileMode == fTileMode) { + } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { shadeProc = shadeSpan16_linear_clamp; - } else if (SkShader::kMirror_TileMode == fTileMode) { + } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { shadeProc = shadeSpan16_linear_mirror; } else { - SkASSERT(SkShader::kRepeat_TileMode == fTileMode); + SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); } (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); } else { diff --git a/src/effects/gradients/SkLinearGradient.h b/src/effects/gradients/SkLinearGradient.h index 013c4499b0..8d806672f8 100644 --- a/src/effects/gradients/SkLinearGradient.h +++ b/src/effects/gradients/SkLinearGradient.h @@ -15,9 +15,23 @@ class SkLinearGradient : public SkGradientShaderBase { public: SkLinearGradient(const SkPoint pts[2], const Descriptor&); - virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, + void* storage) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + + class LinearGradientContext : public SkGradientShaderBase::GradientShaderBaseContext { + public: + LinearGradientContext(const SkLinearGradient& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); + ~LinearGradientContext() {} + + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; + + private: + typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED; + }; + virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*) const SK_OVERRIDE; virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE; virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint&) const SK_OVERRIDE; diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp index 1b9e7258c4..bc2ea3b92b 100644 --- a/src/effects/gradients/SkRadialGradient.cpp +++ b/src/effects/gradients/SkRadialGradient.cpp @@ -157,16 +157,36 @@ SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, rad_to_unit_matrix(center, radius, &fPtsToUnit); } -void SkRadialGradient::shadeSpan16(int x, int y, uint16_t* dstCParam, - int count) { +size_t SkRadialGradient::contextSize() const { + return sizeof(RadialGradientContext); +} + +SkShader::Context* SkRadialGradient::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + return SkNEW_PLACEMENT_ARGS(storage, RadialGradientContext, (*this, device, paint, matrix)); +} + +SkRadialGradient::RadialGradientContext::RadialGradientContext( + const SkRadialGradient& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) {} + +void SkRadialGradient::RadialGradientContext::shadeSpan16(int x, int y, uint16_t* dstCParam, + int count) { SkASSERT(count > 0); + const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader); + uint16_t* SK_RESTRICT dstC = dstCParam; SkPoint srcPt; SkMatrix::MapXYProc dstProc = fDstToIndexProc; - TileProc proc = fTileProc; - const uint16_t* SK_RESTRICT cache = this->getCache16(); + TileProc proc = radialGradient.fTileProc; + const uint16_t* SK_RESTRICT cache = fCache->getCache16(); int toggle = init_dither_toggle16(x, y); if (fDstToIndexClass != kPerspective_MatrixClass) { @@ -187,12 +207,12 @@ void SkRadialGradient::shadeSpan16(int x, int y, uint16_t* dstCParam, } RadialShade16Proc shadeProc = shadeSpan16_radial_repeat; - if (SkShader::kClamp_TileMode == fTileMode) { + if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { shadeProc = shadeSpan16_radial_clamp; - } else if (SkShader::kMirror_TileMode == fTileMode) { + } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { shadeProc = shadeSpan16_radial_mirror; } else { - SkASSERT(SkShader::kRepeat_TileMode == fTileMode); + SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); } (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, toggle, count); @@ -389,14 +409,16 @@ void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, } // namespace -void SkRadialGradient::shadeSpan(int x, int y, - SkPMColor* SK_RESTRICT dstC, int count) { +void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, + SkPMColor* SK_RESTRICT dstC, int count) { SkASSERT(count > 0); + const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader); + SkPoint srcPt; SkMatrix::MapXYProc dstProc = fDstToIndexProc; - TileProc proc = fTileProc; - const SkPMColor* SK_RESTRICT cache = this->getCache32(); + TileProc proc = radialGradient.fTileProc; + const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); int toggle = init_dither_toggle(x, y); if (fDstToIndexClass != kPerspective_MatrixClass) { @@ -416,12 +438,12 @@ void SkRadialGradient::shadeSpan(int x, int y, } RadialShadeProc shadeProc = shadeSpan_radial_repeat; - if (SkShader::kClamp_TileMode == fTileMode) { + if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { shadeProc = shadeSpan_radial_clamp; - } else if (SkShader::kMirror_TileMode == fTileMode) { + } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { shadeProc = shadeSpan_radial_mirror; } else { - SkASSERT(SkShader::kRepeat_TileMode == fTileMode); + SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); } (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); } else { // perspective case diff --git a/src/effects/gradients/SkRadialGradient.h b/src/effects/gradients/SkRadialGradient.h index 4a725145b0..a3d04b1aaf 100644 --- a/src/effects/gradients/SkRadialGradient.h +++ b/src/effects/gradients/SkRadialGradient.h @@ -14,10 +14,24 @@ class SkRadialGradient : public SkGradientShaderBase { public: SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor&); - virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count) - SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t* dstCParam, - int count) SK_OVERRIDE; + + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, + void* storage) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + + class RadialGradientContext : public SkGradientShaderBase::GradientShaderBaseContext { + public: + RadialGradientContext(const SkRadialGradient& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); + ~RadialGradientContext() {} + + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; + + private: + typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED; + }; + virtual BitmapType asABitmap(SkBitmap* bitmap, SkMatrix* matrix, TileMode* xy) const SK_OVERRIDE; diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp index 7024945bf0..6dff1e71cd 100644 --- a/src/effects/gradients/SkSweepGradient.cpp +++ b/src/effects/gradients/SkSweepGradient.cpp @@ -52,6 +52,24 @@ void SkSweepGradient::flatten(SkWriteBuffer& buffer) const { buffer.writePoint(fCenter); } +size_t SkSweepGradient::contextSize() const { + return sizeof(SweepGradientContext); +} + +SkShader::Context* SkSweepGradient::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + return SkNEW_PLACEMENT_ARGS(storage, SweepGradientContext, (*this, device, paint, matrix)); +} + +SkSweepGradient::SweepGradientContext::SweepGradientContext( + const SkSweepGradient& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) {} + // returns angle in a circle [0..2PI) -> [0..255] static unsigned SkATan2_255(float y, float x) { // static const float g255Over2PI = 255 / (2 * SK_ScalarPI); @@ -69,11 +87,11 @@ static unsigned SkATan2_255(float y, float x) { return ir; } -void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, - int count) { +void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, + int count) { SkMatrix::MapXYProc proc = fDstToIndexProc; const SkMatrix& matrix = fDstToIndex; - const SkPMColor* SK_RESTRICT cache = this->getCache32(); + const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); int toggle = init_dither_toggle(x, y); SkPoint srcPt; @@ -111,11 +129,11 @@ void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, } } -void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, - int count) { +void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, + int count) { SkMatrix::MapXYProc proc = fDstToIndexProc; const SkMatrix& matrix = fDstToIndex; - const uint16_t* SK_RESTRICT cache = this->getCache16(); + const uint16_t* SK_RESTRICT cache = fCache->getCache16(); int toggle = init_dither_toggle16(x, y); SkPoint srcPt; diff --git a/src/effects/gradients/SkSweepGradient.h b/src/effects/gradients/SkSweepGradient.h index ca19da25ba..9998ed16a7 100644 --- a/src/effects/gradients/SkSweepGradient.h +++ b/src/effects/gradients/SkSweepGradient.h @@ -14,8 +14,23 @@ class SkSweepGradient : public SkGradientShaderBase { public: SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor&); - virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; - virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; + + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, + void* storage) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + + class SweepGradientContext : public SkGradientShaderBase::GradientShaderBaseContext { + public: + SweepGradientContext(const SkSweepGradient& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix); + ~SweepGradientContext() {} + + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE; + + private: + typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED; + }; virtual BitmapType asABitmap(SkBitmap* bitmap, SkMatrix* matrix, @@ -33,8 +48,9 @@ protected: virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE; private: - typedef SkGradientShaderBase INHERITED; const SkPoint fCenter; + + typedef SkGradientShaderBase INHERITED; }; #endif diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp index de8c2364c3..b0955a2583 100644 --- a/src/effects/gradients/SkTwoPointConicalGradient.cpp +++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp @@ -9,6 +9,18 @@ #include "SkTwoPointConicalGradient_gpu.h" +struct TwoPtRadialContext { + const TwoPtRadial& fRec; + float fRelX, fRelY; + const float fIncX, fIncY; + float fB; + const float fDB; + + TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy, + SkScalar dfx, SkScalar dfy); + SkFixed nextT(); +}; + static int valid_divide(float numer, float denom, float* ratio) { SkASSERT(ratio); if (0 == denom) { @@ -77,47 +89,48 @@ void TwoPtRadial::init(const SkPoint& center0, SkScalar rad0, fRDR = fRadius * fDRadius; } -void TwoPtRadial::setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy) { - fRelX = SkScalarToFloat(fx) - fCenterX; - fRelY = SkScalarToFloat(fy) - fCenterY; - fIncX = SkScalarToFloat(dfx); - fIncY = SkScalarToFloat(dfy); - fB = -2 * (fDCenterX * fRelX + fDCenterY * fRelY + fRDR); - fDB = -2 * (fDCenterX * fIncX + fDCenterY * fIncY); -} - -SkFixed TwoPtRadial::nextT() { +TwoPtRadialContext::TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy, + SkScalar dfx, SkScalar dfy) + : fRec(rec) + , fRelX(SkScalarToFloat(fx) - rec.fCenterX) + , fRelY(SkScalarToFloat(fy) - rec.fCenterY) + , fIncX(SkScalarToFloat(dfx)) + , fIncY(SkScalarToFloat(dfy)) + , fB(-2 * (rec.fDCenterX * fRelX + rec.fDCenterY * fRelY + rec.fRDR)) + , fDB(-2 * (rec.fDCenterX * fIncX + rec.fDCenterY * fIncY)) {} + +SkFixed TwoPtRadialContext::nextT() { float roots[2]; - float C = sqr(fRelX) + sqr(fRelY) - fRadius2; - int countRoots = find_quad_roots(fA, fB, C, roots); + float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2; + int countRoots = find_quad_roots(fRec.fA, fB, C, roots); fRelX += fIncX; fRelY += fIncY; fB += fDB; if (0 == countRoots) { - return kDontDrawT; + return TwoPtRadial::kDontDrawT; } // Prefer the bigger t value if both give a radius(t) > 0 // find_quad_roots returns the values sorted, so we start with the last float t = roots[countRoots - 1]; - float r = lerp(fRadius, fDRadius, t); + float r = lerp(fRec.fRadius, fRec.fDRadius, t); if (r <= 0) { t = roots[0]; // might be the same as roots[countRoots-1] - r = lerp(fRadius, fDRadius, t); + r = lerp(fRec.fRadius, fRec.fDRadius, t); if (r <= 0) { - return kDontDrawT; + return TwoPtRadial::kDontDrawT; } } return SkFloatToFixed(t); } -typedef void (*TwoPointConicalProc)(TwoPtRadial* rec, SkPMColor* dstC, +typedef void (*TwoPointConicalProc)(TwoPtRadialContext* rec, SkPMColor* dstC, const SkPMColor* cache, int toggle, int count); -static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, +static void twopoint_clamp(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, int toggle, int count) { for (; count > 0; --count) { @@ -134,7 +147,7 @@ static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, } } -static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, +static void twopoint_repeat(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, int toggle, int count) { for (; count > 0; --count) { @@ -151,7 +164,7 @@ static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, } } -static void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, +static void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, int toggle, int count) { for (; count > 0; --count) { @@ -196,8 +209,39 @@ bool SkTwoPointConicalGradient::isOpaque() const { return false; } -void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, - int count) { +size_t SkTwoPointConicalGradient::contextSize() const { + return sizeof(TwoPointConicalGradientContext); +} + +SkShader::Context* SkTwoPointConicalGradient::createContext( + const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + return SkNEW_PLACEMENT_ARGS(storage, TwoPointConicalGradientContext, + (*this, device, paint, matrix)); +} + +SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradientContext( + const SkTwoPointConicalGradient& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) +{ + // we don't have a span16 proc + fFlags &= ~kHasSpan16_Flag; + + // in general, we might discard based on computed-radius, so clear + // this flag (todo: sometimes we can detect that we never discard...) + fFlags &= ~kOpaqueAlpha_Flag; +} + +void SkTwoPointConicalGradient::TwoPointConicalGradientContext::shadeSpan( + int x, int y, SkPMColor* dstCParam, int count) { + const SkTwoPointConicalGradient& twoPointConicalGradient = + static_cast<const SkTwoPointConicalGradient&>(fShader); + int toggle = init_dither_toggle(x, y); SkASSERT(count > 0); @@ -206,15 +250,15 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, SkMatrix::MapXYProc dstProc = fDstToIndexProc; - const SkPMColor* SK_RESTRICT cache = this->getCache32(); + const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); TwoPointConicalProc shadeProc = twopoint_repeat; - if (SkShader::kClamp_TileMode == fTileMode) { + if (SkShader::kClamp_TileMode == twoPointConicalGradient.fTileMode) { shadeProc = twopoint_clamp; - } else if (SkShader::kMirror_TileMode == fTileMode) { + } else if (SkShader::kMirror_TileMode == twoPointConicalGradient.fTileMode) { shadeProc = twopoint_mirror; } else { - SkASSERT(SkShader::kRepeat_TileMode == fTileMode); + SkASSERT(SkShader::kRepeat_TileMode == twoPointConicalGradient.fTileMode); } if (fDstToIndexClass != kPerspective_MatrixClass) { @@ -235,16 +279,16 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, dy = fDstToIndex.getSkewY(); } - fRec.setup(fx, fy, dx, dy); - (*shadeProc)(&fRec, dstC, cache, toggle, count); + TwoPtRadialContext rec(twoPointConicalGradient.fRec, fx, fy, dx, dy); + (*shadeProc)(&rec, dstC, cache, toggle, count); } else { // perspective case SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf; SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf; for (; count > 0; --count) { SkPoint srcPt; dstProc(fDstToIndex, dstX, dstY, &srcPt); - fRec.setup(srcPt.fX, srcPt.fY, 0, 0); - (*shadeProc)(&fRec, dstC, cache, toggle, 1); + TwoPtRadialContext rec(twoPointConicalGradient.fRec, srcPt.fX, srcPt.fY, 0, 0); + (*shadeProc)(&rec, dstC, cache, toggle, 1); dstX += SK_Scalar1; toggle = next_dither_toggle(toggle); @@ -253,23 +297,6 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, } } -bool SkTwoPointConicalGradient::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; - } - - // we don't have a span16 proc - fFlags &= ~kHasSpan16_Flag; - - // in general, we might discard based on computed-radius, so clear - // this flag (todo: sometimes we can detect that we never discard...) - fFlags &= ~kOpaqueAlpha_Flag; - - return true; -} - SkShader::BitmapType SkTwoPointConicalGradient::asABitmap( SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const { SkPoint diff = fCenter2 - fCenter1; diff --git a/src/effects/gradients/SkTwoPointConicalGradient.h b/src/effects/gradients/SkTwoPointConicalGradient.h index 041f8b8be4..4c049172d3 100644 --- a/src/effects/gradients/SkTwoPointConicalGradient.h +++ b/src/effects/gradients/SkTwoPointConicalGradient.h @@ -11,6 +11,8 @@ #include "SkGradientShaderPriv.h" +// TODO(dominikg): Worth making it truly immutable (i.e. set values in constructor)? +// Should only be initialized once via init(). Immutable afterwards. struct TwoPtRadial { enum { kDontDrawT = 0x80000000 @@ -27,13 +29,6 @@ struct TwoPtRadial { void init(const SkPoint& center0, SkScalar rad0, const SkPoint& center1, SkScalar rad1); - // used by setup and nextT - float fRelX, fRelY, fIncX, fIncY; - float fB, fDB; - - void setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy); - SkFixed nextT(); - static bool DontDrawT(SkFixed t) { return kDontDrawT == (uint32_t)t; } @@ -49,11 +44,24 @@ public: const SkPoint& end, SkScalar endRadius, const Descriptor&); - virtual void shadeSpan(int x, int y, SkPMColor* dstCParam, - int count) SK_OVERRIDE; - virtual bool setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) SK_OVERRIDE; + + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, + void* storage) const SK_OVERRIDE; + virtual size_t contextSize() const SK_OVERRIDE; + + class TwoPointConicalGradientContext : public SkGradientShaderBase::GradientShaderBaseContext { + public: + TwoPointConicalGradientContext(const SkTwoPointConicalGradient& shader, + const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix); + ~TwoPointConicalGradientContext() {} + + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + + private: + typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED; + }; virtual BitmapType asABitmap(SkBitmap* bitmap, SkMatrix* matrix, @@ -77,11 +85,12 @@ protected: virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE; private: - typedef SkGradientShaderBase INHERITED; const SkPoint fCenter1; const SkPoint fCenter2; const SkScalar fRadius1; const SkScalar fRadius2; + + typedef SkGradientShaderBase INHERITED; }; #endif diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp index e1359b12dd..a598c6e0e3 100644 --- a/src/effects/gradients/SkTwoPointRadialGradient.cpp +++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp @@ -220,23 +220,60 @@ SkShader::GradientType SkTwoPointRadialGradient::asAGradient( return kRadial2_GradientType; } -void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, - int count) { +size_t SkTwoPointRadialGradient::contextSize() const { + return sizeof(TwoPointRadialGradientContext); +} + +bool SkTwoPointRadialGradient::validContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse) const { + // For now, we might have divided by zero, so detect that. + if (0 == fDiffRadius) { + return false; + } + + return this->INHERITED::validContext(device, paint, matrix, totalInverse); +} + +SkShader::Context* SkTwoPointRadialGradient::createContext( + const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + return SkNEW_PLACEMENT_ARGS(storage, TwoPointRadialGradientContext, + (*this, device, paint, matrix)); +} + +SkTwoPointRadialGradient::TwoPointRadialGradientContext::TwoPointRadialGradientContext( + const SkTwoPointRadialGradient& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix) + : INHERITED(shader, device, paint, matrix) +{ + // we don't have a span16 proc + fFlags &= ~kHasSpan16_Flag; +} + +void SkTwoPointRadialGradient::TwoPointRadialGradientContext::shadeSpan( + int x, int y, SkPMColor* dstCParam, int count) { SkASSERT(count > 0); + const SkTwoPointRadialGradient& twoPointRadialGradient = + static_cast<const SkTwoPointRadialGradient&>(fShader); + SkPMColor* SK_RESTRICT dstC = dstCParam; // Zero difference between radii: fill with transparent black. - if (fDiffRadius == 0) { + if (twoPointRadialGradient.fDiffRadius == 0) { sk_bzero(dstC, count * sizeof(*dstC)); return; } SkMatrix::MapXYProc dstProc = fDstToIndexProc; - TileProc proc = fTileProc; - const SkPMColor* SK_RESTRICT cache = this->getCache32(); + TileProc proc = twoPointRadialGradient.fTileProc; + const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); - SkScalar foura = fA * 4; - bool posRoot = fDiffRadius < 0; + SkScalar foura = twoPointRadialGradient.fA * 4; + bool posRoot = twoPointRadialGradient.fDiffRadius < 0; if (fDstToIndexClass != kPerspective_MatrixClass) { SkPoint srcPt; dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, @@ -254,21 +291,23 @@ void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, dx = fDstToIndex.getScaleX(); dy = fDstToIndex.getSkewY(); } - SkScalar b = (SkScalarMul(fDiff.fX, fx) + - SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2; - SkScalar db = (SkScalarMul(fDiff.fX, dx) + - SkScalarMul(fDiff.fY, dy)) * 2; + SkScalar b = (SkScalarMul(twoPointRadialGradient.fDiff.fX, fx) + + SkScalarMul(twoPointRadialGradient.fDiff.fY, fy) - + twoPointRadialGradient.fStartRadius) * 2; + SkScalar db = (SkScalarMul(twoPointRadialGradient.fDiff.fX, dx) + + SkScalarMul(twoPointRadialGradient.fDiff.fY, dy)) * 2; TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat; - if (SkShader::kClamp_TileMode == fTileMode) { + if (SkShader::kClamp_TileMode == twoPointRadialGradient.fTileMode) { shadeProc = shadeSpan_twopoint_clamp; - } else if (SkShader::kMirror_TileMode == fTileMode) { + } else if (SkShader::kMirror_TileMode == twoPointRadialGradient.fTileMode) { shadeProc = shadeSpan_twopoint_mirror; } else { - SkASSERT(SkShader::kRepeat_TileMode == fTileMode); + SkASSERT(SkShader::kRepeat_TileMode == twoPointRadialGradient.fTileMode); } (*shadeProc)(fx, dx, fy, dy, b, db, - fSr2D2, foura, fOneOverTwoA, posRoot, + twoPointRadialGradient.fSr2D2, foura, + twoPointRadialGradient.fOneOverTwoA, posRoot, dstC, cache, count); } else { // perspective case SkScalar dstX = SkIntToScalar(x); @@ -278,10 +317,11 @@ void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, dstProc(fDstToIndex, dstX, dstY, &srcPt); SkScalar fx = srcPt.fX; SkScalar fy = srcPt.fY; - SkScalar b = (SkScalarMul(fDiff.fX, fx) + - SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2; - SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, - fOneOverTwoA, posRoot); + SkScalar b = (SkScalarMul(twoPointRadialGradient.fDiff.fX, fx) + + SkScalarMul(twoPointRadialGradient.fDiff.fY, fy) - + twoPointRadialGradient.fStartRadius) * 2; + SkFixed t = two_point_radial(b, fx, fy, twoPointRadialGradient.fSr2D2, foura, + twoPointRadialGradient.fOneOverTwoA, posRoot); SkFixed index = proc(t); SkASSERT(index <= 0xFFFF); *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift]; @@ -290,23 +330,6 @@ void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, } } -bool SkTwoPointRadialGradient::setContext( const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix){ - // For now, we might have divided by zero, so detect that - if (0 == fDiffRadius) { - return false; - } - - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; - } - - // we don't have a span16 proc - fFlags &= ~kHasSpan16_Flag; - return true; -} - #ifndef SK_IGNORE_TO_STRING void SkTwoPointRadialGradient::toString(SkString* str) const { str->append("SkTwoPointRadialGradient: ("); diff --git a/src/effects/gradients/SkTwoPointRadialGradient.h b/src/effects/gradients/SkTwoPointRadialGradient.h index ee1b49ee95..9ba89f2920 100644 --- a/src/effects/gradients/SkTwoPointRadialGradient.h +++ b/src/effects/gradients/SkTwoPointRadialGradient.h @@ -23,11 +23,26 @@ public: virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE; virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint&) const SK_OVERRIDE; - virtual void shadeSpan(int x, int y, SkPMColor* dstCParam, - int count) SK_OVERRIDE; - virtual bool setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) SK_OVERRIDE; + + virtual size_t contextSize() const SK_OVERRIDE; + virtual bool validContext(const SkBitmap&, const SkPaint&, + const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE; + virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, + void* storage) const SK_OVERRIDE; + + class TwoPointRadialGradientContext : public SkGradientShaderBase::GradientShaderBaseContext { + public: + TwoPointRadialGradientContext(const SkTwoPointRadialGradient& shader, + const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix); + ~TwoPointRadialGradientContext() {} + + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; + + private: + typedef SkGradientShaderBase::GradientShaderBaseContext INHERITED; + }; SkScalar getCenterX1() const { return fDiff.length(); } SkScalar getStartRadius() const { return fStartRadius; } @@ -41,7 +56,6 @@ protected: virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE; private: - typedef SkGradientShaderBase INHERITED; const SkPoint fCenter1; const SkPoint fCenter2; const SkScalar fRadius1; @@ -50,6 +64,8 @@ private: SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA; void init(); + + typedef SkGradientShaderBase INHERITED; }; #endif |