blob: 7f8887dd714ae90348ed920b7b9f61e3135e5fd2 [file] [log] [blame]
sugoi@google.come3b4c502013-04-05 13:47:09 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/effects/SkPerlinNoiseShader.h"
Herb Derby83e939b2017-02-07 14:25:11 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkColorFilter.h"
11#include "include/core/SkShader.h"
12#include "include/core/SkString.h"
13#include "include/core/SkUnPreMultiply.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040014#include "src/core/SkArenaAlloc.h"
Brian Osman449b1152020-04-15 16:43:00 -040015#include "src/core/SkMatrixProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/core/SkReadBuffer.h"
17#include "src/core/SkWriteBuffer.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000018
19#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/private/GrRecordingContext.h"
21#include "src/gpu/GrCoordTransform.h"
22#include "src/gpu/GrRecordingContextPriv.h"
23#include "src/gpu/SkGr.h"
24#include "src/gpu/effects/generated/GrConstColorProcessor.h"
25#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
26#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
27#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
28#include "src/gpu/glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000029#endif
30
31static const int kBlockSize = 256;
32static const int kBlockMask = kBlockSize - 1;
33static const int kPerlinNoise = 4096;
34static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
35
Mike Reedf2ae2b22017-05-30 15:22:54 -040036static uint8_t improved_noise_permutations[] = {
37 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
38 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
39 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
40 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
41 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
42 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
43 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
44 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
45 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
46 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
47 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
48 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
49 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
50 141, 128, 195, 78, 66, 215, 61, 156, 180,
51 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
52 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
53 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
54 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
55 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
56 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
57 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
58 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
59 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
60 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
61 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
62 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
63 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
64 141, 128, 195, 78, 66, 215, 61, 156, 180
65};
66
67class SkPerlinNoiseShaderImpl : public SkShaderBase {
68public:
Florin Malita83223bc2017-05-31 14:14:05 -040069 struct StitchData {
70 StitchData()
71 : fWidth(0)
72 , fWrapX(0)
73 , fHeight(0)
74 , fWrapY(0)
75 {}
76
Florin Malita102c8cf2018-06-05 17:37:12 -040077 StitchData(SkScalar w, SkScalar h)
Brian Osman788b9162020-02-07 10:36:46 -050078 : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040079 , fWrapX(kPerlinNoise + fWidth)
Brian Osman788b9162020-02-07 10:36:46 -050080 , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040081 , fWrapY(kPerlinNoise + fHeight) {}
82
Florin Malita83223bc2017-05-31 14:14:05 -040083 bool operator==(const StitchData& other) const {
84 return fWidth == other.fWidth &&
85 fWrapX == other.fWrapX &&
86 fHeight == other.fHeight &&
87 fWrapY == other.fWrapY;
88 }
89
90 int fWidth; // How much to subtract to wrap for stitching.
91 int fWrapX; // Minimum value to wrap.
92 int fHeight;
93 int fWrapY;
94 };
95
96 struct PaintingData {
97 PaintingData(const SkISize& tileSize, SkScalar seed,
98 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
99 const SkMatrix& matrix)
100 {
Ethan Nicholas82940152019-01-10 13:58:14 -0500101 SkVector tileVec;
102 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
103 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -0400104
Ethan Nicholas82940152019-01-10 13:58:14 -0500105 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -0500106 if (!matrix.decomposeScale(&scale, nullptr)) {
107 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
108 }
Ethan Nicholas82940152019-01-10 13:58:14 -0500109 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
110 baseFrequencyY * SkScalarInvert(scale.height()));
111 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -0400112 this->init(seed);
113 if (!fTileSize.isEmpty()) {
114 this->stitch();
115 }
116
117 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500118 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500119 fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
120 fPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400121
Greg Daniel7e1912a2018-02-08 09:15:33 -0500122 info = SkImageInfo::MakeN32Premul(kBlockSize, 4);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500123 fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
124 fNoiseBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400125
Greg Daniel7e1912a2018-02-08 09:15:33 -0500126 info = SkImageInfo::MakeA8(256, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500127 fImprovedPermutationsBitmap.installPixels(info, improved_noise_permutations,
128 info.minRowBytes());
129 fImprovedPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400130
Florin Malita83223bc2017-05-31 14:14:05 -0400131 static uint8_t gradients[] = { 2, 2, 1, 0,
132 0, 2, 1, 0,
133 2, 0, 1, 0,
134 0, 0, 1, 0,
135 2, 1, 2, 0,
136 0, 1, 2, 0,
137 2, 1, 0, 0,
138 0, 1, 0, 0,
139 1, 2, 2, 0,
140 1, 0, 2, 0,
141 1, 2, 0, 0,
142 1, 0, 0, 0,
143 2, 2, 1, 0,
144 1, 0, 2, 0,
145 0, 2, 1, 0,
146 1, 0, 0, 0 };
Greg Daniel7e1912a2018-02-08 09:15:33 -0500147 info = SkImageInfo::MakeN32Premul(16, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500148 fGradientBitmap.installPixels(info, gradients, info.minRowBytes());
149 fGradientBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400150 #endif
151 }
152
Brian Salomon4331e462017-07-26 14:58:11 -0400153 #if SK_SUPPORT_GPU
154 PaintingData(const PaintingData& that)
155 : fSeed(that.fSeed)
156 , fTileSize(that.fTileSize)
157 , fBaseFrequency(that.fBaseFrequency)
158 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel6f5441a2020-01-28 17:02:49 -0500159 , fPermutationsBitmap(that.fPermutationsBitmap)
160 , fNoiseBitmap(that.fNoiseBitmap)
161 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
162 , fGradientBitmap(that.fGradientBitmap) {
Brian Salomon4331e462017-07-26 14:58:11 -0400163 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
164 memcpy(fNoise, that.fNoise, sizeof(fNoise));
165 memcpy(fGradient, that.fGradient, sizeof(fGradient));
166 }
167 #endif
168
Florin Malita83223bc2017-05-31 14:14:05 -0400169 int fSeed;
170 uint8_t fLatticeSelector[kBlockSize];
171 uint16_t fNoise[4][kBlockSize][2];
172 SkPoint fGradient[4][kBlockSize];
173 SkISize fTileSize;
174 SkVector fBaseFrequency;
175 StitchData fStitchDataInit;
176
177 private:
178
179 #if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500180 SkBitmap fPermutationsBitmap;
181 SkBitmap fNoiseBitmap;
182 SkBitmap fImprovedPermutationsBitmap;
183 SkBitmap fGradientBitmap;
Florin Malita83223bc2017-05-31 14:14:05 -0400184 #endif
185
186 inline int random() {
187 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
188 static const int gRandQ = 127773; // m / a
189 static const int gRandR = 2836; // m % a
190
191 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
192 if (result <= 0)
193 result += kRandMaximum;
194 fSeed = result;
195 return result;
196 }
197
198 // Only called once. Could be part of the constructor.
199 void init(SkScalar seed)
200 {
201 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
202
203 // According to the SVG spec, we must truncate (not round) the seed value.
204 fSeed = SkScalarTruncToInt(seed);
205 // The seed value clamp to the range [1, kRandMaximum - 1].
206 if (fSeed <= 0) {
207 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
208 }
209 if (fSeed > kRandMaximum - 1) {
210 fSeed = kRandMaximum - 1;
211 }
212 for (int channel = 0; channel < 4; ++channel) {
213 for (int i = 0; i < kBlockSize; ++i) {
214 fLatticeSelector[i] = i;
215 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
216 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
217 }
218 }
219 for (int i = kBlockSize - 1; i > 0; --i) {
220 int k = fLatticeSelector[i];
221 int j = random() % kBlockSize;
222 SkASSERT(j >= 0);
223 SkASSERT(j < kBlockSize);
224 fLatticeSelector[i] = fLatticeSelector[j];
225 fLatticeSelector[j] = k;
226 }
227
228 // Perform the permutations now
229 {
230 // Copy noise data
231 uint16_t noise[4][kBlockSize][2];
232 for (int i = 0; i < kBlockSize; ++i) {
233 for (int channel = 0; channel < 4; ++channel) {
234 for (int j = 0; j < 2; ++j) {
235 noise[channel][i][j] = fNoise[channel][i][j];
236 }
237 }
238 }
239 // Do permutations on noise data
240 for (int i = 0; i < kBlockSize; ++i) {
241 for (int channel = 0; channel < 4; ++channel) {
242 for (int j = 0; j < 2; ++j) {
243 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
244 }
245 }
246 }
247 }
248
249 // Half of the largest possible value for 16 bit unsigned int
250 static const SkScalar gHalfMax16bits = 32767.5f;
251
252 // Compute gradients from permutated noise data
253 for (int channel = 0; channel < 4; ++channel) {
254 for (int i = 0; i < kBlockSize; ++i) {
255 fGradient[channel][i] = SkPoint::Make(
256 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
257 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
258 fGradient[channel][i].normalize();
259 // Put the normalized gradient back into the noise data
260 fNoise[channel][i][0] = SkScalarRoundToInt(
261 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
262 fNoise[channel][i][1] = SkScalarRoundToInt(
263 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
264 }
265 }
266 }
267
268 // Only called once. Could be part of the constructor.
269 void stitch() {
270 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
271 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
272 SkASSERT(tileWidth > 0 && tileHeight > 0);
273 // When stitching tiled turbulence, the frequencies must be adjusted
274 // so that the tile borders will be continuous.
275 if (fBaseFrequency.fX) {
276 SkScalar lowFrequencx =
277 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
278 SkScalar highFrequencx =
279 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
280 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400281 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
282 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400283 fBaseFrequency.fX = lowFrequencx;
284 } else {
285 fBaseFrequency.fX = highFrequencx;
286 }
287 }
288 if (fBaseFrequency.fY) {
289 SkScalar lowFrequency =
290 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
291 SkScalar highFrequency =
292 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400293 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
294 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400295 fBaseFrequency.fY = lowFrequency;
296 } else {
297 fBaseFrequency.fY = highFrequency;
298 }
299 }
300 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400301 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
302 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400303 }
304
305 public:
306
307#if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500308 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400309
Greg Daniel6f5441a2020-01-28 17:02:49 -0500310 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400311
Greg Daniel6f5441a2020-01-28 17:02:49 -0500312 const SkBitmap& getImprovedPermutationsBitmap() const {
313 return fImprovedPermutationsBitmap;
Greg Daniel7e1912a2018-02-08 09:15:33 -0500314 }
Florin Malita83223bc2017-05-31 14:14:05 -0400315
Greg Daniel6f5441a2020-01-28 17:02:49 -0500316 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400317#endif
318 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400319
320 /**
321 * About the noise types : the difference between the first 2 is just minor tweaks to the
322 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
323 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
324 * doing :
325 * kFractalNoise_Type : noise * 0.5 + 0.5
326 * kTurbulence_Type : abs(noise)
327 * Very little differences between the 2 types, although you can tell the difference visually.
328 * "Improved" is based on the Improved Perlin Noise algorithm described at
329 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
330 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
331 * changes to the noise, making it suitable for animated noise.
332 */
333 enum Type {
334 kFractalNoise_Type,
335 kTurbulence_Type,
336 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500337 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400338 };
339
Robert Phillipsbee27322018-01-23 09:58:18 -0500340 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
341
Mike Reedf2ae2b22017-05-30 15:22:54 -0400342 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
343 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
344 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400345
346 class PerlinNoiseShaderContext : public Context {
347 public:
348 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400349
350 void shadeSpan(int x, int y, SkPMColor[], int count) override;
351
352 private:
353 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
354 SkScalar calculateTurbulenceValueForPoint(
355 int channel,
356 StitchData& stitchData, const SkPoint& point) const;
357 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
358 SkScalar noise2D(int channel,
359 const StitchData& stitchData, const SkPoint& noiseVector) const;
360
Florin Malita83223bc2017-05-31 14:14:05 -0400361 SkMatrix fMatrix;
362 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400363
364 typedef Context INHERITED;
365 };
366
367#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500368 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400369#endif
370
Mike Reedf2ae2b22017-05-30 15:22:54 -0400371protected:
372 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400373#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400374 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400375#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400376
377private:
Mike Klein4fee3232018-10-18 17:27:16 -0400378 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
379
Mike Reedf2ae2b22017-05-30 15:22:54 -0400380 const SkPerlinNoiseShaderImpl::Type fType;
381 const SkScalar fBaseFrequencyX;
382 const SkScalar fBaseFrequencyY;
383 const int fNumOctaves;
384 const SkScalar fSeed;
385 const SkISize fTileSize;
386 const bool fStitchTiles;
387
388 friend class ::SkPerlinNoiseShader;
389
390 typedef SkShaderBase INHERITED;
391};
392
sugoi@google.come3b4c502013-04-05 13:47:09 +0000393namespace {
394
395// noiseValue is the color component's value (or color)
396// limitValue is the maximum perlin noise array index value allowed
397// newValue is the current noise dimension (either width or height)
398inline int checkNoise(int noiseValue, int limitValue, int newValue) {
399 // If the noise value would bring us out of bounds of the current noise array while we are
400 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
401 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
402 if (noiseValue >= limitValue) {
403 noiseValue -= newValue;
404 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000405 return noiseValue;
406}
407
408inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500409 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000410}
411
412} // end namespace
413
Mike Reedf2ae2b22017-05-30 15:22:54 -0400414SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500415 SkScalar baseFrequencyX,
416 SkScalar baseFrequencyY,
417 int numOctaves,
418 SkScalar seed,
419 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000420 : fType(type)
421 , fBaseFrequencyX(baseFrequencyX)
422 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500423 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000424 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700425 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000426 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000427{
Robert Phillipsbee27322018-01-23 09:58:18 -0500428 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400429 SkASSERT(fBaseFrequencyX >= 0);
430 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400431}
432
Florin Malita14d54c22017-05-18 11:52:59 -0400433sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500434 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500435
reed9fa60da2014-08-21 07:59:51 -0700436 SkScalar freqX = buffer.readScalar();
437 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500438 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500439
reed9fa60da2014-08-21 07:59:51 -0700440 SkScalar seed = buffer.readScalar();
441 SkISize tileSize;
442 tileSize.fWidth = buffer.readInt();
443 tileSize.fHeight = buffer.readInt();
444
445 switch (type) {
446 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400447 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700448 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400449 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
450 case kImprovedNoise_Type:
451 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700452 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500453 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500454 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700455 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700456 }
457}
458
Florin Malita14d54c22017-05-18 11:52:59 -0400459void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000460 buffer.writeInt((int) fType);
461 buffer.writeScalar(fBaseFrequencyX);
462 buffer.writeScalar(fBaseFrequencyY);
463 buffer.writeInt(fNumOctaves);
464 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000465 buffer.writeInt(fTileSize.fWidth);
466 buffer.writeInt(fTileSize.fHeight);
467}
468
Florin Malita14d54c22017-05-18 11:52:59 -0400469SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700470 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000471 struct Noise {
472 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700473 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000474 SkScalar noisePositionFractionValue;
475 Noise(SkScalar component)
476 {
477 SkScalar position = component + kPerlinNoise;
478 noisePositionIntegerValue = SkScalarFloorToInt(position);
479 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700480 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000481 }
482 };
483 Noise noiseX(noiseVector.x());
484 Noise noiseY(noiseVector.y());
485 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400486 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000487 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000488 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000489 noiseX.noisePositionIntegerValue =
490 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
491 noiseY.noisePositionIntegerValue =
492 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700493 noiseX.nextNoisePositionIntegerValue =
494 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
495 noiseY.nextNoisePositionIntegerValue =
496 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000497 }
498 noiseX.noisePositionIntegerValue &= kBlockMask;
499 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700500 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
501 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400502 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
503 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700504 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
505 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
506 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
507 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000508 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
509 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400510
Hal Canaryfda46002017-05-08 17:17:47 -0400511 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
512 return 0; // Check for pathological inputs.
513 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400514
sugoi@google.come3b4c502013-04-05 13:47:09 +0000515 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
516 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
517 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400518 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000519 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400520 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000521 SkScalar a = SkScalarInterp(u, v, sx);
522 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400523 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000524 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400525 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000526 SkScalar b = SkScalarInterp(u, v, sx);
527 return SkScalarInterp(a, b, sy);
528}
529
Florin Malita14d54c22017-05-18 11:52:59 -0400530SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700531 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400532 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000533 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000534 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400535 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000536 }
537 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400538 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
539 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000540 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000541 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700542 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700543 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
544 noise : SkScalarAbs(noise);
545 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000546 noiseVector.fX *= 2;
547 noiseVector.fY *= 2;
548 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000549 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000550 // Update stitch values
Florin Malita102c8cf2018-06-05 17:37:12 -0400551 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
552 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000553 }
554 }
555
556 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
557 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000558 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400559 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000560 }
561
562 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700563 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000564 }
565
566 // Clamp result
Brian Osmanaba642c2020-02-06 12:52:25 -0500567 return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000568}
569
Mike Reedf2ae2b22017-05-30 15:22:54 -0400570////////////////////////////////////////////////////////////////////////////////////////////////////
571// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
572static SkScalar fade(SkScalar t) {
573 return t * t * t * (t * (t * 6 - 15) + 10);
574}
575
576static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
577 return a + t * (b - a);
578}
579
580static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
581 int h = hash & 15;
582 SkScalar u = h < 8 ? x : y;
583 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
584 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
585}
586
587SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
588 int channel, const SkPoint& point) const {
589 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
590 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
591 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
592 // z offset between different channels, chosen arbitrarily
593 static const SkScalar CHANNEL_DELTA = 1000.0f;
594 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
595 SkScalar result = 0;
596 SkScalar ratio = SK_Scalar1;
597 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
598 int X = SkScalarFloorToInt(x) & 255;
599 int Y = SkScalarFloorToInt(y) & 255;
600 int Z = SkScalarFloorToInt(z) & 255;
601 SkScalar px = x - SkScalarFloorToScalar(x);
602 SkScalar py = y - SkScalarFloorToScalar(y);
603 SkScalar pz = z - SkScalarFloorToScalar(z);
604 SkScalar u = fade(px);
605 SkScalar v = fade(py);
606 SkScalar w = fade(pz);
607 uint8_t* permutations = improved_noise_permutations;
608 int A = permutations[X] + Y;
609 int AA = permutations[A] + Z;
610 int AB = permutations[A + 1] + Z;
611 int B = permutations[X + 1] + Y;
612 int BA = permutations[B] + Z;
613 int BB = permutations[B + 1] + Z;
614 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
615 grad(permutations[BA ], px - 1, py , pz )),
616 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
617 grad(permutations[BB ], px - 1, py - 1, pz ))),
618 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
619 grad(permutations[BA + 1], px - 1, py , pz - 1)),
620 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
621 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
622 ratio;
623 x *= 2;
624 y *= 2;
625 ratio *= 2;
626 }
Brian Osmanaba642c2020-02-06 12:52:25 -0500627 result = SkTPin((result + 1.0f) / 2.0f, 0.0f, 1.0f);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400628 return result;
629}
630////////////////////////////////////////////////////////////////////////////////////////////////////
631
Florin Malita14d54c22017-05-18 11:52:59 -0400632SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000633 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400634 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000635 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000636 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000637 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
638 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
639
640 U8CPU rgba[4];
641 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400642 SkScalar value;
643 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
644 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
645 }
646 else {
647 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
648 }
649 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000650 }
651 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
652}
653
Mike Reede92aae62018-10-17 10:21:51 -0400654#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400655SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400656 SkArenaAlloc* alloc) const {
Mike Reed011d1662019-02-28 17:19:25 -0500657 // should we pay attention to rec's device-colorspace?
Herb Derby83e939b2017-02-07 14:25:11 -0500658 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000659}
Mike Reede92aae62018-10-17 10:21:51 -0400660#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000661
Florin Malita83223bc2017-05-31 14:14:05 -0400662static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
663 const SkShaderBase& shader) {
664 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
665 if (rec.fLocalMatrix) {
666 matrix.preConcat(*rec.fLocalMatrix);
667 }
668
669 return matrix;
670}
671
Florin Malita14d54c22017-05-18 11:52:59 -0400672SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
673 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000674 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400675 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
676 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
677 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000678{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000679 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
680 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400681 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
682 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700683}
684
Florin Malita14d54c22017-05-18 11:52:59 -0400685void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000686 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000687 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
688 StitchData stitchData;
689 for (int i = 0; i < count; ++i) {
690 result[i] = shade(point, stitchData);
691 point.fX += SK_Scalar1;
692 }
693}
694
sugoi@google.come3b4c502013-04-05 13:47:09 +0000695/////////////////////////////////////////////////////////////////////
696
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000697#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000698
egdaniel64c47282015-11-13 06:54:19 -0800699class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000700public:
robertphillips9cdb9922016-02-03 12:25:40 -0800701 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000702
Mike Reedf2ae2b22017-05-30 15:22:54 -0400703 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000704
wangyixb1daa862015-08-18 11:29:31 -0700705protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400706 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700707
sugoi@google.com4775cba2013-04-17 13:46:56 +0000708private:
egdaniel018fb622015-10-28 07:26:40 -0700709 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700710 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700711
egdaniel64c47282015-11-13 06:54:19 -0800712 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000713};
714
715/////////////////////////////////////////////////////////////////////
716
Mike Reedf2ae2b22017-05-30 15:22:54 -0400717class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000718public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400719 static std::unique_ptr<GrFragmentProcessor> Make(
720 SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
721 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -0500722 GrSurfaceProxyView permutationsView, GrSurfaceProxyView noiseView,
Brian Salomonaff329b2017-08-11 09:40:37 -0400723 const SkMatrix& matrix) {
724 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
725 type, numOctaves, stitchTiles, std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -0500726 std::move(permutationsView), std::move(noiseView), matrix));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000727 }
728
mtklein36352bf2015-03-25 18:17:31 -0700729 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800730
Brian Salomonaff329b2017-08-11 09:40:37 -0400731 std::unique_ptr<GrFragmentProcessor> clone() const override {
732 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400733 }
734
Mike Reedf2ae2b22017-05-30 15:22:54 -0400735 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000736
Florin Malita14d54c22017-05-18 11:52:59 -0400737 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700738 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700739 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700740 int numOctaves() const { return fNumOctaves; }
Brian Salomon7d8b3972019-11-26 22:34:44 -0500741 const SkMatrix& matrix() const { return fCoordTransform.matrix(); }
senorblancof3b50272014-06-16 10:49:58 -0700742
sugoi@google.come3b4c502013-04-05 13:47:09 +0000743private:
egdaniel57d3b032015-11-13 11:57:27 -0800744 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800745 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700746 }
747
Brian Salomon94efbf52016-11-29 13:43:05 -0500748 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800749 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700750 GrGLPerlinNoise::GenKey(*this, caps, b);
751 }
752
mtklein36352bf2015-03-25 18:17:31 -0700753 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400754 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700755 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700756 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700757 fNumOctaves == s.fNumOctaves &&
758 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700759 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000760 }
761
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400762 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400763 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -0500764 GrSurfaceProxyView permutationsView,
765 GrSurfaceProxyView noiseView,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400766 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400767 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500768 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500769 , fNumOctaves(numOctaves)
770 , fStitchTiles(stitchTiles)
Greg Danielc52db712020-01-28 17:03:46 -0500771 , fPermutationsSampler(std::move(permutationsView))
772 , fNoiseSampler(std::move(noiseView))
Florin Malitab365cf52017-05-30 17:18:01 -0400773 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400774 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -0500775 fCoordTransform = GrCoordTransform(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700776 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000777 }
778
Brian Salomon4331e462017-07-26 14:58:11 -0400779 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400780 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400781 , fType(that.fType)
782 , fCoordTransform(that.fCoordTransform)
783 , fNumOctaves(that.fNumOctaves)
784 , fStitchTiles(that.fStitchTiles)
785 , fPermutationsSampler(that.fPermutationsSampler)
786 , fNoiseSampler(that.fNoiseSampler)
787 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400788 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -0400789 this->addCoordTransform(&fCoordTransform);
790 }
791
Brian Salomonf7dcd762018-07-30 14:48:15 -0400792 const TextureSampler& onTextureSampler(int i) const override {
793 return IthTextureSampler(i, fPermutationsSampler, fNoiseSampler);
794 }
795
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400796 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000797
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400798 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400799 GrCoordTransform fCoordTransform;
800 int fNumOctaves;
801 bool fStitchTiles;
802 TextureSampler fPermutationsSampler;
803 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400804 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000805
joshualittb0a8a372014-09-23 09:50:21 -0700806 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000807};
808
809/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400810GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000811
Hal Canary6f6961e2017-01-31 13:50:44 -0500812#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400813std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700814 int numOctaves = d->fRandom->nextRangeU(2, 10);
815 bool stitchTiles = d->fRandom->nextBool();
816 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
817 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
818 d->fRandom->nextRangeU(4, 4096));
819 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
820 0.99f);
821 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
822 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000823
reedfe630452016-03-25 09:08:00 -0700824 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
825 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400826 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700827 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400828 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000829
Brian Osman9f532a32016-10-19 11:12:09 -0400830 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400831 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000832}
Hal Canary6f6961e2017-01-31 13:50:44 -0500833#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000834
wangyix7c157a92015-07-22 15:08:53 -0700835void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400836 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800837
Mike Reedf2ae2b22017-05-30 15:22:54 -0400838 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800839 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Ethan Nicholas58430122020-04-14 09:54:02 -0400840 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint,
841 pne.sampleMatrix());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000842
Ethan Nicholas16464c32020-04-06 13:53:05 -0400843 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800844 "baseFrequency");
845 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000846
halcanary96fcdcc2015-08-27 07:41:13 -0700847 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800848 if (pne.stitchTiles()) {
Ethan Nicholas16464c32020-04-06 13:53:05 -0400849 fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800850 "stitchData");
851 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000852 }
853
sugoi@google.comd537af52013-06-10 13:59:25 +0000854 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
855 const char* chanCoordR = "0.125";
856 const char* chanCoordG = "0.375";
857 const char* chanCoordB = "0.625";
858 const char* chanCoordA = "0.875";
859 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000860 const char* stitchData = "stitchData";
861 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000862 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000863 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700864 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000865 const char* fractVal = "fractVal";
866 const char* uv = "uv";
867 const char* ab = "ab";
868 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700869 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000870 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000871 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
872 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
873 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400874 const char* dotLattice = "dot(((%s.ga + %s.rb * half2(%s)) * half2(2.0) - half2(1.0)), %s);";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000875
sugoi@google.comd537af52013-06-10 13:59:25 +0000876 // Add noise function
Nico Webere50efdf2018-10-01 14:40:44 -0400877 const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400878 GrShaderVar(chanCoord, kHalf_GrSLType),
879 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000880 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000881
Nico Webere50efdf2018-10-01 14:40:44 -0400882 const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400883 GrShaderVar(chanCoord, kHalf_GrSLType),
884 GrShaderVar(noiseVec, kHalf2_GrSLType),
885 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000886 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000887
sugoi@google.comd537af52013-06-10 13:59:25 +0000888 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000889
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400890 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700891 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400892 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
893 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000894
895 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400896 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700897 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000898
899 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800900 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000901 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400902 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000903 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400904 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700905 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400906 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700907 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400908 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000909 }
910
911 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400912 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400913 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000914
915 // Get permutation for x
916 {
917 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400918 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000919
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400920 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
Brian Salomond19cd762020-01-06 13:16:31 -0500921 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000922 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000923 }
924
925 // Get permutation for x + 1
926 {
927 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400928 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000929
sugoi@google.comd537af52013-06-10 13:59:25 +0000930 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
Brian Salomond19cd762020-01-06 13:16:31 -0500931 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000932 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000933 }
934
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000935#if defined(SK_BUILD_FOR_ANDROID)
936 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
937 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
938 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
939 // (or 0.484368 here). The following rounding operation prevents these precision issues from
940 // affecting the result of the noise by making sure that we only have multiples of 1/255.
941 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400942 noiseCode.appendf("\n\t%s = floor(%s * half2(255.0) + half2(0.5)) * half2(0.003921569);",
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000943 latticeIdx, latticeIdx);
944#endif
945
sugoi@google.come3b4c502013-04-05 13:47:09 +0000946 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400947 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000948
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400949 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000950 // Compute u, at offset (0,0)
951 {
952 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400953 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
954 noiseCode.appendf("\n\thalf4 %s = ", lattice);
Brian Salomond19cd762020-01-06 13:16:31 -0500955 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000956 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
957 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000958 }
959
sugoi@google.comd537af52013-06-10 13:59:25 +0000960 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000961 // Compute v, at offset (-1,0)
962 {
963 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400964 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000965 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500966 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000967 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
968 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000969 }
970
971 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400972 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000973 noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000974
sugoi@google.comd537af52013-06-10 13:59:25 +0000975 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000976 // Compute v, at offset (-1,-1)
977 {
978 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400979 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000980 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500981 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000982 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
983 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000984 }
985
sugoi@google.comd537af52013-06-10 13:59:25 +0000986 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000987 // Compute u, at offset (0,-1)
988 {
989 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400990 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000991 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500992 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000993 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
994 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000995 }
996
997 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000998 noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000999 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +00001000 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001001
sugoi@google.comd537af52013-06-10 13:59:25 +00001002 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -08001003 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001004 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001005 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
1006 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001007 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001008 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001009 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
1010 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001011 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001012
sugoi@google.comd537af52013-06-10 13:59:25 +00001013 // There are rounding errors if the floor operation is not performed here
Ethan Nicholase1f55022019-02-05 17:17:40 -05001014 fragBuilder->codeAppendf("\n\t\thalf2 %s = half2(floor(%s.xy) * %s);",
egdaniel4ca2e602015-11-18 08:01:26 -08001015 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001016
1017 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001018 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001019
robertphillipsbf536af2016-02-04 06:11:53 -08001020 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001021 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001022 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001023 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001024
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001025 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001026
1027 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001028 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001029
Mike Reedf2ae2b22017-05-30 15:22:54 -04001030 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001031 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001032 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001033 }
robertphillipsbf536af2016-02-04 06:11:53 -08001034 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001035 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001036 "half4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s),"
sugoi@google.comd537af52013-06-10 13:59:25 +00001037 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1038 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1039 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1040 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1041 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1042 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001043 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001044 "half4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s),"
sugoi@google.comd537af52013-06-10 13:59:25 +00001045 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1046 noiseFuncName.c_str(), chanCoordR, noiseVec,
1047 noiseFuncName.c_str(), chanCoordG, noiseVec,
1048 noiseFuncName.c_str(), chanCoordB, noiseVec,
1049 noiseFuncName.c_str(), chanCoordA, noiseVec);
1050 }
Florin Malita14d54c22017-05-18 11:52:59 -04001051 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001052 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001053 }
egdaniel4ca2e602015-11-18 08:01:26 -08001054 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001055
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001056 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001057 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001058
robertphillipsbf536af2016-02-04 06:11:53 -08001059 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001060 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001061 }
egdaniel4ca2e602015-11-18 08:01:26 -08001062 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001063
Florin Malita14d54c22017-05-18 11:52:59 -04001064 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001065 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1066 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001067 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001068 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001069 }
1070
sugoi@google.come3b4c502013-04-05 13:47:09 +00001071 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001072 fragBuilder->codeAppendf("\n\t\t%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001073
1074 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001075 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001076 args.fOutputColor, args.fOutputColor,
1077 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001078}
1079
Brian Salomon94efbf52016-11-29 13:43:05 -05001080void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001081 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001082 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001083
bsalomon63e99f72014-07-21 08:03:14 -07001084 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001085
1086 key = key << 3; // Make room for next 3 bits
1087
1088 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001089 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001090 key |= 0x1;
1091 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001092 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001093 key |= 0x2;
1094 break;
1095 default:
1096 // leave key at 0
1097 break;
1098 }
1099
1100 if (turbulence.stitchTiles()) {
1101 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1102 }
1103
bsalomon63e99f72014-07-21 08:03:14 -07001104 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001105}
1106
egdaniel018fb622015-10-28 07:26:40 -07001107void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001108 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001109 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001110
Mike Reedf2ae2b22017-05-30 15:22:54 -04001111 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001112
1113 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001114 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001115
sugoi@google.com4775cba2013-04-17 13:46:56 +00001116 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001117 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001118 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001119 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001120 }
1121}
1122
sugoi@google.come3b4c502013-04-05 13:47:09 +00001123/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001124
1125class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1126public:
1127 void emitCode(EmitArgs&) override;
1128
1129 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1130
1131protected:
1132 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1133
1134private:
1135 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001136 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1137
1138 typedef GrGLSLFragmentProcessor INHERITED;
1139};
1140
1141/////////////////////////////////////////////////////////////////////
1142
1143class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1144public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001145 static std::unique_ptr<GrFragmentProcessor> Make(
1146 int octaves, SkScalar z,
1147 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -05001148 GrSurfaceProxyView permutationsView, GrSurfaceProxyView gradientView,
Brian Salomonaff329b2017-08-11 09:40:37 -04001149 const SkMatrix& matrix) {
1150 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
Greg Danielc52db712020-01-28 17:03:46 -05001151 octaves, z, std::move(paintingData), std::move(permutationsView),
1152 std::move(gradientView), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001153 }
1154
Mike Reedf2ae2b22017-05-30 15:22:54 -04001155 const char* name() const override { return "ImprovedPerlinNoise"; }
1156
Brian Salomonaff329b2017-08-11 09:40:37 -04001157 std::unique_ptr<GrFragmentProcessor> clone() const override {
1158 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001159 }
1160
Mike Reedf2ae2b22017-05-30 15:22:54 -04001161 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1162 SkScalar z() const { return fZ; }
1163 int octaves() const { return fOctaves; }
Brian Salomon7d8b3972019-11-26 22:34:44 -05001164 const SkMatrix& matrix() const { return fCoordTransform.matrix(); }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001165
1166private:
1167 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1168 return new GrGLImprovedPerlinNoise;
1169 }
1170
1171 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1172 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1173 }
1174
1175 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1176 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1177 return fZ == fZ &&
1178 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1179 }
1180
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001181 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001182 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -05001183 GrSurfaceProxyView permutationsView,
1184 GrSurfaceProxyView gradientView,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001185 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001186 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001187 , fOctaves(octaves)
1188 , fZ(z)
Greg Danielc52db712020-01-28 17:03:46 -05001189 , fPermutationsSampler(std::move(permutationsView))
1190 , fGradientSampler(std::move(gradientView))
Florin Malitab365cf52017-05-30 17:18:01 -04001191 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001192 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -05001193 fCoordTransform = GrCoordTransform(matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001194 this->addCoordTransform(&fCoordTransform);
1195 }
1196
Brian Salomon4331e462017-07-26 14:58:11 -04001197 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001198 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001199 , fCoordTransform(that.fCoordTransform)
1200 , fOctaves(that.fOctaves)
1201 , fZ(that.fZ)
1202 , fPermutationsSampler(that.fPermutationsSampler)
1203 , fGradientSampler(that.fGradientSampler)
1204 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001205 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -04001206 this->addCoordTransform(&fCoordTransform);
1207 }
1208
Brian Salomonf7dcd762018-07-30 14:48:15 -04001209 const TextureSampler& onTextureSampler(int i) const override {
1210 return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
1211 }
1212
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001213 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001214
1215 GrCoordTransform fCoordTransform;
1216 int fOctaves;
1217 SkScalar fZ;
1218 TextureSampler fPermutationsSampler;
1219 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001220 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001221
1222 typedef GrFragmentProcessor INHERITED;
1223};
1224
1225/////////////////////////////////////////////////////////////////////
1226GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1227
1228#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001229std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1230 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001231 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1232 0.99f);
1233 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1234 0.99f);
1235 int numOctaves = d->fRandom->nextRangeU(2, 10);
1236 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1237
1238 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1239 baseFrequencyY,
1240 numOctaves,
1241 z));
1242
1243 GrTest::TestAsFPArgs asFPArgs(d);
1244 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1245}
1246#endif
1247
1248void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001249 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001250 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1251 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Ethan Nicholas58430122020-04-14 09:54:02 -04001252 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint,
1253 pne.sampleMatrix());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001254
Ethan Nicholas16464c32020-04-06 13:53:05 -04001255 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001256 "baseFrequency");
1257 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1258
Ethan Nicholas16464c32020-04-06 13:53:05 -04001259 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001260 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1261
1262 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001263 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001264 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001265 };
1266 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001267 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001268 fadeArgs,
1269 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1270 &fadeFuncName);
1271
1272 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001273 const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001274 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001275 };
1276 SkString permFuncName;
1277 SkString permCode("return ");
1278 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1279 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Brian Salomond19cd762020-01-06 13:16:31 -05001280 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0],
1281 "float2(fract(x / 256.0), 0.0)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001282 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001283 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001284 permCode.c_str(), &permFuncName);
1285
1286 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001287 const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001288 GrShaderVar("x", kHalf_GrSLType),
1289 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001290 };
1291 SkString gradFuncName;
Ethan Nicholase1f55022019-02-05 17:17:40 -05001292 SkString gradCode("return half(dot(");
Brian Salomond19cd762020-01-06 13:16:31 -05001293 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1],
1294 "float2(fract(x / 16.0), 0.0)");
Ethan Nicholase1f55022019-02-05 17:17:40 -05001295 gradCode.append(".rgb * 255.0 - float3(1.0), p));");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001296 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001297 gradCode.c_str(), &gradFuncName);
1298
1299 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001300 const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001301 GrShaderVar("a", kHalf_GrSLType),
1302 GrShaderVar("b", kHalf_GrSLType),
1303 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001304 };
1305 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001306 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001307 "return a + w * (b - a);", &lerpFuncName);
1308
1309 // noise function
Nico Webere50efdf2018-10-01 14:40:44 -04001310 const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001311 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001312 };
1313 SkString noiseFuncName;
1314 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001315 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001316 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001317 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1318 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1319 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1320 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1321 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1322 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1323 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1324 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001325 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1326 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001327 noiseCode.appendf("%s(%s(BA), p + half3(-1.0, 0.0, 0.0)), f.x),", gradFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001328 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001329 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001330 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001331 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001332 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001333 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001334 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1335 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001336 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001337 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001338 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001339 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001340 noiseCode.appendf("%s(%s(BB + 1.0), p + half3(-1.0, -1.0, -1.0)), f.x), f.y), f.z);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001341 gradFuncName.c_str(), permFuncName.c_str());
1342 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001343 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001344 noiseCode.c_str(), &noiseFuncName);
1345
1346 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001347 const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001348 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001349 };
1350 SkString noiseOctavesFuncName;
1351 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001352 noiseOctavesCode.append("half result = 0.0;");
1353 noiseOctavesCode.append("half ratio = 1.0;");
1354 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001355 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1356 noiseOctavesCode.append("p *= 2.0;");
1357 noiseOctavesCode.append("ratio *= 2.0;");
1358 noiseOctavesCode.append("}");
1359 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001360 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001361 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1362
Ethan Nicholase1f55022019-02-05 17:17:40 -05001363 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", vCoords.c_str(), baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001364 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001365 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001366 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001367 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001368 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001369 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001370 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001371 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001372 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001373
1374 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001375 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001376
1377 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001378 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001379 args.fOutputColor, args.fOutputColor,
1380 args.fOutputColor, args.fOutputColor);
1381}
1382
1383void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1384 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001385 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1386 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001387}
1388
1389void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1390 const GrFragmentProcessor& processor) {
1391 INHERITED::onSetData(pdman, processor);
1392
1393 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1394
1395 const SkVector& baseFrequency = noise.baseFrequency();
1396 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1397
Mike Reedf2ae2b22017-05-30 15:22:54 -04001398 pdman.set1f(fZUni, noise.z());
1399}
1400
1401/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001402std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001403 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001404 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001405
Florin Malita52f02912020-03-09 16:33:17 -04001406 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Brian Osman449b1152020-04-15 16:43:00 -04001407 const auto paintMatrix = SkMatrix::Concat(args.fMatrixProvider.localToDevice(), *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001408
Mike Reedf2ae2b22017-05-30 15:22:54 -04001409 // Either we don't stitch tiles, either we have a valid tile size
1410 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1411
Florin Malitab365cf52017-05-30 17:18:01 -04001412 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001413 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001414 fSeed,
1415 fBaseFrequencyX,
1416 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001417 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001418
Brian Osman449b1152020-04-15 16:43:00 -04001419 SkMatrix m = args.fMatrixProvider.localToDevice();
Florin Malitac6c5ead2018-04-11 15:33:40 -04001420 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1421 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001422
Greg Daniel6f5441a2020-01-28 17:02:49 -05001423 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001424 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001425 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1426 // We also know that we will not be using mipmaps. If things things weren't true we should
1427 // go through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001428 const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
1429 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001430 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001431
Greg Daniel6f5441a2020-01-28 17:02:49 -05001432 const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
1433 SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001434 auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001435 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001436 std::move(permutationsView),
1437 std::move(gradientView), m);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001438 }
1439
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001440 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001441 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001442 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001443 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1444 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1445 // the destination.
John Stilese3a39f72020-06-15 13:58:48 -04001446 auto inner = GrConstColorProcessor::Make(
1447 /*inputFP=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040),
1448 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001449 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001450 }
bsalomonc21b09e2015-08-28 18:46:56 -07001451 // Emit zero.
John Stilese3a39f72020-06-15 13:58:48 -04001452 return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001453 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001454 }
1455
Greg Daniel7e1912a2018-02-08 09:15:33 -05001456 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1457 // also know that we will not be using mipmaps. If things things weren't true we should go
1458 // through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001459 const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
1460 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001461 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001462
Greg Daniel6f5441a2020-01-28 17:02:49 -05001463 const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
1464 SkASSERT(SkIsPow2(noiseBitmap.width()) && SkIsPow2(noiseBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001465 auto noiseView = GrMakeCachedBitmapProxyView(context, noiseBitmap);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001466
Greg Danielc52db712020-01-28 17:03:46 -05001467 if (permutationsView.proxy() && noiseView.proxy()) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001468 auto inner = GrPerlinNoise2Effect::Make(fType,
1469 fNumOctaves,
1470 fStitchTiles,
1471 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001472 std::move(permutationsView),
1473 std::move(noiseView),
Brian Salomonaff329b2017-08-11 09:40:37 -04001474 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001475 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001476 }
bsalomonc21b09e2015-08-28 18:46:56 -07001477 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001478}
1479
1480#endif
1481
Mike Reedf2ae2b22017-05-30 15:22:54 -04001482///////////////////////////////////////////////////////////////////////////////////////////////////
1483
Mike Reed832aa112018-05-18 11:48:50 -04001484static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1485 SkScalar seed) {
1486 if (!(baseX >= 0 && baseY >= 0)) {
1487 return false;
1488 }
1489 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1490 return false;
1491 }
1492 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1493 return false;
1494 }
1495 if (!SkScalarIsFinite(seed)) {
1496 return false;
1497 }
1498 return true;
1499}
1500
Mike Reedf2ae2b22017-05-30 15:22:54 -04001501sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1502 SkScalar baseFrequencyY,
1503 int numOctaves, SkScalar seed,
1504 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001505 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1506 return nullptr;
1507 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001508 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1509 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1510 tileSize));
1511}
1512
1513sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1514 SkScalar baseFrequencyY,
1515 int numOctaves, SkScalar seed,
1516 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001517 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1518 return nullptr;
1519 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001520 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1521 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1522 tileSize));
1523}
1524
1525sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1526 SkScalar baseFrequencyY,
1527 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001528 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1529 return nullptr;
1530 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001531 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1532 baseFrequencyX, baseFrequencyY, numOctaves, z,
1533 nullptr));
1534}
1535
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001536void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001537 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001538}