Index: src/effects/SkPerlinNoiseShader.cpp |
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp |
index 47de924b997e41b34bf902ee1174f7313e514cfe..0447d271ddfd566eee7ebd64986e27fe620bb859 100644 |
--- a/src/effects/SkPerlinNoiseShader.cpp |
+++ b/src/effects/SkPerlinNoiseShader.cpp |
@@ -9,10 +9,11 @@ |
#include "SkPerlinNoiseShader.h" |
#include "SkColorFilter.h" |
#include "SkReadBuffer.h" |
-#include "SkWriteBuffer.h" |
#include "SkShader.h" |
-#include "SkUnPreMultiply.h" |
#include "SkString.h" |
+#include "SkThread.h" |
+#include "SkUnPreMultiply.h" |
+#include "SkWriteBuffer.h" |
#if SK_SUPPORT_GPU |
#include "GrContext.h" |
@@ -81,12 +82,18 @@ struct SkPerlinNoiseShader::StitchData { |
}; |
struct SkPerlinNoiseShader::PaintingData { |
- PaintingData(const SkISize& tileSize) |
- : fSeed(0) |
- , fTileSize(tileSize) |
+ PaintingData(const SkISize& tileSize, SkScalar seed, |
+ SkScalar baseFrequencyX, SkScalar baseFrequencyY) |
+ : fTileSize(tileSize) |
+ , fBaseFrequency(SkPoint::Make(baseFrequencyX, baseFrequencyY)) |
, fPermutationsBitmap(NULL) |
, fNoiseBitmap(NULL) |
- {} |
+ { |
+ this->init(seed); |
+ if (!fTileSize.isEmpty()) { |
+ this->stitch(); |
+ } |
+ } |
~PaintingData() |
{ |
@@ -107,7 +114,9 @@ private: |
SkBitmap* fPermutationsBitmap; |
SkBitmap* fNoiseBitmap; |
-public: |
+ // Guards for the bitmap caches. |
+ SkMutex fPermutationsMutex; |
+ SkMutex fNoiseMutex; |
inline int random() { |
static const int gRandAmplitude = 16807; // 7**5; primitive root of m |
@@ -121,6 +130,7 @@ public: |
return result; |
} |
+ // Only called once. Could be part of the constructor. |
void init(SkScalar seed) |
{ |
static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize)); |
@@ -190,14 +200,9 @@ public: |
fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits)); |
} |
} |
- |
- // Invalidate bitmaps |
- SkDELETE(fPermutationsBitmap); |
- fPermutationsBitmap = NULL; |
- SkDELETE(fNoiseBitmap); |
- fNoiseBitmap = NULL; |
} |
+ // Only called once. Could be part of the constructor. |
void stitch() { |
SkScalar tileWidth = SkIntToScalar(fTileSize.width()); |
SkScalar tileHeight = SkIntToScalar(fTileSize.height()); |
@@ -238,13 +243,18 @@ public: |
fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight; |
} |
+public: |
+ |
SkBitmap* getPermutationsBitmap() |
{ |
if (!fPermutationsBitmap) { |
- fPermutationsBitmap = SkNEW(SkBitmap); |
- fPermutationsBitmap->allocPixels(SkImageInfo::MakeA8(kBlockSize, 1)); |
- uint8_t* bitmapPixels = fPermutationsBitmap->getAddr8(0, 0); |
- memcpy(bitmapPixels, fLatticeSelector, sizeof(uint8_t) * kBlockSize); |
+ SkAutoMutexAcquire autoMutex(fPermutationsMutex); |
Stephen White
2014/03/05 21:37:50
Maybe I'm being dense, but can these bitmaps just
|
+ if (!fPermutationsBitmap) { |
+ fPermutationsBitmap = SkNEW(SkBitmap); |
+ fPermutationsBitmap->allocPixels(SkImageInfo::MakeA8(kBlockSize, 1)); |
+ uint8_t* bitmapPixels = fPermutationsBitmap->getAddr8(0, 0); |
+ memcpy(bitmapPixels, fLatticeSelector, sizeof(uint8_t) * kBlockSize); |
+ } |
} |
return fPermutationsBitmap; |
} |
@@ -252,10 +262,13 @@ public: |
SkBitmap* getNoiseBitmap() |
{ |
if (!fNoiseBitmap) { |
- fNoiseBitmap = SkNEW(SkBitmap); |
- fNoiseBitmap->allocPixels(SkImageInfo::MakeN32Premul(kBlockSize, 4)); |
- uint32_t* bitmapPixels = fNoiseBitmap->getAddr32(0, 0); |
- memcpy(bitmapPixels, fNoise[0][0], sizeof(uint16_t) * kBlockSize * 4 * 2); |
+ SkAutoMutexAcquire autoMutex(fNoiseMutex); |
+ if (!fNoiseBitmap) { |
+ fNoiseBitmap = SkNEW(SkBitmap); |
+ fNoiseBitmap->allocPixels(SkImageInfo::MakeN32Premul(kBlockSize, 4)); |
+ uint32_t* bitmapPixels = fNoiseBitmap->getAddr32(0, 0); |
+ memcpy(bitmapPixels, fNoise[0][0], sizeof(uint16_t) * kBlockSize * 4 * 2); |
+ } |
} |
return fNoiseBitmap; |
} |
@@ -286,16 +299,17 @@ SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, |
, fBaseFrequencyY(baseFrequencyY) |
, fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/) |
, fSeed(seed) |
- , fStitchTiles((tileSize != NULL) && !tileSize->isEmpty()) |
- , fPaintingData(NULL) |
+ , fTileSize(NULL == tileSize ? SkISize::Make(0, 0) : *tileSize) |
+ , fStitchTiles(!fTileSize.isEmpty()) |
{ |
SkASSERT(numOctaves >= 0 && numOctaves < 256); |
- setTileSize(fStitchTiles ? *tileSize : SkISize::Make(0,0)); |
fMatrix.reset(); |
+ fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY)); |
} |
-SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) : |
- INHERITED(buffer), fPaintingData(NULL) { |
+SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) |
+ : INHERITED(buffer) |
+{ |
fType = (SkPerlinNoiseShader::Type) buffer.readInt(); |
fBaseFrequencyX = buffer.readScalar(); |
fBaseFrequencyY = buffer.readScalar(); |
@@ -304,10 +318,11 @@ SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) : |
fStitchTiles = buffer.readBool(); |
fTileSize.fWidth = buffer.readInt(); |
fTileSize.fHeight = buffer.readInt(); |
- setTileSize(fTileSize); |
fMatrix.reset(); |
+ fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY)); |
buffer.validate(perlin_noise_type_is_valid(fType) && |
- (fNumOctaves >= 0) && (fNumOctaves <= 255)); |
+ (fNumOctaves >= 0) && (fNumOctaves <= 255) && |
+ (fStitchTiles != fTileSize.isEmpty())); |
} |
SkPerlinNoiseShader::~SkPerlinNoiseShader() { |
@@ -327,39 +342,9 @@ void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const { |
buffer.writeInt(fTileSize.fHeight); |
} |
-void SkPerlinNoiseShader::initPaint(PaintingData& paintingData) |
-{ |
- paintingData.init(fSeed); |
- |
- // Set frequencies to original values |
- paintingData.fBaseFrequency.set(fBaseFrequencyX, fBaseFrequencyY); |
- // Adjust frequecies based on size if stitching is enabled |
- if (fStitchTiles) { |
- paintingData.stitch(); |
- } |
-} |
- |
-void SkPerlinNoiseShader::setTileSize(const SkISize& tileSize) { |
- fTileSize = tileSize; |
- |
- if (NULL == fPaintingData) { |
- fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize)); |
- initPaint(*fPaintingData); |
- } else { |
- // Set Size |
- fPaintingData->fTileSize = fTileSize; |
- // Set frequencies to original values |
- fPaintingData->fBaseFrequency.set(fBaseFrequencyX, fBaseFrequencyY); |
- // Adjust frequecies based on size if stitching is enabled |
- if (fStitchTiles) { |
- fPaintingData->stitch(); |
- } |
- } |
-} |
- |
SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingData, |
- const StitchData& stitchData, const SkPoint& noiseVector) |
-{ |
+ const StitchData& stitchData, |
+ const SkPoint& noiseVector) const { |
struct Noise { |
int noisePositionIntegerValue; |
SkScalar noisePositionFractionValue; |
@@ -405,9 +390,10 @@ 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) |
-{ |
+SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel, |
+ const PaintingData& paintingData, |
+ StitchData& stitchData, |
+ const SkPoint& point) const { |
if (fStitchTiles) { |
// Set up TurbulenceInitial stitch values. |
stitchData = paintingData.fStitchDataInit; |
@@ -448,7 +434,7 @@ SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint( |
return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1); |
} |
-SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchData) { |
+SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchData) const { |
SkMatrix matrix = fMatrix; |
matrix.postConcat(getLocalMatrix()); |
SkMatrix invMatrix; |