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
Committed: http://code.google.com/p/skia/source/detail?r=14216
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@14323 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp
index ed63faf..5adb582 100644
--- a/src/effects/SkPerlinNoiseShader.cpp
+++ b/src/effects/SkPerlinNoiseShader.cpp
@@ -278,7 +278,6 @@
, fStitchTiles(!fTileSize.isEmpty())
{
SkASSERT(numOctaves >= 0 && numOctaves < 256);
- fMatrix.reset();
fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY));
}
@@ -293,7 +292,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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::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 bd8b99a..0997e62 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 this->INHERITED::setContext(device, paint, matrix);
+ return SkNEW_PLACEMENT_ARGS(storage, TransparentShaderContext, (*this, device, paint, matrix));
}
-uint32_t SkTransparentShader::getFlags() {
+size_t SkTransparentShader::contextSize() const {
+ return sizeof(TransparentShaderContext);
+}
+
+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 @@
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 @@
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::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 2e92076..46e0c95 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.fGradFlags);
@@ -26,10 +24,6 @@
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
@@ -146,14 +140,8 @@
}
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;
@@ -188,10 +176,6 @@
}
SkGradientShaderBase::~SkGradientShaderBase() {
- if (fCache16Storage) {
- sk_free(fCache16Storage);
- }
- SkSafeUnref(fCache32PixelRef);
if (fOrigColors != fStorage) {
sk_free(fOrigColors);
}
@@ -199,7 +183,6 @@
}
void SkGradientShaderBase::initCommon() {
- fFlags = 0;
unsigned colorAlpha = 0xFF;
for (int i = 0; i < fColorCount; i++) {
colorAlpha &= SkColorGetA(fOrigColors[i]);
@@ -267,49 +250,50 @@
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.refCache(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;
}
-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(
+ 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;
+}
+
+SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() {
+ sk_free(fCache16Storage);
+ SkSafeUnref(fCache32PixelRef);
}
#define Fixed_To_Dot8(x) (((x) + 0x80) >> 8)
@@ -318,8 +302,8 @@
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);
@@ -367,8 +351,9 @@
*/
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
@@ -511,99 +496,123 @@
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;
-
- 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;
- }
- }
-
- 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;
- }
- }
+const uint16_t* SkGradientShaderBase::GradientShaderCache::getCache16() {
+ SkOnce(&fCache16Inited, &fCache16Mutex, SkGradientShaderBase::GradientShaderCache::initCache16,
+ this);
+ SkASSERT(fCache16);
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;
+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;
- 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);
+ 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)
- Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
- fOrigColors[i], nextIndex - prevIndex + 1,
- fCacheAlpha, 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 (nextIndex > prevIndex)
+ Build16bitCache(cache->fCache16 + prevIndex, cache->fShader.fOrigColors[i-1],
+ cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1);
+ prevIndex = nextIndex;
}
}
+
+ 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;
+ }
+}
+
+const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() {
+ SkOnce(&fCache32Inited, &fCache32Mutex, SkGradientShaderBase::GradientShaderCache::initCache32,
+ this);
+ SkASSERT(fCache32);
return fCache32;
}
+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 (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();
+ }
+}
+
+/*
+ * 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::refCache(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;
+}
+
/*
* Because our caller might rebuild the same (logically the same) gradient
* over and over, we'd like to return exactly the same "bitmap" if possible,
@@ -615,14 +624,14 @@
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);
+ SkAutoTUnref<GradientShaderCache> cache(this->refCache(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;
}
@@ -661,9 +670,9 @@
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 02bb50b..5dec665 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 @@
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;
@@ -148,13 +205,9 @@
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 {
@@ -163,9 +216,6 @@
};
Rec* fRecs;
- const uint16_t* getCache16() const;
- const SkPMColor* getCache32() const;
-
void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
/*
@@ -191,20 +241,13 @@
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
+ GradientShaderCache* refCache(U8CPU alpha) const;
+ mutable SkMutex fCacheMutex;
+ mutable SkAutoTUnref<GradientShaderCache> fCache;
- 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
-
- 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 b24a634..e660d7c 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -71,12 +71,24 @@
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 @@
fFlags |= SkShader::kConstInY16_Flag;
}
}
- return true;
}
#define NO_CHECK_ITER \
@@ -196,14 +207,16 @@
}
-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 @@
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 @@
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 @@
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 013c449..8d80667 100644
--- a/src/effects/gradients/SkLinearGradient.h
+++ b/src/effects/gradients/SkLinearGradient.h
@@ -15,9 +15,23 @@
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 1b9e725..bc2ea3b 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -157,16 +157,36 @@
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 @@
}
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 @@
} // 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 @@
}
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 4a72514..a3d04b1 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 7024945..6dff1e7 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -52,6 +52,24 @@
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 @@
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::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 ca19da2..9998ed1 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 @@
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 1e6a0d8..b7aba82 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) {
@@ -83,47 +95,48 @@
fFlipped = flipped;
}
-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);
-}
+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 TwoPtRadial::nextT() {
+SkFixed TwoPtRadialContext::nextT() {
float roots[2];
- float C = sqr(fRelX) + sqr(fRelY) - fRadius2;
- int countRoots = find_quad_roots(fA, fB, C, roots, fFlipped);
+ float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2;
+ int countRoots = find_quad_roots(fRec.fA, fB, C, roots, fRec.fFlipped);
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) {
@@ -140,7 +153,7 @@
}
}
-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) {
@@ -157,7 +170,7 @@
}
}
-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) {
@@ -203,8 +216,39 @@
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);
@@ -213,15 +257,15 @@
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) {
@@ -242,16 +286,16 @@
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);
@@ -260,23 +304,6 @@
}
}
-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 b2e258e..80aa6fa 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
@@ -29,13 +31,6 @@
const SkPoint& center1, SkScalar rad1,
bool flipped);
- // 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;
}
@@ -51,11 +46,24 @@
const SkPoint& end, SkScalar endRadius,
bool flippedGrad, 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,
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index e1359b1..a598c6e 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -220,23 +220,60 @@
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 @@
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 @@
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 @@
}
}
-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 ee1b49e..9ba89f2 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.h
+++ b/src/effects/gradients/SkTwoPointRadialGradient.h
@@ -23,11 +23,26 @@
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 @@
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 @@
SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
void init();
+
+ typedef SkGradientShaderBase INHERITED;
};
#endif