xref: /aosp_15_r20/external/skia/src/shaders/SkPerlinNoiseShaderImpl.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2013 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkPerlinNoiseShaderImpl_DEFINED
8*c8dee2aaSAndroid Build Coastguard Worker #define SkPerlinNoiseShaderImpl_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFlattenable.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h"
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
25*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
26*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
27*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker class SkReadBuffer;
30*c8dee2aaSAndroid Build Coastguard Worker enum class SkPerlinNoiseShaderType;
31*c8dee2aaSAndroid Build Coastguard Worker struct SkStageRec;
32*c8dee2aaSAndroid Build Coastguard Worker class SkWriteBuffer;
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker class SkPerlinNoiseShader : public SkShaderBase {
35*c8dee2aaSAndroid Build Coastguard Worker private:
36*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int kBlockSize = 256;
37*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int kBlockMask = kBlockSize - 1;
38*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int kPerlinNoise = 4096;
39*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int kRandMaximum = SK_MaxS32;  // 2**31 - 1
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker public:
42*c8dee2aaSAndroid Build Coastguard Worker     struct StitchData {
43*c8dee2aaSAndroid Build Coastguard Worker         StitchData() = default;
44*c8dee2aaSAndroid Build Coastguard Worker 
StitchDataStitchData45*c8dee2aaSAndroid Build Coastguard Worker         StitchData(SkScalar w, SkScalar h)
46*c8dee2aaSAndroid Build Coastguard Worker                 : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
47*c8dee2aaSAndroid Build Coastguard Worker                 , fWrapX(kPerlinNoise + fWidth)
48*c8dee2aaSAndroid Build Coastguard Worker                 , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
49*c8dee2aaSAndroid Build Coastguard Worker                 , fWrapY(kPerlinNoise + fHeight) {}
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker         bool operator==(const StitchData& other) const {
52*c8dee2aaSAndroid Build Coastguard Worker             return fWidth == other.fWidth && fWrapX == other.fWrapX && fHeight == other.fHeight &&
53*c8dee2aaSAndroid Build Coastguard Worker                    fWrapY == other.fWrapY;
54*c8dee2aaSAndroid Build Coastguard Worker         }
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker         int fWidth = 0;  // How much to subtract to wrap for stitching.
57*c8dee2aaSAndroid Build Coastguard Worker         int fWrapX = 0;  // Minimum value to wrap.
58*c8dee2aaSAndroid Build Coastguard Worker         int fHeight = 0;
59*c8dee2aaSAndroid Build Coastguard Worker         int fWrapY = 0;
60*c8dee2aaSAndroid Build Coastguard Worker     };
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker     struct PaintingData {
PaintingDataPaintingData63*c8dee2aaSAndroid Build Coastguard Worker         PaintingData(const SkISize& tileSize,
64*c8dee2aaSAndroid Build Coastguard Worker                      SkScalar seed,
65*c8dee2aaSAndroid Build Coastguard Worker                      SkScalar baseFrequencyX,
66*c8dee2aaSAndroid Build Coastguard Worker                      SkScalar baseFrequencyY) {
67*c8dee2aaSAndroid Build Coastguard Worker             fBaseFrequency.set(baseFrequencyX, baseFrequencyY);
68*c8dee2aaSAndroid Build Coastguard Worker             fTileSize.set(SkScalarRoundToInt(tileSize.fWidth),
69*c8dee2aaSAndroid Build Coastguard Worker                           SkScalarRoundToInt(tileSize.fHeight));
70*c8dee2aaSAndroid Build Coastguard Worker             this->init(seed);
71*c8dee2aaSAndroid Build Coastguard Worker             if (!fTileSize.isEmpty()) {
72*c8dee2aaSAndroid Build Coastguard Worker                 this->stitch();
73*c8dee2aaSAndroid Build Coastguard Worker             }
74*c8dee2aaSAndroid Build Coastguard Worker         }
75*c8dee2aaSAndroid Build Coastguard Worker 
generateBitmapsPaintingData76*c8dee2aaSAndroid Build Coastguard Worker         void generateBitmaps() {
77*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
78*c8dee2aaSAndroid Build Coastguard Worker             fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
79*c8dee2aaSAndroid Build Coastguard Worker             fPermutationsBitmap.setImmutable();
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker             info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
82*c8dee2aaSAndroid Build Coastguard Worker             fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
83*c8dee2aaSAndroid Build Coastguard Worker             fNoiseBitmap.setImmutable();
84*c8dee2aaSAndroid Build Coastguard Worker         }
85*c8dee2aaSAndroid Build Coastguard Worker 
PaintingDataPaintingData86*c8dee2aaSAndroid Build Coastguard Worker         PaintingData(const PaintingData& that)
87*c8dee2aaSAndroid Build Coastguard Worker                 : fSeed(that.fSeed)
88*c8dee2aaSAndroid Build Coastguard Worker                 , fTileSize(that.fTileSize)
89*c8dee2aaSAndroid Build Coastguard Worker                 , fBaseFrequency(that.fBaseFrequency)
90*c8dee2aaSAndroid Build Coastguard Worker                 , fStitchDataInit(that.fStitchDataInit)
91*c8dee2aaSAndroid Build Coastguard Worker                 , fPermutationsBitmap(that.fPermutationsBitmap)
92*c8dee2aaSAndroid Build Coastguard Worker                 , fNoiseBitmap(that.fNoiseBitmap) {
93*c8dee2aaSAndroid Build Coastguard Worker             memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
94*c8dee2aaSAndroid Build Coastguard Worker             memcpy(fNoise, that.fNoise, sizeof(fNoise));
95*c8dee2aaSAndroid Build Coastguard Worker         }
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker         int fSeed;
98*c8dee2aaSAndroid Build Coastguard Worker         uint8_t fLatticeSelector[kBlockSize];
99*c8dee2aaSAndroid Build Coastguard Worker         uint16_t fNoise[4][kBlockSize][2];
100*c8dee2aaSAndroid Build Coastguard Worker         SkISize fTileSize;
101*c8dee2aaSAndroid Build Coastguard Worker         SkVector fBaseFrequency;
102*c8dee2aaSAndroid Build Coastguard Worker         StitchData fStitchDataInit;
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     private:
105*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap fPermutationsBitmap;
106*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap fNoiseBitmap;
107*c8dee2aaSAndroid Build Coastguard Worker 
randomPaintingData108*c8dee2aaSAndroid Build Coastguard Worker         int random() {
109*c8dee2aaSAndroid Build Coastguard Worker             // See https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
110*c8dee2aaSAndroid Build Coastguard Worker             // m = kRandMaximum, 2**31 - 1 (2147483647)
111*c8dee2aaSAndroid Build Coastguard Worker             static constexpr int kRandAmplitude = 16807;  // 7**5; primitive root of m
112*c8dee2aaSAndroid Build Coastguard Worker             static constexpr int kRandQ = 127773;         // m / a
113*c8dee2aaSAndroid Build Coastguard Worker             static constexpr int kRandR = 2836;           // m % a
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker             int result = kRandAmplitude * (fSeed % kRandQ) - kRandR * (fSeed / kRandQ);
116*c8dee2aaSAndroid Build Coastguard Worker             if (result <= 0) {
117*c8dee2aaSAndroid Build Coastguard Worker                 result += kRandMaximum;
118*c8dee2aaSAndroid Build Coastguard Worker             }
119*c8dee2aaSAndroid Build Coastguard Worker             fSeed = result;
120*c8dee2aaSAndroid Build Coastguard Worker             return result;
121*c8dee2aaSAndroid Build Coastguard Worker         }
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker         // Only called once. Could be part of the constructor.
initPaintingData124*c8dee2aaSAndroid Build Coastguard Worker         void init(SkScalar seed) {
125*c8dee2aaSAndroid Build Coastguard Worker             // According to the SVG spec, we must truncate (not round) the seed value.
126*c8dee2aaSAndroid Build Coastguard Worker             fSeed = SkScalarTruncToInt(seed);
127*c8dee2aaSAndroid Build Coastguard Worker             // The seed value clamp to the range [1, kRandMaximum - 1].
128*c8dee2aaSAndroid Build Coastguard Worker             if (fSeed <= 0) {
129*c8dee2aaSAndroid Build Coastguard Worker                 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
130*c8dee2aaSAndroid Build Coastguard Worker             }
131*c8dee2aaSAndroid Build Coastguard Worker             if (fSeed > kRandMaximum - 1) {
132*c8dee2aaSAndroid Build Coastguard Worker                 fSeed = kRandMaximum - 1;
133*c8dee2aaSAndroid Build Coastguard Worker             }
134*c8dee2aaSAndroid Build Coastguard Worker             for (int channel = 0; channel < 4; ++channel) {
135*c8dee2aaSAndroid Build Coastguard Worker                 for (int i = 0; i < kBlockSize; ++i) {
136*c8dee2aaSAndroid Build Coastguard Worker                     fLatticeSelector[i] = i;
137*c8dee2aaSAndroid Build Coastguard Worker                     fNoise[channel][i][0] = (random() % (2 * kBlockSize));
138*c8dee2aaSAndroid Build Coastguard Worker                     fNoise[channel][i][1] = (random() % (2 * kBlockSize));
139*c8dee2aaSAndroid Build Coastguard Worker                 }
140*c8dee2aaSAndroid Build Coastguard Worker             }
141*c8dee2aaSAndroid Build Coastguard Worker             for (int i = kBlockSize - 1; i > 0; --i) {
142*c8dee2aaSAndroid Build Coastguard Worker                 int k = fLatticeSelector[i];
143*c8dee2aaSAndroid Build Coastguard Worker                 int j = random() % kBlockSize;
144*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(j >= 0);
145*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(j < kBlockSize);
146*c8dee2aaSAndroid Build Coastguard Worker                 fLatticeSelector[i] = fLatticeSelector[j];
147*c8dee2aaSAndroid Build Coastguard Worker                 fLatticeSelector[j] = k;
148*c8dee2aaSAndroid Build Coastguard Worker             }
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker             // Perform the permutations now
151*c8dee2aaSAndroid Build Coastguard Worker             {
152*c8dee2aaSAndroid Build Coastguard Worker                 // Copy noise data
153*c8dee2aaSAndroid Build Coastguard Worker                 uint16_t noise[4][kBlockSize][2];
154*c8dee2aaSAndroid Build Coastguard Worker                 for (int i = 0; i < kBlockSize; ++i) {
155*c8dee2aaSAndroid Build Coastguard Worker                     for (int channel = 0; channel < 4; ++channel) {
156*c8dee2aaSAndroid Build Coastguard Worker                         for (int j = 0; j < 2; ++j) {
157*c8dee2aaSAndroid Build Coastguard Worker                             noise[channel][i][j] = fNoise[channel][i][j];
158*c8dee2aaSAndroid Build Coastguard Worker                         }
159*c8dee2aaSAndroid Build Coastguard Worker                     }
160*c8dee2aaSAndroid Build Coastguard Worker                 }
161*c8dee2aaSAndroid Build Coastguard Worker                 // Do permutations on noise data
162*c8dee2aaSAndroid Build Coastguard Worker                 for (int i = 0; i < kBlockSize; ++i) {
163*c8dee2aaSAndroid Build Coastguard Worker                     for (int channel = 0; channel < 4; ++channel) {
164*c8dee2aaSAndroid Build Coastguard Worker                         for (int j = 0; j < 2; ++j) {
165*c8dee2aaSAndroid Build Coastguard Worker                             fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
166*c8dee2aaSAndroid Build Coastguard Worker                         }
167*c8dee2aaSAndroid Build Coastguard Worker                     }
168*c8dee2aaSAndroid Build Coastguard Worker                 }
169*c8dee2aaSAndroid Build Coastguard Worker             }
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker             // Half of the largest possible value for 16 bit unsigned int
172*c8dee2aaSAndroid Build Coastguard Worker             static constexpr SkScalar kHalfMax16bits = 32767.5f;
173*c8dee2aaSAndroid Build Coastguard Worker 
174*c8dee2aaSAndroid Build Coastguard Worker             // Compute gradients from permuted noise data
175*c8dee2aaSAndroid Build Coastguard Worker             static constexpr SkScalar kInvBlockSizef = 1.0 / SkIntToScalar(kBlockSize);
176*c8dee2aaSAndroid Build Coastguard Worker             for (int channel = 0; channel < 4; ++channel) {
177*c8dee2aaSAndroid Build Coastguard Worker                 for (int i = 0; i < kBlockSize; ++i) {
178*c8dee2aaSAndroid Build Coastguard Worker                     SkPoint gradient =
179*c8dee2aaSAndroid Build Coastguard Worker                             SkPoint::Make((fNoise[channel][i][0] - kBlockSize) * kInvBlockSizef,
180*c8dee2aaSAndroid Build Coastguard Worker                                           (fNoise[channel][i][1] - kBlockSize) * kInvBlockSizef);
181*c8dee2aaSAndroid Build Coastguard Worker                     gradient.normalize();
182*c8dee2aaSAndroid Build Coastguard Worker                     // Put the normalized gradient back into the noise data
183*c8dee2aaSAndroid Build Coastguard Worker                     fNoise[channel][i][0] = SkScalarRoundToInt((gradient.fX + 1) * kHalfMax16bits);
184*c8dee2aaSAndroid Build Coastguard Worker                     fNoise[channel][i][1] = SkScalarRoundToInt((gradient.fY + 1) * kHalfMax16bits);
185*c8dee2aaSAndroid Build Coastguard Worker                 }
186*c8dee2aaSAndroid Build Coastguard Worker             }
187*c8dee2aaSAndroid Build Coastguard Worker         }
188*c8dee2aaSAndroid Build Coastguard Worker 
189*c8dee2aaSAndroid Build Coastguard Worker         // Only called once. Could be part of the constructor.
stitchPaintingData190*c8dee2aaSAndroid Build Coastguard Worker         void stitch() {
191*c8dee2aaSAndroid Build Coastguard Worker             SkScalar tileWidth = SkIntToScalar(fTileSize.width());
192*c8dee2aaSAndroid Build Coastguard Worker             SkScalar tileHeight = SkIntToScalar(fTileSize.height());
193*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(tileWidth > 0 && tileHeight > 0);
194*c8dee2aaSAndroid Build Coastguard Worker             // When stitching tiled turbulence, the frequencies must be adjusted
195*c8dee2aaSAndroid Build Coastguard Worker             // so that the tile borders will be continuous.
196*c8dee2aaSAndroid Build Coastguard Worker             if (fBaseFrequency.fX) {
197*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar lowFrequencx =
198*c8dee2aaSAndroid Build Coastguard Worker                         SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
199*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar highFrequencx =
200*c8dee2aaSAndroid Build Coastguard Worker                         SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
201*c8dee2aaSAndroid Build Coastguard Worker                 // BaseFrequency should be non-negative according to the standard.
202*c8dee2aaSAndroid Build Coastguard Worker                 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
203*c8dee2aaSAndroid Build Coastguard Worker                 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) <
204*c8dee2aaSAndroid Build Coastguard Worker                     highFrequencx / fBaseFrequency.fX) {
205*c8dee2aaSAndroid Build Coastguard Worker                     fBaseFrequency.fX = lowFrequencx;
206*c8dee2aaSAndroid Build Coastguard Worker                 } else {
207*c8dee2aaSAndroid Build Coastguard Worker                     fBaseFrequency.fX = highFrequencx;
208*c8dee2aaSAndroid Build Coastguard Worker                 }
209*c8dee2aaSAndroid Build Coastguard Worker             }
210*c8dee2aaSAndroid Build Coastguard Worker             if (fBaseFrequency.fY) {
211*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar lowFrequency =
212*c8dee2aaSAndroid Build Coastguard Worker                         SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
213*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar highFrequency =
214*c8dee2aaSAndroid Build Coastguard Worker                         SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
215*c8dee2aaSAndroid Build Coastguard Worker                 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
216*c8dee2aaSAndroid Build Coastguard Worker                 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) <
217*c8dee2aaSAndroid Build Coastguard Worker                     highFrequency / fBaseFrequency.fY) {
218*c8dee2aaSAndroid Build Coastguard Worker                     fBaseFrequency.fY = lowFrequency;
219*c8dee2aaSAndroid Build Coastguard Worker                 } else {
220*c8dee2aaSAndroid Build Coastguard Worker                     fBaseFrequency.fY = highFrequency;
221*c8dee2aaSAndroid Build Coastguard Worker                 }
222*c8dee2aaSAndroid Build Coastguard Worker             }
223*c8dee2aaSAndroid Build Coastguard Worker             fStitchDataInit =
224*c8dee2aaSAndroid Build Coastguard Worker                     StitchData(tileWidth * fBaseFrequency.fX, tileHeight * fBaseFrequency.fY);
225*c8dee2aaSAndroid Build Coastguard Worker         }
226*c8dee2aaSAndroid Build Coastguard Worker 
227*c8dee2aaSAndroid Build Coastguard Worker     public:
getPermutationsBitmapPaintingData228*c8dee2aaSAndroid Build Coastguard Worker         const SkBitmap& getPermutationsBitmap() const {
229*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!fPermutationsBitmap.drawsNothing());
230*c8dee2aaSAndroid Build Coastguard Worker             return fPermutationsBitmap;
231*c8dee2aaSAndroid Build Coastguard Worker         }
getNoiseBitmapPaintingData232*c8dee2aaSAndroid Build Coastguard Worker         const SkBitmap& getNoiseBitmap() const {
233*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!fNoiseBitmap.drawsNothing());
234*c8dee2aaSAndroid Build Coastguard Worker             return fNoiseBitmap;
235*c8dee2aaSAndroid Build Coastguard Worker         }
236*c8dee2aaSAndroid Build Coastguard Worker     };  // struct PaintingData
237*c8dee2aaSAndroid Build Coastguard Worker 
238*c8dee2aaSAndroid Build Coastguard Worker     static const int kMaxOctaves = 255;  // numOctaves must be <= 0 and <= kMaxOctaves
239*c8dee2aaSAndroid Build Coastguard Worker 
240*c8dee2aaSAndroid Build Coastguard Worker     SkPerlinNoiseShader(SkPerlinNoiseShaderType type,
241*c8dee2aaSAndroid Build Coastguard Worker                         SkScalar baseFrequencyX,
242*c8dee2aaSAndroid Build Coastguard Worker                         SkScalar baseFrequencyY,
243*c8dee2aaSAndroid Build Coastguard Worker                         int numOctaves,
244*c8dee2aaSAndroid Build Coastguard Worker                         SkScalar seed,
245*c8dee2aaSAndroid Build Coastguard Worker                         const SkISize* tileSize);
246*c8dee2aaSAndroid Build Coastguard Worker 
type()247*c8dee2aaSAndroid Build Coastguard Worker     ShaderType type() const override { return ShaderType::kPerlinNoise; }
248*c8dee2aaSAndroid Build Coastguard Worker 
noiseType()249*c8dee2aaSAndroid Build Coastguard Worker     SkPerlinNoiseShaderType noiseType() const { return fType; }
numOctaves()250*c8dee2aaSAndroid Build Coastguard Worker     int numOctaves() const { return fNumOctaves; }
stitchTiles()251*c8dee2aaSAndroid Build Coastguard Worker     bool stitchTiles() const { return fStitchTiles; }
tileSize()252*c8dee2aaSAndroid Build Coastguard Worker     SkISize tileSize() const { return fTileSize; }
253*c8dee2aaSAndroid Build Coastguard Worker 
getPaintingData()254*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<PaintingData> getPaintingData() const {
255*c8dee2aaSAndroid Build Coastguard Worker         return std::make_unique<PaintingData>(fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY);
256*c8dee2aaSAndroid Build Coastguard Worker     }
257*c8dee2aaSAndroid Build Coastguard Worker 
258*c8dee2aaSAndroid Build Coastguard Worker     bool appendStages(const SkStageRec& rec, const SkShaders::MatrixRec& mRec) const override;
259*c8dee2aaSAndroid Build Coastguard Worker 
260*c8dee2aaSAndroid Build Coastguard Worker protected:
261*c8dee2aaSAndroid Build Coastguard Worker     void flatten(SkWriteBuffer&) const override;
262*c8dee2aaSAndroid Build Coastguard Worker 
263*c8dee2aaSAndroid Build Coastguard Worker private:
264*c8dee2aaSAndroid Build Coastguard Worker     SK_FLATTENABLE_HOOKS(SkPerlinNoiseShader)
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker     const SkPerlinNoiseShaderType fType;
267*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar fBaseFrequencyX;
268*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar fBaseFrequencyY;
269*c8dee2aaSAndroid Build Coastguard Worker     const int fNumOctaves;
270*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar fSeed;
271*c8dee2aaSAndroid Build Coastguard Worker     const SkISize fTileSize;
272*c8dee2aaSAndroid Build Coastguard Worker     const bool fStitchTiles;
273*c8dee2aaSAndroid Build Coastguard Worker 
274*c8dee2aaSAndroid Build Coastguard Worker     mutable SkOnce fInitPaintingDataOnce;
275*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<PaintingData> fPaintingData;
276*c8dee2aaSAndroid Build Coastguard Worker 
277*c8dee2aaSAndroid Build Coastguard Worker     friend void SkRegisterPerlinNoiseShaderFlattenable();
278*c8dee2aaSAndroid Build Coastguard Worker };
279*c8dee2aaSAndroid Build Coastguard Worker 
280*c8dee2aaSAndroid Build Coastguard Worker #endif
281