1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/effects/SkPerlinNoiseShader.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1356 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkDither.h" 1.12 +#include "SkPerlinNoiseShader.h" 1.13 +#include "SkColorFilter.h" 1.14 +#include "SkReadBuffer.h" 1.15 +#include "SkWriteBuffer.h" 1.16 +#include "SkShader.h" 1.17 +#include "SkUnPreMultiply.h" 1.18 +#include "SkString.h" 1.19 + 1.20 +#if SK_SUPPORT_GPU 1.21 +#include "GrContext.h" 1.22 +#include "GrCoordTransform.h" 1.23 +#include "gl/GrGLEffect.h" 1.24 +#include "GrTBackendEffectFactory.h" 1.25 +#include "SkGr.h" 1.26 +#endif 1.27 + 1.28 +static const int kBlockSize = 256; 1.29 +static const int kBlockMask = kBlockSize - 1; 1.30 +static const int kPerlinNoise = 4096; 1.31 +static const int kRandMaximum = SK_MaxS32; // 2**31 - 1 1.32 + 1.33 +namespace { 1.34 + 1.35 +// noiseValue is the color component's value (or color) 1.36 +// limitValue is the maximum perlin noise array index value allowed 1.37 +// newValue is the current noise dimension (either width or height) 1.38 +inline int checkNoise(int noiseValue, int limitValue, int newValue) { 1.39 + // If the noise value would bring us out of bounds of the current noise array while we are 1.40 + // stiching noise tiles together, wrap the noise around the current dimension of the noise to 1.41 + // stay within the array bounds in a continuous fashion (so that tiling lines are not visible) 1.42 + if (noiseValue >= limitValue) { 1.43 + noiseValue -= newValue; 1.44 + } 1.45 + if (noiseValue >= limitValue - 1) { 1.46 + noiseValue -= newValue - 1; 1.47 + } 1.48 + return noiseValue; 1.49 +} 1.50 + 1.51 +inline SkScalar smoothCurve(SkScalar t) { 1.52 + static const SkScalar SK_Scalar3 = 3.0f; 1.53 + 1.54 + // returns t * t * (3 - 2 * t) 1.55 + return SkScalarMul(SkScalarSquare(t), SK_Scalar3 - 2 * t); 1.56 +} 1.57 + 1.58 +bool perlin_noise_type_is_valid(SkPerlinNoiseShader::Type type) { 1.59 + return (SkPerlinNoiseShader::kFractalNoise_Type == type) || 1.60 + (SkPerlinNoiseShader::kTurbulence_Type == type); 1.61 +} 1.62 + 1.63 +} // end namespace 1.64 + 1.65 +struct SkPerlinNoiseShader::StitchData { 1.66 + StitchData() 1.67 + : fWidth(0) 1.68 + , fWrapX(0) 1.69 + , fHeight(0) 1.70 + , fWrapY(0) 1.71 + {} 1.72 + 1.73 + bool operator==(const StitchData& other) const { 1.74 + return fWidth == other.fWidth && 1.75 + fWrapX == other.fWrapX && 1.76 + fHeight == other.fHeight && 1.77 + fWrapY == other.fWrapY; 1.78 + } 1.79 + 1.80 + int fWidth; // How much to subtract to wrap for stitching. 1.81 + int fWrapX; // Minimum value to wrap. 1.82 + int fHeight; 1.83 + int fWrapY; 1.84 +}; 1.85 + 1.86 +struct SkPerlinNoiseShader::PaintingData { 1.87 + PaintingData(const SkISize& tileSize, SkScalar seed, 1.88 + SkScalar baseFrequencyX, SkScalar baseFrequencyY) 1.89 + : fTileSize(tileSize) 1.90 + , fBaseFrequency(SkPoint::Make(baseFrequencyX, baseFrequencyY)) 1.91 + { 1.92 + this->init(seed); 1.93 + if (!fTileSize.isEmpty()) { 1.94 + this->stitch(); 1.95 + } 1.96 + 1.97 +#if SK_SUPPORT_GPU && !defined(SK_USE_SIMPLEX_NOISE) 1.98 + fPermutationsBitmap.setConfig(SkImageInfo::MakeA8(kBlockSize, 1)); 1.99 + fPermutationsBitmap.setPixels(fLatticeSelector); 1.100 + 1.101 + fNoiseBitmap.setConfig(SkImageInfo::MakeN32Premul(kBlockSize, 4)); 1.102 + fNoiseBitmap.setPixels(fNoise[0][0]); 1.103 +#endif 1.104 + } 1.105 + 1.106 + int fSeed; 1.107 + uint8_t fLatticeSelector[kBlockSize]; 1.108 + uint16_t fNoise[4][kBlockSize][2]; 1.109 + SkPoint fGradient[4][kBlockSize]; 1.110 + SkISize fTileSize; 1.111 + SkVector fBaseFrequency; 1.112 + StitchData fStitchDataInit; 1.113 + 1.114 +private: 1.115 + 1.116 +#if SK_SUPPORT_GPU && !defined(SK_USE_SIMPLEX_NOISE) 1.117 + SkBitmap fPermutationsBitmap; 1.118 + SkBitmap fNoiseBitmap; 1.119 +#endif 1.120 + 1.121 + inline int random() { 1.122 + static const int gRandAmplitude = 16807; // 7**5; primitive root of m 1.123 + static const int gRandQ = 127773; // m / a 1.124 + static const int gRandR = 2836; // m % a 1.125 + 1.126 + int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ); 1.127 + if (result <= 0) 1.128 + result += kRandMaximum; 1.129 + fSeed = result; 1.130 + return result; 1.131 + } 1.132 + 1.133 + // Only called once. Could be part of the constructor. 1.134 + void init(SkScalar seed) 1.135 + { 1.136 + static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize)); 1.137 + 1.138 + // According to the SVG spec, we must truncate (not round) the seed value. 1.139 + fSeed = SkScalarTruncToInt(seed); 1.140 + // The seed value clamp to the range [1, kRandMaximum - 1]. 1.141 + if (fSeed <= 0) { 1.142 + fSeed = -(fSeed % (kRandMaximum - 1)) + 1; 1.143 + } 1.144 + if (fSeed > kRandMaximum - 1) { 1.145 + fSeed = kRandMaximum - 1; 1.146 + } 1.147 + for (int channel = 0; channel < 4; ++channel) { 1.148 + for (int i = 0; i < kBlockSize; ++i) { 1.149 + fLatticeSelector[i] = i; 1.150 + fNoise[channel][i][0] = (random() % (2 * kBlockSize)); 1.151 + fNoise[channel][i][1] = (random() % (2 * kBlockSize)); 1.152 + } 1.153 + } 1.154 + for (int i = kBlockSize - 1; i > 0; --i) { 1.155 + int k = fLatticeSelector[i]; 1.156 + int j = random() % kBlockSize; 1.157 + SkASSERT(j >= 0); 1.158 + SkASSERT(j < kBlockSize); 1.159 + fLatticeSelector[i] = fLatticeSelector[j]; 1.160 + fLatticeSelector[j] = k; 1.161 + } 1.162 + 1.163 + // Perform the permutations now 1.164 + { 1.165 + // Copy noise data 1.166 + uint16_t noise[4][kBlockSize][2]; 1.167 + for (int i = 0; i < kBlockSize; ++i) { 1.168 + for (int channel = 0; channel < 4; ++channel) { 1.169 + for (int j = 0; j < 2; ++j) { 1.170 + noise[channel][i][j] = fNoise[channel][i][j]; 1.171 + } 1.172 + } 1.173 + } 1.174 + // Do permutations on noise data 1.175 + for (int i = 0; i < kBlockSize; ++i) { 1.176 + for (int channel = 0; channel < 4; ++channel) { 1.177 + for (int j = 0; j < 2; ++j) { 1.178 + fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j]; 1.179 + } 1.180 + } 1.181 + } 1.182 + } 1.183 + 1.184 + // Half of the largest possible value for 16 bit unsigned int 1.185 + static const SkScalar gHalfMax16bits = 32767.5f; 1.186 + 1.187 + // Compute gradients from permutated noise data 1.188 + for (int channel = 0; channel < 4; ++channel) { 1.189 + for (int i = 0; i < kBlockSize; ++i) { 1.190 + fGradient[channel][i] = SkPoint::Make( 1.191 + SkScalarMul(SkIntToScalar(fNoise[channel][i][0] - kBlockSize), 1.192 + gInvBlockSizef), 1.193 + SkScalarMul(SkIntToScalar(fNoise[channel][i][1] - kBlockSize), 1.194 + gInvBlockSizef)); 1.195 + fGradient[channel][i].normalize(); 1.196 + // Put the normalized gradient back into the noise data 1.197 + fNoise[channel][i][0] = SkScalarRoundToInt(SkScalarMul( 1.198 + fGradient[channel][i].fX + SK_Scalar1, gHalfMax16bits)); 1.199 + fNoise[channel][i][1] = SkScalarRoundToInt(SkScalarMul( 1.200 + fGradient[channel][i].fY + SK_Scalar1, gHalfMax16bits)); 1.201 + } 1.202 + } 1.203 + } 1.204 + 1.205 + // Only called once. Could be part of the constructor. 1.206 + void stitch() { 1.207 + SkScalar tileWidth = SkIntToScalar(fTileSize.width()); 1.208 + SkScalar tileHeight = SkIntToScalar(fTileSize.height()); 1.209 + SkASSERT(tileWidth > 0 && tileHeight > 0); 1.210 + // When stitching tiled turbulence, the frequencies must be adjusted 1.211 + // so that the tile borders will be continuous. 1.212 + if (fBaseFrequency.fX) { 1.213 + SkScalar lowFrequencx = 1.214 + SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth; 1.215 + SkScalar highFrequencx = 1.216 + SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth; 1.217 + // BaseFrequency should be non-negative according to the standard. 1.218 + if (SkScalarDiv(fBaseFrequency.fX, lowFrequencx) < 1.219 + SkScalarDiv(highFrequencx, fBaseFrequency.fX)) { 1.220 + fBaseFrequency.fX = lowFrequencx; 1.221 + } else { 1.222 + fBaseFrequency.fX = highFrequencx; 1.223 + } 1.224 + } 1.225 + if (fBaseFrequency.fY) { 1.226 + SkScalar lowFrequency = 1.227 + SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight; 1.228 + SkScalar highFrequency = 1.229 + SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight; 1.230 + if (SkScalarDiv(fBaseFrequency.fY, lowFrequency) < 1.231 + SkScalarDiv(highFrequency, fBaseFrequency.fY)) { 1.232 + fBaseFrequency.fY = lowFrequency; 1.233 + } else { 1.234 + fBaseFrequency.fY = highFrequency; 1.235 + } 1.236 + } 1.237 + // Set up TurbulenceInitial stitch values. 1.238 + fStitchDataInit.fWidth = 1.239 + SkScalarRoundToInt(tileWidth * fBaseFrequency.fX); 1.240 + fStitchDataInit.fWrapX = kPerlinNoise + fStitchDataInit.fWidth; 1.241 + fStitchDataInit.fHeight = 1.242 + SkScalarRoundToInt(tileHeight * fBaseFrequency.fY); 1.243 + fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight; 1.244 + } 1.245 + 1.246 +public: 1.247 + 1.248 +#if SK_SUPPORT_GPU && !defined(SK_USE_SIMPLEX_NOISE) 1.249 + const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; } 1.250 + 1.251 + const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; } 1.252 +#endif 1.253 +}; 1.254 + 1.255 +SkShader* SkPerlinNoiseShader::CreateFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, 1.256 + int numOctaves, SkScalar seed, 1.257 + const SkISize* tileSize) { 1.258 + return SkNEW_ARGS(SkPerlinNoiseShader, (kFractalNoise_Type, baseFrequencyX, baseFrequencyY, 1.259 + numOctaves, seed, tileSize)); 1.260 +} 1.261 + 1.262 +SkShader* SkPerlinNoiseShader::CreateTubulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, 1.263 + int numOctaves, SkScalar seed, 1.264 + const SkISize* tileSize) { 1.265 + return SkNEW_ARGS(SkPerlinNoiseShader, (kTurbulence_Type, baseFrequencyX, baseFrequencyY, 1.266 + numOctaves, seed, tileSize)); 1.267 +} 1.268 + 1.269 +SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShader::Type type, 1.270 + SkScalar baseFrequencyX, 1.271 + SkScalar baseFrequencyY, 1.272 + int numOctaves, 1.273 + SkScalar seed, 1.274 + const SkISize* tileSize) 1.275 + : fType(type) 1.276 + , fBaseFrequencyX(baseFrequencyX) 1.277 + , fBaseFrequencyY(baseFrequencyY) 1.278 + , fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/) 1.279 + , fSeed(seed) 1.280 + , fTileSize(NULL == tileSize ? SkISize::Make(0, 0) : *tileSize) 1.281 + , fStitchTiles(!fTileSize.isEmpty()) 1.282 +{ 1.283 + SkASSERT(numOctaves >= 0 && numOctaves < 256); 1.284 + fMatrix.reset(); 1.285 + fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY)); 1.286 +} 1.287 + 1.288 +SkPerlinNoiseShader::SkPerlinNoiseShader(SkReadBuffer& buffer) 1.289 + : INHERITED(buffer) 1.290 +{ 1.291 + fType = (SkPerlinNoiseShader::Type) buffer.readInt(); 1.292 + fBaseFrequencyX = buffer.readScalar(); 1.293 + fBaseFrequencyY = buffer.readScalar(); 1.294 + fNumOctaves = buffer.readInt(); 1.295 + fSeed = buffer.readScalar(); 1.296 + fStitchTiles = buffer.readBool(); 1.297 + fTileSize.fWidth = buffer.readInt(); 1.298 + fTileSize.fHeight = buffer.readInt(); 1.299 + fMatrix.reset(); 1.300 + fPaintingData = SkNEW_ARGS(PaintingData, (fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY)); 1.301 + buffer.validate(perlin_noise_type_is_valid(fType) && 1.302 + (fNumOctaves >= 0) && (fNumOctaves <= 255) && 1.303 + (fStitchTiles != fTileSize.isEmpty())); 1.304 +} 1.305 + 1.306 +SkPerlinNoiseShader::~SkPerlinNoiseShader() { 1.307 + // Safety, should have been done in endContext() 1.308 + SkDELETE(fPaintingData); 1.309 +} 1.310 + 1.311 +void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const { 1.312 + this->INHERITED::flatten(buffer); 1.313 + buffer.writeInt((int) fType); 1.314 + buffer.writeScalar(fBaseFrequencyX); 1.315 + buffer.writeScalar(fBaseFrequencyY); 1.316 + buffer.writeInt(fNumOctaves); 1.317 + buffer.writeScalar(fSeed); 1.318 + buffer.writeBool(fStitchTiles); 1.319 + buffer.writeInt(fTileSize.fWidth); 1.320 + buffer.writeInt(fTileSize.fHeight); 1.321 +} 1.322 + 1.323 +SkScalar SkPerlinNoiseShader::noise2D(int channel, const PaintingData& paintingData, 1.324 + const StitchData& stitchData, 1.325 + const SkPoint& noiseVector) const { 1.326 + struct Noise { 1.327 + int noisePositionIntegerValue; 1.328 + SkScalar noisePositionFractionValue; 1.329 + Noise(SkScalar component) 1.330 + { 1.331 + SkScalar position = component + kPerlinNoise; 1.332 + noisePositionIntegerValue = SkScalarFloorToInt(position); 1.333 + noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue); 1.334 + } 1.335 + }; 1.336 + Noise noiseX(noiseVector.x()); 1.337 + Noise noiseY(noiseVector.y()); 1.338 + SkScalar u, v; 1.339 + // If stitching, adjust lattice points accordingly. 1.340 + if (fStitchTiles) { 1.341 + noiseX.noisePositionIntegerValue = 1.342 + checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth); 1.343 + noiseY.noisePositionIntegerValue = 1.344 + checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight); 1.345 + } 1.346 + noiseX.noisePositionIntegerValue &= kBlockMask; 1.347 + noiseY.noisePositionIntegerValue &= kBlockMask; 1.348 + int latticeIndex = 1.349 + paintingData.fLatticeSelector[noiseX.noisePositionIntegerValue] + 1.350 + noiseY.noisePositionIntegerValue; 1.351 + int nextLatticeIndex = 1.352 + paintingData.fLatticeSelector[(noiseX.noisePositionIntegerValue + 1) & kBlockMask] + 1.353 + noiseY.noisePositionIntegerValue; 1.354 + SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue); 1.355 + SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue); 1.356 + // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement 1.357 + SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue, 1.358 + noiseY.noisePositionFractionValue); // Offset (0,0) 1.359 + u = paintingData.fGradient[channel][latticeIndex & kBlockMask].dot(fractionValue); 1.360 + fractionValue.fX -= SK_Scalar1; // Offset (-1,0) 1.361 + v = paintingData.fGradient[channel][nextLatticeIndex & kBlockMask].dot(fractionValue); 1.362 + SkScalar a = SkScalarInterp(u, v, sx); 1.363 + fractionValue.fY -= SK_Scalar1; // Offset (-1,-1) 1.364 + v = paintingData.fGradient[channel][(nextLatticeIndex + 1) & kBlockMask].dot(fractionValue); 1.365 + fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1) 1.366 + u = paintingData.fGradient[channel][(latticeIndex + 1) & kBlockMask].dot(fractionValue); 1.367 + SkScalar b = SkScalarInterp(u, v, sx); 1.368 + return SkScalarInterp(a, b, sy); 1.369 +} 1.370 + 1.371 +SkScalar SkPerlinNoiseShader::calculateTurbulenceValueForPoint(int channel, 1.372 + const PaintingData& paintingData, 1.373 + StitchData& stitchData, 1.374 + const SkPoint& point) const { 1.375 + if (fStitchTiles) { 1.376 + // Set up TurbulenceInitial stitch values. 1.377 + stitchData = paintingData.fStitchDataInit; 1.378 + } 1.379 + SkScalar turbulenceFunctionResult = 0; 1.380 + SkPoint noiseVector(SkPoint::Make(SkScalarMul(point.x(), paintingData.fBaseFrequency.fX), 1.381 + SkScalarMul(point.y(), paintingData.fBaseFrequency.fY))); 1.382 + SkScalar ratio = SK_Scalar1; 1.383 + for (int octave = 0; octave < fNumOctaves; ++octave) { 1.384 + SkScalar noise = noise2D(channel, paintingData, stitchData, noiseVector); 1.385 + turbulenceFunctionResult += SkScalarDiv( 1.386 + (fType == kFractalNoise_Type) ? noise : SkScalarAbs(noise), ratio); 1.387 + noiseVector.fX *= 2; 1.388 + noiseVector.fY *= 2; 1.389 + ratio *= 2; 1.390 + if (fStitchTiles) { 1.391 + // Update stitch values 1.392 + stitchData.fWidth *= 2; 1.393 + stitchData.fWrapX = stitchData.fWidth + kPerlinNoise; 1.394 + stitchData.fHeight *= 2; 1.395 + stitchData.fWrapY = stitchData.fHeight + kPerlinNoise; 1.396 + } 1.397 + } 1.398 + 1.399 + // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 1.400 + // by fractalNoise and (turbulenceFunctionResult) by turbulence. 1.401 + if (fType == kFractalNoise_Type) { 1.402 + turbulenceFunctionResult = 1.403 + SkScalarMul(turbulenceFunctionResult, SK_ScalarHalf) + SK_ScalarHalf; 1.404 + } 1.405 + 1.406 + if (channel == 3) { // Scale alpha by paint value 1.407 + turbulenceFunctionResult = SkScalarMul(turbulenceFunctionResult, 1.408 + SkScalarDiv(SkIntToScalar(getPaintAlpha()), SkIntToScalar(255))); 1.409 + } 1.410 + 1.411 + // Clamp result 1.412 + return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1); 1.413 +} 1.414 + 1.415 +SkPMColor SkPerlinNoiseShader::shade(const SkPoint& point, StitchData& stitchData) const { 1.416 + SkMatrix matrix = fMatrix; 1.417 + matrix.postConcat(getLocalMatrix()); 1.418 + SkMatrix invMatrix; 1.419 + if (!matrix.invert(&invMatrix)) { 1.420 + invMatrix.reset(); 1.421 + } else { 1.422 + invMatrix.postConcat(invMatrix); // Square the matrix 1.423 + } 1.424 + // This (1,1) translation is due to WebKit's 1 based coordinates for the noise 1.425 + // (as opposed to 0 based, usually). The same adjustment is in the setData() function. 1.426 + matrix.postTranslate(SK_Scalar1, SK_Scalar1); 1.427 + SkPoint newPoint; 1.428 + matrix.mapPoints(&newPoint, &point, 1); 1.429 + invMatrix.mapPoints(&newPoint, &newPoint, 1); 1.430 + newPoint.fX = SkScalarRoundToScalar(newPoint.fX); 1.431 + newPoint.fY = SkScalarRoundToScalar(newPoint.fY); 1.432 + 1.433 + U8CPU rgba[4]; 1.434 + for (int channel = 3; channel >= 0; --channel) { 1.435 + rgba[channel] = SkScalarFloorToInt(255 * 1.436 + calculateTurbulenceValueForPoint(channel, *fPaintingData, stitchData, newPoint)); 1.437 + } 1.438 + return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]); 1.439 +} 1.440 + 1.441 +bool SkPerlinNoiseShader::setContext(const SkBitmap& device, const SkPaint& paint, 1.442 + const SkMatrix& matrix) { 1.443 + fMatrix = matrix; 1.444 + return INHERITED::setContext(device, paint, matrix); 1.445 +} 1.446 + 1.447 +void SkPerlinNoiseShader::shadeSpan(int x, int y, SkPMColor result[], int count) { 1.448 + SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y)); 1.449 + StitchData stitchData; 1.450 + for (int i = 0; i < count; ++i) { 1.451 + result[i] = shade(point, stitchData); 1.452 + point.fX += SK_Scalar1; 1.453 + } 1.454 +} 1.455 + 1.456 +void SkPerlinNoiseShader::shadeSpan16(int x, int y, uint16_t result[], int count) { 1.457 + SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y)); 1.458 + StitchData stitchData; 1.459 + DITHER_565_SCAN(y); 1.460 + for (int i = 0; i < count; ++i) { 1.461 + unsigned dither = DITHER_VALUE(x); 1.462 + result[i] = SkDitherRGB32To565(shade(point, stitchData), dither); 1.463 + DITHER_INC_X(x); 1.464 + point.fX += SK_Scalar1; 1.465 + } 1.466 +} 1.467 + 1.468 +///////////////////////////////////////////////////////////////////// 1.469 + 1.470 +#if SK_SUPPORT_GPU 1.471 + 1.472 +#include "GrTBackendEffectFactory.h" 1.473 + 1.474 +class GrGLNoise : public GrGLEffect { 1.475 +public: 1.476 + GrGLNoise(const GrBackendEffectFactory& factory, 1.477 + const GrDrawEffect& drawEffect); 1.478 + virtual ~GrGLNoise() {} 1.479 + 1.480 + static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 1.481 + 1.482 + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 1.483 + 1.484 +protected: 1.485 + SkPerlinNoiseShader::Type fType; 1.486 + bool fStitchTiles; 1.487 + int fNumOctaves; 1.488 + GrGLUniformManager::UniformHandle fBaseFrequencyUni; 1.489 + GrGLUniformManager::UniformHandle fAlphaUni; 1.490 + GrGLUniformManager::UniformHandle fInvMatrixUni; 1.491 + 1.492 +private: 1.493 + typedef GrGLEffect INHERITED; 1.494 +}; 1.495 + 1.496 +class GrGLPerlinNoise : public GrGLNoise { 1.497 +public: 1.498 + GrGLPerlinNoise(const GrBackendEffectFactory& factory, 1.499 + const GrDrawEffect& drawEffect) 1.500 + : GrGLNoise(factory, drawEffect) {} 1.501 + virtual ~GrGLPerlinNoise() {} 1.502 + 1.503 + virtual void emitCode(GrGLShaderBuilder*, 1.504 + const GrDrawEffect&, 1.505 + EffectKey, 1.506 + const char* outputColor, 1.507 + const char* inputColor, 1.508 + const TransformedCoordsArray&, 1.509 + const TextureSamplerArray&) SK_OVERRIDE; 1.510 + 1.511 + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 1.512 + 1.513 +private: 1.514 + GrGLUniformManager::UniformHandle fStitchDataUni; 1.515 + 1.516 + typedef GrGLNoise INHERITED; 1.517 +}; 1.518 + 1.519 +class GrGLSimplexNoise : public GrGLNoise { 1.520 + // Note : This is for reference only. GrGLPerlinNoise is used for processing. 1.521 +public: 1.522 + GrGLSimplexNoise(const GrBackendEffectFactory& factory, 1.523 + const GrDrawEffect& drawEffect) 1.524 + : GrGLNoise(factory, drawEffect) {} 1.525 + 1.526 + virtual ~GrGLSimplexNoise() {} 1.527 + 1.528 + virtual void emitCode(GrGLShaderBuilder*, 1.529 + const GrDrawEffect&, 1.530 + EffectKey, 1.531 + const char* outputColor, 1.532 + const char* inputColor, 1.533 + const TransformedCoordsArray&, 1.534 + const TextureSamplerArray&) SK_OVERRIDE; 1.535 + 1.536 + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 1.537 + 1.538 +private: 1.539 + GrGLUniformManager::UniformHandle fSeedUni; 1.540 + 1.541 + typedef GrGLNoise INHERITED; 1.542 +}; 1.543 + 1.544 +///////////////////////////////////////////////////////////////////// 1.545 + 1.546 +class GrNoiseEffect : public GrEffect { 1.547 +public: 1.548 + virtual ~GrNoiseEffect() { } 1.549 + 1.550 + SkPerlinNoiseShader::Type type() const { return fType; } 1.551 + bool stitchTiles() const { return fStitchTiles; } 1.552 + const SkVector& baseFrequency() const { return fBaseFrequency; } 1.553 + int numOctaves() const { return fNumOctaves; } 1.554 + const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); } 1.555 + uint8_t alpha() const { return fAlpha; } 1.556 + 1.557 + void getConstantColorComponents(GrColor*, uint32_t* validFlags) const SK_OVERRIDE { 1.558 + *validFlags = 0; // This is noise. Nothing is constant. 1.559 + } 1.560 + 1.561 +protected: 1.562 + virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE { 1.563 + const GrNoiseEffect& s = CastEffect<GrNoiseEffect>(sBase); 1.564 + return fType == s.fType && 1.565 + fBaseFrequency == s.fBaseFrequency && 1.566 + fNumOctaves == s.fNumOctaves && 1.567 + fStitchTiles == s.fStitchTiles && 1.568 + fCoordTransform.getMatrix() == s.fCoordTransform.getMatrix() && 1.569 + fAlpha == s.fAlpha; 1.570 + } 1.571 + 1.572 + GrNoiseEffect(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, int numOctaves, 1.573 + bool stitchTiles, const SkMatrix& matrix, uint8_t alpha) 1.574 + : fType(type) 1.575 + , fBaseFrequency(baseFrequency) 1.576 + , fNumOctaves(numOctaves) 1.577 + , fStitchTiles(stitchTiles) 1.578 + , fMatrix(matrix) 1.579 + , fAlpha(alpha) { 1.580 + // This (1,1) translation is due to WebKit's 1 based coordinates for the noise 1.581 + // (as opposed to 0 based, usually). The same adjustment is in the shadeSpan() functions. 1.582 + SkMatrix m = matrix; 1.583 + m.postTranslate(SK_Scalar1, SK_Scalar1); 1.584 + fCoordTransform.reset(kLocal_GrCoordSet, m); 1.585 + this->addCoordTransform(&fCoordTransform); 1.586 + this->setWillNotUseInputColor(); 1.587 + } 1.588 + 1.589 + SkPerlinNoiseShader::Type fType; 1.590 + GrCoordTransform fCoordTransform; 1.591 + SkVector fBaseFrequency; 1.592 + int fNumOctaves; 1.593 + bool fStitchTiles; 1.594 + SkMatrix fMatrix; 1.595 + uint8_t fAlpha; 1.596 + 1.597 +private: 1.598 + typedef GrEffect INHERITED; 1.599 +}; 1.600 + 1.601 +class GrPerlinNoiseEffect : public GrNoiseEffect { 1.602 +public: 1.603 + static GrEffectRef* Create(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, 1.604 + int numOctaves, bool stitchTiles, 1.605 + const SkPerlinNoiseShader::StitchData& stitchData, 1.606 + GrTexture* permutationsTexture, GrTexture* noiseTexture, 1.607 + const SkMatrix& matrix, uint8_t alpha) { 1.608 + AutoEffectUnref effect(SkNEW_ARGS(GrPerlinNoiseEffect, (type, baseFrequency, numOctaves, 1.609 + stitchTiles, stitchData, permutationsTexture, noiseTexture, matrix, alpha))); 1.610 + return CreateEffectRef(effect); 1.611 + } 1.612 + 1.613 + virtual ~GrPerlinNoiseEffect() { } 1.614 + 1.615 + static const char* Name() { return "PerlinNoise"; } 1.616 + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 1.617 + return GrTBackendEffectFactory<GrPerlinNoiseEffect>::getInstance(); 1.618 + } 1.619 + const SkPerlinNoiseShader::StitchData& stitchData() const { return fStitchData; } 1.620 + 1.621 + typedef GrGLPerlinNoise GLEffect; 1.622 + 1.623 +private: 1.624 + virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE { 1.625 + const GrPerlinNoiseEffect& s = CastEffect<GrPerlinNoiseEffect>(sBase); 1.626 + return INHERITED::onIsEqual(sBase) && 1.627 + fPermutationsAccess.getTexture() == s.fPermutationsAccess.getTexture() && 1.628 + fNoiseAccess.getTexture() == s.fNoiseAccess.getTexture() && 1.629 + fStitchData == s.fStitchData; 1.630 + } 1.631 + 1.632 + GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, 1.633 + int numOctaves, bool stitchTiles, 1.634 + const SkPerlinNoiseShader::StitchData& stitchData, 1.635 + GrTexture* permutationsTexture, GrTexture* noiseTexture, 1.636 + const SkMatrix& matrix, uint8_t alpha) 1.637 + : GrNoiseEffect(type, baseFrequency, numOctaves, stitchTiles, matrix, alpha) 1.638 + , fPermutationsAccess(permutationsTexture) 1.639 + , fNoiseAccess(noiseTexture) 1.640 + , fStitchData(stitchData) { 1.641 + this->addTextureAccess(&fPermutationsAccess); 1.642 + this->addTextureAccess(&fNoiseAccess); 1.643 + } 1.644 + 1.645 + GR_DECLARE_EFFECT_TEST; 1.646 + 1.647 + GrTextureAccess fPermutationsAccess; 1.648 + GrTextureAccess fNoiseAccess; 1.649 + SkPerlinNoiseShader::StitchData fStitchData; 1.650 + 1.651 + typedef GrNoiseEffect INHERITED; 1.652 +}; 1.653 + 1.654 +class GrSimplexNoiseEffect : public GrNoiseEffect { 1.655 + // Note : This is for reference only. GrPerlinNoiseEffect is used for processing. 1.656 +public: 1.657 + static GrEffectRef* Create(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, 1.658 + int numOctaves, bool stitchTiles, const SkScalar seed, 1.659 + const SkMatrix& matrix, uint8_t alpha) { 1.660 + AutoEffectUnref effect(SkNEW_ARGS(GrSimplexNoiseEffect, (type, baseFrequency, numOctaves, 1.661 + stitchTiles, seed, matrix, alpha))); 1.662 + return CreateEffectRef(effect); 1.663 + } 1.664 + 1.665 + virtual ~GrSimplexNoiseEffect() { } 1.666 + 1.667 + static const char* Name() { return "SimplexNoise"; } 1.668 + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 1.669 + return GrTBackendEffectFactory<GrSimplexNoiseEffect>::getInstance(); 1.670 + } 1.671 + const SkScalar& seed() const { return fSeed; } 1.672 + 1.673 + typedef GrGLSimplexNoise GLEffect; 1.674 + 1.675 +private: 1.676 + virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE { 1.677 + const GrSimplexNoiseEffect& s = CastEffect<GrSimplexNoiseEffect>(sBase); 1.678 + return INHERITED::onIsEqual(sBase) && fSeed == s.fSeed; 1.679 + } 1.680 + 1.681 + GrSimplexNoiseEffect(SkPerlinNoiseShader::Type type, const SkVector& baseFrequency, 1.682 + int numOctaves, bool stitchTiles, const SkScalar seed, 1.683 + const SkMatrix& matrix, uint8_t alpha) 1.684 + : GrNoiseEffect(type, baseFrequency, numOctaves, stitchTiles, matrix, alpha) 1.685 + , fSeed(seed) { 1.686 + } 1.687 + 1.688 + SkScalar fSeed; 1.689 + 1.690 + typedef GrNoiseEffect INHERITED; 1.691 +}; 1.692 + 1.693 +///////////////////////////////////////////////////////////////////// 1.694 +GR_DEFINE_EFFECT_TEST(GrPerlinNoiseEffect); 1.695 + 1.696 +GrEffectRef* GrPerlinNoiseEffect::TestCreate(SkRandom* random, 1.697 + GrContext* context, 1.698 + const GrDrawTargetCaps&, 1.699 + GrTexture**) { 1.700 + int numOctaves = random->nextRangeU(2, 10); 1.701 + bool stitchTiles = random->nextBool(); 1.702 + SkScalar seed = SkIntToScalar(random->nextU()); 1.703 + SkISize tileSize = SkISize::Make(random->nextRangeU(4, 4096), random->nextRangeU(4, 4096)); 1.704 + SkScalar baseFrequencyX = random->nextRangeScalar(0.01f, 1.705 + 0.99f); 1.706 + SkScalar baseFrequencyY = random->nextRangeScalar(0.01f, 1.707 + 0.99f); 1.708 + 1.709 + SkShader* shader = random->nextBool() ? 1.710 + SkPerlinNoiseShader::CreateFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed, 1.711 + stitchTiles ? &tileSize : NULL) : 1.712 + SkPerlinNoiseShader::CreateTubulence(baseFrequencyX, baseFrequencyY, numOctaves, seed, 1.713 + stitchTiles ? &tileSize : NULL); 1.714 + 1.715 + SkPaint paint; 1.716 + GrEffectRef* effect = shader->asNewEffect(context, paint); 1.717 + 1.718 + SkDELETE(shader); 1.719 + 1.720 + return effect; 1.721 +} 1.722 + 1.723 +///////////////////////////////////////////////////////////////////// 1.724 + 1.725 +void GrGLSimplexNoise::emitCode(GrGLShaderBuilder* builder, 1.726 + const GrDrawEffect&, 1.727 + EffectKey key, 1.728 + const char* outputColor, 1.729 + const char* inputColor, 1.730 + const TransformedCoordsArray& coords, 1.731 + const TextureSamplerArray&) { 1.732 + sk_ignore_unused_variable(inputColor); 1.733 + 1.734 + SkString vCoords = builder->ensureFSCoords2D(coords, 0); 1.735 + 1.736 + fSeedUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.737 + kFloat_GrSLType, "seed"); 1.738 + const char* seedUni = builder->getUniformCStr(fSeedUni); 1.739 + fInvMatrixUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.740 + kMat33f_GrSLType, "invMatrix"); 1.741 + const char* invMatrixUni = builder->getUniformCStr(fInvMatrixUni); 1.742 + fBaseFrequencyUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.743 + kVec2f_GrSLType, "baseFrequency"); 1.744 + const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni); 1.745 + fAlphaUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.746 + kFloat_GrSLType, "alpha"); 1.747 + const char* alphaUni = builder->getUniformCStr(fAlphaUni); 1.748 + 1.749 + // Add vec3 modulo 289 function 1.750 + static const GrGLShaderVar gVec3Args[] = { 1.751 + GrGLShaderVar("x", kVec3f_GrSLType) 1.752 + }; 1.753 + 1.754 + SkString mod289_3_funcName; 1.755 + builder->fsEmitFunction(kVec3f_GrSLType, 1.756 + "mod289", SK_ARRAY_COUNT(gVec3Args), gVec3Args, 1.757 + "const vec2 C = vec2(1.0 / 289.0, 289.0);\n" 1.758 + "return x - floor(x * C.xxx) * C.yyy;", &mod289_3_funcName); 1.759 + 1.760 + // Add vec4 modulo 289 function 1.761 + static const GrGLShaderVar gVec4Args[] = { 1.762 + GrGLShaderVar("x", kVec4f_GrSLType) 1.763 + }; 1.764 + 1.765 + SkString mod289_4_funcName; 1.766 + builder->fsEmitFunction(kVec4f_GrSLType, 1.767 + "mod289", SK_ARRAY_COUNT(gVec4Args), gVec4Args, 1.768 + "const vec2 C = vec2(1.0 / 289.0, 289.0);\n" 1.769 + "return x - floor(x * C.xxxx) * C.yyyy;", &mod289_4_funcName); 1.770 + 1.771 + // Add vec4 permute function 1.772 + SkString permuteCode; 1.773 + permuteCode.appendf("const vec2 C = vec2(34.0, 1.0);\n" 1.774 + "return %s(((x * C.xxxx) + C.yyyy) * x);", mod289_4_funcName.c_str()); 1.775 + SkString permuteFuncName; 1.776 + builder->fsEmitFunction(kVec4f_GrSLType, 1.777 + "permute", SK_ARRAY_COUNT(gVec4Args), gVec4Args, 1.778 + permuteCode.c_str(), &permuteFuncName); 1.779 + 1.780 + // Add vec4 taylorInvSqrt function 1.781 + SkString taylorInvSqrtFuncName; 1.782 + builder->fsEmitFunction(kVec4f_GrSLType, 1.783 + "taylorInvSqrt", SK_ARRAY_COUNT(gVec4Args), gVec4Args, 1.784 + "const vec2 C = vec2(-0.85373472095314, 1.79284291400159);\n" 1.785 + "return x * C.xxxx + C.yyyy;", &taylorInvSqrtFuncName); 1.786 + 1.787 + // Add vec3 noise function 1.788 + static const GrGLShaderVar gNoiseVec3Args[] = { 1.789 + GrGLShaderVar("v", kVec3f_GrSLType) 1.790 + }; 1.791 + 1.792 + SkString noiseCode; 1.793 + noiseCode.append( 1.794 + "const vec2 C = vec2(1.0/6.0, 1.0/3.0);\n" 1.795 + "const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n" 1.796 + 1.797 + // First corner 1.798 + "vec3 i = floor(v + dot(v, C.yyy));\n" 1.799 + "vec3 x0 = v - i + dot(i, C.xxx);\n" 1.800 + 1.801 + // Other corners 1.802 + "vec3 g = step(x0.yzx, x0.xyz);\n" 1.803 + "vec3 l = 1.0 - g;\n" 1.804 + "vec3 i1 = min(g.xyz, l.zxy);\n" 1.805 + "vec3 i2 = max(g.xyz, l.zxy);\n" 1.806 + 1.807 + "vec3 x1 = x0 - i1 + C.xxx;\n" 1.808 + "vec3 x2 = x0 - i2 + C.yyy;\n" // 2.0*C.x = 1/3 = C.y 1.809 + "vec3 x3 = x0 - D.yyy;\n" // -1.0+3.0*C.x = -0.5 = -D.y 1.810 + ); 1.811 + 1.812 + noiseCode.appendf( 1.813 + // Permutations 1.814 + "i = %s(i);\n" 1.815 + "vec4 p = %s(%s(%s(\n" 1.816 + " i.z + vec4(0.0, i1.z, i2.z, 1.0)) +\n" 1.817 + " i.y + vec4(0.0, i1.y, i2.y, 1.0)) +\n" 1.818 + " i.x + vec4(0.0, i1.x, i2.x, 1.0));\n", 1.819 + mod289_3_funcName.c_str(), permuteFuncName.c_str(), permuteFuncName.c_str(), 1.820 + permuteFuncName.c_str()); 1.821 + 1.822 + noiseCode.append( 1.823 + // Gradients: 7x7 points over a square, mapped onto an octahedron. 1.824 + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 1.825 + "float n_ = 0.142857142857;\n" // 1.0/7.0 1.826 + "vec3 ns = n_ * D.wyz - D.xzx;\n" 1.827 + 1.828 + "vec4 j = p - 49.0 * floor(p * ns.z * ns.z);\n" // mod(p,7*7) 1.829 + 1.830 + "vec4 x_ = floor(j * ns.z);\n" 1.831 + "vec4 y_ = floor(j - 7.0 * x_);" // mod(j,N) 1.832 + 1.833 + "vec4 x = x_ *ns.x + ns.yyyy;\n" 1.834 + "vec4 y = y_ *ns.x + ns.yyyy;\n" 1.835 + "vec4 h = 1.0 - abs(x) - abs(y);\n" 1.836 + 1.837 + "vec4 b0 = vec4(x.xy, y.xy);\n" 1.838 + "vec4 b1 = vec4(x.zw, y.zw);\n" 1.839 + ); 1.840 + 1.841 + noiseCode.append( 1.842 + "vec4 s0 = floor(b0) * 2.0 + 1.0;\n" 1.843 + "vec4 s1 = floor(b1) * 2.0 + 1.0;\n" 1.844 + "vec4 sh = -step(h, vec4(0.0));\n" 1.845 + 1.846 + "vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;\n" 1.847 + "vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;\n" 1.848 + 1.849 + "vec3 p0 = vec3(a0.xy, h.x);\n" 1.850 + "vec3 p1 = vec3(a0.zw, h.y);\n" 1.851 + "vec3 p2 = vec3(a1.xy, h.z);\n" 1.852 + "vec3 p3 = vec3(a1.zw, h.w);\n" 1.853 + ); 1.854 + 1.855 + noiseCode.appendf( 1.856 + // Normalise gradients 1.857 + "vec4 norm = %s(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));\n" 1.858 + "p0 *= norm.x;\n" 1.859 + "p1 *= norm.y;\n" 1.860 + "p2 *= norm.z;\n" 1.861 + "p3 *= norm.w;\n" 1.862 + 1.863 + // Mix final noise value 1.864 + "vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n" 1.865 + "m = m * m;\n" 1.866 + "return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));", 1.867 + taylorInvSqrtFuncName.c_str()); 1.868 + 1.869 + SkString noiseFuncName; 1.870 + builder->fsEmitFunction(kFloat_GrSLType, 1.871 + "snoise", SK_ARRAY_COUNT(gNoiseVec3Args), gNoiseVec3Args, 1.872 + noiseCode.c_str(), &noiseFuncName); 1.873 + 1.874 + const char* noiseVecIni = "noiseVecIni"; 1.875 + const char* factors = "factors"; 1.876 + const char* sum = "sum"; 1.877 + const char* xOffsets = "xOffsets"; 1.878 + const char* yOffsets = "yOffsets"; 1.879 + const char* channel = "channel"; 1.880 + 1.881 + // Fill with some prime numbers 1.882 + builder->fsCodeAppendf("\t\tconst vec4 %s = vec4(13.0, 53.0, 101.0, 151.0);\n", xOffsets); 1.883 + builder->fsCodeAppendf("\t\tconst vec4 %s = vec4(109.0, 167.0, 23.0, 67.0);\n", yOffsets); 1.884 + 1.885 + // There are rounding errors if the floor operation is not performed here 1.886 + builder->fsCodeAppendf( 1.887 + "\t\tvec3 %s = vec3(floor((%s*vec3(%s, 1.0)).xy) * vec2(0.66) * %s, 0.0);\n", 1.888 + noiseVecIni, invMatrixUni, vCoords.c_str(), baseFrequencyUni); 1.889 + 1.890 + // Perturb the texcoords with three components of noise 1.891 + builder->fsCodeAppendf("\t\t%s += 0.1 * vec3(%s(%s + vec3( 0.0, 0.0, %s))," 1.892 + "%s(%s + vec3( 43.0, 17.0, %s))," 1.893 + "%s(%s + vec3(-17.0, -43.0, %s)));\n", 1.894 + noiseVecIni, noiseFuncName.c_str(), noiseVecIni, seedUni, 1.895 + noiseFuncName.c_str(), noiseVecIni, seedUni, 1.896 + noiseFuncName.c_str(), noiseVecIni, seedUni); 1.897 + 1.898 + builder->fsCodeAppendf("\t\t%s = vec4(0.0);\n", outputColor); 1.899 + 1.900 + builder->fsCodeAppendf("\t\tvec3 %s = vec3(1.0);\n", factors); 1.901 + builder->fsCodeAppendf("\t\tfloat %s = 0.0;\n", sum); 1.902 + 1.903 + // Loop over all octaves 1.904 + builder->fsCodeAppendf("\t\tfor (int octave = 0; octave < %d; ++octave) {\n", fNumOctaves); 1.905 + 1.906 + // Loop over the 4 channels 1.907 + builder->fsCodeAppendf("\t\t\tfor (int %s = 3; %s >= 0; --%s) {\n", channel, channel, channel); 1.908 + 1.909 + builder->fsCodeAppendf( 1.910 + "\t\t\t\t%s[channel] += %s.x * %s(%s * %s.yyy - vec3(%s[%s], %s[%s], %s * %s.z));\n", 1.911 + outputColor, factors, noiseFuncName.c_str(), noiseVecIni, factors, xOffsets, channel, 1.912 + yOffsets, channel, seedUni, factors); 1.913 + 1.914 + builder->fsCodeAppend("\t\t\t}\n"); // end of the for loop on channels 1.915 + 1.916 + builder->fsCodeAppendf("\t\t\t%s += %s.x;\n", sum, factors); 1.917 + builder->fsCodeAppendf("\t\t\t%s *= vec3(0.5, 2.0, 0.75);\n", factors); 1.918 + 1.919 + builder->fsCodeAppend("\t\t}\n"); // end of the for loop on octaves 1.920 + 1.921 + if (fType == SkPerlinNoiseShader::kFractalNoise_Type) { 1.922 + // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 1.923 + // by fractalNoise and (turbulenceFunctionResult) by turbulence. 1.924 + builder->fsCodeAppendf("\t\t%s = %s * vec4(0.5 / %s) + vec4(0.5);\n", 1.925 + outputColor, outputColor, sum); 1.926 + } else { 1.927 + builder->fsCodeAppendf("\t\t%s = abs(%s / vec4(%s));\n", 1.928 + outputColor, outputColor, sum); 1.929 + } 1.930 + 1.931 + builder->fsCodeAppendf("\t\t%s.a *= %s;\n", outputColor, alphaUni); 1.932 + 1.933 + // Clamp values 1.934 + builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); 1.935 + 1.936 + // Pre-multiply the result 1.937 + builder->fsCodeAppendf("\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n", 1.938 + outputColor, outputColor, outputColor, outputColor); 1.939 +} 1.940 + 1.941 +void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder, 1.942 + const GrDrawEffect&, 1.943 + EffectKey key, 1.944 + const char* outputColor, 1.945 + const char* inputColor, 1.946 + const TransformedCoordsArray& coords, 1.947 + const TextureSamplerArray& samplers) { 1.948 + sk_ignore_unused_variable(inputColor); 1.949 + 1.950 + SkString vCoords = builder->ensureFSCoords2D(coords, 0); 1.951 + 1.952 + fInvMatrixUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.953 + kMat33f_GrSLType, "invMatrix"); 1.954 + const char* invMatrixUni = builder->getUniformCStr(fInvMatrixUni); 1.955 + fBaseFrequencyUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.956 + kVec2f_GrSLType, "baseFrequency"); 1.957 + const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni); 1.958 + fAlphaUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.959 + kFloat_GrSLType, "alpha"); 1.960 + const char* alphaUni = builder->getUniformCStr(fAlphaUni); 1.961 + 1.962 + const char* stitchDataUni = NULL; 1.963 + if (fStitchTiles) { 1.964 + fStitchDataUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.965 + kVec2f_GrSLType, "stitchData"); 1.966 + stitchDataUni = builder->getUniformCStr(fStitchDataUni); 1.967 + } 1.968 + 1.969 + // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8 1.970 + const char* chanCoordR = "0.125"; 1.971 + const char* chanCoordG = "0.375"; 1.972 + const char* chanCoordB = "0.625"; 1.973 + const char* chanCoordA = "0.875"; 1.974 + const char* chanCoord = "chanCoord"; 1.975 + const char* stitchData = "stitchData"; 1.976 + const char* ratio = "ratio"; 1.977 + const char* noiseXY = "noiseXY"; 1.978 + const char* noiseVec = "noiseVec"; 1.979 + const char* noiseSmooth = "noiseSmooth"; 1.980 + const char* fractVal = "fractVal"; 1.981 + const char* uv = "uv"; 1.982 + const char* ab = "ab"; 1.983 + const char* latticeIdx = "latticeIdx"; 1.984 + const char* lattice = "lattice"; 1.985 + const char* inc8bit = "0.00390625"; // 1.0 / 256.0 1.986 + // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a 1.987 + // [-1,1] vector and perform a dot product between that vector and the provided vector. 1.988 + const char* dotLattice = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);"; 1.989 + 1.990 + // Add noise function 1.991 + static const GrGLShaderVar gPerlinNoiseArgs[] = { 1.992 + GrGLShaderVar(chanCoord, kFloat_GrSLType), 1.993 + GrGLShaderVar(noiseVec, kVec2f_GrSLType) 1.994 + }; 1.995 + 1.996 + static const GrGLShaderVar gPerlinNoiseStitchArgs[] = { 1.997 + GrGLShaderVar(chanCoord, kFloat_GrSLType), 1.998 + GrGLShaderVar(noiseVec, kVec2f_GrSLType), 1.999 + GrGLShaderVar(stitchData, kVec2f_GrSLType) 1.1000 + }; 1.1001 + 1.1002 + SkString noiseCode; 1.1003 + 1.1004 + noiseCode.appendf("\tvec4 %s = vec4(floor(%s), fract(%s));", noiseXY, noiseVec, noiseVec); 1.1005 + 1.1006 + // smooth curve : t * t * (3 - 2 * t) 1.1007 + noiseCode.appendf("\n\tvec2 %s = %s.zw * %s.zw * (vec2(3.0) - vec2(2.0) * %s.zw);", 1.1008 + noiseSmooth, noiseXY, noiseXY, noiseXY); 1.1009 + 1.1010 + // Adjust frequencies if we're stitching tiles 1.1011 + if (fStitchTiles) { 1.1012 + noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }", 1.1013 + noiseXY, stitchData, noiseXY, stitchData); 1.1014 + noiseCode.appendf("\n\tif(%s.x >= (%s.x - 1.0)) { %s.x -= (%s.x - 1.0); }", 1.1015 + noiseXY, stitchData, noiseXY, stitchData); 1.1016 + noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }", 1.1017 + noiseXY, stitchData, noiseXY, stitchData); 1.1018 + noiseCode.appendf("\n\tif(%s.y >= (%s.y - 1.0)) { %s.y -= (%s.y - 1.0); }", 1.1019 + noiseXY, stitchData, noiseXY, stitchData); 1.1020 + } 1.1021 + 1.1022 + // Get texture coordinates and normalize 1.1023 + noiseCode.appendf("\n\t%s.xy = fract(floor(mod(%s.xy, 256.0)) / vec2(256.0));\n", 1.1024 + noiseXY, noiseXY); 1.1025 + 1.1026 + // Get permutation for x 1.1027 + { 1.1028 + SkString xCoords(""); 1.1029 + xCoords.appendf("vec2(%s.x, 0.5)", noiseXY); 1.1030 + 1.1031 + noiseCode.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx); 1.1032 + builder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType); 1.1033 + noiseCode.append(".r;"); 1.1034 + } 1.1035 + 1.1036 + // Get permutation for x + 1 1.1037 + { 1.1038 + SkString xCoords(""); 1.1039 + xCoords.appendf("vec2(fract(%s.x + %s), 0.5)", noiseXY, inc8bit); 1.1040 + 1.1041 + noiseCode.appendf("\n\t%s.y = ", latticeIdx); 1.1042 + builder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType); 1.1043 + noiseCode.append(".r;"); 1.1044 + } 1.1045 + 1.1046 +#if defined(SK_BUILD_FOR_ANDROID) 1.1047 + // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3). 1.1048 + // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit 1.1049 + // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725 1.1050 + // (or 0.484368 here). The following rounding operation prevents these precision issues from 1.1051 + // affecting the result of the noise by making sure that we only have multiples of 1/255. 1.1052 + // (Note that 1/255 is about 0.003921569, which is the value used here). 1.1053 + noiseCode.appendf("\n\t%s = floor(%s * vec2(255.0) + vec2(0.5)) * vec2(0.003921569);", 1.1054 + latticeIdx, latticeIdx); 1.1055 +#endif 1.1056 + 1.1057 + // Get (x,y) coordinates with the permutated x 1.1058 + noiseCode.appendf("\n\t%s = fract(%s + %s.yy);", latticeIdx, latticeIdx, noiseXY); 1.1059 + 1.1060 + noiseCode.appendf("\n\tvec2 %s = %s.zw;", fractVal, noiseXY); 1.1061 + 1.1062 + noiseCode.appendf("\n\n\tvec2 %s;", uv); 1.1063 + // Compute u, at offset (0,0) 1.1064 + { 1.1065 + SkString latticeCoords(""); 1.1066 + latticeCoords.appendf("vec2(%s.x, %s)", latticeIdx, chanCoord); 1.1067 + noiseCode.appendf("\n\tvec4 %s = ", lattice); 1.1068 + builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(), 1.1069 + kVec2f_GrSLType); 1.1070 + noiseCode.appendf(".bgra;\n\t%s.x = ", uv); 1.1071 + noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); 1.1072 + } 1.1073 + 1.1074 + noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal); 1.1075 + // Compute v, at offset (-1,0) 1.1076 + { 1.1077 + SkString latticeCoords(""); 1.1078 + latticeCoords.appendf("vec2(%s.y, %s)", latticeIdx, chanCoord); 1.1079 + noiseCode.append("\n\tlattice = "); 1.1080 + builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(), 1.1081 + kVec2f_GrSLType); 1.1082 + noiseCode.appendf(".bgra;\n\t%s.y = ", uv); 1.1083 + noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); 1.1084 + } 1.1085 + 1.1086 + // Compute 'a' as a linear interpolation of 'u' and 'v' 1.1087 + noiseCode.appendf("\n\tvec2 %s;", ab); 1.1088 + noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); 1.1089 + 1.1090 + noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal); 1.1091 + // Compute v, at offset (-1,-1) 1.1092 + { 1.1093 + SkString latticeCoords(""); 1.1094 + latticeCoords.appendf("vec2(fract(%s.y + %s), %s)", latticeIdx, inc8bit, chanCoord); 1.1095 + noiseCode.append("\n\tlattice = "); 1.1096 + builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(), 1.1097 + kVec2f_GrSLType); 1.1098 + noiseCode.appendf(".bgra;\n\t%s.y = ", uv); 1.1099 + noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); 1.1100 + } 1.1101 + 1.1102 + noiseCode.appendf("\n\t%s.x += 1.0;", fractVal); 1.1103 + // Compute u, at offset (0,-1) 1.1104 + { 1.1105 + SkString latticeCoords(""); 1.1106 + latticeCoords.appendf("vec2(fract(%s.x + %s), %s)", latticeIdx, inc8bit, chanCoord); 1.1107 + noiseCode.append("\n\tlattice = "); 1.1108 + builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(), 1.1109 + kVec2f_GrSLType); 1.1110 + noiseCode.appendf(".bgra;\n\t%s.x = ", uv); 1.1111 + noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); 1.1112 + } 1.1113 + 1.1114 + // Compute 'b' as a linear interpolation of 'u' and 'v' 1.1115 + noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); 1.1116 + // Compute the noise as a linear interpolation of 'a' and 'b' 1.1117 + noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth); 1.1118 + 1.1119 + SkString noiseFuncName; 1.1120 + if (fStitchTiles) { 1.1121 + builder->fsEmitFunction(kFloat_GrSLType, 1.1122 + "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs), 1.1123 + gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName); 1.1124 + } else { 1.1125 + builder->fsEmitFunction(kFloat_GrSLType, 1.1126 + "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs), 1.1127 + gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName); 1.1128 + } 1.1129 + 1.1130 + // There are rounding errors if the floor operation is not performed here 1.1131 + builder->fsCodeAppendf("\n\t\tvec2 %s = floor((%s * vec3(%s, 1.0)).xy) * %s;", 1.1132 + noiseVec, invMatrixUni, vCoords.c_str(), baseFrequencyUni); 1.1133 + 1.1134 + // Clear the color accumulator 1.1135 + builder->fsCodeAppendf("\n\t\t%s = vec4(0.0);", outputColor); 1.1136 + 1.1137 + if (fStitchTiles) { 1.1138 + // Set up TurbulenceInitial stitch values. 1.1139 + builder->fsCodeAppendf("\n\t\tvec2 %s = %s;", stitchData, stitchDataUni); 1.1140 + } 1.1141 + 1.1142 + builder->fsCodeAppendf("\n\t\tfloat %s = 1.0;", ratio); 1.1143 + 1.1144 + // Loop over all octaves 1.1145 + builder->fsCodeAppendf("\n\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves); 1.1146 + 1.1147 + builder->fsCodeAppendf("\n\t\t\t%s += ", outputColor); 1.1148 + if (fType != SkPerlinNoiseShader::kFractalNoise_Type) { 1.1149 + builder->fsCodeAppend("abs("); 1.1150 + } 1.1151 + if (fStitchTiles) { 1.1152 + builder->fsCodeAppendf( 1.1153 + "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s)," 1.1154 + "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))", 1.1155 + noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData, 1.1156 + noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData, 1.1157 + noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData, 1.1158 + noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData); 1.1159 + } else { 1.1160 + builder->fsCodeAppendf( 1.1161 + "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s)," 1.1162 + "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))", 1.1163 + noiseFuncName.c_str(), chanCoordR, noiseVec, 1.1164 + noiseFuncName.c_str(), chanCoordG, noiseVec, 1.1165 + noiseFuncName.c_str(), chanCoordB, noiseVec, 1.1166 + noiseFuncName.c_str(), chanCoordA, noiseVec); 1.1167 + } 1.1168 + if (fType != SkPerlinNoiseShader::kFractalNoise_Type) { 1.1169 + builder->fsCodeAppendf(")"); // end of "abs(" 1.1170 + } 1.1171 + builder->fsCodeAppendf(" * %s;", ratio); 1.1172 + 1.1173 + builder->fsCodeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec); 1.1174 + builder->fsCodeAppendf("\n\t\t\t%s *= 0.5;", ratio); 1.1175 + 1.1176 + if (fStitchTiles) { 1.1177 + builder->fsCodeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData); 1.1178 + } 1.1179 + builder->fsCodeAppend("\n\t\t}"); // end of the for loop on octaves 1.1180 + 1.1181 + if (fType == SkPerlinNoiseShader::kFractalNoise_Type) { 1.1182 + // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 1.1183 + // by fractalNoise and (turbulenceFunctionResult) by turbulence. 1.1184 + builder->fsCodeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);", outputColor, outputColor); 1.1185 + } 1.1186 + 1.1187 + builder->fsCodeAppendf("\n\t\t%s.a *= %s;", outputColor, alphaUni); 1.1188 + 1.1189 + // Clamp values 1.1190 + builder->fsCodeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", outputColor, outputColor); 1.1191 + 1.1192 + // Pre-multiply the result 1.1193 + builder->fsCodeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n", 1.1194 + outputColor, outputColor, outputColor, outputColor); 1.1195 +} 1.1196 + 1.1197 +GrGLNoise::GrGLNoise(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect) 1.1198 + : INHERITED (factory) 1.1199 + , fType(drawEffect.castEffect<GrPerlinNoiseEffect>().type()) 1.1200 + , fStitchTiles(drawEffect.castEffect<GrPerlinNoiseEffect>().stitchTiles()) 1.1201 + , fNumOctaves(drawEffect.castEffect<GrPerlinNoiseEffect>().numOctaves()) { 1.1202 +} 1.1203 + 1.1204 +GrGLEffect::EffectKey GrGLNoise::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 1.1205 + const GrPerlinNoiseEffect& turbulence = drawEffect.castEffect<GrPerlinNoiseEffect>(); 1.1206 + 1.1207 + EffectKey key = turbulence.numOctaves(); 1.1208 + 1.1209 + key = key << 3; // Make room for next 3 bits 1.1210 + 1.1211 + switch (turbulence.type()) { 1.1212 + case SkPerlinNoiseShader::kFractalNoise_Type: 1.1213 + key |= 0x1; 1.1214 + break; 1.1215 + case SkPerlinNoiseShader::kTurbulence_Type: 1.1216 + key |= 0x2; 1.1217 + break; 1.1218 + default: 1.1219 + // leave key at 0 1.1220 + break; 1.1221 + } 1.1222 + 1.1223 + if (turbulence.stitchTiles()) { 1.1224 + key |= 0x4; // Flip the 3rd bit if tile stitching is on 1.1225 + } 1.1226 + 1.1227 + return key; 1.1228 +} 1.1229 + 1.1230 +void GrGLNoise::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { 1.1231 + const GrPerlinNoiseEffect& turbulence = drawEffect.castEffect<GrPerlinNoiseEffect>(); 1.1232 + 1.1233 + const SkVector& baseFrequency = turbulence.baseFrequency(); 1.1234 + uman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY); 1.1235 + uman.set1f(fAlphaUni, SkScalarDiv(SkIntToScalar(turbulence.alpha()), SkIntToScalar(255))); 1.1236 + 1.1237 + SkMatrix m = turbulence.matrix(); 1.1238 + m.postTranslate(-SK_Scalar1, -SK_Scalar1); 1.1239 + SkMatrix invM; 1.1240 + if (!m.invert(&invM)) { 1.1241 + invM.reset(); 1.1242 + } else { 1.1243 + invM.postConcat(invM); // Square the matrix 1.1244 + } 1.1245 + uman.setSkMatrix(fInvMatrixUni, invM); 1.1246 +} 1.1247 + 1.1248 +void GrGLPerlinNoise::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { 1.1249 + INHERITED::setData(uman, drawEffect); 1.1250 + 1.1251 + const GrPerlinNoiseEffect& turbulence = drawEffect.castEffect<GrPerlinNoiseEffect>(); 1.1252 + if (turbulence.stitchTiles()) { 1.1253 + const SkPerlinNoiseShader::StitchData& stitchData = turbulence.stitchData(); 1.1254 + uman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth), 1.1255 + SkIntToScalar(stitchData.fHeight)); 1.1256 + } 1.1257 +} 1.1258 + 1.1259 +void GrGLSimplexNoise::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { 1.1260 + INHERITED::setData(uman, drawEffect); 1.1261 + 1.1262 + const GrSimplexNoiseEffect& turbulence = drawEffect.castEffect<GrSimplexNoiseEffect>(); 1.1263 + uman.set1f(fSeedUni, turbulence.seed()); 1.1264 +} 1.1265 + 1.1266 +///////////////////////////////////////////////////////////////////// 1.1267 + 1.1268 +GrEffectRef* SkPerlinNoiseShader::asNewEffect(GrContext* context, const SkPaint& paint) const { 1.1269 + SkASSERT(NULL != context); 1.1270 + 1.1271 + if (0 == fNumOctaves) { 1.1272 + SkColor clearColor = 0; 1.1273 + if (kFractalNoise_Type == fType) { 1.1274 + clearColor = SkColorSetARGB(paint.getAlpha() / 2, 127, 127, 127); 1.1275 + } 1.1276 + SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter( 1.1277 + clearColor, SkXfermode::kSrc_Mode)); 1.1278 + return cf->asNewEffect(context); 1.1279 + } 1.1280 + 1.1281 + // Either we don't stitch tiles, either we have a valid tile size 1.1282 + SkASSERT(!fStitchTiles || !fTileSize.isEmpty()); 1.1283 + 1.1284 +#ifdef SK_USE_SIMPLEX_NOISE 1.1285 + // Simplex noise is currently disabled but can be enabled by defining SK_USE_SIMPLEX_NOISE 1.1286 + sk_ignore_unused_variable(context); 1.1287 + GrEffectRef* effect = 1.1288 + GrSimplexNoiseEffect::Create(fType, fPaintingData->fBaseFrequency, 1.1289 + fNumOctaves, fStitchTiles, fSeed, 1.1290 + this->getLocalMatrix(), paint.getAlpha()); 1.1291 +#else 1.1292 + GrTexture* permutationsTexture = GrLockAndRefCachedBitmapTexture( 1.1293 + context, fPaintingData->getPermutationsBitmap(), NULL); 1.1294 + GrTexture* noiseTexture = GrLockAndRefCachedBitmapTexture( 1.1295 + context, fPaintingData->getNoiseBitmap(), NULL); 1.1296 + 1.1297 + GrEffectRef* effect = (NULL != permutationsTexture) && (NULL != noiseTexture) ? 1.1298 + GrPerlinNoiseEffect::Create(fType, fPaintingData->fBaseFrequency, 1.1299 + fNumOctaves, fStitchTiles, 1.1300 + fPaintingData->fStitchDataInit, 1.1301 + permutationsTexture, noiseTexture, 1.1302 + this->getLocalMatrix(), paint.getAlpha()) : 1.1303 + NULL; 1.1304 + 1.1305 + // Unlock immediately, this is not great, but we don't have a way of 1.1306 + // knowing when else to unlock it currently. TODO: Remove this when 1.1307 + // unref becomes the unlock replacement for all types of textures. 1.1308 + if (NULL != permutationsTexture) { 1.1309 + GrUnlockAndUnrefCachedBitmapTexture(permutationsTexture); 1.1310 + } 1.1311 + if (NULL != noiseTexture) { 1.1312 + GrUnlockAndUnrefCachedBitmapTexture(noiseTexture); 1.1313 + } 1.1314 +#endif 1.1315 + 1.1316 + return effect; 1.1317 +} 1.1318 + 1.1319 +#else 1.1320 + 1.1321 +GrEffectRef* SkPerlinNoiseShader::asNewEffect(GrContext*, const SkPaint&) const { 1.1322 + SkDEBUGFAIL("Should not call in GPU-less build"); 1.1323 + return NULL; 1.1324 +} 1.1325 + 1.1326 +#endif 1.1327 + 1.1328 +#ifndef SK_IGNORE_TO_STRING 1.1329 +void SkPerlinNoiseShader::toString(SkString* str) const { 1.1330 + str->append("SkPerlinNoiseShader: ("); 1.1331 + 1.1332 + str->append("type: "); 1.1333 + switch (fType) { 1.1334 + case kFractalNoise_Type: 1.1335 + str->append("\"fractal noise\""); 1.1336 + break; 1.1337 + case kTurbulence_Type: 1.1338 + str->append("\"turbulence\""); 1.1339 + break; 1.1340 + default: 1.1341 + str->append("\"unknown\""); 1.1342 + break; 1.1343 + } 1.1344 + str->append(" base frequency: ("); 1.1345 + str->appendScalar(fBaseFrequencyX); 1.1346 + str->append(", "); 1.1347 + str->appendScalar(fBaseFrequencyY); 1.1348 + str->append(") number of octaves: "); 1.1349 + str->appendS32(fNumOctaves); 1.1350 + str->append(" seed: "); 1.1351 + str->appendScalar(fSeed); 1.1352 + str->append(" stitch tiles: "); 1.1353 + str->append(fStitchTiles ? "true " : "false "); 1.1354 + 1.1355 + this->INHERITED::toString(str); 1.1356 + 1.1357 + str->append(")"); 1.1358 +} 1.1359 +#endif