blob: f1b287a5c92a22415caa868b8a4b99fb51296403 [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 Nicholasd4efe682019-08-29 16:10:13 -0400839 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000840
Ethan Nicholas16464c32020-04-06 13:53:05 -0400841 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800842 "baseFrequency");
843 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000844
halcanary96fcdcc2015-08-27 07:41:13 -0700845 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800846 if (pne.stitchTiles()) {
Ethan Nicholas16464c32020-04-06 13:53:05 -0400847 fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800848 "stitchData");
849 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000850 }
851
sugoi@google.comd537af52013-06-10 13:59:25 +0000852 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
853 const char* chanCoordR = "0.125";
854 const char* chanCoordG = "0.375";
855 const char* chanCoordB = "0.625";
856 const char* chanCoordA = "0.875";
857 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000858 const char* stitchData = "stitchData";
859 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000860 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000861 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700862 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000863 const char* fractVal = "fractVal";
864 const char* uv = "uv";
865 const char* ab = "ab";
866 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700867 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000868 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000869 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
870 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
871 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400872 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 +0000873
sugoi@google.comd537af52013-06-10 13:59:25 +0000874 // Add noise function
Nico Webere50efdf2018-10-01 14:40:44 -0400875 const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400876 GrShaderVar(chanCoord, kHalf_GrSLType),
877 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000878 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000879
Nico Webere50efdf2018-10-01 14:40:44 -0400880 const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400881 GrShaderVar(chanCoord, kHalf_GrSLType),
882 GrShaderVar(noiseVec, kHalf2_GrSLType),
883 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000884 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000885
sugoi@google.comd537af52013-06-10 13:59:25 +0000886 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000887
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400888 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700889 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400890 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
891 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000892
893 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400894 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700895 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000896
897 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800898 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000899 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400900 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000901 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400902 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700903 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400904 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700905 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400906 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000907 }
908
909 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400910 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400911 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000912
913 // Get permutation for x
914 {
915 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400916 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000917
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400918 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
Brian Salomond19cd762020-01-06 13:16:31 -0500919 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000920 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000921 }
922
923 // Get permutation for x + 1
924 {
925 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400926 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000927
sugoi@google.comd537af52013-06-10 13:59:25 +0000928 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
Brian Salomond19cd762020-01-06 13:16:31 -0500929 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000930 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000931 }
932
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000933#if defined(SK_BUILD_FOR_ANDROID)
934 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
935 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
936 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
937 // (or 0.484368 here). The following rounding operation prevents these precision issues from
938 // affecting the result of the noise by making sure that we only have multiples of 1/255.
939 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400940 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 +0000941 latticeIdx, latticeIdx);
942#endif
943
sugoi@google.come3b4c502013-04-05 13:47:09 +0000944 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400945 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000946
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400947 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000948 // Compute u, at offset (0,0)
949 {
950 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400951 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
952 noiseCode.appendf("\n\thalf4 %s = ", lattice);
Brian Salomond19cd762020-01-06 13:16:31 -0500953 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000954 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
955 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000956 }
957
sugoi@google.comd537af52013-06-10 13:59:25 +0000958 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000959 // Compute v, at offset (-1,0)
960 {
961 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400962 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000963 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500964 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000965 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
966 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000967 }
968
969 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400970 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000971 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 +0000972
sugoi@google.comd537af52013-06-10 13:59:25 +0000973 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000974 // Compute v, at offset (-1,-1)
975 {
976 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400977 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000978 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500979 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000980 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
981 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000982 }
983
sugoi@google.comd537af52013-06-10 13:59:25 +0000984 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000985 // Compute u, at offset (0,-1)
986 {
987 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400988 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000989 noiseCode.append("\n\tlattice = ");
Brian Salomond19cd762020-01-06 13:16:31 -0500990 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000991 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
992 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000993 }
994
995 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000996 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 +0000997 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +0000998 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000999
sugoi@google.comd537af52013-06-10 13:59:25 +00001000 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -08001001 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001002 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001003 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
1004 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001005 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001006 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001007 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
1008 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001009 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001010
sugoi@google.comd537af52013-06-10 13:59:25 +00001011 // There are rounding errors if the floor operation is not performed here
Ethan Nicholase1f55022019-02-05 17:17:40 -05001012 fragBuilder->codeAppendf("\n\t\thalf2 %s = half2(floor(%s.xy) * %s);",
egdaniel4ca2e602015-11-18 08:01:26 -08001013 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001014
1015 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001016 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001017
robertphillipsbf536af2016-02-04 06:11:53 -08001018 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001019 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001020 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001021 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001022
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001023 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001024
1025 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001026 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001027
Mike Reedf2ae2b22017-05-30 15:22:54 -04001028 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001029 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001030 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001031 }
robertphillipsbf536af2016-02-04 06:11:53 -08001032 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001033 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001034 "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 +00001035 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1036 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1037 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1038 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1039 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1040 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001041 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001042 "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 +00001043 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1044 noiseFuncName.c_str(), chanCoordR, noiseVec,
1045 noiseFuncName.c_str(), chanCoordG, noiseVec,
1046 noiseFuncName.c_str(), chanCoordB, noiseVec,
1047 noiseFuncName.c_str(), chanCoordA, noiseVec);
1048 }
Florin Malita14d54c22017-05-18 11:52:59 -04001049 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001050 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001051 }
egdaniel4ca2e602015-11-18 08:01:26 -08001052 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001053
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001054 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001055 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001056
robertphillipsbf536af2016-02-04 06:11:53 -08001057 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001058 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001059 }
egdaniel4ca2e602015-11-18 08:01:26 -08001060 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001061
Florin Malita14d54c22017-05-18 11:52:59 -04001062 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001063 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1064 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001065 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001066 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001067 }
1068
sugoi@google.come3b4c502013-04-05 13:47:09 +00001069 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001070 fragBuilder->codeAppendf("\n\t\t%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001071
1072 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001073 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001074 args.fOutputColor, args.fOutputColor,
1075 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001076}
1077
Brian Salomon94efbf52016-11-29 13:43:05 -05001078void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001079 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001080 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001081
bsalomon63e99f72014-07-21 08:03:14 -07001082 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001083
1084 key = key << 3; // Make room for next 3 bits
1085
1086 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001087 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001088 key |= 0x1;
1089 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001090 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001091 key |= 0x2;
1092 break;
1093 default:
1094 // leave key at 0
1095 break;
1096 }
1097
1098 if (turbulence.stitchTiles()) {
1099 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1100 }
1101
bsalomon63e99f72014-07-21 08:03:14 -07001102 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001103}
1104
egdaniel018fb622015-10-28 07:26:40 -07001105void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001106 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001107 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001108
Mike Reedf2ae2b22017-05-30 15:22:54 -04001109 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001110
1111 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001112 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001113
sugoi@google.com4775cba2013-04-17 13:46:56 +00001114 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001115 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001116 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001117 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001118 }
1119}
1120
sugoi@google.come3b4c502013-04-05 13:47:09 +00001121/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001122
1123class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1124public:
1125 void emitCode(EmitArgs&) override;
1126
1127 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1128
1129protected:
1130 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1131
1132private:
1133 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001134 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1135
1136 typedef GrGLSLFragmentProcessor INHERITED;
1137};
1138
1139/////////////////////////////////////////////////////////////////////
1140
1141class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1142public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001143 static std::unique_ptr<GrFragmentProcessor> Make(
1144 int octaves, SkScalar z,
1145 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -05001146 GrSurfaceProxyView permutationsView, GrSurfaceProxyView gradientView,
Brian Salomonaff329b2017-08-11 09:40:37 -04001147 const SkMatrix& matrix) {
1148 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
Greg Danielc52db712020-01-28 17:03:46 -05001149 octaves, z, std::move(paintingData), std::move(permutationsView),
1150 std::move(gradientView), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001151 }
1152
Mike Reedf2ae2b22017-05-30 15:22:54 -04001153 const char* name() const override { return "ImprovedPerlinNoise"; }
1154
Brian Salomonaff329b2017-08-11 09:40:37 -04001155 std::unique_ptr<GrFragmentProcessor> clone() const override {
1156 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001157 }
1158
Mike Reedf2ae2b22017-05-30 15:22:54 -04001159 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1160 SkScalar z() const { return fZ; }
1161 int octaves() const { return fOctaves; }
Brian Salomon7d8b3972019-11-26 22:34:44 -05001162 const SkMatrix& matrix() const { return fCoordTransform.matrix(); }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001163
1164private:
1165 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1166 return new GrGLImprovedPerlinNoise;
1167 }
1168
1169 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1170 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1171 }
1172
1173 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1174 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1175 return fZ == fZ &&
1176 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1177 }
1178
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001179 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001180 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Greg Danielc52db712020-01-28 17:03:46 -05001181 GrSurfaceProxyView permutationsView,
1182 GrSurfaceProxyView gradientView,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001183 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001184 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001185 , fOctaves(octaves)
1186 , fZ(z)
Greg Danielc52db712020-01-28 17:03:46 -05001187 , fPermutationsSampler(std::move(permutationsView))
1188 , fGradientSampler(std::move(gradientView))
Florin Malitab365cf52017-05-30 17:18:01 -04001189 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001190 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -05001191 fCoordTransform = GrCoordTransform(matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001192 this->addCoordTransform(&fCoordTransform);
1193 }
1194
Brian Salomon4331e462017-07-26 14:58:11 -04001195 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001196 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001197 , fCoordTransform(that.fCoordTransform)
1198 , fOctaves(that.fOctaves)
1199 , fZ(that.fZ)
1200 , fPermutationsSampler(that.fPermutationsSampler)
1201 , fGradientSampler(that.fGradientSampler)
1202 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001203 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -04001204 this->addCoordTransform(&fCoordTransform);
1205 }
1206
Brian Salomonf7dcd762018-07-30 14:48:15 -04001207 const TextureSampler& onTextureSampler(int i) const override {
1208 return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
1209 }
1210
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001211 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001212
1213 GrCoordTransform fCoordTransform;
1214 int fOctaves;
1215 SkScalar fZ;
1216 TextureSampler fPermutationsSampler;
1217 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001218 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001219
1220 typedef GrFragmentProcessor INHERITED;
1221};
1222
1223/////////////////////////////////////////////////////////////////////
1224GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1225
1226#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001227std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1228 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001229 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1230 0.99f);
1231 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1232 0.99f);
1233 int numOctaves = d->fRandom->nextRangeU(2, 10);
1234 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1235
1236 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1237 baseFrequencyY,
1238 numOctaves,
1239 z));
1240
1241 GrTest::TestAsFPArgs asFPArgs(d);
1242 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1243}
1244#endif
1245
1246void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001247 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001248 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1249 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Ethan Nicholasd4efe682019-08-29 16:10:13 -04001250 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001251
Ethan Nicholas16464c32020-04-06 13:53:05 -04001252 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001253 "baseFrequency");
1254 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1255
Ethan Nicholas16464c32020-04-06 13:53:05 -04001256 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001257 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1258
1259 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001260 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001261 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001262 };
1263 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001264 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001265 fadeArgs,
1266 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1267 &fadeFuncName);
1268
1269 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001270 const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001271 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001272 };
1273 SkString permFuncName;
1274 SkString permCode("return ");
1275 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1276 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Brian Salomond19cd762020-01-06 13:16:31 -05001277 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0],
1278 "float2(fract(x / 256.0), 0.0)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001279 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001280 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001281 permCode.c_str(), &permFuncName);
1282
1283 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001284 const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001285 GrShaderVar("x", kHalf_GrSLType),
1286 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001287 };
1288 SkString gradFuncName;
Ethan Nicholase1f55022019-02-05 17:17:40 -05001289 SkString gradCode("return half(dot(");
Brian Salomond19cd762020-01-06 13:16:31 -05001290 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1],
1291 "float2(fract(x / 16.0), 0.0)");
Ethan Nicholase1f55022019-02-05 17:17:40 -05001292 gradCode.append(".rgb * 255.0 - float3(1.0), p));");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001293 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001294 gradCode.c_str(), &gradFuncName);
1295
1296 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001297 const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001298 GrShaderVar("a", kHalf_GrSLType),
1299 GrShaderVar("b", kHalf_GrSLType),
1300 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001301 };
1302 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001303 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001304 "return a + w * (b - a);", &lerpFuncName);
1305
1306 // noise function
Nico Webere50efdf2018-10-01 14:40:44 -04001307 const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001308 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001309 };
1310 SkString noiseFuncName;
1311 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001312 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001313 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001314 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1315 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1316 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1317 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1318 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1319 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1320 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1321 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001322 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1323 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001324 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 -04001325 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001326 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001327 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001328 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
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(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001331 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1332 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001333 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001334 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001335 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001336 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001337 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 -04001338 gradFuncName.c_str(), permFuncName.c_str());
1339 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001340 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001341 noiseCode.c_str(), &noiseFuncName);
1342
1343 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001344 const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001345 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001346 };
1347 SkString noiseOctavesFuncName;
1348 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001349 noiseOctavesCode.append("half result = 0.0;");
1350 noiseOctavesCode.append("half ratio = 1.0;");
1351 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001352 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1353 noiseOctavesCode.append("p *= 2.0;");
1354 noiseOctavesCode.append("ratio *= 2.0;");
1355 noiseOctavesCode.append("}");
1356 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001357 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001358 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1359
Ethan Nicholase1f55022019-02-05 17:17:40 -05001360 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", vCoords.c_str(), baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001361 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001362 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001363 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001364 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001365 fragBuilder->codeAppendf("half b = %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 a = %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("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001370
1371 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001372 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001373
1374 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001375 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001376 args.fOutputColor, args.fOutputColor,
1377 args.fOutputColor, args.fOutputColor);
1378}
1379
1380void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1381 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001382 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1383 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001384}
1385
1386void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1387 const GrFragmentProcessor& processor) {
1388 INHERITED::onSetData(pdman, processor);
1389
1390 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1391
1392 const SkVector& baseFrequency = noise.baseFrequency();
1393 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1394
Mike Reedf2ae2b22017-05-30 15:22:54 -04001395 pdman.set1f(fZUni, noise.z());
1396}
1397
1398/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001399std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001400 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001401 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001402
Florin Malita52f02912020-03-09 16:33:17 -04001403 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Ethan Nicholas82940152019-01-10 13:58:14 -05001404 const auto paintMatrix = SkMatrix::Concat(*args.fViewMatrix, *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001405
Mike Reedf2ae2b22017-05-30 15:22:54 -04001406 // Either we don't stitch tiles, either we have a valid tile size
1407 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1408
Florin Malitab365cf52017-05-30 17:18:01 -04001409 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001410 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001411 fSeed,
1412 fBaseFrequencyX,
1413 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001414 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001415
1416 SkMatrix m = *args.fViewMatrix;
Florin Malitac6c5ead2018-04-11 15:33:40 -04001417 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1418 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001419
Greg Daniel6f5441a2020-01-28 17:02:49 -05001420 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001421 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001422 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1423 // We also know that we will not be using mipmaps. If things things weren't true we should
1424 // go through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001425 const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
1426 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001427 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001428
Greg Daniel6f5441a2020-01-28 17:02:49 -05001429 const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
1430 SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001431 auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001432 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001433 std::move(permutationsView),
1434 std::move(gradientView), m);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001435 }
1436
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001437 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001438 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001439 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001440 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1441 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1442 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001443 auto inner =
Brian Osmancb3d0872018-10-16 15:19:28 -04001444 GrConstColorProcessor::Make(SkPMColor4f::FromBytes_RGBA(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001445 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001446 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001447 }
bsalomonc21b09e2015-08-28 18:46:56 -07001448 // Emit zero.
Brian Osmanf28e55d2018-10-03 16:35:54 -04001449 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001450 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001451 }
1452
Greg Daniel7e1912a2018-02-08 09:15:33 -05001453 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1454 // also know that we will not be using mipmaps. If things things weren't true we should go
1455 // through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001456 const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
1457 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001458 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001459
Greg Daniel6f5441a2020-01-28 17:02:49 -05001460 const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
1461 SkASSERT(SkIsPow2(noiseBitmap.width()) && SkIsPow2(noiseBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001462 auto noiseView = GrMakeCachedBitmapProxyView(context, noiseBitmap);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001463
Greg Danielc52db712020-01-28 17:03:46 -05001464 if (permutationsView.proxy() && noiseView.proxy()) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001465 auto inner = GrPerlinNoise2Effect::Make(fType,
1466 fNumOctaves,
1467 fStitchTiles,
1468 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001469 std::move(permutationsView),
1470 std::move(noiseView),
Brian Salomonaff329b2017-08-11 09:40:37 -04001471 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001472 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001473 }
bsalomonc21b09e2015-08-28 18:46:56 -07001474 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001475}
1476
1477#endif
1478
Mike Reedf2ae2b22017-05-30 15:22:54 -04001479///////////////////////////////////////////////////////////////////////////////////////////////////
1480
Mike Reed832aa112018-05-18 11:48:50 -04001481static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1482 SkScalar seed) {
1483 if (!(baseX >= 0 && baseY >= 0)) {
1484 return false;
1485 }
1486 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1487 return false;
1488 }
1489 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1490 return false;
1491 }
1492 if (!SkScalarIsFinite(seed)) {
1493 return false;
1494 }
1495 return true;
1496}
1497
Mike Reedf2ae2b22017-05-30 15:22:54 -04001498sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1499 SkScalar baseFrequencyY,
1500 int numOctaves, SkScalar seed,
1501 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001502 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1503 return nullptr;
1504 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001505 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1506 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1507 tileSize));
1508}
1509
1510sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1511 SkScalar baseFrequencyY,
1512 int numOctaves, SkScalar seed,
1513 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001514 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1515 return nullptr;
1516 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001517 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1518 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1519 tileSize));
1520}
1521
1522sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1523 SkScalar baseFrequencyY,
1524 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001525 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1526 return nullptr;
1527 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001528 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1529 baseFrequencyX, baseFrequencyY, numOctaves, z,
1530 nullptr));
1531}
1532
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001533void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001534 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001535}