• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/effects/SkPerlinNoiseShader.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkShader.h"
13 #include "include/core/SkString.h"
14 #include "include/core/SkUnPreMultiply.h"
15 #include "include/private/base/SkTPin.h"
16 #include "src/base/SkArenaAlloc.h"
17 #include "src/core/SkMatrixProvider.h"
18 #include "src/core/SkReadBuffer.h"
19 #include "src/core/SkVM.h"
20 #include "src/core/SkWriteBuffer.h"
21 
22 #if defined(SK_GANESH)
23 #include "include/gpu/GrRecordingContext.h"
24 #include "src/gpu/KeyBuilder.h"
25 #include "src/gpu/ganesh/GrFPArgs.h"
26 #include "src/gpu/ganesh/GrFragmentProcessor.h"
27 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
28 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
29 #include "src/gpu/ganesh/SkGr.h"
30 #include "src/gpu/ganesh/effects/GrMatrixEffect.h"
31 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
32 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
33 #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
34 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
35 #endif
36 
37 static const int kBlockSize = 256;
38 static const int kBlockMask = kBlockSize - 1;
39 static const int kPerlinNoise = 4096;
40 static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
41 
42 class SkPerlinNoiseShaderImpl : public SkShaderBase {
43 public:
44     struct StitchData {
StitchDataSkPerlinNoiseShaderImpl::StitchData45         StitchData()
46           : fWidth(0)
47           , fWrapX(0)
48           , fHeight(0)
49           , fWrapY(0)
50         {}
51 
StitchDataSkPerlinNoiseShaderImpl::StitchData52         StitchData(SkScalar w, SkScalar h)
53           : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
54           , fWrapX(kPerlinNoise + fWidth)
55           , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
56           , fWrapY(kPerlinNoise + fHeight) {}
57 
operator ==SkPerlinNoiseShaderImpl::StitchData58         bool operator==(const StitchData& other) const {
59             return fWidth == other.fWidth &&
60                    fWrapX == other.fWrapX &&
61                    fHeight == other.fHeight &&
62                    fWrapY == other.fWrapY;
63         }
64 
65         int fWidth; // How much to subtract to wrap for stitching.
66         int fWrapX; // Minimum value to wrap.
67         int fHeight;
68         int fWrapY;
69     };
70 
71     struct PaintingData {
PaintingDataSkPerlinNoiseShaderImpl::PaintingData72         PaintingData(const SkISize& tileSize, SkScalar seed,
73                      SkScalar baseFrequencyX, SkScalar baseFrequencyY,
74                      const SkMatrix& matrix)
75         {
76             SkVector tileVec;
77             matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
78                              &tileVec);
79 
80             SkSize scale;
81             if (!matrix.decomposeScale(&scale, nullptr)) {
82                 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
83             }
84             fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
85                                baseFrequencyY * SkScalarInvert(scale.height()));
86             fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
87             this->init(seed);
88             if (!fTileSize.isEmpty()) {
89                 this->stitch();
90             }
91 
92     #if defined(SK_GANESH)
93             SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
94             fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
95             fPermutationsBitmap.setImmutable();
96 
97             info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
98             fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
99             fNoiseBitmap.setImmutable();
100     #endif
101         }
102 
103     #if defined(SK_GANESH)
PaintingDataSkPerlinNoiseShaderImpl::PaintingData104         PaintingData(const PaintingData& that)
105                 : fSeed(that.fSeed)
106                 , fTileSize(that.fTileSize)
107                 , fBaseFrequency(that.fBaseFrequency)
108                 , fStitchDataInit(that.fStitchDataInit)
109                 , fPermutationsBitmap(that.fPermutationsBitmap)
110                 , fNoiseBitmap(that.fNoiseBitmap) {
111             memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
112             memcpy(fNoise, that.fNoise, sizeof(fNoise));
113             memcpy(fGradient, that.fGradient, sizeof(fGradient));
114         }
115     #endif
116 
117         int         fSeed;
118         uint8_t     fLatticeSelector[kBlockSize];
119         uint16_t    fNoise[4][kBlockSize][2];
120         SkPoint     fGradient[4][kBlockSize];
121         SkISize     fTileSize;
122         SkVector    fBaseFrequency;
123         StitchData  fStitchDataInit;
124 
125     private:
126 
127     #if defined(SK_GANESH)
128         SkBitmap fPermutationsBitmap;
129         SkBitmap fNoiseBitmap;
130     #endif
131 
randomSkPerlinNoiseShaderImpl::PaintingData132         inline int random()  {
133             // See https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
134             // m = kRandMaximum, 2**31 - 1 (2147483647)
135             static constexpr int kRandAmplitude = 16807; // 7**5; primitive root of m
136             static constexpr int kRandQ = 127773; // m / a
137             static constexpr int kRandR = 2836; // m % a
138 
139             int result = kRandAmplitude * (fSeed % kRandQ) - kRandR * (fSeed / kRandQ);
140             if (result <= 0) {
141                 result += kRandMaximum;
142             }
143             fSeed = result;
144             return result;
145         }
146 
147         // Only called once. Could be part of the constructor.
initSkPerlinNoiseShaderImpl::PaintingData148         void init(SkScalar seed)
149         {
150             // According to the SVG spec, we must truncate (not round) the seed value.
151             fSeed = SkScalarTruncToInt(seed);
152             // The seed value clamp to the range [1, kRandMaximum - 1].
153             if (fSeed <= 0) {
154                 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
155             }
156             if (fSeed > kRandMaximum - 1) {
157                 fSeed = kRandMaximum - 1;
158             }
159             for (int channel = 0; channel < 4; ++channel) {
160                 for (int i = 0; i < kBlockSize; ++i) {
161                     fLatticeSelector[i] = i;
162                     fNoise[channel][i][0] = (random() % (2 * kBlockSize));
163                     fNoise[channel][i][1] = (random() % (2 * kBlockSize));
164                 }
165             }
166             for (int i = kBlockSize - 1; i > 0; --i) {
167                 int k = fLatticeSelector[i];
168                 int j = random() % kBlockSize;
169                 SkASSERT(j >= 0);
170                 SkASSERT(j < kBlockSize);
171                 fLatticeSelector[i] = fLatticeSelector[j];
172                 fLatticeSelector[j] = k;
173             }
174 
175             // Perform the permutations now
176             {
177                 // Copy noise data
178                 uint16_t noise[4][kBlockSize][2];
179                 for (int i = 0; i < kBlockSize; ++i) {
180                     for (int channel = 0; channel < 4; ++channel) {
181                         for (int j = 0; j < 2; ++j) {
182                             noise[channel][i][j] = fNoise[channel][i][j];
183                         }
184                     }
185                 }
186                 // Do permutations on noise data
187                 for (int i = 0; i < kBlockSize; ++i) {
188                     for (int channel = 0; channel < 4; ++channel) {
189                         for (int j = 0; j < 2; ++j) {
190                             fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
191                         }
192                     }
193                 }
194             }
195 
196             // Half of the largest possible value for 16 bit unsigned int
197             static constexpr SkScalar kHalfMax16bits = 32767.5f;
198 
199             // Compute gradients from permutated noise data
200             static constexpr SkScalar kInvBlockSizef = 1.0 / SkIntToScalar(kBlockSize);
201             for (int channel = 0; channel < 4; ++channel) {
202                 for (int i = 0; i < kBlockSize; ++i) {
203                     fGradient[channel][i] = SkPoint::Make(
204                         (fNoise[channel][i][0] - kBlockSize) * kInvBlockSizef,
205                         (fNoise[channel][i][1] - kBlockSize) * kInvBlockSizef);
206                     fGradient[channel][i].normalize();
207                     // Put the normalized gradient back into the noise data
208                     fNoise[channel][i][0] =
209                             SkScalarRoundToInt((fGradient[channel][i].fX + 1) * kHalfMax16bits);
210                     fNoise[channel][i][1] =
211                             SkScalarRoundToInt((fGradient[channel][i].fY + 1) * kHalfMax16bits);
212                 }
213             }
214         }
215 
216         // Only called once. Could be part of the constructor.
stitchSkPerlinNoiseShaderImpl::PaintingData217         void stitch() {
218             SkScalar tileWidth  = SkIntToScalar(fTileSize.width());
219             SkScalar tileHeight = SkIntToScalar(fTileSize.height());
220             SkASSERT(tileWidth > 0 && tileHeight > 0);
221             // When stitching tiled turbulence, the frequencies must be adjusted
222             // so that the tile borders will be continuous.
223             if (fBaseFrequency.fX) {
224                 SkScalar lowFrequencx =
225                     SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
226                 SkScalar highFrequencx =
227                     SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
228                 // BaseFrequency should be non-negative according to the standard.
229                 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
230                 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
231                     fBaseFrequency.fX = lowFrequencx;
232                 } else {
233                     fBaseFrequency.fX = highFrequencx;
234                 }
235             }
236             if (fBaseFrequency.fY) {
237                 SkScalar lowFrequency =
238                     SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
239                 SkScalar highFrequency =
240                     SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
241                 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
242                 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
243                     fBaseFrequency.fY = lowFrequency;
244                 } else {
245                     fBaseFrequency.fY = highFrequency;
246                 }
247             }
248             // Set up TurbulenceInitial stitch values.
249             fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
250                                          tileHeight * fBaseFrequency.fY);
251         }
252 
253     public:
254 
255 #if defined(SK_GANESH)
getPermutationsBitmapSkPerlinNoiseShaderImpl::PaintingData256         const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
257 
getNoiseBitmapSkPerlinNoiseShaderImpl::PaintingData258         const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
259 #endif
260     };
261 
262     /**
263      *  About the noise types : the difference between the first 2 is just minor tweaks to the
264      *  algorithm, they're not 2 entirely different noises. The output looks different, but once the
265      *  noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
266      *  doing :
267      *  kFractalNoise_Type : noise * 0.5 + 0.5
268      *  kTurbulence_Type   : abs(noise)
269      *  Very little differences between the 2 types, although you can tell the difference visually.
270      */
271     enum Type {
272         kFractalNoise_Type,
273         kTurbulence_Type,
274         kLast_Type = kTurbulence_Type
275     };
276 
277     static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
278 
279     SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
280                       SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
281                       const SkISize* tileSize);
282 
283     class PerlinNoiseShaderContext : public Context {
284     public:
285         PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
286 
287         void shadeSpan(int x, int y, SkPMColor[], int count) override;
288 
289     private:
290         SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
291         SkScalar calculateTurbulenceValueForPoint(
292                                                   int channel,
293                                                   StitchData& stitchData, const SkPoint& point) const;
294         SkScalar noise2D(int channel,
295                          const StitchData& stitchData, const SkPoint& noiseVector) const;
296 
297         SkMatrix     fMatrix;
298         PaintingData fPaintingData;
299 
300         using INHERITED = Context;
301     };
302 
303 #if defined(SK_GANESH)
304     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&,
305                                                              const MatrixRec&) const override;
306 #endif
307 
program(skvm::Builder *,skvm::Coord,skvm::Coord,skvm::Color,const MatrixRec &,const SkColorInfo &,skvm::Uniforms *,SkArenaAlloc *) const308     skvm::Color program(skvm::Builder*,
309                         skvm::Coord,
310                         skvm::Coord,
311                         skvm::Color,
312                         const MatrixRec&,
313                         const SkColorInfo&,
314                         skvm::Uniforms*,
315                         SkArenaAlloc*) const override {
316         // TODO?
317         return {};
318     }
319 
320 protected:
321     void flatten(SkWriteBuffer&) const override;
322 #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
323     Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
324 #endif
325 
326 private:
327     SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
328 
329     const SkPerlinNoiseShaderImpl::Type fType;
330     const SkScalar                  fBaseFrequencyX;
331     const SkScalar                  fBaseFrequencyY;
332     const int                       fNumOctaves;
333     const SkScalar                  fSeed;
334     const SkISize                   fTileSize;
335     const bool                      fStitchTiles;
336 
337     friend class ::SkPerlinNoiseShader;
338 
339     using INHERITED = SkShaderBase;
340 };
341 
342 namespace {
343 
344 // noiseValue is the color component's value (or color)
345 // limitValue is the maximum perlin noise array index value allowed
346 // newValue is the current noise dimension (either width or height)
checkNoise(int noiseValue,int limitValue,int newValue)347 inline int checkNoise(int noiseValue, int limitValue, int newValue) {
348     // If the noise value would bring us out of bounds of the current noise array while we are
349     // stiching noise tiles together, wrap the noise around the current dimension of the noise to
350     // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
351     if (noiseValue >= limitValue) {
352         noiseValue -= newValue;
353     }
354     return noiseValue;
355 }
356 
smoothCurve(SkScalar t)357 inline SkScalar smoothCurve(SkScalar t) {
358     return t * t * (3 - 2 * t);
359 }
360 
361 } // end namespace
362 
SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,SkScalar baseFrequencyX,SkScalar baseFrequencyY,int numOctaves,SkScalar seed,const SkISize * tileSize)363 SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
364                                                  SkScalar baseFrequencyX,
365                                                  SkScalar baseFrequencyY,
366                                                  int numOctaves,
367                                                  SkScalar seed,
368                                                  const SkISize* tileSize)
369   : fType(type)
370   , fBaseFrequencyX(baseFrequencyX)
371   , fBaseFrequencyY(baseFrequencyY)
372   , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
373   , fSeed(seed)
374   , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
375   , fStitchTiles(!fTileSize.isEmpty())
376 {
377     SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
378     SkASSERT(fBaseFrequencyX >= 0);
379     SkASSERT(fBaseFrequencyY >= 0);
380 }
381 
CreateProc(SkReadBuffer & buffer)382 sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
383     Type type = buffer.read32LE(kLast_Type);
384 
385     SkScalar freqX = buffer.readScalar();
386     SkScalar freqY = buffer.readScalar();
387     int octaves = buffer.read32LE<int>(kMaxOctaves);
388 
389     SkScalar seed = buffer.readScalar();
390     SkISize tileSize;
391     tileSize.fWidth = buffer.readInt();
392     tileSize.fHeight = buffer.readInt();
393 
394     switch (type) {
395         case kFractalNoise_Type:
396             return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
397         case kTurbulence_Type:
398             return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
399         default:
400             // Really shouldn't get here b.c. of earlier check on type
401             buffer.validate(false);
402             return nullptr;
403     }
404 }
405 
flatten(SkWriteBuffer & buffer) const406 void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
407     buffer.writeInt((int) fType);
408     buffer.writeScalar(fBaseFrequencyX);
409     buffer.writeScalar(fBaseFrequencyY);
410     buffer.writeInt(fNumOctaves);
411     buffer.writeScalar(fSeed);
412     buffer.writeInt(fTileSize.fWidth);
413     buffer.writeInt(fTileSize.fHeight);
414 }
415 
noise2D(int channel,const StitchData & stitchData,const SkPoint & noiseVector) const416 SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
417         int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
418     struct Noise {
419         int noisePositionIntegerValue;
420         int nextNoisePositionIntegerValue;
421         SkScalar noisePositionFractionValue;
422         Noise(SkScalar component)
423         {
424             SkScalar position = component + kPerlinNoise;
425             noisePositionIntegerValue = SkScalarFloorToInt(position);
426             noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
427             nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
428         }
429     };
430     Noise noiseX(noiseVector.x());
431     Noise noiseY(noiseVector.y());
432     SkScalar u, v;
433     const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
434     // If stitching, adjust lattice points accordingly.
435     if (perlinNoiseShader.fStitchTiles) {
436         noiseX.noisePositionIntegerValue =
437             checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
438         noiseY.noisePositionIntegerValue =
439             checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
440         noiseX.nextNoisePositionIntegerValue =
441             checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
442         noiseY.nextNoisePositionIntegerValue =
443             checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
444     }
445     noiseX.noisePositionIntegerValue &= kBlockMask;
446     noiseY.noisePositionIntegerValue &= kBlockMask;
447     noiseX.nextNoisePositionIntegerValue &= kBlockMask;
448     noiseY.nextNoisePositionIntegerValue &= kBlockMask;
449     int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
450     int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
451     int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
452     int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
453     int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
454     int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
455     SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
456     SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
457 
458     if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
459         return 0;  // Check for pathological inputs.
460     }
461 
462     // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
463     SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
464                                           noiseY.noisePositionFractionValue); // Offset (0,0)
465     u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
466     fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
467     v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
468     SkScalar a = SkScalarInterp(u, v, sx);
469     fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
470     v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
471     fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
472     u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
473     SkScalar b = SkScalarInterp(u, v, sx);
474     return SkScalarInterp(a, b, sy);
475 }
476 
calculateTurbulenceValueForPoint(int channel,StitchData & stitchData,const SkPoint & point) const477 SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
478         int channel, StitchData& stitchData, const SkPoint& point) const {
479     const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
480     if (perlinNoiseShader.fStitchTiles) {
481         // Set up TurbulenceInitial stitch values.
482         stitchData = fPaintingData.fStitchDataInit;
483     }
484     SkScalar turbulenceFunctionResult = 0;
485     SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
486                                       point.y() * fPaintingData.fBaseFrequency.fY));
487     SkScalar ratio = SK_Scalar1;
488     for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
489         SkScalar noise = noise2D(channel, stitchData, noiseVector);
490         SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
491                             noise : SkScalarAbs(noise);
492         turbulenceFunctionResult += numer / ratio;
493         noiseVector.fX *= 2;
494         noiseVector.fY *= 2;
495         ratio *= 2;
496         if (perlinNoiseShader.fStitchTiles) {
497             // Update stitch values
498             stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
499                                     SkIntToScalar(stitchData.fHeight) * 2);
500         }
501     }
502 
503     // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
504     // by fractalNoise and (turbulenceFunctionResult) by turbulence.
505     if (perlinNoiseShader.fType == kFractalNoise_Type) {
506         turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
507     }
508 
509     if (channel == 3) { // Scale alpha by paint value
510         turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
511     }
512 
513     // Clamp result
514     return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
515 }
516 
517 ////////////////////////////////////////////////////////////////////////////////////////////////////
518 
shade(const SkPoint & point,StitchData & stitchData) const519 SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
520         const SkPoint& point, StitchData& stitchData) const {
521     SkPoint newPoint;
522     fMatrix.mapPoints(&newPoint, &point, 1);
523     newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
524     newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
525 
526     U8CPU rgba[4];
527     for (int channel = 3; channel >= 0; --channel) {
528         SkScalar value;
529         value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
530         rgba[channel] = SkScalarFloorToInt(255 * value);
531     }
532     return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
533 }
534 
535 #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const536 SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
537                                                               SkArenaAlloc* alloc) const {
538     // should we pay attention to rec's device-colorspace?
539     return alloc->make<PerlinNoiseShaderContext>(*this, rec);
540 }
541 #endif
542 
total_matrix(const SkShaderBase::ContextRec & rec,const SkShaderBase & shader)543 static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
544                                     const SkShaderBase& shader) {
545     if (rec.fLocalMatrix) {
546         return SkMatrix::Concat(*rec.fMatrix, *rec.fLocalMatrix);
547     }
548     return *rec.fMatrix;
549 }
550 
PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl & shader,const ContextRec & rec)551 SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
552         const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
553     : INHERITED(shader, rec)
554     , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
555     , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
556                     shader.fBaseFrequencyY, fMatrix)
557 {
558     // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
559     // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
560     fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
561                          -fMatrix.getTranslateY() + SK_Scalar1);
562 }
563 
shadeSpan(int x,int y,SkPMColor result[],int count)564 void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
565         int x, int y, SkPMColor result[], int count) {
566     SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
567     StitchData stitchData;
568     for (int i = 0; i < count; ++i) {
569         result[i] = shade(point, stitchData);
570         point.fX += SK_Scalar1;
571     }
572 }
573 
574 /////////////////////////////////////////////////////////////////////
575 
576 #if defined(SK_GANESH)
577 
578 class GrPerlinNoise2Effect : public GrFragmentProcessor {
579 public:
Make(SkPerlinNoiseShaderImpl::Type type,int numOctaves,bool stitchTiles,std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,GrSurfaceProxyView permutationsView,GrSurfaceProxyView noiseView,const GrCaps & caps)580     static std::unique_ptr<GrFragmentProcessor> Make(
581             SkPerlinNoiseShaderImpl::Type type,
582             int numOctaves,
583             bool stitchTiles,
584             std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
585             GrSurfaceProxyView permutationsView,
586             GrSurfaceProxyView noiseView,
587             const GrCaps& caps) {
588         static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
589                                                            GrSamplerState::WrapMode::kClamp,
590                                                            GrSamplerState::Filter::kNearest};
591         auto permutationsFP =
592                 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
593                                       SkMatrix::I(), kRepeatXSampler, caps);
594         auto noiseFP = GrTextureEffect::Make(std::move(noiseView), kPremul_SkAlphaType,
595                                              SkMatrix::I(), kRepeatXSampler, caps);
596 
597         return std::unique_ptr<GrFragmentProcessor>(
598                 new GrPerlinNoise2Effect(type,
599                                          numOctaves,
600                                          stitchTiles,
601                                          std::move(paintingData),
602                                          std::move(permutationsFP),
603                                          std::move(noiseFP)));
604     }
605 
name() const606     const char* name() const override { return "PerlinNoise"; }
607 
clone() const608     std::unique_ptr<GrFragmentProcessor> clone() const override {
609         return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
610     }
611 
stitchData() const612     const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
613 
type() const614     SkPerlinNoiseShaderImpl::Type type() const { return fType; }
stitchTiles() const615     bool stitchTiles() const { return fStitchTiles; }
baseFrequency() const616     const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
numOctaves() const617     int numOctaves() const { return fNumOctaves; }
618 
619 private:
620     class Impl : public ProgramImpl {
621     public:
622         void emitCode(EmitArgs&) override;
623 
624     private:
625         void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
626 
627         GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
628         GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
629     };
630 
onMakeProgramImpl() const631     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
632         return std::make_unique<Impl>();
633     }
634 
635     void onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override;
636 
onIsEqual(const GrFragmentProcessor & sBase) const637     bool onIsEqual(const GrFragmentProcessor& sBase) const override {
638         const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
639         return fType == s.fType &&
640                fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
641                fNumOctaves == s.fNumOctaves &&
642                fStitchTiles == s.fStitchTiles &&
643                fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
644     }
645 
GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type,int numOctaves,bool stitchTiles,std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,std::unique_ptr<GrFragmentProcessor> permutationsFP,std::unique_ptr<GrFragmentProcessor> noiseFP)646     GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type,
647                          int numOctaves,
648                          bool stitchTiles,
649                          std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
650                          std::unique_ptr<GrFragmentProcessor> permutationsFP,
651                          std::unique_ptr<GrFragmentProcessor> noiseFP)
652             : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
653             , fType(type)
654             , fNumOctaves(numOctaves)
655             , fStitchTiles(stitchTiles)
656             , fPaintingData(std::move(paintingData)) {
657         this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
658         this->registerChild(std::move(noiseFP), SkSL::SampleUsage::Explicit());
659         this->setUsesSampleCoordsDirectly();
660     }
661 
GrPerlinNoise2Effect(const GrPerlinNoise2Effect & that)662     GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
663             : INHERITED(that)
664             , fType(that.fType)
665             , fNumOctaves(that.fNumOctaves)
666             , fStitchTiles(that.fStitchTiles)
667             , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {}
668 
669     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
670 
671     SkPerlinNoiseShaderImpl::Type       fType;
672     int                                 fNumOctaves;
673     bool                                fStitchTiles;
674 
675     std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
676 
677     using INHERITED = GrFragmentProcessor;
678 };
679 
680 /////////////////////////////////////////////////////////////////////
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect)681 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect)
682 
683 #if GR_TEST_UTILS
684 std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
685     int      numOctaves = d->fRandom->nextRangeU(2, 10);
686     bool     stitchTiles = d->fRandom->nextBool();
687     SkScalar seed = SkIntToScalar(d->fRandom->nextU());
688     SkISize  tileSize;
689     tileSize.fWidth = d->fRandom->nextRangeU(4, 4096);
690     tileSize.fHeight = d->fRandom->nextRangeU(4, 4096);
691     SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f, 0.99f);
692     SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f, 0.99f);
693 
694     sk_sp<SkShader> shader(d->fRandom->nextBool() ?
695         SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
696                                                stitchTiles ? &tileSize : nullptr) :
697         SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
698                                              stitchTiles ? &tileSize : nullptr));
699 
700     GrTest::TestAsFPArgs asFPArgs(d);
701     return as_SB(shader)->asRootFragmentProcessor(asFPArgs.args(), GrTest::TestMatrix(d->fRandom));
702 }
703 #endif
704 
emitCode(EmitArgs & args)705 void GrPerlinNoise2Effect::Impl::emitCode(EmitArgs& args) {
706     const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
707 
708     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
709     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
710 
711     fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, SkSLType::kHalf2,
712                                                    "baseFrequency");
713     const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
714 
715     const char* stitchDataUni = nullptr;
716     if (pne.stitchTiles()) {
717         fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, SkSLType::kHalf2,
718                                                     "stitchData");
719         stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
720     }
721 
722     // Add noise function
723     const GrShaderVar gPerlinNoiseArgs[] = {{"chanCoord", SkSLType::kHalf },
724                                             {"noiseVec ", SkSLType::kHalf2}};
725 
726     const GrShaderVar gPerlinNoiseStitchArgs[] = {{"chanCoord" , SkSLType::kHalf },
727                                                   {"noiseVec"  , SkSLType::kHalf2},
728                                                   {"stitchData", SkSLType::kHalf2}};
729 
730     SkString noiseCode;
731 
732     noiseCode.append(
733         "half4 floorVal;"
734         "floorVal.xy = floor(noiseVec);"
735         "floorVal.zw = floorVal.xy + half2(1);"
736         "half2 fractVal = fract(noiseVec);"
737         // smooth curve : t^2*(3 - 2*t)
738         "half2 noiseSmooth = fractVal*fractVal*(half2(3) - 2*fractVal);"
739     );
740 
741     // Adjust frequencies if we're stitching tiles
742     if (pne.stitchTiles()) {
743         noiseCode.append(
744             "if (floorVal.x >= stitchData.x) { floorVal.x -= stitchData.x; };"
745             "if (floorVal.y >= stitchData.y) { floorVal.y -= stitchData.y; };"
746             "if (floorVal.z >= stitchData.x) { floorVal.z -= stitchData.x; };"
747             "if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };"
748         );
749     }
750 
751     // NOTE: We need to explicitly pass half4(1) as input color here, because the helper function
752     // can't see fInputColor (which is "_input" in the FP's outer function). skbug.com/10506
753     SkString sampleX = this->invokeChild(0, "half4(1)", args, "half2(floorVal.x, 0.5)");
754     SkString sampleY = this->invokeChild(0, "half4(1)", args, "half2(floorVal.z, 0.5)");
755     noiseCode.appendf("half2 latticeIdx = half2(%s.a, %s.a);", sampleX.c_str(), sampleY.c_str());
756 
757 #if defined(SK_BUILD_FOR_ANDROID)
758     // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
759     // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
760     // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
761     // (or 0.484368 here). The following rounding operation prevents these precision issues from
762     // affecting the result of the noise by making sure that we only have multiples of 1/255.
763     // (Note that 1/255 is about 0.003921569, which is the value used here).
764     noiseCode.append(
765             "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);");
766 #endif
767 
768     // Get (x,y) coordinates with the permutated x
769     noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
770 
771     noiseCode.append("half2 uv;");
772 
773     // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
774     // [-1,1] vector and perform a dot product between that vector and the provided vector.
775     // Save it as a string because we will repeat it 4x.
776     static constexpr const char* inc8bit = "0.00390625";  // 1.0 / 256.0
777     SkString dotLattice =
778             SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
779 
780     SkString sampleA = this->invokeChild(1, "half4(1)", args, "half2(bcoords.x, chanCoord)");
781     SkString sampleB = this->invokeChild(1, "half4(1)", args, "half2(bcoords.y, chanCoord)");
782     SkString sampleC = this->invokeChild(1, "half4(1)", args, "half2(bcoords.w, chanCoord)");
783     SkString sampleD = this->invokeChild(1, "half4(1)", args, "half2(bcoords.z, chanCoord)");
784 
785     // Compute u, at offset (0,0)
786     noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
787     noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
788 
789     // Compute v, at offset (-1,0)
790     noiseCode.append("fractVal.x -= 1.0;");
791     noiseCode.appendf("lattice = %s;", sampleB.c_str());
792     noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
793 
794     // Compute 'a' as a linear interpolation of 'u' and 'v'
795     noiseCode.append("half2 ab;");
796     noiseCode.append("ab.x = mix(uv.x, uv.y, noiseSmooth.x);");
797 
798     // Compute v, at offset (-1,-1)
799     noiseCode.append("fractVal.y -= 1.0;");
800     noiseCode.appendf("lattice = %s;", sampleC.c_str());
801     noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
802 
803     // Compute u, at offset (0,-1)
804     noiseCode.append("fractVal.x += 1.0;");
805     noiseCode.appendf("lattice = %s;", sampleD.c_str());
806     noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
807 
808     // Compute 'b' as a linear interpolation of 'u' and 'v'
809     noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);");
810     // Compute the noise as a linear interpolation of 'a' and 'b'
811     noiseCode.append("return mix(ab.x, ab.y, noiseSmooth.y);");
812 
813     SkString noiseFuncName = fragBuilder->getMangledFunctionName("noiseFuncName");
814     if (pne.stitchTiles()) {
815         fragBuilder->emitFunction(SkSLType::kHalf, noiseFuncName.c_str(),
816                                   {gPerlinNoiseStitchArgs, std::size(gPerlinNoiseStitchArgs)},
817                                   noiseCode.c_str());
818     } else {
819         fragBuilder->emitFunction(SkSLType::kHalf, noiseFuncName.c_str(),
820                                   {gPerlinNoiseArgs, std::size(gPerlinNoiseArgs)},
821                                   noiseCode.c_str());
822     }
823 
824     // There are rounding errors if the floor operation is not performed here
825     fragBuilder->codeAppendf("half2 noiseVec = half2(floor(%s.xy) * %s);",
826                              args.fSampleCoord, baseFrequencyUni);
827 
828     // Clear the color accumulator
829     fragBuilder->codeAppendf("half4 color = half4(0);");
830 
831     if (pne.stitchTiles()) {
832         // Set up TurbulenceInitial stitch values.
833         fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni);
834     }
835 
836     fragBuilder->codeAppendf("half ratio = 1.0;");
837 
838     // Loop over all octaves
839     fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
840     fragBuilder->codeAppendf(    "color += ");
841     if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
842         fragBuilder->codeAppend("abs(");
843     }
844 
845     // There are 4 lines, put y coords at center of each.
846     static constexpr const char* chanCoordR = "0.5";
847     static constexpr const char* chanCoordG = "1.5";
848     static constexpr const char* chanCoordB = "2.5";
849     static constexpr const char* chanCoordA = "3.5";
850     if (pne.stitchTiles()) {
851         fragBuilder->codeAppendf(
852            "half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),"
853                  "%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData))",
854             noiseFuncName.c_str(), chanCoordR,
855             noiseFuncName.c_str(), chanCoordG,
856             noiseFuncName.c_str(), chanCoordB,
857             noiseFuncName.c_str(), chanCoordA);
858     } else {
859         fragBuilder->codeAppendf(
860             "half4(%s(%s, noiseVec), %s(%s, noiseVec),"
861                   "%s(%s, noiseVec), %s(%s, noiseVec))",
862             noiseFuncName.c_str(), chanCoordR,
863             noiseFuncName.c_str(), chanCoordG,
864             noiseFuncName.c_str(), chanCoordB,
865             noiseFuncName.c_str(), chanCoordA);
866     }
867     if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
868         fragBuilder->codeAppend(")");  // end of "abs("
869     }
870     fragBuilder->codeAppend(" * ratio;");
871 
872     fragBuilder->codeAppend("noiseVec *= half2(2.0);"
873                             "ratio *= 0.5;");
874 
875     if (pne.stitchTiles()) {
876         fragBuilder->codeAppend("stitchData *= half2(2.0);");
877     }
878     fragBuilder->codeAppend("}");  // end of the for loop on octaves
879 
880     if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
881         // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
882         // by fractalNoise and (turbulenceFunctionResult) by turbulence.
883         fragBuilder->codeAppendf("color = color * half4(0.5) + half4(0.5);");
884     }
885 
886     // Clamp values
887     fragBuilder->codeAppendf("color = saturate(color);");
888 
889     // Pre-multiply the result
890     fragBuilder->codeAppendf("return half4(color.rgb * color.aaa, color.a);");
891 }
892 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & processor)893 void GrPerlinNoise2Effect::Impl::onSetData(const GrGLSLProgramDataManager& pdman,
894                                            const GrFragmentProcessor& processor) {
895     const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
896 
897     const SkVector& baseFrequency = turbulence.baseFrequency();
898     pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
899 
900     if (turbulence.stitchTiles()) {
901         const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
902         pdman.set2f(fStitchDataUni,
903                     SkIntToScalar(stitchData.fWidth),
904                     SkIntToScalar(stitchData.fHeight));
905     }
906 }
907 
onAddToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const908 void GrPerlinNoise2Effect::onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
909     uint32_t key = fNumOctaves;
910     key = key << 3;  // Make room for next 3 bits
911     switch (fType) {
912         case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
913             key |= 0x1;
914             break;
915         case SkPerlinNoiseShaderImpl::kTurbulence_Type:
916             key |= 0x2;
917             break;
918         default:
919             // leave key at 0
920             break;
921     }
922     if (fStitchTiles) {
923         key |= 0x4; // Flip the 3rd bit if tile stitching is on
924     }
925     b->add32(key);
926 }
927 
928 /////////////////////////////////////////////////////////////////////
929 
asFragmentProcessor(const GrFPArgs & args,const MatrixRec & mRec) const930 std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
931         const GrFPArgs& args, const MatrixRec& mRec) const {
932     SkASSERT(args.fContext);
933 
934     const SkMatrix& totalMatrix = mRec.totalMatrix();
935 
936     // Either we don't stitch tiles, either we have a valid tile size
937     SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
938 
939     auto paintingData = std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
940                                                                                 fSeed,
941                                                                                 fBaseFrequencyX,
942                                                                                 fBaseFrequencyY,
943                                                                                 totalMatrix);
944 
945     // Like shadeSpan, we start from device space. We will account for that below with a device
946     // space effect.
947 
948     auto context = args.fContext;
949 
950     if (0 == fNumOctaves) {
951         if (kFractalNoise_Type == fType) {
952             // Incoming alpha is assumed to be 1. So emit rgba = (1/4, 1/4, 1/4, 1/2)
953             // TODO: Either treat the output of this shader as sRGB or allow client to specify a
954             // color space of the noise. Either way, this case (and the GLSL) need to convert to
955             // the destination.
956             return GrFragmentProcessor::MakeColor(SkPMColor4f::FromBytes_RGBA(0x80404040));
957         }
958         // Emit zero.
959         return GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT);
960     }
961 
962     const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
963     const SkBitmap& noiseBitmap        = paintingData->getNoiseBitmap();
964 
965     auto permutationsView = std::get<0>(GrMakeCachedBitmapProxyView(
966             context,
967             permutationsBitmap,
968             /*label=*/"PerlinNoiseShader_FragmentProcessor_PermutationsView"));
969     auto noiseView = std::get<0>(GrMakeCachedBitmapProxyView(
970             context, noiseBitmap, /*label=*/"PerlinNoiseShader_FragmentProcessor_NoiseView"));
971 
972     if (permutationsView && noiseView) {
973         return GrFragmentProcessor::DeviceSpace(
974                 GrMatrixEffect::Make(SkMatrix::Translate(1 - totalMatrix.getTranslateX(),
975                                                          1 - totalMatrix.getTranslateY()),
976                                      GrPerlinNoise2Effect::Make(fType,
977                                                                 fNumOctaves,
978                                                                 fStitchTiles,
979                                                                 std::move(paintingData),
980                                                                 std::move(permutationsView),
981                                                                 std::move(noiseView),
982                                                                 *context->priv().caps())));
983     }
984     return nullptr;
985 }
986 
987 #endif
988 
989 ///////////////////////////////////////////////////////////////////////////////////////////////////
990 
valid_input(SkScalar baseX,SkScalar baseY,int numOctaves,const SkISize * tileSize,SkScalar seed)991 static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
992                         SkScalar seed) {
993     if (!(baseX >= 0 && baseY >= 0)) {
994         return false;
995     }
996     if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
997         return false;
998     }
999     if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1000         return false;
1001     }
1002     if (!SkScalarIsFinite(seed)) {
1003         return false;
1004     }
1005     return true;
1006 }
1007 
MakeFractalNoise(SkScalar baseFrequencyX,SkScalar baseFrequencyY,int numOctaves,SkScalar seed,const SkISize * tileSize)1008 sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1009                                                       SkScalar baseFrequencyY,
1010                                                       int numOctaves, SkScalar seed,
1011                                                       const SkISize* tileSize) {
1012     if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1013         return nullptr;
1014     }
1015     return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1016                                                  baseFrequencyX, baseFrequencyY, numOctaves, seed,
1017                                                  tileSize));
1018 }
1019 
MakeTurbulence(SkScalar baseFrequencyX,SkScalar baseFrequencyY,int numOctaves,SkScalar seed,const SkISize * tileSize)1020 sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1021                                                     SkScalar baseFrequencyY,
1022                                                     int numOctaves, SkScalar seed,
1023                                                     const SkISize* tileSize) {
1024     if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1025         return nullptr;
1026     }
1027     return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1028                                                  baseFrequencyX, baseFrequencyY, numOctaves, seed,
1029                                                  tileSize));
1030 }
1031 
RegisterFlattenables()1032 void SkPerlinNoiseShader::RegisterFlattenables() {
1033     SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
1034 }
1035