blob: 96cdc79caa48c3b3819fde76e30485ede98c7f3d [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/core/SkReadBuffer.h"
16#include "src/core/SkWriteBuffer.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000017
18#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "include/private/GrRecordingContext.h"
20#include "src/gpu/GrCoordTransform.h"
21#include "src/gpu/GrRecordingContextPriv.h"
22#include "src/gpu/SkGr.h"
23#include "src/gpu/effects/generated/GrConstColorProcessor.h"
24#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
25#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
26#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
27#include "src/gpu/glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000028#endif
29
30static const int kBlockSize = 256;
31static const int kBlockMask = kBlockSize - 1;
32static const int kPerlinNoise = 4096;
33static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
34
Mike Reedf2ae2b22017-05-30 15:22:54 -040035static uint8_t improved_noise_permutations[] = {
36 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
37 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
38 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
39 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
40 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
41 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
42 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
43 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
44 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
45 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
46 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
47 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
48 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
49 141, 128, 195, 78, 66, 215, 61, 156, 180,
50 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
51 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
52 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
53 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
54 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
55 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
56 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
57 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
58 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
59 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
60 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
61 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
62 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
63 141, 128, 195, 78, 66, 215, 61, 156, 180
64};
65
66class SkPerlinNoiseShaderImpl : public SkShaderBase {
67public:
Florin Malita83223bc2017-05-31 14:14:05 -040068 struct StitchData {
69 StitchData()
70 : fWidth(0)
71 , fWrapX(0)
72 , fHeight(0)
73 , fWrapY(0)
74 {}
75
Florin Malita102c8cf2018-06-05 17:37:12 -040076 StitchData(SkScalar w, SkScalar h)
Brian Osman788b9162020-02-07 10:36:46 -050077 : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040078 , fWrapX(kPerlinNoise + fWidth)
Brian Osman788b9162020-02-07 10:36:46 -050079 , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040080 , fWrapY(kPerlinNoise + fHeight) {}
81
Florin Malita83223bc2017-05-31 14:14:05 -040082 bool operator==(const StitchData& other) const {
83 return fWidth == other.fWidth &&
84 fWrapX == other.fWrapX &&
85 fHeight == other.fHeight &&
86 fWrapY == other.fWrapY;
87 }
88
89 int fWidth; // How much to subtract to wrap for stitching.
90 int fWrapX; // Minimum value to wrap.
91 int fHeight;
92 int fWrapY;
93 };
94
95 struct PaintingData {
96 PaintingData(const SkISize& tileSize, SkScalar seed,
97 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
98 const SkMatrix& matrix)
99 {
Ethan Nicholas82940152019-01-10 13:58:14 -0500100 SkVector tileVec;
101 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
102 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -0400103
Ethan Nicholas82940152019-01-10 13:58:14 -0500104 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -0500105 if (!matrix.decomposeScale(&scale, nullptr)) {
106 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
107 }
Ethan Nicholas82940152019-01-10 13:58:14 -0500108 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
109 baseFrequencyY * SkScalarInvert(scale.height()));
110 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -0400111 this->init(seed);
112 if (!fTileSize.isEmpty()) {
113 this->stitch();
114 }
115
116 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500117 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500118 fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
119 fPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400120
Greg Daniel7e1912a2018-02-08 09:15:33 -0500121 info = SkImageInfo::MakeN32Premul(kBlockSize, 4);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500122 fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
123 fNoiseBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400124
Greg Daniel7e1912a2018-02-08 09:15:33 -0500125 info = SkImageInfo::MakeA8(256, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500126 fImprovedPermutationsBitmap.installPixels(info, improved_noise_permutations,
127 info.minRowBytes());
128 fImprovedPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400129
Florin Malita83223bc2017-05-31 14:14:05 -0400130 static uint8_t gradients[] = { 2, 2, 1, 0,
131 0, 2, 1, 0,
132 2, 0, 1, 0,
133 0, 0, 1, 0,
134 2, 1, 2, 0,
135 0, 1, 2, 0,
136 2, 1, 0, 0,
137 0, 1, 0, 0,
138 1, 2, 2, 0,
139 1, 0, 2, 0,
140 1, 2, 0, 0,
141 1, 0, 0, 0,
142 2, 2, 1, 0,
143 1, 0, 2, 0,
144 0, 2, 1, 0,
145 1, 0, 0, 0 };
Greg Daniel7e1912a2018-02-08 09:15:33 -0500146 info = SkImageInfo::MakeN32Premul(16, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500147 fGradientBitmap.installPixels(info, gradients, info.minRowBytes());
148 fGradientBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400149 #endif
150 }
151
Brian Salomon4331e462017-07-26 14:58:11 -0400152 #if SK_SUPPORT_GPU
153 PaintingData(const PaintingData& that)
154 : fSeed(that.fSeed)
155 , fTileSize(that.fTileSize)
156 , fBaseFrequency(that.fBaseFrequency)
157 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel6f5441a2020-01-28 17:02:49 -0500158 , fPermutationsBitmap(that.fPermutationsBitmap)
159 , fNoiseBitmap(that.fNoiseBitmap)
160 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
161 , fGradientBitmap(that.fGradientBitmap) {
Brian Salomon4331e462017-07-26 14:58:11 -0400162 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
163 memcpy(fNoise, that.fNoise, sizeof(fNoise));
164 memcpy(fGradient, that.fGradient, sizeof(fGradient));
165 }
166 #endif
167
Florin Malita83223bc2017-05-31 14:14:05 -0400168 int fSeed;
169 uint8_t fLatticeSelector[kBlockSize];
170 uint16_t fNoise[4][kBlockSize][2];
171 SkPoint fGradient[4][kBlockSize];
172 SkISize fTileSize;
173 SkVector fBaseFrequency;
174 StitchData fStitchDataInit;
175
176 private:
177
178 #if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500179 SkBitmap fPermutationsBitmap;
180 SkBitmap fNoiseBitmap;
181 SkBitmap fImprovedPermutationsBitmap;
182 SkBitmap fGradientBitmap;
Florin Malita83223bc2017-05-31 14:14:05 -0400183 #endif
184
185 inline int random() {
186 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
187 static const int gRandQ = 127773; // m / a
188 static const int gRandR = 2836; // m % a
189
190 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
191 if (result <= 0)
192 result += kRandMaximum;
193 fSeed = result;
194 return result;
195 }
196
197 // Only called once. Could be part of the constructor.
198 void init(SkScalar seed)
199 {
200 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
201
202 // According to the SVG spec, we must truncate (not round) the seed value.
203 fSeed = SkScalarTruncToInt(seed);
204 // The seed value clamp to the range [1, kRandMaximum - 1].
205 if (fSeed <= 0) {
206 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
207 }
208 if (fSeed > kRandMaximum - 1) {
209 fSeed = kRandMaximum - 1;
210 }
211 for (int channel = 0; channel < 4; ++channel) {
212 for (int i = 0; i < kBlockSize; ++i) {
213 fLatticeSelector[i] = i;
214 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
215 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
216 }
217 }
218 for (int i = kBlockSize - 1; i > 0; --i) {
219 int k = fLatticeSelector[i];
220 int j = random() % kBlockSize;
221 SkASSERT(j >= 0);
222 SkASSERT(j < kBlockSize);
223 fLatticeSelector[i] = fLatticeSelector[j];
224 fLatticeSelector[j] = k;
225 }
226
227 // Perform the permutations now
228 {
229 // Copy noise data
230 uint16_t noise[4][kBlockSize][2];
231 for (int i = 0; i < kBlockSize; ++i) {
232 for (int channel = 0; channel < 4; ++channel) {
233 for (int j = 0; j < 2; ++j) {
234 noise[channel][i][j] = fNoise[channel][i][j];
235 }
236 }
237 }
238 // Do permutations on noise data
239 for (int i = 0; i < kBlockSize; ++i) {
240 for (int channel = 0; channel < 4; ++channel) {
241 for (int j = 0; j < 2; ++j) {
242 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
243 }
244 }
245 }
246 }
247
248 // Half of the largest possible value for 16 bit unsigned int
249 static const SkScalar gHalfMax16bits = 32767.5f;
250
251 // Compute gradients from permutated noise data
252 for (int channel = 0; channel < 4; ++channel) {
253 for (int i = 0; i < kBlockSize; ++i) {
254 fGradient[channel][i] = SkPoint::Make(
255 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
256 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
257 fGradient[channel][i].normalize();
258 // Put the normalized gradient back into the noise data
259 fNoise[channel][i][0] = SkScalarRoundToInt(
260 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
261 fNoise[channel][i][1] = SkScalarRoundToInt(
262 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
263 }
264 }
265 }
266
267 // Only called once. Could be part of the constructor.
268 void stitch() {
269 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
270 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
271 SkASSERT(tileWidth > 0 && tileHeight > 0);
272 // When stitching tiled turbulence, the frequencies must be adjusted
273 // so that the tile borders will be continuous.
274 if (fBaseFrequency.fX) {
275 SkScalar lowFrequencx =
276 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
277 SkScalar highFrequencx =
278 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
279 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400280 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
281 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400282 fBaseFrequency.fX = lowFrequencx;
283 } else {
284 fBaseFrequency.fX = highFrequencx;
285 }
286 }
287 if (fBaseFrequency.fY) {
288 SkScalar lowFrequency =
289 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
290 SkScalar highFrequency =
291 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400292 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
293 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400294 fBaseFrequency.fY = lowFrequency;
295 } else {
296 fBaseFrequency.fY = highFrequency;
297 }
298 }
299 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400300 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
301 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400302 }
303
304 public:
305
306#if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500307 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400308
Greg Daniel6f5441a2020-01-28 17:02:49 -0500309 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400310
Greg Daniel6f5441a2020-01-28 17:02:49 -0500311 const SkBitmap& getImprovedPermutationsBitmap() const {
312 return fImprovedPermutationsBitmap;
Greg Daniel7e1912a2018-02-08 09:15:33 -0500313 }
Florin Malita83223bc2017-05-31 14:14:05 -0400314
Greg Daniel6f5441a2020-01-28 17:02:49 -0500315 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400316#endif
317 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400318
319 /**
320 * About the noise types : the difference between the first 2 is just minor tweaks to the
321 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
322 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
323 * doing :
324 * kFractalNoise_Type : noise * 0.5 + 0.5
325 * kTurbulence_Type : abs(noise)
326 * Very little differences between the 2 types, although you can tell the difference visually.
327 * "Improved" is based on the Improved Perlin Noise algorithm described at
328 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
329 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
330 * changes to the noise, making it suitable for animated noise.
331 */
332 enum Type {
333 kFractalNoise_Type,
334 kTurbulence_Type,
335 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500336 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400337 };
338
Robert Phillipsbee27322018-01-23 09:58:18 -0500339 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
340
Mike Reedf2ae2b22017-05-30 15:22:54 -0400341 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
342 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
343 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400344
345 class PerlinNoiseShaderContext : public Context {
346 public:
347 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400348
349 void shadeSpan(int x, int y, SkPMColor[], int count) override;
350
351 private:
352 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
353 SkScalar calculateTurbulenceValueForPoint(
354 int channel,
355 StitchData& stitchData, const SkPoint& point) const;
356 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
357 SkScalar noise2D(int channel,
358 const StitchData& stitchData, const SkPoint& noiseVector) const;
359
Florin Malita83223bc2017-05-31 14:14:05 -0400360 SkMatrix fMatrix;
361 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400362
363 typedef Context INHERITED;
364 };
365
366#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500367 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400368#endif
369
Mike Reedf2ae2b22017-05-30 15:22:54 -0400370protected:
371 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400372#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400373 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400374#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400375
376private:
Mike Klein4fee3232018-10-18 17:27:16 -0400377 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
378
Mike Reedf2ae2b22017-05-30 15:22:54 -0400379 const SkPerlinNoiseShaderImpl::Type fType;
380 const SkScalar fBaseFrequencyX;
381 const SkScalar fBaseFrequencyY;
382 const int fNumOctaves;
383 const SkScalar fSeed;
384 const SkISize fTileSize;
385 const bool fStitchTiles;
386
387 friend class ::SkPerlinNoiseShader;
388
389 typedef SkShaderBase INHERITED;
390};
391
sugoi@google.come3b4c502013-04-05 13:47:09 +0000392namespace {
393
394// noiseValue is the color component's value (or color)
395// limitValue is the maximum perlin noise array index value allowed
396// newValue is the current noise dimension (either width or height)
397inline int checkNoise(int noiseValue, int limitValue, int newValue) {
398 // If the noise value would bring us out of bounds of the current noise array while we are
399 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
400 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
401 if (noiseValue >= limitValue) {
402 noiseValue -= newValue;
403 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000404 return noiseValue;
405}
406
407inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500408 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000409}
410
411} // end namespace
412
Mike Reedf2ae2b22017-05-30 15:22:54 -0400413SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500414 SkScalar baseFrequencyX,
415 SkScalar baseFrequencyY,
416 int numOctaves,
417 SkScalar seed,
418 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000419 : fType(type)
420 , fBaseFrequencyX(baseFrequencyX)
421 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500422 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000423 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700424 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000425 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000426{
Robert Phillipsbee27322018-01-23 09:58:18 -0500427 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400428 SkASSERT(fBaseFrequencyX >= 0);
429 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400430}
431
Florin Malita14d54c22017-05-18 11:52:59 -0400432sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500433 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500434
reed9fa60da2014-08-21 07:59:51 -0700435 SkScalar freqX = buffer.readScalar();
436 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500437 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500438
reed9fa60da2014-08-21 07:59:51 -0700439 SkScalar seed = buffer.readScalar();
440 SkISize tileSize;
441 tileSize.fWidth = buffer.readInt();
442 tileSize.fHeight = buffer.readInt();
443
444 switch (type) {
445 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400446 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700447 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400448 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
449 case kImprovedNoise_Type:
450 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700451 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500452 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500453 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700454 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700455 }
456}
457
Florin Malita14d54c22017-05-18 11:52:59 -0400458void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000459 buffer.writeInt((int) fType);
460 buffer.writeScalar(fBaseFrequencyX);
461 buffer.writeScalar(fBaseFrequencyY);
462 buffer.writeInt(fNumOctaves);
463 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000464 buffer.writeInt(fTileSize.fWidth);
465 buffer.writeInt(fTileSize.fHeight);
466}
467
Florin Malita14d54c22017-05-18 11:52:59 -0400468SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700469 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000470 struct Noise {
471 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700472 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000473 SkScalar noisePositionFractionValue;
474 Noise(SkScalar component)
475 {
476 SkScalar position = component + kPerlinNoise;
477 noisePositionIntegerValue = SkScalarFloorToInt(position);
478 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700479 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000480 }
481 };
482 Noise noiseX(noiseVector.x());
483 Noise noiseY(noiseVector.y());
484 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400485 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000486 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000487 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000488 noiseX.noisePositionIntegerValue =
489 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
490 noiseY.noisePositionIntegerValue =
491 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700492 noiseX.nextNoisePositionIntegerValue =
493 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
494 noiseY.nextNoisePositionIntegerValue =
495 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000496 }
497 noiseX.noisePositionIntegerValue &= kBlockMask;
498 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700499 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
500 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400501 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
502 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700503 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
504 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
505 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
506 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000507 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
508 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400509
Hal Canaryfda46002017-05-08 17:17:47 -0400510 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
511 return 0; // Check for pathological inputs.
512 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400513
sugoi@google.come3b4c502013-04-05 13:47:09 +0000514 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
515 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
516 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400517 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000518 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400519 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000520 SkScalar a = SkScalarInterp(u, v, sx);
521 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400522 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000523 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400524 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000525 SkScalar b = SkScalarInterp(u, v, sx);
526 return SkScalarInterp(a, b, sy);
527}
528
Florin Malita14d54c22017-05-18 11:52:59 -0400529SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700530 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400531 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000532 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000533 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400534 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000535 }
536 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400537 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
538 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000539 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000540 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700541 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700542 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
543 noise : SkScalarAbs(noise);
544 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000545 noiseVector.fX *= 2;
546 noiseVector.fY *= 2;
547 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000548 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000549 // Update stitch values
Florin Malita102c8cf2018-06-05 17:37:12 -0400550 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
551 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000552 }
553 }
554
555 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
556 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000557 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400558 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000559 }
560
561 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700562 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000563 }
564
565 // Clamp result
Brian Osmanaba642c2020-02-06 12:52:25 -0500566 return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000567}
568
Mike Reedf2ae2b22017-05-30 15:22:54 -0400569////////////////////////////////////////////////////////////////////////////////////////////////////
570// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
571static SkScalar fade(SkScalar t) {
572 return t * t * t * (t * (t * 6 - 15) + 10);
573}
574
575static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
576 return a + t * (b - a);
577}
578
579static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
580 int h = hash & 15;
581 SkScalar u = h < 8 ? x : y;
582 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
583 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
584}
585
586SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
587 int channel, const SkPoint& point) const {
588 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
589 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
590 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
591 // z offset between different channels, chosen arbitrarily
592 static const SkScalar CHANNEL_DELTA = 1000.0f;
593 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
594 SkScalar result = 0;
595 SkScalar ratio = SK_Scalar1;
596 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
597 int X = SkScalarFloorToInt(x) & 255;
598 int Y = SkScalarFloorToInt(y) & 255;
599 int Z = SkScalarFloorToInt(z) & 255;
600 SkScalar px = x - SkScalarFloorToScalar(x);
601 SkScalar py = y - SkScalarFloorToScalar(y);
602 SkScalar pz = z - SkScalarFloorToScalar(z);
603 SkScalar u = fade(px);
604 SkScalar v = fade(py);
605 SkScalar w = fade(pz);
606 uint8_t* permutations = improved_noise_permutations;
607 int A = permutations[X] + Y;
608 int AA = permutations[A] + Z;
609 int AB = permutations[A + 1] + Z;
610 int B = permutations[X + 1] + Y;
611 int BA = permutations[B] + Z;
612 int BB = permutations[B + 1] + Z;
613 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
614 grad(permutations[BA ], px - 1, py , pz )),
615 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
616 grad(permutations[BB ], px - 1, py - 1, pz ))),
617 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
618 grad(permutations[BA + 1], px - 1, py , pz - 1)),
619 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
620 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
621 ratio;
622 x *= 2;
623 y *= 2;
624 ratio *= 2;
625 }
Brian Osmanaba642c2020-02-06 12:52:25 -0500626 result = SkTPin((result + 1.0f) / 2.0f, 0.0f, 1.0f);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400627 return result;
628}
629////////////////////////////////////////////////////////////////////////////////////////////////////
630
Florin Malita14d54c22017-05-18 11:52:59 -0400631SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000632 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400633 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000634 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000635 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000636 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
637 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
638
639 U8CPU rgba[4];
640 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400641 SkScalar value;
642 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
643 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
644 }
645 else {
646 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
647 }
648 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000649 }
650 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
651}
652
Mike Reede92aae62018-10-17 10:21:51 -0400653#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400654SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400655 SkArenaAlloc* alloc) const {
Mike Reed011d1662019-02-28 17:19:25 -0500656 // should we pay attention to rec's device-colorspace?
Herb Derby83e939b2017-02-07 14:25:11 -0500657 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000658}
Mike Reede92aae62018-10-17 10:21:51 -0400659#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000660
Florin Malita83223bc2017-05-31 14:14:05 -0400661static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
662 const SkShaderBase& shader) {
663 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
664 if (rec.fLocalMatrix) {
665 matrix.preConcat(*rec.fLocalMatrix);
666 }
667
668 return matrix;
669}
670
Florin Malita14d54c22017-05-18 11:52:59 -0400671SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
672 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000673 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400674 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
675 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
676 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000677{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000678 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
679 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400680 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
681 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700682}
683
Florin Malita14d54c22017-05-18 11:52:59 -0400684void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000685 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000686 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
687 StitchData stitchData;
688 for (int i = 0; i < count; ++i) {
689 result[i] = shade(point, stitchData);
690 point.fX += SK_Scalar1;
691 }
692}
693
sugoi@google.come3b4c502013-04-05 13:47:09 +0000694/////////////////////////////////////////////////////////////////////
695
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000696#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000697
egdaniel64c47282015-11-13 06:54:19 -0800698class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000699public:
robertphillips9cdb9922016-02-03 12:25:40 -0800700 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000701
Mike Reedf2ae2b22017-05-30 15:22:54 -0400702 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000703
wangyixb1daa862015-08-18 11:29:31 -0700704protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400705 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700706
sugoi@google.com4775cba2013-04-17 13:46:56 +0000707private:
egdaniel018fb622015-10-28 07:26:40 -0700708 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700709 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700710
egdaniel64c47282015-11-13 06:54:19 -0800711 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000712};
713
714/////////////////////////////////////////////////////////////////////
715
Mike Reedf2ae2b22017-05-30 15:22:54 -0400716class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000717public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400718 static std::unique_ptr<GrFragmentProcessor> Make(
719 SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
720 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -0500721 GrSurfaceProxyView permutationsView, GrSurfaceProxyView noiseView,
Brian Salomonaff329b2017-08-11 09:40:37 -0400722 const SkMatrix& matrix) {
723 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
724 type, numOctaves, stitchTiles, std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -0500725 std::move(permutationsView), std::move(noiseView), matrix));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000726 }
727
mtklein36352bf2015-03-25 18:17:31 -0700728 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800729
Brian Salomonaff329b2017-08-11 09:40:37 -0400730 std::unique_ptr<GrFragmentProcessor> clone() const override {
731 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400732 }
733
Mike Reedf2ae2b22017-05-30 15:22:54 -0400734 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000735
Florin Malita14d54c22017-05-18 11:52:59 -0400736 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700737 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700738 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700739 int numOctaves() const { return fNumOctaves; }
Brian Salomon7d8b3972019-11-26 22:34:44 -0500740 const SkMatrix& matrix() const { return fCoordTransform.matrix(); }
senorblancof3b50272014-06-16 10:49:58 -0700741
sugoi@google.come3b4c502013-04-05 13:47:09 +0000742private:
egdaniel57d3b032015-11-13 11:57:27 -0800743 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800744 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700745 }
746
Brian Salomon94efbf52016-11-29 13:43:05 -0500747 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800748 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700749 GrGLPerlinNoise::GenKey(*this, caps, b);
750 }
751
mtklein36352bf2015-03-25 18:17:31 -0700752 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400753 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700754 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700755 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700756 fNumOctaves == s.fNumOctaves &&
757 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700758 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000759 }
760
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400761 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400762 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -0500763 GrSurfaceProxyView permutationsView,
764 GrSurfaceProxyView noiseView,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400765 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400766 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500767 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500768 , fNumOctaves(numOctaves)
769 , fStitchTiles(stitchTiles)
Greg Danielc52db712020-01-28 17:03:46 -0500770 , fPermutationsSampler(std::move(permutationsView))
771 , fNoiseSampler(std::move(noiseView))
Florin Malitab365cf52017-05-30 17:18:01 -0400772 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400773 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -0500774 fCoordTransform = GrCoordTransform(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700775 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000776 }
777
Brian Salomon4331e462017-07-26 14:58:11 -0400778 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400779 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400780 , fType(that.fType)
781 , fCoordTransform(that.fCoordTransform)
782 , fNumOctaves(that.fNumOctaves)
783 , fStitchTiles(that.fStitchTiles)
784 , fPermutationsSampler(that.fPermutationsSampler)
785 , fNoiseSampler(that.fNoiseSampler)
786 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400787 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -0400788 this->addCoordTransform(&fCoordTransform);
789 }
790
Brian Salomonf7dcd762018-07-30 14:48:15 -0400791 const TextureSampler& onTextureSampler(int i) const override {
792 return IthTextureSampler(i, fPermutationsSampler, fNoiseSampler);
793 }
794
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400795 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000796
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400797 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400798 GrCoordTransform fCoordTransform;
799 int fNumOctaves;
800 bool fStitchTiles;
801 TextureSampler fPermutationsSampler;
802 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400803 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000804
joshualittb0a8a372014-09-23 09:50:21 -0700805 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000806};
807
808/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400809GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000810
Hal Canary6f6961e2017-01-31 13:50:44 -0500811#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400812std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700813 int numOctaves = d->fRandom->nextRangeU(2, 10);
814 bool stitchTiles = d->fRandom->nextBool();
815 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
816 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
817 d->fRandom->nextRangeU(4, 4096));
818 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
819 0.99f);
820 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
821 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000822
reedfe630452016-03-25 09:08:00 -0700823 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
824 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400825 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700826 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400827 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000828
Brian Osman9f532a32016-10-19 11:12:09 -0400829 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400830 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000831}
Hal Canary6f6961e2017-01-31 13:50:44 -0500832#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000833
wangyix7c157a92015-07-22 15:08:53 -0700834void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400835 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800836
Mike Reedf2ae2b22017-05-30 15:22:54 -0400837 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800838 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Ethan Nicholas58430122020-04-14 09:54:02 -0400839 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint,
840 pne.sampleMatrix());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000841
Ethan Nicholas16464c32020-04-06 13:53:05 -0400842 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800843 "baseFrequency");
844 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000845
halcanary96fcdcc2015-08-27 07:41:13 -0700846 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800847 if (pne.stitchTiles()) {
Ethan Nicholas16464c32020-04-06 13:53:05 -0400848 fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800849 "stitchData");
850 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000851 }
852
sugoi@google.comd537af52013-06-10 13:59:25 +0000853 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
854 const char* chanCoordR = "0.125";
855 const char* chanCoordG = "0.375";
856 const char* chanCoordB = "0.625";
857 const char* chanCoordA = "0.875";
858 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000859 const char* stitchData = "stitchData";
860 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000861 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000862 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700863 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000864 const char* fractVal = "fractVal";
865 const char* uv = "uv";
866 const char* ab = "ab";
867 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700868 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000869 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000870 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
871 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
872 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400873 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 +0000874
sugoi@google.comd537af52013-06-10 13:59:25 +0000875 // Add noise function
Nico Webere50efdf2018-10-01 14:40:44 -0400876 const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400877 GrShaderVar(chanCoord, kHalf_GrSLType),
878 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000879 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000880
Nico Webere50efdf2018-10-01 14:40:44 -0400881 const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400882 GrShaderVar(chanCoord, kHalf_GrSLType),
883 GrShaderVar(noiseVec, kHalf2_GrSLType),
884 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000885 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000886
sugoi@google.comd537af52013-06-10 13:59:25 +0000887 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000888
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400889 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700890 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400891 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
892 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000893
894 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400895 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700896 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000897
898 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800899 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000900 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400901 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000902 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400903 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700904 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400905 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700906 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400907 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000908 }
909
910 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400911 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400912 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000913
914 // Get permutation for x
915 {
916 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400917 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000918
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400919 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
Brian Salomond19cd762020-01-06 13:16:31 -0500920 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000921 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000922 }
923
924 // Get permutation for x + 1
925 {
926 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400927 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000928
sugoi@google.comd537af52013-06-10 13:59:25 +0000929 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
Brian Salomond19cd762020-01-06 13:16:31 -0500930 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000931 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000932 }
933
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000934#if defined(SK_BUILD_FOR_ANDROID)
935 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
936 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
937 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
938 // (or 0.484368 here). The following rounding operation prevents these precision issues from
939 // affecting the result of the noise by making sure that we only have multiples of 1/255.
940 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400941 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 +0000942 latticeIdx, latticeIdx);
943#endif
944
sugoi@google.come3b4c502013-04-05 13:47:09 +0000945 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400946 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000947
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400948 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000949 // Compute u, at offset (0,0)
950 {
951 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400952 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
953 noiseCode.appendf("\n\thalf4 %s = ", lattice);
Brian Salomond19cd762020-01-06 13:16:31 -0500954 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000955 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
956 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000957 }
958
sugoi@google.comd537af52013-06-10 13:59:25 +0000959 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000960 // Compute v, at offset (-1,0)
961 {
962 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400963 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000964 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500965 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000966 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
967 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000968 }
969
970 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400971 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000972 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 +0000973
sugoi@google.comd537af52013-06-10 13:59:25 +0000974 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000975 // Compute v, at offset (-1,-1)
976 {
977 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400978 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000979 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500980 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000981 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
982 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000983 }
984
sugoi@google.comd537af52013-06-10 13:59:25 +0000985 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000986 // Compute u, at offset (0,-1)
987 {
988 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400989 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000990 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500991 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000992 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
993 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000994 }
995
996 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000997 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 +0000998 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +0000999 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001000
sugoi@google.comd537af52013-06-10 13:59:25 +00001001 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -08001002 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001003 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001004 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
1005 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001006 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001007 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001008 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
1009 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001010 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001011
sugoi@google.comd537af52013-06-10 13:59:25 +00001012 // There are rounding errors if the floor operation is not performed here
Ethan Nicholase1f55022019-02-05 17:17:40 -05001013 fragBuilder->codeAppendf("\n\t\thalf2 %s = half2(floor(%s.xy) * %s);",
egdaniel4ca2e602015-11-18 08:01:26 -08001014 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001015
1016 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001017 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001018
robertphillipsbf536af2016-02-04 06:11:53 -08001019 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001020 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001021 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001022 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001023
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001024 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001025
1026 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001027 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001028
Mike Reedf2ae2b22017-05-30 15:22:54 -04001029 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001030 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001031 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001032 }
robertphillipsbf536af2016-02-04 06:11:53 -08001033 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001034 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001035 "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 +00001036 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1037 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1038 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1039 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1040 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1041 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001042 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001043 "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 +00001044 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1045 noiseFuncName.c_str(), chanCoordR, noiseVec,
1046 noiseFuncName.c_str(), chanCoordG, noiseVec,
1047 noiseFuncName.c_str(), chanCoordB, noiseVec,
1048 noiseFuncName.c_str(), chanCoordA, noiseVec);
1049 }
Florin Malita14d54c22017-05-18 11:52:59 -04001050 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001051 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001052 }
egdaniel4ca2e602015-11-18 08:01:26 -08001053 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001054
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001055 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001056 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001057
robertphillipsbf536af2016-02-04 06:11:53 -08001058 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001059 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001060 }
egdaniel4ca2e602015-11-18 08:01:26 -08001061 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001062
Florin Malita14d54c22017-05-18 11:52:59 -04001063 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001064 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1065 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001066 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001067 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001068 }
1069
sugoi@google.come3b4c502013-04-05 13:47:09 +00001070 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001071 fragBuilder->codeAppendf("\n\t\t%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001072
1073 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001074 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001075 args.fOutputColor, args.fOutputColor,
1076 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001077}
1078
Brian Salomon94efbf52016-11-29 13:43:05 -05001079void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001080 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001081 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001082
bsalomon63e99f72014-07-21 08:03:14 -07001083 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001084
1085 key = key << 3; // Make room for next 3 bits
1086
1087 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001088 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001089 key |= 0x1;
1090 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001091 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001092 key |= 0x2;
1093 break;
1094 default:
1095 // leave key at 0
1096 break;
1097 }
1098
1099 if (turbulence.stitchTiles()) {
1100 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1101 }
1102
bsalomon63e99f72014-07-21 08:03:14 -07001103 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001104}
1105
egdaniel018fb622015-10-28 07:26:40 -07001106void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001107 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001108 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001109
Mike Reedf2ae2b22017-05-30 15:22:54 -04001110 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001111
1112 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001113 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001114
sugoi@google.com4775cba2013-04-17 13:46:56 +00001115 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001116 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001117 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001118 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001119 }
1120}
1121
sugoi@google.come3b4c502013-04-05 13:47:09 +00001122/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001123
1124class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1125public:
1126 void emitCode(EmitArgs&) override;
1127
1128 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1129
1130protected:
1131 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1132
1133private:
1134 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001135 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1136
1137 typedef GrGLSLFragmentProcessor INHERITED;
1138};
1139
1140/////////////////////////////////////////////////////////////////////
1141
1142class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1143public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001144 static std::unique_ptr<GrFragmentProcessor> Make(
1145 int octaves, SkScalar z,
1146 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -05001147 GrSurfaceProxyView permutationsView, GrSurfaceProxyView gradientView,
Brian Salomonaff329b2017-08-11 09:40:37 -04001148 const SkMatrix& matrix) {
1149 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
Greg Danielc52db712020-01-28 17:03:46 -05001150 octaves, z, std::move(paintingData), std::move(permutationsView),
1151 std::move(gradientView), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001152 }
1153
Mike Reedf2ae2b22017-05-30 15:22:54 -04001154 const char* name() const override { return "ImprovedPerlinNoise"; }
1155
Brian Salomonaff329b2017-08-11 09:40:37 -04001156 std::unique_ptr<GrFragmentProcessor> clone() const override {
1157 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001158 }
1159
Mike Reedf2ae2b22017-05-30 15:22:54 -04001160 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1161 SkScalar z() const { return fZ; }
1162 int octaves() const { return fOctaves; }
Brian Salomon7d8b3972019-11-26 22:34:44 -05001163 const SkMatrix& matrix() const { return fCoordTransform.matrix(); }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001164
1165private:
1166 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1167 return new GrGLImprovedPerlinNoise;
1168 }
1169
1170 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1171 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1172 }
1173
1174 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1175 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1176 return fZ == fZ &&
1177 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1178 }
1179
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001180 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001181 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -05001182 GrSurfaceProxyView permutationsView,
1183 GrSurfaceProxyView gradientView,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001184 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001185 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001186 , fOctaves(octaves)
1187 , fZ(z)
Greg Danielc52db712020-01-28 17:03:46 -05001188 , fPermutationsSampler(std::move(permutationsView))
1189 , fGradientSampler(std::move(gradientView))
Florin Malitab365cf52017-05-30 17:18:01 -04001190 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001191 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -05001192 fCoordTransform = GrCoordTransform(matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001193 this->addCoordTransform(&fCoordTransform);
1194 }
1195
Brian Salomon4331e462017-07-26 14:58:11 -04001196 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001197 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001198 , fCoordTransform(that.fCoordTransform)
1199 , fOctaves(that.fOctaves)
1200 , fZ(that.fZ)
1201 , fPermutationsSampler(that.fPermutationsSampler)
1202 , fGradientSampler(that.fGradientSampler)
1203 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001204 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -04001205 this->addCoordTransform(&fCoordTransform);
1206 }
1207
Brian Salomonf7dcd762018-07-30 14:48:15 -04001208 const TextureSampler& onTextureSampler(int i) const override {
1209 return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
1210 }
1211
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001212 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001213
1214 GrCoordTransform fCoordTransform;
1215 int fOctaves;
1216 SkScalar fZ;
1217 TextureSampler fPermutationsSampler;
1218 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001219 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001220
1221 typedef GrFragmentProcessor INHERITED;
1222};
1223
1224/////////////////////////////////////////////////////////////////////
1225GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1226
1227#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001228std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1229 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001230 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1231 0.99f);
1232 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1233 0.99f);
1234 int numOctaves = d->fRandom->nextRangeU(2, 10);
1235 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1236
1237 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1238 baseFrequencyY,
1239 numOctaves,
1240 z));
1241
1242 GrTest::TestAsFPArgs asFPArgs(d);
1243 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1244}
1245#endif
1246
1247void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001248 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001249 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1250 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Ethan Nicholas58430122020-04-14 09:54:02 -04001251 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint,
1252 pne.sampleMatrix());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001253
Ethan Nicholas16464c32020-04-06 13:53:05 -04001254 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001255 "baseFrequency");
1256 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1257
Ethan Nicholas16464c32020-04-06 13:53:05 -04001258 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001259 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1260
1261 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001262 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001263 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001264 };
1265 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001266 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001267 fadeArgs,
1268 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1269 &fadeFuncName);
1270
1271 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001272 const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001273 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001274 };
1275 SkString permFuncName;
1276 SkString permCode("return ");
1277 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1278 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Brian Salomond19cd762020-01-06 13:16:31 -05001279 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0],
1280 "float2(fract(x / 256.0), 0.0)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001281 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001282 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001283 permCode.c_str(), &permFuncName);
1284
1285 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001286 const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001287 GrShaderVar("x", kHalf_GrSLType),
1288 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001289 };
1290 SkString gradFuncName;
Ethan Nicholase1f55022019-02-05 17:17:40 -05001291 SkString gradCode("return half(dot(");
Brian Salomond19cd762020-01-06 13:16:31 -05001292 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1],
1293 "float2(fract(x / 16.0), 0.0)");
Ethan Nicholase1f55022019-02-05 17:17:40 -05001294 gradCode.append(".rgb * 255.0 - float3(1.0), p));");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001295 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001296 gradCode.c_str(), &gradFuncName);
1297
1298 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001299 const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001300 GrShaderVar("a", kHalf_GrSLType),
1301 GrShaderVar("b", kHalf_GrSLType),
1302 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001303 };
1304 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001305 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001306 "return a + w * (b - a);", &lerpFuncName);
1307
1308 // noise function
Nico Webere50efdf2018-10-01 14:40:44 -04001309 const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001310 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001311 };
1312 SkString noiseFuncName;
1313 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001314 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001315 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001316 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1317 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1318 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1319 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1320 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1321 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1322 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1323 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001324 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1325 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001326 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 -04001327 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001328 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001329 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001330 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001331 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001332 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001333 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1334 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001335 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001336 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001337 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001338 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001339 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 -04001340 gradFuncName.c_str(), permFuncName.c_str());
1341 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001342 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001343 noiseCode.c_str(), &noiseFuncName);
1344
1345 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001346 const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001347 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001348 };
1349 SkString noiseOctavesFuncName;
1350 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001351 noiseOctavesCode.append("half result = 0.0;");
1352 noiseOctavesCode.append("half ratio = 1.0;");
1353 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001354 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1355 noiseOctavesCode.append("p *= 2.0;");
1356 noiseOctavesCode.append("ratio *= 2.0;");
1357 noiseOctavesCode.append("}");
1358 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001359 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001360 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1361
Ethan Nicholase1f55022019-02-05 17:17:40 -05001362 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", vCoords.c_str(), baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001363 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001364 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001365 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001366 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001367 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001368 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001369 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001370 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001371 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001372
1373 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001374 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001375
1376 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001377 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001378 args.fOutputColor, args.fOutputColor,
1379 args.fOutputColor, args.fOutputColor);
1380}
1381
1382void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1383 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001384 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1385 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001386}
1387
1388void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1389 const GrFragmentProcessor& processor) {
1390 INHERITED::onSetData(pdman, processor);
1391
1392 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1393
1394 const SkVector& baseFrequency = noise.baseFrequency();
1395 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1396
Mike Reedf2ae2b22017-05-30 15:22:54 -04001397 pdman.set1f(fZUni, noise.z());
1398}
1399
1400/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001401std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001402 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001403 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001404
Florin Malita52f02912020-03-09 16:33:17 -04001405 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Ethan Nicholas82940152019-01-10 13:58:14 -05001406 const auto paintMatrix = SkMatrix::Concat(*args.fViewMatrix, *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001407
Mike Reedf2ae2b22017-05-30 15:22:54 -04001408 // Either we don't stitch tiles, either we have a valid tile size
1409 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1410
Florin Malitab365cf52017-05-30 17:18:01 -04001411 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001412 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001413 fSeed,
1414 fBaseFrequencyX,
1415 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001416 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001417
1418 SkMatrix m = *args.fViewMatrix;
Florin Malitac6c5ead2018-04-11 15:33:40 -04001419 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1420 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001421
Greg Daniel6f5441a2020-01-28 17:02:49 -05001422 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001423 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001424 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1425 // We also know that we will not be using mipmaps. If things things weren't true we should
1426 // go through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001427 const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
1428 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001429 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001430
Greg Daniel6f5441a2020-01-28 17:02:49 -05001431 const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
1432 SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001433 auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001434 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001435 std::move(permutationsView),
1436 std::move(gradientView), m);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001437 }
1438
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001439 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001440 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001441 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001442 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1443 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1444 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001445 auto inner =
Brian Osmancb3d0872018-10-16 15:19:28 -04001446 GrConstColorProcessor::Make(SkPMColor4f::FromBytes_RGBA(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001447 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001448 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001449 }
bsalomonc21b09e2015-08-28 18:46:56 -07001450 // Emit zero.
Brian Osmanf28e55d2018-10-03 16:35:54 -04001451 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001452 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001453 }
1454
Greg Daniel7e1912a2018-02-08 09:15:33 -05001455 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1456 // also know that we will not be using mipmaps. If things things weren't true we should go
1457 // through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001458 const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
1459 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001460 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001461
Greg Daniel6f5441a2020-01-28 17:02:49 -05001462 const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
1463 SkASSERT(SkIsPow2(noiseBitmap.width()) && SkIsPow2(noiseBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001464 auto noiseView = GrMakeCachedBitmapProxyView(context, noiseBitmap);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001465
Greg Danielc52db712020-01-28 17:03:46 -05001466 if (permutationsView.proxy() && noiseView.proxy()) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001467 auto inner = GrPerlinNoise2Effect::Make(fType,
1468 fNumOctaves,
1469 fStitchTiles,
1470 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001471 std::move(permutationsView),
1472 std::move(noiseView),
Brian Salomonaff329b2017-08-11 09:40:37 -04001473 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001474 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001475 }
bsalomonc21b09e2015-08-28 18:46:56 -07001476 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001477}
1478
1479#endif
1480
Mike Reedf2ae2b22017-05-30 15:22:54 -04001481///////////////////////////////////////////////////////////////////////////////////////////////////
1482
Mike Reed832aa112018-05-18 11:48:50 -04001483static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1484 SkScalar seed) {
1485 if (!(baseX >= 0 && baseY >= 0)) {
1486 return false;
1487 }
1488 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1489 return false;
1490 }
1491 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1492 return false;
1493 }
1494 if (!SkScalarIsFinite(seed)) {
1495 return false;
1496 }
1497 return true;
1498}
1499
Mike Reedf2ae2b22017-05-30 15:22:54 -04001500sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1501 SkScalar baseFrequencyY,
1502 int numOctaves, SkScalar seed,
1503 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001504 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1505 return nullptr;
1506 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001507 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1508 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1509 tileSize));
1510}
1511
1512sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1513 SkScalar baseFrequencyY,
1514 int numOctaves, SkScalar seed,
1515 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001516 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1517 return nullptr;
1518 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001519 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1520 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1521 tileSize));
1522}
1523
1524sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1525 SkScalar baseFrequencyY,
1526 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001527 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1528 return nullptr;
1529 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001530 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1531 baseFrequencyX, baseFrequencyY, numOctaves, z,
1532 nullptr));
1533}
1534
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001535void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001536 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001537}