blob: 307d2d8622fd4c7561ea13658606c5fda0af5b2d [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)
77 : fWidth(SkTMin(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
78 , fWrapX(kPerlinNoise + fWidth)
79 , fHeight(SkTMin(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
80 , 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);
118 SkPixmap permutationsPixmap(info, fLatticeSelector, info.minRowBytes());
119 fPermutationsImage = SkImage::MakeFromRaster(permutationsPixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400120
Greg Daniel7e1912a2018-02-08 09:15:33 -0500121 info = SkImageInfo::MakeN32Premul(kBlockSize, 4);
122 SkPixmap noisePixmap(info, fNoise[0][0], info.minRowBytes());
123 fNoiseImage = SkImage::MakeFromRaster(noisePixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400124
Greg Daniel7e1912a2018-02-08 09:15:33 -0500125 info = SkImageInfo::MakeA8(256, 1);
126 SkPixmap impPermutationsPixmap(info, improved_noise_permutations, info.minRowBytes());
127 fImprovedPermutationsImage = SkImage::MakeFromRaster(impPermutationsPixmap, nullptr,
128 nullptr);
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);
147 SkPixmap gradPixmap(info, gradients, info.minRowBytes());
148 fGradientImage = SkImage::MakeFromRaster(gradPixmap, nullptr, nullptr);
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 Daniel7e1912a2018-02-08 09:15:33 -0500158 , fPermutationsImage(that.fPermutationsImage)
159 , fNoiseImage(that.fNoiseImage)
160 , fImprovedPermutationsImage(that.fImprovedPermutationsImage)
161 , fGradientImage(that.fGradientImage) {
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 Daniel7e1912a2018-02-08 09:15:33 -0500179 sk_sp<SkImage> fPermutationsImage;
180 sk_sp<SkImage> fNoiseImage;
181 sk_sp<SkImage> fImprovedPermutationsImage;
182 sk_sp<SkImage> fGradientImage;
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 Daniel7e1912a2018-02-08 09:15:33 -0500307 const sk_sp<SkImage> getPermutationsImage() const { return fPermutationsImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400308
Greg Daniel7e1912a2018-02-08 09:15:33 -0500309 const sk_sp<SkImage> getNoiseImage() const { return fNoiseImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400310
Greg Daniel7e1912a2018-02-08 09:15:33 -0500311 const sk_sp<SkImage> getImprovedPermutationsImage() const {
312 return fImprovedPermutationsImage;
313 }
Florin Malita83223bc2017-05-31 14:14:05 -0400314
Greg Daniel7e1912a2018-02-08 09:15:33 -0500315 const sk_sp<SkImage> getGradientImage() const { return fGradientImage; }
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
566 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
567}
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 }
626 result = SkScalarClampMax((result + 1.0f) / 2.0f, 1.0f);
627 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,
721 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> noiseProxy,
722 const SkMatrix& matrix) {
723 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
724 type, numOctaves, stitchTiles, std::move(paintingData),
725 std::move(permutationsProxy), std::move(noiseProxy), 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,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400763 sk_sp<GrTextureProxy> permutationsProxy,
764 sk_sp<GrTextureProxy> noiseProxy,
765 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)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400770 , fPermutationsSampler(std::move(permutationsProxy))
771 , fNoiseSampler(std::move(noiseProxy))
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 Nicholasf7b88202017-09-18 14:10:39 -0400841 fBaseFrequencyUni = uniformHandler->addUniform(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 Nicholasf7b88202017-09-18 14:10:39 -0400847 fStitchDataUni = uniformHandler->addUniform(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);
cdalton3f6f76f2016-04-11 12:18:09 -0700919 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400920 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000921 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000922 }
923
924 // Get permutation for x + 1
925 {
926 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400927 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000928
sugoi@google.comd537af52013-06-10 13:59:25 +0000929 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700930 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400931 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000932 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000933 }
934
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000935#if defined(SK_BUILD_FOR_ANDROID)
936 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
937 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
938 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
939 // (or 0.484368 here). The following rounding operation prevents these precision issues from
940 // affecting the result of the noise by making sure that we only have multiples of 1/255.
941 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400942 noiseCode.appendf("\n\t%s = floor(%s * half2(255.0) + half2(0.5)) * half2(0.003921569);",
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000943 latticeIdx, latticeIdx);
944#endif
945
sugoi@google.come3b4c502013-04-05 13:47:09 +0000946 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400947 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000948
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400949 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000950 // Compute u, at offset (0,0)
951 {
952 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400953 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
954 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700955 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400956 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000957 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
958 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000959 }
960
sugoi@google.comd537af52013-06-10 13:59:25 +0000961 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000962 // Compute v, at offset (-1,0)
963 {
964 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400965 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000966 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700967 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400968 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000969 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
970 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000971 }
972
973 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400974 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000975 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 +0000976
sugoi@google.comd537af52013-06-10 13:59:25 +0000977 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000978 // Compute v, at offset (-1,-1)
979 {
980 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400981 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000982 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700983 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400984 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000985 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
986 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000987 }
988
sugoi@google.comd537af52013-06-10 13:59:25 +0000989 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000990 // Compute u, at offset (0,-1)
991 {
992 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400993 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000994 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700995 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400996 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000997 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
998 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000999 }
1000
1001 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +00001002 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 +00001003 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +00001004 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001005
sugoi@google.comd537af52013-06-10 13:59:25 +00001006 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -08001007 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001008 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001009 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
1010 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001011 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001012 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001013 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
1014 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001015 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001016
sugoi@google.comd537af52013-06-10 13:59:25 +00001017 // There are rounding errors if the floor operation is not performed here
Ethan Nicholase1f55022019-02-05 17:17:40 -05001018 fragBuilder->codeAppendf("\n\t\thalf2 %s = half2(floor(%s.xy) * %s);",
egdaniel4ca2e602015-11-18 08:01:26 -08001019 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001020
1021 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001022 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001023
robertphillipsbf536af2016-02-04 06:11:53 -08001024 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001025 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001026 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001027 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001028
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001029 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001030
1031 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001032 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001033
Mike Reedf2ae2b22017-05-30 15:22:54 -04001034 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001035 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001036 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001037 }
robertphillipsbf536af2016-02-04 06:11:53 -08001038 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001039 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001040 "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 +00001041 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1042 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1043 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1044 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1045 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1046 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001047 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001048 "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 +00001049 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1050 noiseFuncName.c_str(), chanCoordR, noiseVec,
1051 noiseFuncName.c_str(), chanCoordG, noiseVec,
1052 noiseFuncName.c_str(), chanCoordB, noiseVec,
1053 noiseFuncName.c_str(), chanCoordA, noiseVec);
1054 }
Florin Malita14d54c22017-05-18 11:52:59 -04001055 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001056 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001057 }
egdaniel4ca2e602015-11-18 08:01:26 -08001058 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001059
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001060 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001061 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001062
robertphillipsbf536af2016-02-04 06:11:53 -08001063 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001064 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001065 }
egdaniel4ca2e602015-11-18 08:01:26 -08001066 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001067
Florin Malita14d54c22017-05-18 11:52:59 -04001068 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001069 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1070 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001071 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001072 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001073 }
1074
sugoi@google.come3b4c502013-04-05 13:47:09 +00001075 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001076 fragBuilder->codeAppendf("\n\t\t%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001077
1078 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001079 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001080 args.fOutputColor, args.fOutputColor,
1081 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001082}
1083
Brian Salomon94efbf52016-11-29 13:43:05 -05001084void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001085 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001086 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001087
bsalomon63e99f72014-07-21 08:03:14 -07001088 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001089
1090 key = key << 3; // Make room for next 3 bits
1091
1092 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001093 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001094 key |= 0x1;
1095 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001096 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001097 key |= 0x2;
1098 break;
1099 default:
1100 // leave key at 0
1101 break;
1102 }
1103
1104 if (turbulence.stitchTiles()) {
1105 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1106 }
1107
bsalomon63e99f72014-07-21 08:03:14 -07001108 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001109}
1110
egdaniel018fb622015-10-28 07:26:40 -07001111void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001112 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001113 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001114
Mike Reedf2ae2b22017-05-30 15:22:54 -04001115 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001116
1117 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001118 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001119
sugoi@google.com4775cba2013-04-17 13:46:56 +00001120 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001121 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001122 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001123 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001124 }
1125}
1126
sugoi@google.come3b4c502013-04-05 13:47:09 +00001127/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001128
1129class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1130public:
1131 void emitCode(EmitArgs&) override;
1132
1133 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1134
1135protected:
1136 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1137
1138private:
1139 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001140 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1141
1142 typedef GrGLSLFragmentProcessor INHERITED;
1143};
1144
1145/////////////////////////////////////////////////////////////////////
1146
1147class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1148public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001149 static std::unique_ptr<GrFragmentProcessor> Make(
1150 int octaves, SkScalar z,
1151 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1152 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1153 const SkMatrix& matrix) {
1154 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1155 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1156 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001157 }
1158
Mike Reedf2ae2b22017-05-30 15:22:54 -04001159 const char* name() const override { return "ImprovedPerlinNoise"; }
1160
Brian Salomonaff329b2017-08-11 09:40:37 -04001161 std::unique_ptr<GrFragmentProcessor> clone() const override {
1162 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001163 }
1164
Mike Reedf2ae2b22017-05-30 15:22:54 -04001165 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1166 SkScalar z() const { return fZ; }
1167 int octaves() const { return fOctaves; }
Brian Salomon7d8b3972019-11-26 22:34:44 -05001168 const SkMatrix& matrix() const { return fCoordTransform.matrix(); }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001169
1170private:
1171 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1172 return new GrGLImprovedPerlinNoise;
1173 }
1174
1175 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1176 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1177 }
1178
1179 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1180 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1181 return fZ == fZ &&
1182 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1183 }
1184
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001185 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001186 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001187 sk_sp<GrTextureProxy> permutationsProxy,
1188 sk_sp<GrTextureProxy> gradientProxy,
1189 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001190 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001191 , fOctaves(octaves)
1192 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001193 , fPermutationsSampler(std::move(permutationsProxy))
1194 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001195 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001196 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -05001197 fCoordTransform = GrCoordTransform(matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001198 this->addCoordTransform(&fCoordTransform);
1199 }
1200
Brian Salomon4331e462017-07-26 14:58:11 -04001201 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001202 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001203 , fCoordTransform(that.fCoordTransform)
1204 , fOctaves(that.fOctaves)
1205 , fZ(that.fZ)
1206 , fPermutationsSampler(that.fPermutationsSampler)
1207 , fGradientSampler(that.fGradientSampler)
1208 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001209 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -04001210 this->addCoordTransform(&fCoordTransform);
1211 }
1212
Brian Salomonf7dcd762018-07-30 14:48:15 -04001213 const TextureSampler& onTextureSampler(int i) const override {
1214 return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
1215 }
1216
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001217 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001218
1219 GrCoordTransform fCoordTransform;
1220 int fOctaves;
1221 SkScalar fZ;
1222 TextureSampler fPermutationsSampler;
1223 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001224 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001225
1226 typedef GrFragmentProcessor INHERITED;
1227};
1228
1229/////////////////////////////////////////////////////////////////////
1230GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1231
1232#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001233std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1234 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001235 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1236 0.99f);
1237 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1238 0.99f);
1239 int numOctaves = d->fRandom->nextRangeU(2, 10);
1240 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1241
1242 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1243 baseFrequencyY,
1244 numOctaves,
1245 z));
1246
1247 GrTest::TestAsFPArgs asFPArgs(d);
1248 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1249}
1250#endif
1251
1252void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001253 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001254 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1255 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Ethan Nicholasd4efe682019-08-29 16:10:13 -04001256 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001257
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001258 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001259 "baseFrequency");
1260 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1261
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001262 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001263 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1264
1265 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001266 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001267 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001268 };
1269 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001270 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001271 fadeArgs,
1272 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1273 &fadeFuncName);
1274
1275 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001276 const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001277 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001278 };
1279 SkString permFuncName;
1280 SkString permCode("return ");
1281 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1282 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001283 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001284 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001285 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001286 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001287 permCode.c_str(), &permFuncName);
1288
1289 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001290 const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001291 GrShaderVar("x", kHalf_GrSLType),
1292 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001293 };
1294 SkString gradFuncName;
Ethan Nicholase1f55022019-02-05 17:17:40 -05001295 SkString gradCode("return half(dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001296 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001297 kHalf2_GrSLType);
Ethan Nicholase1f55022019-02-05 17:17:40 -05001298 gradCode.append(".rgb * 255.0 - float3(1.0), p));");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001299 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001300 gradCode.c_str(), &gradFuncName);
1301
1302 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001303 const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001304 GrShaderVar("a", kHalf_GrSLType),
1305 GrShaderVar("b", kHalf_GrSLType),
1306 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001307 };
1308 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001309 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001310 "return a + w * (b - a);", &lerpFuncName);
1311
1312 // noise function
Nico Webere50efdf2018-10-01 14:40:44 -04001313 const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001314 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001315 };
1316 SkString noiseFuncName;
1317 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001318 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001319 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001320 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1321 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1322 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1323 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1324 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1325 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1326 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1327 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001328 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1329 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001330 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 -04001331 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001332 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001333 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001334 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001335 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001336 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001337 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1338 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001339 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001340 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001341 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001342 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001343 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 -04001344 gradFuncName.c_str(), permFuncName.c_str());
1345 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001346 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001347 noiseCode.c_str(), &noiseFuncName);
1348
1349 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001350 const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001351 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001352 };
1353 SkString noiseOctavesFuncName;
1354 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001355 noiseOctavesCode.append("half result = 0.0;");
1356 noiseOctavesCode.append("half ratio = 1.0;");
1357 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001358 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1359 noiseOctavesCode.append("p *= 2.0;");
1360 noiseOctavesCode.append("ratio *= 2.0;");
1361 noiseOctavesCode.append("}");
1362 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001363 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001364 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1365
Ethan Nicholase1f55022019-02-05 17:17:40 -05001366 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", vCoords.c_str(), baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001367 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001368 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001369 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001370 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001371 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001372 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001373 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001374 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001375 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001376
1377 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001378 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001379
1380 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001381 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001382 args.fOutputColor, args.fOutputColor,
1383 args.fOutputColor, args.fOutputColor);
1384}
1385
1386void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1387 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001388 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1389 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001390}
1391
1392void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1393 const GrFragmentProcessor& processor) {
1394 INHERITED::onSetData(pdman, processor);
1395
1396 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1397
1398 const SkVector& baseFrequency = noise.baseFrequency();
1399 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1400
Mike Reedf2ae2b22017-05-30 15:22:54 -04001401 pdman.set1f(fZUni, noise.z());
1402}
1403
1404/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001405std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001406 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001407 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001408
Florin Malitac6c5ead2018-04-11 15:33:40 -04001409 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
Ethan Nicholas82940152019-01-10 13:58:14 -05001410 const auto paintMatrix = SkMatrix::Concat(*args.fViewMatrix, *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001411
Mike Reedf2ae2b22017-05-30 15:22:54 -04001412 // Either we don't stitch tiles, either we have a valid tile size
1413 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1414
Florin Malitab365cf52017-05-30 17:18:01 -04001415 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001416 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001417 fSeed,
1418 fBaseFrequencyX,
1419 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001420 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001421
1422 SkMatrix m = *args.fViewMatrix;
Florin Malitac6c5ead2018-04-11 15:33:40 -04001423 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1424 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001425
Robert Phillips9da87e02019-02-04 13:26:26 -05001426 auto proxyProvider = args.fContext->priv().proxyProvider();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001427 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001428 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1429 // We also know that we will not be using mipmaps. If things things weren't true we should
1430 // go through GrBitmapTextureMaker to handle needed copies.
1431 const sk_sp<SkImage> permutationsImage = paintingData->getImprovedPermutationsImage();
1432 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001433 sk_sp<GrTextureProxy> permutationsTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001434 GrMakeCachedImageProxy(proxyProvider, std::move(permutationsImage)));
1435
1436 const sk_sp<SkImage> gradientImage = paintingData->getGradientImage();
1437 SkASSERT(SkIsPow2(gradientImage->width()) && SkIsPow2(gradientImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001438 sk_sp<GrTextureProxy> gradientTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001439 GrMakeCachedImageProxy(proxyProvider, std::move(gradientImage)));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001440 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001441 std::move(permutationsTexture),
1442 std::move(gradientTexture), m);
1443 }
1444
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001445 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001446 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001447 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001448 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1449 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1450 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001451 auto inner =
Brian Osmancb3d0872018-10-16 15:19:28 -04001452 GrConstColorProcessor::Make(SkPMColor4f::FromBytes_RGBA(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001453 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001454 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001455 }
bsalomonc21b09e2015-08-28 18:46:56 -07001456 // Emit zero.
Brian Osmanf28e55d2018-10-03 16:35:54 -04001457 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001458 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001459 }
1460
Greg Daniel7e1912a2018-02-08 09:15:33 -05001461 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1462 // also know that we will not be using mipmaps. If things things weren't true we should go
1463 // through GrBitmapTextureMaker to handle needed copies.
1464 const sk_sp<SkImage> permutationsImage = paintingData->getPermutationsImage();
1465 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
1466 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedImageProxy(proxyProvider,
1467 std::move(permutationsImage));
1468
1469 const sk_sp<SkImage> noiseImage = paintingData->getNoiseImage();
1470 SkASSERT(SkIsPow2(noiseImage->width()) && SkIsPow2(noiseImage->height()));
1471 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedImageProxy(proxyProvider,
1472 std::move(noiseImage));
sugoi@google.come3b4c502013-04-05 13:47:09 +00001473
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001474 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001475 auto inner = GrPerlinNoise2Effect::Make(fType,
1476 fNumOctaves,
1477 fStitchTiles,
1478 std::move(paintingData),
1479 std::move(permutationsProxy),
1480 std::move(noiseProxy),
1481 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001482 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001483 }
bsalomonc21b09e2015-08-28 18:46:56 -07001484 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001485}
1486
1487#endif
1488
Mike Reedf2ae2b22017-05-30 15:22:54 -04001489///////////////////////////////////////////////////////////////////////////////////////////////////
1490
Mike Reed832aa112018-05-18 11:48:50 -04001491static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1492 SkScalar seed) {
1493 if (!(baseX >= 0 && baseY >= 0)) {
1494 return false;
1495 }
1496 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1497 return false;
1498 }
1499 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1500 return false;
1501 }
1502 if (!SkScalarIsFinite(seed)) {
1503 return false;
1504 }
1505 return true;
1506}
1507
Mike Reedf2ae2b22017-05-30 15:22:54 -04001508sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1509 SkScalar baseFrequencyY,
1510 int numOctaves, SkScalar seed,
1511 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001512 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1513 return nullptr;
1514 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001515 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1516 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1517 tileSize));
1518}
1519
1520sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1521 SkScalar baseFrequencyY,
1522 int numOctaves, SkScalar seed,
1523 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001524 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1525 return nullptr;
1526 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001527 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1528 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1529 tileSize));
1530}
1531
1532sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1533 SkScalar baseFrequencyY,
1534 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001535 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1536 return nullptr;
1537 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001538 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1539 baseFrequencyX, baseFrequencyY, numOctaves, z,
1540 nullptr));
1541}
1542
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001543void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001544 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001545}