blob: 46cf30cb82dc41040d0c03d911edbbd7fb8f2d33 [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/SkMakeUnique.h"
16#include "src/core/SkReadBuffer.h"
17#include "src/core/SkWriteBuffer.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000018
19#if SK_SUPPORT_GPU
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/private/GrRecordingContext.h"
21#include "src/gpu/GrCoordTransform.h"
22#include "src/gpu/GrRecordingContextPriv.h"
23#include "src/gpu/SkGr.h"
24#include "src/gpu/effects/generated/GrConstColorProcessor.h"
25#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
26#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
27#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
28#include "src/gpu/glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000029#endif
30
31static const int kBlockSize = 256;
32static const int kBlockMask = kBlockSize - 1;
33static const int kPerlinNoise = 4096;
34static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
35
Mike Reedf2ae2b22017-05-30 15:22:54 -040036static uint8_t improved_noise_permutations[] = {
37 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
38 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
39 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
40 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
41 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
42 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
43 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
44 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
45 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
46 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
47 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
48 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
49 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
50 141, 128, 195, 78, 66, 215, 61, 156, 180,
51 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
52 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
53 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
54 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
55 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
56 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
57 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
58 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
59 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
60 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
61 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
62 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
63 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
64 141, 128, 195, 78, 66, 215, 61, 156, 180
65};
66
67class SkPerlinNoiseShaderImpl : public SkShaderBase {
68public:
Florin Malita83223bc2017-05-31 14:14:05 -040069 struct StitchData {
70 StitchData()
71 : fWidth(0)
72 , fWrapX(0)
73 , fHeight(0)
74 , fWrapY(0)
75 {}
76
Florin Malita102c8cf2018-06-05 17:37:12 -040077 StitchData(SkScalar w, SkScalar h)
78 : fWidth(SkTMin(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
79 , fWrapX(kPerlinNoise + fWidth)
80 , fHeight(SkTMin(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
81 , fWrapY(kPerlinNoise + fHeight) {}
82
Florin Malita83223bc2017-05-31 14:14:05 -040083 bool operator==(const StitchData& other) const {
84 return fWidth == other.fWidth &&
85 fWrapX == other.fWrapX &&
86 fHeight == other.fHeight &&
87 fWrapY == other.fWrapY;
88 }
89
90 int fWidth; // How much to subtract to wrap for stitching.
91 int fWrapX; // Minimum value to wrap.
92 int fHeight;
93 int fWrapY;
94 };
95
96 struct PaintingData {
97 PaintingData(const SkISize& tileSize, SkScalar seed,
98 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
99 const SkMatrix& matrix)
100 {
Ethan Nicholas82940152019-01-10 13:58:14 -0500101 SkVector tileVec;
102 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
103 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -0400104
Ethan Nicholas82940152019-01-10 13:58:14 -0500105 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -0500106 if (!matrix.decomposeScale(&scale, nullptr)) {
107 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
108 }
Ethan Nicholas82940152019-01-10 13:58:14 -0500109 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
110 baseFrequencyY * SkScalarInvert(scale.height()));
111 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -0400112 this->init(seed);
113 if (!fTileSize.isEmpty()) {
114 this->stitch();
115 }
116
117 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500118 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
119 SkPixmap permutationsPixmap(info, fLatticeSelector, info.minRowBytes());
120 fPermutationsImage = SkImage::MakeFromRaster(permutationsPixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400121
Greg Daniel7e1912a2018-02-08 09:15:33 -0500122 info = SkImageInfo::MakeN32Premul(kBlockSize, 4);
123 SkPixmap noisePixmap(info, fNoise[0][0], info.minRowBytes());
124 fNoiseImage = SkImage::MakeFromRaster(noisePixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400125
Greg Daniel7e1912a2018-02-08 09:15:33 -0500126 info = SkImageInfo::MakeA8(256, 1);
127 SkPixmap impPermutationsPixmap(info, improved_noise_permutations, info.minRowBytes());
128 fImprovedPermutationsImage = SkImage::MakeFromRaster(impPermutationsPixmap, nullptr,
129 nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400130
Florin Malita83223bc2017-05-31 14:14:05 -0400131 static uint8_t gradients[] = { 2, 2, 1, 0,
132 0, 2, 1, 0,
133 2, 0, 1, 0,
134 0, 0, 1, 0,
135 2, 1, 2, 0,
136 0, 1, 2, 0,
137 2, 1, 0, 0,
138 0, 1, 0, 0,
139 1, 2, 2, 0,
140 1, 0, 2, 0,
141 1, 2, 0, 0,
142 1, 0, 0, 0,
143 2, 2, 1, 0,
144 1, 0, 2, 0,
145 0, 2, 1, 0,
146 1, 0, 0, 0 };
Greg Daniel7e1912a2018-02-08 09:15:33 -0500147 info = SkImageInfo::MakeN32Premul(16, 1);
148 SkPixmap gradPixmap(info, gradients, info.minRowBytes());
149 fGradientImage = SkImage::MakeFromRaster(gradPixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400150 #endif
151 }
152
Brian Salomon4331e462017-07-26 14:58:11 -0400153 #if SK_SUPPORT_GPU
154 PaintingData(const PaintingData& that)
155 : fSeed(that.fSeed)
156 , fTileSize(that.fTileSize)
157 , fBaseFrequency(that.fBaseFrequency)
158 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel7e1912a2018-02-08 09:15:33 -0500159 , fPermutationsImage(that.fPermutationsImage)
160 , fNoiseImage(that.fNoiseImage)
161 , fImprovedPermutationsImage(that.fImprovedPermutationsImage)
162 , fGradientImage(that.fGradientImage) {
Brian Salomon4331e462017-07-26 14:58:11 -0400163 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
164 memcpy(fNoise, that.fNoise, sizeof(fNoise));
165 memcpy(fGradient, that.fGradient, sizeof(fGradient));
166 }
167 #endif
168
Florin Malita83223bc2017-05-31 14:14:05 -0400169 int fSeed;
170 uint8_t fLatticeSelector[kBlockSize];
171 uint16_t fNoise[4][kBlockSize][2];
172 SkPoint fGradient[4][kBlockSize];
173 SkISize fTileSize;
174 SkVector fBaseFrequency;
175 StitchData fStitchDataInit;
176
177 private:
178
179 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500180 sk_sp<SkImage> fPermutationsImage;
181 sk_sp<SkImage> fNoiseImage;
182 sk_sp<SkImage> fImprovedPermutationsImage;
183 sk_sp<SkImage> fGradientImage;
Florin Malita83223bc2017-05-31 14:14:05 -0400184 #endif
185
186 inline int random() {
187 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
188 static const int gRandQ = 127773; // m / a
189 static const int gRandR = 2836; // m % a
190
191 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
192 if (result <= 0)
193 result += kRandMaximum;
194 fSeed = result;
195 return result;
196 }
197
198 // Only called once. Could be part of the constructor.
199 void init(SkScalar seed)
200 {
201 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
202
203 // According to the SVG spec, we must truncate (not round) the seed value.
204 fSeed = SkScalarTruncToInt(seed);
205 // The seed value clamp to the range [1, kRandMaximum - 1].
206 if (fSeed <= 0) {
207 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
208 }
209 if (fSeed > kRandMaximum - 1) {
210 fSeed = kRandMaximum - 1;
211 }
212 for (int channel = 0; channel < 4; ++channel) {
213 for (int i = 0; i < kBlockSize; ++i) {
214 fLatticeSelector[i] = i;
215 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
216 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
217 }
218 }
219 for (int i = kBlockSize - 1; i > 0; --i) {
220 int k = fLatticeSelector[i];
221 int j = random() % kBlockSize;
222 SkASSERT(j >= 0);
223 SkASSERT(j < kBlockSize);
224 fLatticeSelector[i] = fLatticeSelector[j];
225 fLatticeSelector[j] = k;
226 }
227
228 // Perform the permutations now
229 {
230 // Copy noise data
231 uint16_t noise[4][kBlockSize][2];
232 for (int i = 0; i < kBlockSize; ++i) {
233 for (int channel = 0; channel < 4; ++channel) {
234 for (int j = 0; j < 2; ++j) {
235 noise[channel][i][j] = fNoise[channel][i][j];
236 }
237 }
238 }
239 // Do permutations on noise data
240 for (int i = 0; i < kBlockSize; ++i) {
241 for (int channel = 0; channel < 4; ++channel) {
242 for (int j = 0; j < 2; ++j) {
243 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
244 }
245 }
246 }
247 }
248
249 // Half of the largest possible value for 16 bit unsigned int
250 static const SkScalar gHalfMax16bits = 32767.5f;
251
252 // Compute gradients from permutated noise data
253 for (int channel = 0; channel < 4; ++channel) {
254 for (int i = 0; i < kBlockSize; ++i) {
255 fGradient[channel][i] = SkPoint::Make(
256 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
257 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
258 fGradient[channel][i].normalize();
259 // Put the normalized gradient back into the noise data
260 fNoise[channel][i][0] = SkScalarRoundToInt(
261 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
262 fNoise[channel][i][1] = SkScalarRoundToInt(
263 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
264 }
265 }
266 }
267
268 // Only called once. Could be part of the constructor.
269 void stitch() {
270 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
271 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
272 SkASSERT(tileWidth > 0 && tileHeight > 0);
273 // When stitching tiled turbulence, the frequencies must be adjusted
274 // so that the tile borders will be continuous.
275 if (fBaseFrequency.fX) {
276 SkScalar lowFrequencx =
277 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
278 SkScalar highFrequencx =
279 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
280 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400281 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
282 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400283 fBaseFrequency.fX = lowFrequencx;
284 } else {
285 fBaseFrequency.fX = highFrequencx;
286 }
287 }
288 if (fBaseFrequency.fY) {
289 SkScalar lowFrequency =
290 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
291 SkScalar highFrequency =
292 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400293 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
294 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400295 fBaseFrequency.fY = lowFrequency;
296 } else {
297 fBaseFrequency.fY = highFrequency;
298 }
299 }
300 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400301 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
302 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400303 }
304
305 public:
306
307#if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500308 const sk_sp<SkImage> getPermutationsImage() const { return fPermutationsImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400309
Greg Daniel7e1912a2018-02-08 09:15:33 -0500310 const sk_sp<SkImage> getNoiseImage() const { return fNoiseImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400311
Greg Daniel7e1912a2018-02-08 09:15:33 -0500312 const sk_sp<SkImage> getImprovedPermutationsImage() const {
313 return fImprovedPermutationsImage;
314 }
Florin Malita83223bc2017-05-31 14:14:05 -0400315
Greg Daniel7e1912a2018-02-08 09:15:33 -0500316 const sk_sp<SkImage> getGradientImage() const { return fGradientImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400317#endif
318 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400319
320 /**
321 * About the noise types : the difference between the first 2 is just minor tweaks to the
322 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
323 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
324 * doing :
325 * kFractalNoise_Type : noise * 0.5 + 0.5
326 * kTurbulence_Type : abs(noise)
327 * Very little differences between the 2 types, although you can tell the difference visually.
328 * "Improved" is based on the Improved Perlin Noise algorithm described at
329 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
330 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
331 * changes to the noise, making it suitable for animated noise.
332 */
333 enum Type {
334 kFractalNoise_Type,
335 kTurbulence_Type,
336 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500337 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400338 };
339
Robert Phillipsbee27322018-01-23 09:58:18 -0500340 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
341
Mike Reedf2ae2b22017-05-30 15:22:54 -0400342 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
343 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
344 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400345
346 class PerlinNoiseShaderContext : public Context {
347 public:
348 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400349
350 void shadeSpan(int x, int y, SkPMColor[], int count) override;
351
352 private:
353 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
354 SkScalar calculateTurbulenceValueForPoint(
355 int channel,
356 StitchData& stitchData, const SkPoint& point) const;
357 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
358 SkScalar noise2D(int channel,
359 const StitchData& stitchData, const SkPoint& noiseVector) const;
360
Florin Malita83223bc2017-05-31 14:14:05 -0400361 SkMatrix fMatrix;
362 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400363
364 typedef Context INHERITED;
365 };
366
367#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500368 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400369#endif
370
Mike Reedf2ae2b22017-05-30 15:22:54 -0400371protected:
372 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400373#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400374 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400375#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400376
377private:
Mike Klein4fee3232018-10-18 17:27:16 -0400378 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
379
Mike Reedf2ae2b22017-05-30 15:22:54 -0400380 const SkPerlinNoiseShaderImpl::Type fType;
381 const SkScalar fBaseFrequencyX;
382 const SkScalar fBaseFrequencyY;
383 const int fNumOctaves;
384 const SkScalar fSeed;
385 const SkISize fTileSize;
386 const bool fStitchTiles;
387
388 friend class ::SkPerlinNoiseShader;
389
390 typedef SkShaderBase INHERITED;
391};
392
sugoi@google.come3b4c502013-04-05 13:47:09 +0000393namespace {
394
395// noiseValue is the color component's value (or color)
396// limitValue is the maximum perlin noise array index value allowed
397// newValue is the current noise dimension (either width or height)
398inline int checkNoise(int noiseValue, int limitValue, int newValue) {
399 // If the noise value would bring us out of bounds of the current noise array while we are
400 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
401 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
402 if (noiseValue >= limitValue) {
403 noiseValue -= newValue;
404 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000405 return noiseValue;
406}
407
408inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500409 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000410}
411
412} // end namespace
413
Mike Reedf2ae2b22017-05-30 15:22:54 -0400414SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500415 SkScalar baseFrequencyX,
416 SkScalar baseFrequencyY,
417 int numOctaves,
418 SkScalar seed,
419 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000420 : fType(type)
421 , fBaseFrequencyX(baseFrequencyX)
422 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500423 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000424 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700425 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000426 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000427{
Robert Phillipsbee27322018-01-23 09:58:18 -0500428 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400429 SkASSERT(fBaseFrequencyX >= 0);
430 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400431}
432
Florin Malita14d54c22017-05-18 11:52:59 -0400433sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500434 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500435
reed9fa60da2014-08-21 07:59:51 -0700436 SkScalar freqX = buffer.readScalar();
437 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500438 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500439
reed9fa60da2014-08-21 07:59:51 -0700440 SkScalar seed = buffer.readScalar();
441 SkISize tileSize;
442 tileSize.fWidth = buffer.readInt();
443 tileSize.fHeight = buffer.readInt();
444
445 switch (type) {
446 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400447 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700448 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400449 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
450 case kImprovedNoise_Type:
451 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700452 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500453 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500454 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700455 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700456 }
457}
458
Florin Malita14d54c22017-05-18 11:52:59 -0400459void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000460 buffer.writeInt((int) fType);
461 buffer.writeScalar(fBaseFrequencyX);
462 buffer.writeScalar(fBaseFrequencyY);
463 buffer.writeInt(fNumOctaves);
464 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000465 buffer.writeInt(fTileSize.fWidth);
466 buffer.writeInt(fTileSize.fHeight);
467}
468
Florin Malita14d54c22017-05-18 11:52:59 -0400469SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700470 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000471 struct Noise {
472 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700473 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000474 SkScalar noisePositionFractionValue;
475 Noise(SkScalar component)
476 {
477 SkScalar position = component + kPerlinNoise;
478 noisePositionIntegerValue = SkScalarFloorToInt(position);
479 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700480 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000481 }
482 };
483 Noise noiseX(noiseVector.x());
484 Noise noiseY(noiseVector.y());
485 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400486 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000487 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000488 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000489 noiseX.noisePositionIntegerValue =
490 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
491 noiseY.noisePositionIntegerValue =
492 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700493 noiseX.nextNoisePositionIntegerValue =
494 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
495 noiseY.nextNoisePositionIntegerValue =
496 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000497 }
498 noiseX.noisePositionIntegerValue &= kBlockMask;
499 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700500 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
501 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400502 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
503 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700504 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
505 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
506 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
507 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000508 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
509 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400510
Hal Canaryfda46002017-05-08 17:17:47 -0400511 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
512 return 0; // Check for pathological inputs.
513 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400514
sugoi@google.come3b4c502013-04-05 13:47:09 +0000515 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
516 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
517 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400518 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000519 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400520 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000521 SkScalar a = SkScalarInterp(u, v, sx);
522 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400523 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000524 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400525 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000526 SkScalar b = SkScalarInterp(u, v, sx);
527 return SkScalarInterp(a, b, sy);
528}
529
Florin Malita14d54c22017-05-18 11:52:59 -0400530SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700531 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400532 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000533 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000534 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400535 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000536 }
537 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400538 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
539 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000540 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000541 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700542 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700543 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
544 noise : SkScalarAbs(noise);
545 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000546 noiseVector.fX *= 2;
547 noiseVector.fY *= 2;
548 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000549 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000550 // Update stitch values
Florin Malita102c8cf2018-06-05 17:37:12 -0400551 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
552 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000553 }
554 }
555
556 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
557 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000558 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400559 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000560 }
561
562 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700563 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000564 }
565
566 // Clamp result
567 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
568}
569
Mike Reedf2ae2b22017-05-30 15:22:54 -0400570////////////////////////////////////////////////////////////////////////////////////////////////////
571// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
572static SkScalar fade(SkScalar t) {
573 return t * t * t * (t * (t * 6 - 15) + 10);
574}
575
576static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
577 return a + t * (b - a);
578}
579
580static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
581 int h = hash & 15;
582 SkScalar u = h < 8 ? x : y;
583 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
584 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
585}
586
587SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
588 int channel, const SkPoint& point) const {
589 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
590 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
591 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
592 // z offset between different channels, chosen arbitrarily
593 static const SkScalar CHANNEL_DELTA = 1000.0f;
594 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
595 SkScalar result = 0;
596 SkScalar ratio = SK_Scalar1;
597 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
598 int X = SkScalarFloorToInt(x) & 255;
599 int Y = SkScalarFloorToInt(y) & 255;
600 int Z = SkScalarFloorToInt(z) & 255;
601 SkScalar px = x - SkScalarFloorToScalar(x);
602 SkScalar py = y - SkScalarFloorToScalar(y);
603 SkScalar pz = z - SkScalarFloorToScalar(z);
604 SkScalar u = fade(px);
605 SkScalar v = fade(py);
606 SkScalar w = fade(pz);
607 uint8_t* permutations = improved_noise_permutations;
608 int A = permutations[X] + Y;
609 int AA = permutations[A] + Z;
610 int AB = permutations[A + 1] + Z;
611 int B = permutations[X + 1] + Y;
612 int BA = permutations[B] + Z;
613 int BB = permutations[B + 1] + Z;
614 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
615 grad(permutations[BA ], px - 1, py , pz )),
616 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
617 grad(permutations[BB ], px - 1, py - 1, pz ))),
618 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
619 grad(permutations[BA + 1], px - 1, py , pz - 1)),
620 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
621 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
622 ratio;
623 x *= 2;
624 y *= 2;
625 ratio *= 2;
626 }
627 result = SkScalarClampMax((result + 1.0f) / 2.0f, 1.0f);
628 return result;
629}
630////////////////////////////////////////////////////////////////////////////////////////////////////
631
Florin Malita14d54c22017-05-18 11:52:59 -0400632SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000633 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400634 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000635 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000636 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000637 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
638 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
639
640 U8CPU rgba[4];
641 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400642 SkScalar value;
643 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
644 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
645 }
646 else {
647 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
648 }
649 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000650 }
651 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
652}
653
Mike Reede92aae62018-10-17 10:21:51 -0400654#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400655SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400656 SkArenaAlloc* alloc) const {
Mike Reed011d1662019-02-28 17:19:25 -0500657 // should we pay attention to rec's device-colorspace?
Herb Derby83e939b2017-02-07 14:25:11 -0500658 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000659}
Mike Reede92aae62018-10-17 10:21:51 -0400660#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000661
Florin Malita83223bc2017-05-31 14:14:05 -0400662static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
663 const SkShaderBase& shader) {
664 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
665 if (rec.fLocalMatrix) {
666 matrix.preConcat(*rec.fLocalMatrix);
667 }
668
669 return matrix;
670}
671
Florin Malita14d54c22017-05-18 11:52:59 -0400672SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
673 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000674 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400675 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
676 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
677 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000678{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000679 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
680 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400681 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
682 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700683}
684
Florin Malita14d54c22017-05-18 11:52:59 -0400685void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000686 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000687 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
688 StitchData stitchData;
689 for (int i = 0; i < count; ++i) {
690 result[i] = shade(point, stitchData);
691 point.fX += SK_Scalar1;
692 }
693}
694
sugoi@google.come3b4c502013-04-05 13:47:09 +0000695/////////////////////////////////////////////////////////////////////
696
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000697#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000698
egdaniel64c47282015-11-13 06:54:19 -0800699class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000700public:
robertphillips9cdb9922016-02-03 12:25:40 -0800701 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000702
Mike Reedf2ae2b22017-05-30 15:22:54 -0400703 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000704
wangyixb1daa862015-08-18 11:29:31 -0700705protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400706 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700707
sugoi@google.com4775cba2013-04-17 13:46:56 +0000708private:
egdaniel018fb622015-10-28 07:26:40 -0700709 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700710 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700711
egdaniel64c47282015-11-13 06:54:19 -0800712 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000713};
714
715/////////////////////////////////////////////////////////////////////
716
Mike Reedf2ae2b22017-05-30 15:22:54 -0400717class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000718public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400719 static std::unique_ptr<GrFragmentProcessor> Make(
720 SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
721 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
722 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> noiseProxy,
723 const SkMatrix& matrix) {
724 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
725 type, numOctaves, stitchTiles, std::move(paintingData),
726 std::move(permutationsProxy), std::move(noiseProxy), matrix));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000727 }
728
mtklein36352bf2015-03-25 18:17:31 -0700729 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800730
Brian Salomonaff329b2017-08-11 09:40:37 -0400731 std::unique_ptr<GrFragmentProcessor> clone() const override {
732 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400733 }
734
Mike Reedf2ae2b22017-05-30 15:22:54 -0400735 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000736
Florin Malita14d54c22017-05-18 11:52:59 -0400737 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700738 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700739 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700740 int numOctaves() const { return fNumOctaves; }
Brian Salomon7d8b3972019-11-26 22:34:44 -0500741 const SkMatrix& matrix() const { return fCoordTransform.matrix(); }
senorblancof3b50272014-06-16 10:49:58 -0700742
sugoi@google.come3b4c502013-04-05 13:47:09 +0000743private:
egdaniel57d3b032015-11-13 11:57:27 -0800744 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800745 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700746 }
747
Brian Salomon94efbf52016-11-29 13:43:05 -0500748 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800749 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700750 GrGLPerlinNoise::GenKey(*this, caps, b);
751 }
752
mtklein36352bf2015-03-25 18:17:31 -0700753 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400754 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700755 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700756 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700757 fNumOctaves == s.fNumOctaves &&
758 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700759 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000760 }
761
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400762 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400763 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400764 sk_sp<GrTextureProxy> permutationsProxy,
765 sk_sp<GrTextureProxy> noiseProxy,
766 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400767 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500768 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500769 , fNumOctaves(numOctaves)
770 , fStitchTiles(stitchTiles)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400771 , fPermutationsSampler(std::move(permutationsProxy))
772 , fNoiseSampler(std::move(noiseProxy))
Florin Malitab365cf52017-05-30 17:18:01 -0400773 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400774 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -0500775 fCoordTransform = GrCoordTransform(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700776 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000777 }
778
Brian Salomon4331e462017-07-26 14:58:11 -0400779 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400780 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400781 , fType(that.fType)
782 , fCoordTransform(that.fCoordTransform)
783 , fNumOctaves(that.fNumOctaves)
784 , fStitchTiles(that.fStitchTiles)
785 , fPermutationsSampler(that.fPermutationsSampler)
786 , fNoiseSampler(that.fNoiseSampler)
787 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400788 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -0400789 this->addCoordTransform(&fCoordTransform);
790 }
791
Brian Salomonf7dcd762018-07-30 14:48:15 -0400792 const TextureSampler& onTextureSampler(int i) const override {
793 return IthTextureSampler(i, fPermutationsSampler, fNoiseSampler);
794 }
795
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400796 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000797
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400798 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400799 GrCoordTransform fCoordTransform;
800 int fNumOctaves;
801 bool fStitchTiles;
802 TextureSampler fPermutationsSampler;
803 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400804 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000805
joshualittb0a8a372014-09-23 09:50:21 -0700806 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000807};
808
809/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400810GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000811
Hal Canary6f6961e2017-01-31 13:50:44 -0500812#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400813std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700814 int numOctaves = d->fRandom->nextRangeU(2, 10);
815 bool stitchTiles = d->fRandom->nextBool();
816 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
817 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
818 d->fRandom->nextRangeU(4, 4096));
819 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
820 0.99f);
821 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
822 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000823
reedfe630452016-03-25 09:08:00 -0700824 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
825 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400826 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700827 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400828 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000829
Brian Osman9f532a32016-10-19 11:12:09 -0400830 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400831 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000832}
Hal Canary6f6961e2017-01-31 13:50:44 -0500833#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000834
wangyix7c157a92015-07-22 15:08:53 -0700835void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400836 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800837
Mike Reedf2ae2b22017-05-30 15:22:54 -0400838 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800839 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Ethan Nicholasd4efe682019-08-29 16:10:13 -0400840 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000841
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400842 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800843 "baseFrequency");
844 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000845
halcanary96fcdcc2015-08-27 07:41:13 -0700846 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800847 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400848 fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800849 "stitchData");
850 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000851 }
852
sugoi@google.comd537af52013-06-10 13:59:25 +0000853 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
854 const char* chanCoordR = "0.125";
855 const char* chanCoordG = "0.375";
856 const char* chanCoordB = "0.625";
857 const char* chanCoordA = "0.875";
858 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000859 const char* stitchData = "stitchData";
860 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000861 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000862 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700863 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000864 const char* fractVal = "fractVal";
865 const char* uv = "uv";
866 const char* ab = "ab";
867 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700868 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000869 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000870 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
871 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
872 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400873 const char* dotLattice = "dot(((%s.ga + %s.rb * half2(%s)) * half2(2.0) - half2(1.0)), %s);";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000874
sugoi@google.comd537af52013-06-10 13:59:25 +0000875 // Add noise function
Nico Webere50efdf2018-10-01 14:40:44 -0400876 const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400877 GrShaderVar(chanCoord, kHalf_GrSLType),
878 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000879 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000880
Nico Webere50efdf2018-10-01 14:40:44 -0400881 const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400882 GrShaderVar(chanCoord, kHalf_GrSLType),
883 GrShaderVar(noiseVec, kHalf2_GrSLType),
884 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000885 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000886
sugoi@google.comd537af52013-06-10 13:59:25 +0000887 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000888
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400889 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700890 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400891 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
892 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000893
894 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400895 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700896 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000897
898 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800899 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000900 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400901 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000902 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400903 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700904 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400905 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700906 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400907 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000908 }
909
910 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400911 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400912 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000913
914 // Get permutation for x
915 {
916 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400917 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000918
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400919 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700920 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400921 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000922 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000923 }
924
925 // Get permutation for x + 1
926 {
927 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400928 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000929
sugoi@google.comd537af52013-06-10 13:59:25 +0000930 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700931 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400932 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000933 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000934 }
935
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000936#if defined(SK_BUILD_FOR_ANDROID)
937 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
938 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
939 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
940 // (or 0.484368 here). The following rounding operation prevents these precision issues from
941 // affecting the result of the noise by making sure that we only have multiples of 1/255.
942 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400943 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 +0000944 latticeIdx, latticeIdx);
945#endif
946
sugoi@google.come3b4c502013-04-05 13:47:09 +0000947 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400948 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000949
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400950 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000951 // Compute u, at offset (0,0)
952 {
953 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400954 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
955 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700956 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400957 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000958 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
959 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000960 }
961
sugoi@google.comd537af52013-06-10 13:59:25 +0000962 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000963 // Compute v, at offset (-1,0)
964 {
965 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400966 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000967 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700968 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400969 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000970 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
971 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000972 }
973
974 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400975 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000976 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 +0000977
sugoi@google.comd537af52013-06-10 13:59:25 +0000978 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000979 // Compute v, at offset (-1,-1)
980 {
981 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400982 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000983 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700984 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400985 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000986 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
987 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000988 }
989
sugoi@google.comd537af52013-06-10 13:59:25 +0000990 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000991 // Compute u, at offset (0,-1)
992 {
993 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400994 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000995 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700996 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400997 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000998 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
999 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001000 }
1001
1002 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +00001003 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 +00001004 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +00001005 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001006
sugoi@google.comd537af52013-06-10 13:59:25 +00001007 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -08001008 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001009 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001010 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
1011 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001012 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001013 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001014 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
1015 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001016 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001017
sugoi@google.comd537af52013-06-10 13:59:25 +00001018 // There are rounding errors if the floor operation is not performed here
Ethan Nicholase1f55022019-02-05 17:17:40 -05001019 fragBuilder->codeAppendf("\n\t\thalf2 %s = half2(floor(%s.xy) * %s);",
egdaniel4ca2e602015-11-18 08:01:26 -08001020 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001021
1022 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001023 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001024
robertphillipsbf536af2016-02-04 06:11:53 -08001025 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001026 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001027 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001028 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001029
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001030 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001031
1032 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001033 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001034
Mike Reedf2ae2b22017-05-30 15:22:54 -04001035 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001036 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001037 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001038 }
robertphillipsbf536af2016-02-04 06:11:53 -08001039 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001040 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001041 "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 +00001042 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1043 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1044 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1045 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1046 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1047 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001048 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001049 "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 +00001050 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1051 noiseFuncName.c_str(), chanCoordR, noiseVec,
1052 noiseFuncName.c_str(), chanCoordG, noiseVec,
1053 noiseFuncName.c_str(), chanCoordB, noiseVec,
1054 noiseFuncName.c_str(), chanCoordA, noiseVec);
1055 }
Florin Malita14d54c22017-05-18 11:52:59 -04001056 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001057 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001058 }
egdaniel4ca2e602015-11-18 08:01:26 -08001059 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001060
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001061 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001062 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001063
robertphillipsbf536af2016-02-04 06:11:53 -08001064 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001065 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001066 }
egdaniel4ca2e602015-11-18 08:01:26 -08001067 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001068
Florin Malita14d54c22017-05-18 11:52:59 -04001069 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001070 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1071 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001072 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001073 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001074 }
1075
sugoi@google.come3b4c502013-04-05 13:47:09 +00001076 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001077 fragBuilder->codeAppendf("\n\t\t%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001078
1079 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001080 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001081 args.fOutputColor, args.fOutputColor,
1082 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001083}
1084
Brian Salomon94efbf52016-11-29 13:43:05 -05001085void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001086 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001087 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001088
bsalomon63e99f72014-07-21 08:03:14 -07001089 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001090
1091 key = key << 3; // Make room for next 3 bits
1092
1093 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001094 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001095 key |= 0x1;
1096 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001097 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001098 key |= 0x2;
1099 break;
1100 default:
1101 // leave key at 0
1102 break;
1103 }
1104
1105 if (turbulence.stitchTiles()) {
1106 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1107 }
1108
bsalomon63e99f72014-07-21 08:03:14 -07001109 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001110}
1111
egdaniel018fb622015-10-28 07:26:40 -07001112void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001113 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001114 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001115
Mike Reedf2ae2b22017-05-30 15:22:54 -04001116 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001117
1118 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001119 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001120
sugoi@google.com4775cba2013-04-17 13:46:56 +00001121 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001122 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001123 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001124 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001125 }
1126}
1127
sugoi@google.come3b4c502013-04-05 13:47:09 +00001128/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001129
1130class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1131public:
1132 void emitCode(EmitArgs&) override;
1133
1134 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1135
1136protected:
1137 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1138
1139private:
1140 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001141 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1142
1143 typedef GrGLSLFragmentProcessor INHERITED;
1144};
1145
1146/////////////////////////////////////////////////////////////////////
1147
1148class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1149public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001150 static std::unique_ptr<GrFragmentProcessor> Make(
1151 int octaves, SkScalar z,
1152 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1153 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1154 const SkMatrix& matrix) {
1155 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1156 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1157 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001158 }
1159
Mike Reedf2ae2b22017-05-30 15:22:54 -04001160 const char* name() const override { return "ImprovedPerlinNoise"; }
1161
Brian Salomonaff329b2017-08-11 09:40:37 -04001162 std::unique_ptr<GrFragmentProcessor> clone() const override {
1163 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001164 }
1165
Mike Reedf2ae2b22017-05-30 15:22:54 -04001166 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1167 SkScalar z() const { return fZ; }
1168 int octaves() const { return fOctaves; }
Brian Salomon7d8b3972019-11-26 22:34:44 -05001169 const SkMatrix& matrix() const { return fCoordTransform.matrix(); }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001170
1171private:
1172 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1173 return new GrGLImprovedPerlinNoise;
1174 }
1175
1176 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1177 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1178 }
1179
1180 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1181 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1182 return fZ == fZ &&
1183 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1184 }
1185
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001186 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001187 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001188 sk_sp<GrTextureProxy> permutationsProxy,
1189 sk_sp<GrTextureProxy> gradientProxy,
1190 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001191 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001192 , fOctaves(octaves)
1193 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001194 , fPermutationsSampler(std::move(permutationsProxy))
1195 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001196 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001197 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -05001198 fCoordTransform = GrCoordTransform(matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001199 this->addCoordTransform(&fCoordTransform);
1200 }
1201
Brian Salomon4331e462017-07-26 14:58:11 -04001202 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001203 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001204 , fCoordTransform(that.fCoordTransform)
1205 , fOctaves(that.fOctaves)
1206 , fZ(that.fZ)
1207 , fPermutationsSampler(that.fPermutationsSampler)
1208 , fGradientSampler(that.fGradientSampler)
1209 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001210 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -04001211 this->addCoordTransform(&fCoordTransform);
1212 }
1213
Brian Salomonf7dcd762018-07-30 14:48:15 -04001214 const TextureSampler& onTextureSampler(int i) const override {
1215 return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
1216 }
1217
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001218 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001219
1220 GrCoordTransform fCoordTransform;
1221 int fOctaves;
1222 SkScalar fZ;
1223 TextureSampler fPermutationsSampler;
1224 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001225 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001226
1227 typedef GrFragmentProcessor INHERITED;
1228};
1229
1230/////////////////////////////////////////////////////////////////////
1231GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1232
1233#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001234std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1235 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001236 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1237 0.99f);
1238 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1239 0.99f);
1240 int numOctaves = d->fRandom->nextRangeU(2, 10);
1241 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1242
1243 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1244 baseFrequencyY,
1245 numOctaves,
1246 z));
1247
1248 GrTest::TestAsFPArgs asFPArgs(d);
1249 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1250}
1251#endif
1252
1253void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001254 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001255 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1256 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Ethan Nicholasd4efe682019-08-29 16:10:13 -04001257 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001258
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001259 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001260 "baseFrequency");
1261 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1262
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001263 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001264 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1265
1266 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001267 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001268 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001269 };
1270 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001271 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001272 fadeArgs,
1273 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1274 &fadeFuncName);
1275
1276 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001277 const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001278 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001279 };
1280 SkString permFuncName;
1281 SkString permCode("return ");
1282 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1283 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001284 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001285 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001286 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001287 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001288 permCode.c_str(), &permFuncName);
1289
1290 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001291 const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001292 GrShaderVar("x", kHalf_GrSLType),
1293 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001294 };
1295 SkString gradFuncName;
Ethan Nicholase1f55022019-02-05 17:17:40 -05001296 SkString gradCode("return half(dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001297 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001298 kHalf2_GrSLType);
Ethan Nicholase1f55022019-02-05 17:17:40 -05001299 gradCode.append(".rgb * 255.0 - float3(1.0), p));");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001300 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001301 gradCode.c_str(), &gradFuncName);
1302
1303 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001304 const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001305 GrShaderVar("a", kHalf_GrSLType),
1306 GrShaderVar("b", kHalf_GrSLType),
1307 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001308 };
1309 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001310 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001311 "return a + w * (b - a);", &lerpFuncName);
1312
1313 // noise function
Nico Webere50efdf2018-10-01 14:40:44 -04001314 const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001315 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001316 };
1317 SkString noiseFuncName;
1318 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001319 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001320 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001321 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1322 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1323 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1324 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1325 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1326 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1327 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1328 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001329 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1330 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001331 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 -04001332 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001333 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
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(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001336 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001337 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001338 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1339 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001340 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001341 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001342 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001343 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001344 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 -04001345 gradFuncName.c_str(), permFuncName.c_str());
1346 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001347 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001348 noiseCode.c_str(), &noiseFuncName);
1349
1350 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001351 const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001352 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001353 };
1354 SkString noiseOctavesFuncName;
1355 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001356 noiseOctavesCode.append("half result = 0.0;");
1357 noiseOctavesCode.append("half ratio = 1.0;");
1358 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001359 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1360 noiseOctavesCode.append("p *= 2.0;");
1361 noiseOctavesCode.append("ratio *= 2.0;");
1362 noiseOctavesCode.append("}");
1363 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001364 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001365 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1366
Ethan Nicholase1f55022019-02-05 17:17:40 -05001367 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", vCoords.c_str(), baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001368 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001369 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001370 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001371 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001372 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001373 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001374 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001375 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001376 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001377
1378 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001379 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001380
1381 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001382 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001383 args.fOutputColor, args.fOutputColor,
1384 args.fOutputColor, args.fOutputColor);
1385}
1386
1387void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1388 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001389 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1390 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001391}
1392
1393void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1394 const GrFragmentProcessor& processor) {
1395 INHERITED::onSetData(pdman, processor);
1396
1397 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1398
1399 const SkVector& baseFrequency = noise.baseFrequency();
1400 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1401
Mike Reedf2ae2b22017-05-30 15:22:54 -04001402 pdman.set1f(fZUni, noise.z());
1403}
1404
1405/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001406std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001407 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001408 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001409
Florin Malitac6c5ead2018-04-11 15:33:40 -04001410 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
Ethan Nicholas82940152019-01-10 13:58:14 -05001411 const auto paintMatrix = SkMatrix::Concat(*args.fViewMatrix, *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001412
Mike Reedf2ae2b22017-05-30 15:22:54 -04001413 // Either we don't stitch tiles, either we have a valid tile size
1414 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1415
Florin Malitab365cf52017-05-30 17:18:01 -04001416 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
1417 skstd::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
1418 fSeed,
1419 fBaseFrequencyX,
1420 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001421 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001422
1423 SkMatrix m = *args.fViewMatrix;
Florin Malitac6c5ead2018-04-11 15:33:40 -04001424 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1425 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001426
Robert Phillips9da87e02019-02-04 13:26:26 -05001427 auto proxyProvider = args.fContext->priv().proxyProvider();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001428 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001429 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1430 // We also know that we will not be using mipmaps. If things things weren't true we should
1431 // go through GrBitmapTextureMaker to handle needed copies.
1432 const sk_sp<SkImage> permutationsImage = paintingData->getImprovedPermutationsImage();
1433 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001434 sk_sp<GrTextureProxy> permutationsTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001435 GrMakeCachedImageProxy(proxyProvider, std::move(permutationsImage)));
1436
1437 const sk_sp<SkImage> gradientImage = paintingData->getGradientImage();
1438 SkASSERT(SkIsPow2(gradientImage->width()) && SkIsPow2(gradientImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001439 sk_sp<GrTextureProxy> gradientTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001440 GrMakeCachedImageProxy(proxyProvider, std::move(gradientImage)));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001441 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001442 std::move(permutationsTexture),
1443 std::move(gradientTexture), m);
1444 }
1445
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001446 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001447 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001448 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001449 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1450 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1451 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001452 auto inner =
Brian Osmancb3d0872018-10-16 15:19:28 -04001453 GrConstColorProcessor::Make(SkPMColor4f::FromBytes_RGBA(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001454 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001455 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001456 }
bsalomonc21b09e2015-08-28 18:46:56 -07001457 // Emit zero.
Brian Osmanf28e55d2018-10-03 16:35:54 -04001458 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001459 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001460 }
1461
Greg Daniel7e1912a2018-02-08 09:15:33 -05001462 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1463 // also know that we will not be using mipmaps. If things things weren't true we should go
1464 // through GrBitmapTextureMaker to handle needed copies.
1465 const sk_sp<SkImage> permutationsImage = paintingData->getPermutationsImage();
1466 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
1467 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedImageProxy(proxyProvider,
1468 std::move(permutationsImage));
1469
1470 const sk_sp<SkImage> noiseImage = paintingData->getNoiseImage();
1471 SkASSERT(SkIsPow2(noiseImage->width()) && SkIsPow2(noiseImage->height()));
1472 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedImageProxy(proxyProvider,
1473 std::move(noiseImage));
sugoi@google.come3b4c502013-04-05 13:47:09 +00001474
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001475 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001476 auto inner = GrPerlinNoise2Effect::Make(fType,
1477 fNumOctaves,
1478 fStitchTiles,
1479 std::move(paintingData),
1480 std::move(permutationsProxy),
1481 std::move(noiseProxy),
1482 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001483 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001484 }
bsalomonc21b09e2015-08-28 18:46:56 -07001485 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001486}
1487
1488#endif
1489
Mike Reedf2ae2b22017-05-30 15:22:54 -04001490///////////////////////////////////////////////////////////////////////////////////////////////////
1491
Mike Reed832aa112018-05-18 11:48:50 -04001492static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1493 SkScalar seed) {
1494 if (!(baseX >= 0 && baseY >= 0)) {
1495 return false;
1496 }
1497 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1498 return false;
1499 }
1500 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1501 return false;
1502 }
1503 if (!SkScalarIsFinite(seed)) {
1504 return false;
1505 }
1506 return true;
1507}
1508
Mike Reedf2ae2b22017-05-30 15:22:54 -04001509sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1510 SkScalar baseFrequencyY,
1511 int numOctaves, SkScalar seed,
1512 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001513 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1514 return nullptr;
1515 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001516 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1517 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1518 tileSize));
1519}
1520
1521sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1522 SkScalar baseFrequencyY,
1523 int numOctaves, SkScalar seed,
1524 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001525 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1526 return nullptr;
1527 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001528 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1529 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1530 tileSize));
1531}
1532
1533sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1534 SkScalar baseFrequencyY,
1535 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001536 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1537 return nullptr;
1538 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001539 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1540 baseFrequencyX, baseFrequencyY, numOctaves, z,
1541 nullptr));
1542}
1543
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001544void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001545 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001546}