blob: 5979a9b4b0e6c94f3c59fb853f90f091fd4aeb57 [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
sugoi@google.come3b4c502013-04-05 13:47:09 +00008#include "SkPerlinNoiseShader.h"
Herb Derby83e939b2017-02-07 14:25:11 -05009
10#include "SkArenaAlloc.h"
Mike Reedf2ae2b22017-05-30 15:22:54 -040011#include "SkDither.h"
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +000012#include "SkColorFilter.h"
Florin Malitab365cf52017-05-30 17:18:01 -040013#include "SkMakeUnique.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkReadBuffer.h"
Florin Malita14d54c22017-05-18 11:52:59 -040015#include "SkWriteBuffer.h"
Mike Reedf2ae2b22017-05-30 15:22:54 -040016#include "SkShader.h"
17#include "SkUnPreMultiply.h"
18#include "SkString.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000019
20#if SK_SUPPORT_GPU
21#include "GrContext.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050022#include "GrContextPriv.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +000023#include "GrCoordTransform.h"
joshualitteb2a6762014-12-04 11:35:33 -080024#include "SkGr.h"
bsalomonc21b09e2015-08-28 18:46:56 -070025#include "effects/GrConstColorProcessor.h"
egdaniel64c47282015-11-13 06:54:19 -080026#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080027#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070028#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080029#include "glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000030#endif
31
32static const int kBlockSize = 256;
33static const int kBlockMask = kBlockSize - 1;
34static const int kPerlinNoise = 4096;
35static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
36
Mike Reedf2ae2b22017-05-30 15:22:54 -040037static uint8_t improved_noise_permutations[] = {
38 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
39 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
40 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
41 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
42 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
43 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
44 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
45 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
46 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
47 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
48 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
49 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
50 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
51 141, 128, 195, 78, 66, 215, 61, 156, 180,
52 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
53 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
54 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
55 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
56 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
57 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
58 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
59 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
60 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
61 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
62 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
63 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
64 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
65 141, 128, 195, 78, 66, 215, 61, 156, 180
66};
67
68class SkPerlinNoiseShaderImpl : public SkShaderBase {
69public:
Florin Malita83223bc2017-05-31 14:14:05 -040070 struct StitchData {
71 StitchData()
72 : fWidth(0)
73 , fWrapX(0)
74 , fHeight(0)
75 , fWrapY(0)
76 {}
77
78 bool operator==(const StitchData& other) const {
79 return fWidth == other.fWidth &&
80 fWrapX == other.fWrapX &&
81 fHeight == other.fHeight &&
82 fWrapY == other.fWrapY;
83 }
84
85 int fWidth; // How much to subtract to wrap for stitching.
86 int fWrapX; // Minimum value to wrap.
87 int fHeight;
88 int fWrapY;
89 };
90
91 struct PaintingData {
92 PaintingData(const SkISize& tileSize, SkScalar seed,
93 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
94 const SkMatrix& matrix)
95 {
96 SkVector vec[2] = {
97 { SkScalarInvert(baseFrequencyX), SkScalarInvert(baseFrequencyY) },
98 { SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight) },
99 };
100 matrix.mapVectors(vec, 2);
101
102 fBaseFrequency.set(SkScalarInvert(vec[0].fX), SkScalarInvert(vec[0].fY));
103 fTileSize.set(SkScalarRoundToInt(vec[1].fX), SkScalarRoundToInt(vec[1].fY));
104 this->init(seed);
105 if (!fTileSize.isEmpty()) {
106 this->stitch();
107 }
108
109 #if SK_SUPPORT_GPU
110 fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1));
111 fPermutationsBitmap.setPixels(fLatticeSelector);
112
113 fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4));
114 fNoiseBitmap.setPixels(fNoise[0][0]);
115
116 fImprovedPermutationsBitmap.setInfo(SkImageInfo::MakeA8(256, 1));
117 fImprovedPermutationsBitmap.setPixels(improved_noise_permutations);
118
119 fGradientBitmap.setInfo(SkImageInfo::MakeN32Premul(16, 1));
120 static uint8_t gradients[] = { 2, 2, 1, 0,
121 0, 2, 1, 0,
122 2, 0, 1, 0,
123 0, 0, 1, 0,
124 2, 1, 2, 0,
125 0, 1, 2, 0,
126 2, 1, 0, 0,
127 0, 1, 0, 0,
128 1, 2, 2, 0,
129 1, 0, 2, 0,
130 1, 2, 0, 0,
131 1, 0, 0, 0,
132 2, 2, 1, 0,
133 1, 0, 2, 0,
134 0, 2, 1, 0,
135 1, 0, 0, 0 };
136 fGradientBitmap.setPixels(gradients);
137 #endif
138 }
139
Brian Salomon4331e462017-07-26 14:58:11 -0400140 #if SK_SUPPORT_GPU
141 PaintingData(const PaintingData& that)
142 : fSeed(that.fSeed)
143 , fTileSize(that.fTileSize)
144 , fBaseFrequency(that.fBaseFrequency)
145 , fStitchDataInit(that.fStitchDataInit)
146 , fPermutationsBitmap(that.fPermutationsBitmap)
147 , fNoiseBitmap(that.fNoiseBitmap)
148 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
149 , fGradientBitmap(that.fGradientBitmap) {
150 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
151 memcpy(fNoise, that.fNoise, sizeof(fNoise));
152 memcpy(fGradient, that.fGradient, sizeof(fGradient));
153 }
154 #endif
155
Florin Malita83223bc2017-05-31 14:14:05 -0400156 int fSeed;
157 uint8_t fLatticeSelector[kBlockSize];
158 uint16_t fNoise[4][kBlockSize][2];
159 SkPoint fGradient[4][kBlockSize];
160 SkISize fTileSize;
161 SkVector fBaseFrequency;
162 StitchData fStitchDataInit;
163
164 private:
165
166 #if SK_SUPPORT_GPU
167 SkBitmap fPermutationsBitmap;
168 SkBitmap fNoiseBitmap;
169 SkBitmap fImprovedPermutationsBitmap;
170 SkBitmap fGradientBitmap;
171 #endif
172
173 inline int random() {
174 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
175 static const int gRandQ = 127773; // m / a
176 static const int gRandR = 2836; // m % a
177
178 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
179 if (result <= 0)
180 result += kRandMaximum;
181 fSeed = result;
182 return result;
183 }
184
185 // Only called once. Could be part of the constructor.
186 void init(SkScalar seed)
187 {
188 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
189
190 // According to the SVG spec, we must truncate (not round) the seed value.
191 fSeed = SkScalarTruncToInt(seed);
192 // The seed value clamp to the range [1, kRandMaximum - 1].
193 if (fSeed <= 0) {
194 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
195 }
196 if (fSeed > kRandMaximum - 1) {
197 fSeed = kRandMaximum - 1;
198 }
199 for (int channel = 0; channel < 4; ++channel) {
200 for (int i = 0; i < kBlockSize; ++i) {
201 fLatticeSelector[i] = i;
202 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
203 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
204 }
205 }
206 for (int i = kBlockSize - 1; i > 0; --i) {
207 int k = fLatticeSelector[i];
208 int j = random() % kBlockSize;
209 SkASSERT(j >= 0);
210 SkASSERT(j < kBlockSize);
211 fLatticeSelector[i] = fLatticeSelector[j];
212 fLatticeSelector[j] = k;
213 }
214
215 // Perform the permutations now
216 {
217 // Copy noise data
218 uint16_t noise[4][kBlockSize][2];
219 for (int i = 0; i < kBlockSize; ++i) {
220 for (int channel = 0; channel < 4; ++channel) {
221 for (int j = 0; j < 2; ++j) {
222 noise[channel][i][j] = fNoise[channel][i][j];
223 }
224 }
225 }
226 // Do permutations on noise data
227 for (int i = 0; i < kBlockSize; ++i) {
228 for (int channel = 0; channel < 4; ++channel) {
229 for (int j = 0; j < 2; ++j) {
230 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
231 }
232 }
233 }
234 }
235
236 // Half of the largest possible value for 16 bit unsigned int
237 static const SkScalar gHalfMax16bits = 32767.5f;
238
239 // Compute gradients from permutated noise data
240 for (int channel = 0; channel < 4; ++channel) {
241 for (int i = 0; i < kBlockSize; ++i) {
242 fGradient[channel][i] = SkPoint::Make(
243 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
244 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
245 fGradient[channel][i].normalize();
246 // Put the normalized gradient back into the noise data
247 fNoise[channel][i][0] = SkScalarRoundToInt(
248 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
249 fNoise[channel][i][1] = SkScalarRoundToInt(
250 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
251 }
252 }
253 }
254
255 // Only called once. Could be part of the constructor.
256 void stitch() {
257 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
258 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
259 SkASSERT(tileWidth > 0 && tileHeight > 0);
260 // When stitching tiled turbulence, the frequencies must be adjusted
261 // so that the tile borders will be continuous.
262 if (fBaseFrequency.fX) {
263 SkScalar lowFrequencx =
264 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
265 SkScalar highFrequencx =
266 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
267 // BaseFrequency should be non-negative according to the standard.
268 if (fBaseFrequency.fX / lowFrequencx < highFrequencx / fBaseFrequency.fX) {
269 fBaseFrequency.fX = lowFrequencx;
270 } else {
271 fBaseFrequency.fX = highFrequencx;
272 }
273 }
274 if (fBaseFrequency.fY) {
275 SkScalar lowFrequency =
276 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
277 SkScalar highFrequency =
278 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
279 if (fBaseFrequency.fY / lowFrequency < highFrequency / fBaseFrequency.fY) {
280 fBaseFrequency.fY = lowFrequency;
281 } else {
282 fBaseFrequency.fY = highFrequency;
283 }
284 }
285 // Set up TurbulenceInitial stitch values.
286 fStitchDataInit.fWidth =
287 SkScalarRoundToInt(tileWidth * fBaseFrequency.fX);
288 fStitchDataInit.fWrapX = kPerlinNoise + fStitchDataInit.fWidth;
289 fStitchDataInit.fHeight =
290 SkScalarRoundToInt(tileHeight * fBaseFrequency.fY);
291 fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight;
292 }
293
294 public:
295
296#if SK_SUPPORT_GPU
297 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
298
299 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
300
301 const SkBitmap& getImprovedPermutationsBitmap() const { return fImprovedPermutationsBitmap; }
302
303 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
304#endif
305 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400306
307 /**
308 * About the noise types : the difference between the first 2 is just minor tweaks to the
309 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
310 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
311 * doing :
312 * kFractalNoise_Type : noise * 0.5 + 0.5
313 * kTurbulence_Type : abs(noise)
314 * Very little differences between the 2 types, although you can tell the difference visually.
315 * "Improved" is based on the Improved Perlin Noise algorithm described at
316 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
317 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
318 * changes to the noise, making it suitable for animated noise.
319 */
320 enum Type {
321 kFractalNoise_Type,
322 kTurbulence_Type,
323 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500324 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400325 };
326
Robert Phillipsbee27322018-01-23 09:58:18 -0500327 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
328
Mike Reedf2ae2b22017-05-30 15:22:54 -0400329 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
330 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
331 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400332
333 class PerlinNoiseShaderContext : public Context {
334 public:
335 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400336
337 void shadeSpan(int x, int y, SkPMColor[], int count) override;
338
339 private:
340 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
341 SkScalar calculateTurbulenceValueForPoint(
342 int channel,
343 StitchData& stitchData, const SkPoint& point) const;
344 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
345 SkScalar noise2D(int channel,
346 const StitchData& stitchData, const SkPoint& noiseVector) const;
347
Florin Malita83223bc2017-05-31 14:14:05 -0400348 SkMatrix fMatrix;
349 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400350
351 typedef Context INHERITED;
352 };
353
354#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500355 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400356#endif
357
358 SK_TO_STRING_OVERRIDE()
359 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPerlinNoiseShaderImpl)
360
361protected:
362 void flatten(SkWriteBuffer&) const override;
363 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
364
365private:
366 const SkPerlinNoiseShaderImpl::Type fType;
367 const SkScalar fBaseFrequencyX;
368 const SkScalar fBaseFrequencyY;
369 const int fNumOctaves;
370 const SkScalar fSeed;
371 const SkISize fTileSize;
372 const bool fStitchTiles;
373
374 friend class ::SkPerlinNoiseShader;
375
376 typedef SkShaderBase INHERITED;
377};
378
sugoi@google.come3b4c502013-04-05 13:47:09 +0000379namespace {
380
381// noiseValue is the color component's value (or color)
382// limitValue is the maximum perlin noise array index value allowed
383// newValue is the current noise dimension (either width or height)
384inline int checkNoise(int noiseValue, int limitValue, int newValue) {
385 // If the noise value would bring us out of bounds of the current noise array while we are
386 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
387 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
388 if (noiseValue >= limitValue) {
389 noiseValue -= newValue;
390 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000391 return noiseValue;
392}
393
394inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500395 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000396}
397
398} // end namespace
399
Mike Reedf2ae2b22017-05-30 15:22:54 -0400400SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500401 SkScalar baseFrequencyX,
402 SkScalar baseFrequencyY,
403 int numOctaves,
404 SkScalar seed,
405 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000406 : fType(type)
407 , fBaseFrequencyX(baseFrequencyX)
408 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500409 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000410 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700411 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000412 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000413{
Robert Phillipsbee27322018-01-23 09:58:18 -0500414 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400415}
416
Florin Malita14d54c22017-05-18 11:52:59 -0400417sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500418 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500419
reed9fa60da2014-08-21 07:59:51 -0700420 SkScalar freqX = buffer.readScalar();
421 SkScalar freqY = buffer.readScalar();
Robert Phillipsbee27322018-01-23 09:58:18 -0500422
Mike Reedde5c5022018-01-26 14:59:12 -0500423 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500424
reed9fa60da2014-08-21 07:59:51 -0700425 SkScalar seed = buffer.readScalar();
426 SkISize tileSize;
427 tileSize.fWidth = buffer.readInt();
428 tileSize.fHeight = buffer.readInt();
429
430 switch (type) {
431 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400432 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700433 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400434 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
435 case kImprovedNoise_Type:
436 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700437 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500438 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500439 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700440 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700441 }
442}
443
Florin Malita14d54c22017-05-18 11:52:59 -0400444void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000445 buffer.writeInt((int) fType);
446 buffer.writeScalar(fBaseFrequencyX);
447 buffer.writeScalar(fBaseFrequencyY);
448 buffer.writeInt(fNumOctaves);
449 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000450 buffer.writeInt(fTileSize.fWidth);
451 buffer.writeInt(fTileSize.fHeight);
452}
453
Florin Malita14d54c22017-05-18 11:52:59 -0400454SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700455 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000456 struct Noise {
457 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700458 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000459 SkScalar noisePositionFractionValue;
460 Noise(SkScalar component)
461 {
462 SkScalar position = component + kPerlinNoise;
463 noisePositionIntegerValue = SkScalarFloorToInt(position);
464 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700465 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000466 }
467 };
468 Noise noiseX(noiseVector.x());
469 Noise noiseY(noiseVector.y());
470 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400471 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000472 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000473 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000474 noiseX.noisePositionIntegerValue =
475 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
476 noiseY.noisePositionIntegerValue =
477 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700478 noiseX.nextNoisePositionIntegerValue =
479 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
480 noiseY.nextNoisePositionIntegerValue =
481 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000482 }
483 noiseX.noisePositionIntegerValue &= kBlockMask;
484 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700485 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
486 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400487 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
488 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700489 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
490 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
491 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
492 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000493 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
494 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400495
Hal Canaryfda46002017-05-08 17:17:47 -0400496 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
497 return 0; // Check for pathological inputs.
498 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400499
sugoi@google.come3b4c502013-04-05 13:47:09 +0000500 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
501 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
502 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400503 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000504 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400505 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000506 SkScalar a = SkScalarInterp(u, v, sx);
507 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400508 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000509 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400510 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000511 SkScalar b = SkScalarInterp(u, v, sx);
512 return SkScalarInterp(a, b, sy);
513}
514
Florin Malita14d54c22017-05-18 11:52:59 -0400515SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700516 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400517 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000518 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000519 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400520 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000521 }
522 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400523 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
524 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000525 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000526 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700527 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700528 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
529 noise : SkScalarAbs(noise);
530 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000531 noiseVector.fX *= 2;
532 noiseVector.fY *= 2;
533 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000534 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000535 // Update stitch values
536 stitchData.fWidth *= 2;
537 stitchData.fWrapX = stitchData.fWidth + kPerlinNoise;
538 stitchData.fHeight *= 2;
539 stitchData.fWrapY = stitchData.fHeight + kPerlinNoise;
540 }
541 }
542
543 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
544 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000545 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400546 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000547 }
548
549 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700550 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000551 }
552
553 // Clamp result
554 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
555}
556
Mike Reedf2ae2b22017-05-30 15:22:54 -0400557////////////////////////////////////////////////////////////////////////////////////////////////////
558// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
559static SkScalar fade(SkScalar t) {
560 return t * t * t * (t * (t * 6 - 15) + 10);
561}
562
563static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
564 return a + t * (b - a);
565}
566
567static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
568 int h = hash & 15;
569 SkScalar u = h < 8 ? x : y;
570 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
571 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
572}
573
574SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
575 int channel, const SkPoint& point) const {
576 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
577 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
578 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
579 // z offset between different channels, chosen arbitrarily
580 static const SkScalar CHANNEL_DELTA = 1000.0f;
581 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
582 SkScalar result = 0;
583 SkScalar ratio = SK_Scalar1;
584 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
585 int X = SkScalarFloorToInt(x) & 255;
586 int Y = SkScalarFloorToInt(y) & 255;
587 int Z = SkScalarFloorToInt(z) & 255;
588 SkScalar px = x - SkScalarFloorToScalar(x);
589 SkScalar py = y - SkScalarFloorToScalar(y);
590 SkScalar pz = z - SkScalarFloorToScalar(z);
591 SkScalar u = fade(px);
592 SkScalar v = fade(py);
593 SkScalar w = fade(pz);
594 uint8_t* permutations = improved_noise_permutations;
595 int A = permutations[X] + Y;
596 int AA = permutations[A] + Z;
597 int AB = permutations[A + 1] + Z;
598 int B = permutations[X + 1] + Y;
599 int BA = permutations[B] + Z;
600 int BB = permutations[B + 1] + Z;
601 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
602 grad(permutations[BA ], px - 1, py , pz )),
603 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
604 grad(permutations[BB ], px - 1, py - 1, pz ))),
605 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
606 grad(permutations[BA + 1], px - 1, py , pz - 1)),
607 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
608 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
609 ratio;
610 x *= 2;
611 y *= 2;
612 ratio *= 2;
613 }
614 result = SkScalarClampMax((result + 1.0f) / 2.0f, 1.0f);
615 return result;
616}
617////////////////////////////////////////////////////////////////////////////////////////////////////
618
Florin Malita14d54c22017-05-18 11:52:59 -0400619SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000620 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400621 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000622 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000623 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000624 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
625 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
626
627 U8CPU rgba[4];
628 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400629 SkScalar value;
630 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
631 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
632 }
633 else {
634 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
635 }
636 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000637 }
638 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
639}
640
Mike Reedf2ae2b22017-05-30 15:22:54 -0400641SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
642 SkArenaAlloc* alloc) const {
Herb Derby83e939b2017-02-07 14:25:11 -0500643 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000644}
645
Florin Malita83223bc2017-05-31 14:14:05 -0400646static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
647 const SkShaderBase& shader) {
648 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
649 if (rec.fLocalMatrix) {
650 matrix.preConcat(*rec.fLocalMatrix);
651 }
652
653 return matrix;
654}
655
Florin Malita14d54c22017-05-18 11:52:59 -0400656SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
657 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000658 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400659 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
660 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
661 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000662{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000663 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
664 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400665 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
666 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700667}
668
Florin Malita14d54c22017-05-18 11:52:59 -0400669void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000670 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000671 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
672 StitchData stitchData;
673 for (int i = 0; i < count; ++i) {
674 result[i] = shade(point, stitchData);
675 point.fX += SK_Scalar1;
676 }
677}
678
sugoi@google.come3b4c502013-04-05 13:47:09 +0000679/////////////////////////////////////////////////////////////////////
680
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000681#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000682
egdaniel64c47282015-11-13 06:54:19 -0800683class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000684public:
robertphillips9cdb9922016-02-03 12:25:40 -0800685 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000686
Mike Reedf2ae2b22017-05-30 15:22:54 -0400687 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000688
wangyixb1daa862015-08-18 11:29:31 -0700689protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400690 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700691
sugoi@google.com4775cba2013-04-17 13:46:56 +0000692private:
egdaniel018fb622015-10-28 07:26:40 -0700693 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700694 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700695
egdaniel64c47282015-11-13 06:54:19 -0800696 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000697};
698
699/////////////////////////////////////////////////////////////////////
700
Mike Reedf2ae2b22017-05-30 15:22:54 -0400701class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000702public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400703 static std::unique_ptr<GrFragmentProcessor> Make(
704 SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
705 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
706 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> noiseProxy,
707 const SkMatrix& matrix) {
708 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
709 type, numOctaves, stitchTiles, std::move(paintingData),
710 std::move(permutationsProxy), std::move(noiseProxy), matrix));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000711 }
712
mtklein36352bf2015-03-25 18:17:31 -0700713 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800714
Brian Salomonaff329b2017-08-11 09:40:37 -0400715 std::unique_ptr<GrFragmentProcessor> clone() const override {
716 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400717 }
718
Mike Reedf2ae2b22017-05-30 15:22:54 -0400719 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000720
Florin Malita14d54c22017-05-18 11:52:59 -0400721 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700722 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700723 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700724 int numOctaves() const { return fNumOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -0400725 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
senorblancof3b50272014-06-16 10:49:58 -0700726
sugoi@google.come3b4c502013-04-05 13:47:09 +0000727private:
egdaniel57d3b032015-11-13 11:57:27 -0800728 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800729 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700730 }
731
Brian Salomon94efbf52016-11-29 13:43:05 -0500732 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800733 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700734 GrGLPerlinNoise::GenKey(*this, caps, b);
735 }
736
mtklein36352bf2015-03-25 18:17:31 -0700737 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400738 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700739 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700740 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700741 fNumOctaves == s.fNumOctaves &&
742 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700743 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000744 }
745
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400746 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400747 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400748 sk_sp<GrTextureProxy> permutationsProxy,
749 sk_sp<GrTextureProxy> noiseProxy,
750 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400751 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500752 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500753 , fNumOctaves(numOctaves)
754 , fStitchTiles(stitchTiles)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400755 , fPermutationsSampler(std::move(permutationsProxy))
756 , fNoiseSampler(std::move(noiseProxy))
Florin Malitab365cf52017-05-30 17:18:01 -0400757 , fPaintingData(std::move(paintingData)) {
Brian Salomon0bbecb22016-11-17 11:38:22 -0500758 this->addTextureSampler(&fPermutationsSampler);
759 this->addTextureSampler(&fNoiseSampler);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400760 fCoordTransform.reset(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700761 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000762 }
763
Brian Salomon4331e462017-07-26 14:58:11 -0400764 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400765 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400766 , fType(that.fType)
767 , fCoordTransform(that.fCoordTransform)
768 , fNumOctaves(that.fNumOctaves)
769 , fStitchTiles(that.fStitchTiles)
770 , fPermutationsSampler(that.fPermutationsSampler)
771 , fNoiseSampler(that.fNoiseSampler)
772 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon4331e462017-07-26 14:58:11 -0400773 this->addTextureSampler(&fPermutationsSampler);
774 this->addTextureSampler(&fNoiseSampler);
775 this->addCoordTransform(&fCoordTransform);
776 }
777
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400778 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000779
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400780 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400781 GrCoordTransform fCoordTransform;
782 int fNumOctaves;
783 bool fStitchTiles;
784 TextureSampler fPermutationsSampler;
785 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400786 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000787
joshualittb0a8a372014-09-23 09:50:21 -0700788 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000789};
790
791/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400792GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000793
Hal Canary6f6961e2017-01-31 13:50:44 -0500794#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400795std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700796 int numOctaves = d->fRandom->nextRangeU(2, 10);
797 bool stitchTiles = d->fRandom->nextBool();
798 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
799 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
800 d->fRandom->nextRangeU(4, 4096));
801 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
802 0.99f);
803 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
804 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000805
reedfe630452016-03-25 09:08:00 -0700806 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
807 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400808 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700809 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400810 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000811
Brian Osman9f532a32016-10-19 11:12:09 -0400812 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400813 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000814}
Hal Canary6f6961e2017-01-31 13:50:44 -0500815#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000816
wangyix7c157a92015-07-22 15:08:53 -0700817void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400818 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800819
Mike Reedf2ae2b22017-05-30 15:22:54 -0400820 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800821 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
bsalomon1a1aa932016-09-12 09:30:36 -0700822 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000823
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400824 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800825 "baseFrequency");
826 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000827
halcanary96fcdcc2015-08-27 07:41:13 -0700828 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800829 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400830 fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800831 "stitchData");
832 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000833 }
834
sugoi@google.comd537af52013-06-10 13:59:25 +0000835 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
836 const char* chanCoordR = "0.125";
837 const char* chanCoordG = "0.375";
838 const char* chanCoordB = "0.625";
839 const char* chanCoordA = "0.875";
840 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000841 const char* stitchData = "stitchData";
842 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000843 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000844 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700845 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000846 const char* fractVal = "fractVal";
847 const char* uv = "uv";
848 const char* ab = "ab";
849 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700850 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000851 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000852 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
853 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
854 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400855 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 +0000856
sugoi@google.comd537af52013-06-10 13:59:25 +0000857 // Add noise function
Brian Salomon99938a82016-11-21 13:41:08 -0500858 static const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400859 GrShaderVar(chanCoord, kHalf_GrSLType),
860 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000861 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000862
Brian Salomon99938a82016-11-21 13:41:08 -0500863 static const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400864 GrShaderVar(chanCoord, kHalf_GrSLType),
865 GrShaderVar(noiseVec, kHalf2_GrSLType),
866 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000867 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000868
sugoi@google.comd537af52013-06-10 13:59:25 +0000869 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000870
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400871 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700872 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400873 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
874 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000875
876 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400877 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700878 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000879
880 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800881 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000882 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400883 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000884 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400885 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700886 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400887 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700888 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400889 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000890 }
891
892 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400893 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400894 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000895
896 // Get permutation for x
897 {
898 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400899 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000900
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400901 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700902 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400903 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000904 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000905 }
906
907 // Get permutation for x + 1
908 {
909 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400910 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000911
sugoi@google.comd537af52013-06-10 13:59:25 +0000912 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700913 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400914 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000915 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000916 }
917
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000918#if defined(SK_BUILD_FOR_ANDROID)
919 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
920 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
921 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
922 // (or 0.484368 here). The following rounding operation prevents these precision issues from
923 // affecting the result of the noise by making sure that we only have multiples of 1/255.
924 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400925 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 +0000926 latticeIdx, latticeIdx);
927#endif
928
sugoi@google.come3b4c502013-04-05 13:47:09 +0000929 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400930 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000931
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400932 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000933 // Compute u, at offset (0,0)
934 {
935 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400936 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
937 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700938 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400939 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000940 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
941 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000942 }
943
sugoi@google.comd537af52013-06-10 13:59:25 +0000944 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000945 // Compute v, at offset (-1,0)
946 {
947 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400948 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000949 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700950 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400951 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000952 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
953 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000954 }
955
956 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400957 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000958 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 +0000959
sugoi@google.comd537af52013-06-10 13:59:25 +0000960 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000961 // Compute v, at offset (-1,-1)
962 {
963 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400964 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000965 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700966 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400967 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000968 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
969 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000970 }
971
sugoi@google.comd537af52013-06-10 13:59:25 +0000972 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000973 // Compute u, at offset (0,-1)
974 {
975 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400976 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000977 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700978 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400979 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000980 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
981 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000982 }
983
984 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000985 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 +0000986 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +0000987 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000988
sugoi@google.comd537af52013-06-10 13:59:25 +0000989 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800990 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400991 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800992 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
993 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000994 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400995 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800996 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
997 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000998 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000999
sugoi@google.comd537af52013-06-10 13:59:25 +00001000 // There are rounding errors if the floor operation is not performed here
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001001 fragBuilder->codeAppendf("\n\t\thalf2 %s = floor(%s.xy) * %s;",
egdaniel4ca2e602015-11-18 08:01:26 -08001002 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001003
1004 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001005 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001006
robertphillipsbf536af2016-02-04 06:11:53 -08001007 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001008 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001009 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001010 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001011
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001012 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001013
1014 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001015 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001016
Mike Reedf2ae2b22017-05-30 15:22:54 -04001017 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001018 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001019 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001020 }
robertphillipsbf536af2016-02-04 06:11:53 -08001021 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001022 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001023 "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 +00001024 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1025 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1026 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1027 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1028 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1029 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001030 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001031 "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 +00001032 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1033 noiseFuncName.c_str(), chanCoordR, noiseVec,
1034 noiseFuncName.c_str(), chanCoordG, noiseVec,
1035 noiseFuncName.c_str(), chanCoordB, noiseVec,
1036 noiseFuncName.c_str(), chanCoordA, noiseVec);
1037 }
Florin Malita14d54c22017-05-18 11:52:59 -04001038 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001039 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001040 }
egdaniel4ca2e602015-11-18 08:01:26 -08001041 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001042
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001043 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001044 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001045
robertphillipsbf536af2016-02-04 06:11:53 -08001046 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001047 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001048 }
egdaniel4ca2e602015-11-18 08:01:26 -08001049 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001050
Florin Malita14d54c22017-05-18 11:52:59 -04001051 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001052 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1053 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001054 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001055 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001056 }
1057
sugoi@google.come3b4c502013-04-05 13:47:09 +00001058 // Clamp values
egdaniel4ca2e602015-11-18 08:01:26 -08001059 fragBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001060
1061 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001062 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001063 args.fOutputColor, args.fOutputColor,
1064 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001065}
1066
Brian Salomon94efbf52016-11-29 13:43:05 -05001067void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001068 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001069 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001070
bsalomon63e99f72014-07-21 08:03:14 -07001071 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001072
1073 key = key << 3; // Make room for next 3 bits
1074
1075 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001076 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001077 key |= 0x1;
1078 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001079 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001080 key |= 0x2;
1081 break;
1082 default:
1083 // leave key at 0
1084 break;
1085 }
1086
1087 if (turbulence.stitchTiles()) {
1088 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1089 }
1090
bsalomon63e99f72014-07-21 08:03:14 -07001091 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001092}
1093
egdaniel018fb622015-10-28 07:26:40 -07001094void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001095 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001096 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001097
Mike Reedf2ae2b22017-05-30 15:22:54 -04001098 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001099
1100 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001101 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001102
sugoi@google.com4775cba2013-04-17 13:46:56 +00001103 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001104 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001105 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001106 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001107 }
1108}
1109
sugoi@google.come3b4c502013-04-05 13:47:09 +00001110/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001111
1112class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1113public:
1114 void emitCode(EmitArgs&) override;
1115
1116 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1117
1118protected:
1119 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1120
1121private:
1122 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001123 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1124
1125 typedef GrGLSLFragmentProcessor INHERITED;
1126};
1127
1128/////////////////////////////////////////////////////////////////////
1129
1130class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1131public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001132 static std::unique_ptr<GrFragmentProcessor> Make(
1133 int octaves, SkScalar z,
1134 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1135 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1136 const SkMatrix& matrix) {
1137 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1138 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1139 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001140 }
1141
Mike Reedf2ae2b22017-05-30 15:22:54 -04001142 const char* name() const override { return "ImprovedPerlinNoise"; }
1143
Brian Salomonaff329b2017-08-11 09:40:37 -04001144 std::unique_ptr<GrFragmentProcessor> clone() const override {
1145 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001146 }
1147
Mike Reedf2ae2b22017-05-30 15:22:54 -04001148 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1149 SkScalar z() const { return fZ; }
1150 int octaves() const { return fOctaves; }
1151 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
1152
1153private:
1154 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1155 return new GrGLImprovedPerlinNoise;
1156 }
1157
1158 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1159 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1160 }
1161
1162 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1163 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1164 return fZ == fZ &&
1165 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1166 }
1167
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001168 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001169 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001170 sk_sp<GrTextureProxy> permutationsProxy,
1171 sk_sp<GrTextureProxy> gradientProxy,
1172 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001173 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001174 , fOctaves(octaves)
1175 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001176 , fPermutationsSampler(std::move(permutationsProxy))
1177 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001178 , fPaintingData(std::move(paintingData)) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001179 this->addTextureSampler(&fPermutationsSampler);
1180 this->addTextureSampler(&fGradientSampler);
1181 fCoordTransform.reset(matrix);
1182 this->addCoordTransform(&fCoordTransform);
1183 }
1184
Brian Salomon4331e462017-07-26 14:58:11 -04001185 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001186 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001187 , fCoordTransform(that.fCoordTransform)
1188 , fOctaves(that.fOctaves)
1189 , fZ(that.fZ)
1190 , fPermutationsSampler(that.fPermutationsSampler)
1191 , fGradientSampler(that.fGradientSampler)
1192 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon4331e462017-07-26 14:58:11 -04001193 this->addTextureSampler(&fPermutationsSampler);
1194 this->addTextureSampler(&fGradientSampler);
1195 this->addCoordTransform(&fCoordTransform);
1196 }
1197
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001198 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001199
1200 GrCoordTransform fCoordTransform;
1201 int fOctaves;
1202 SkScalar fZ;
1203 TextureSampler fPermutationsSampler;
1204 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001205 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001206
1207 typedef GrFragmentProcessor INHERITED;
1208};
1209
1210/////////////////////////////////////////////////////////////////////
1211GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1212
1213#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001214std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1215 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001216 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1217 0.99f);
1218 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1219 0.99f);
1220 int numOctaves = d->fRandom->nextRangeU(2, 10);
1221 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1222
1223 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1224 baseFrequencyY,
1225 numOctaves,
1226 z));
1227
1228 GrTest::TestAsFPArgs asFPArgs(d);
1229 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1230}
1231#endif
1232
1233void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001234 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001235 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1236 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1237 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
1238
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001239 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001240 "baseFrequency");
1241 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1242
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001243 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001244 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1245
1246 // fade function
1247 static const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001248 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001249 };
1250 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001251 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001252 fadeArgs,
1253 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1254 &fadeFuncName);
1255
1256 // perm function
1257 static const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001258 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001259 };
1260 SkString permFuncName;
1261 SkString permCode("return ");
1262 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1263 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001264 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001265 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001266 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001267 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001268 permCode.c_str(), &permFuncName);
1269
1270 // grad function
1271 static const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001272 GrShaderVar("x", kHalf_GrSLType),
1273 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001274 };
1275 SkString gradFuncName;
1276 SkString gradCode("return dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001277 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001278 kHalf2_GrSLType);
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001279 gradCode.append(".rgb * 255.0 - float3(1.0), p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001280 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001281 gradCode.c_str(), &gradFuncName);
1282
1283 // lerp function
1284 static const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001285 GrShaderVar("a", kHalf_GrSLType),
1286 GrShaderVar("b", kHalf_GrSLType),
1287 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001288 };
1289 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001290 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001291 "return a + w * (b - a);", &lerpFuncName);
1292
1293 // noise function
1294 static const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001295 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001296 };
1297 SkString noiseFuncName;
1298 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001299 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001300 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001301 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1302 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1303 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1304 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1305 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1306 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1307 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1308 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001309 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1310 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001311 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 -04001312 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001313 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001314 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001315 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001316 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001317 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001318 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1319 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001320 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001321 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001322 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001323 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001324 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 -04001325 gradFuncName.c_str(), permFuncName.c_str());
1326 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001327 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001328 noiseCode.c_str(), &noiseFuncName);
1329
1330 // noiseOctaves function
1331 static const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001332 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001333 };
1334 SkString noiseOctavesFuncName;
1335 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001336 noiseOctavesCode.append("half result = 0.0;");
1337 noiseOctavesCode.append("half ratio = 1.0;");
1338 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001339 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1340 noiseOctavesCode.append("p *= 2.0;");
1341 noiseOctavesCode.append("ratio *= 2.0;");
1342 noiseOctavesCode.append("}");
1343 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001344 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001345 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1346
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001347 fragBuilder->codeAppendf("half2 coords = %s * %s;", vCoords.c_str(), baseFrequencyUni);
1348 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001349 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001350 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001351 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001352 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001353 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001354 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001355 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001356 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001357
1358 // Clamp values
1359 fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
1360
1361 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001362 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001363 args.fOutputColor, args.fOutputColor,
1364 args.fOutputColor, args.fOutputColor);
1365}
1366
1367void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1368 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001369 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1370 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001371}
1372
1373void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1374 const GrFragmentProcessor& processor) {
1375 INHERITED::onSetData(pdman, processor);
1376
1377 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1378
1379 const SkVector& baseFrequency = noise.baseFrequency();
1380 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1381
Mike Reedf2ae2b22017-05-30 15:22:54 -04001382 pdman.set1f(fZUni, noise.z());
1383}
1384
1385/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001386std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001387 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001388 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001389
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001390 SkMatrix localMatrix = this->getLocalMatrix();
brianosman839345d2016-07-22 11:04:53 -07001391 if (args.fLocalMatrix) {
1392 localMatrix.preConcat(*args.fLocalMatrix);
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001393 }
1394
brianosman839345d2016-07-22 11:04:53 -07001395 SkMatrix matrix = *args.fViewMatrix;
senorblancoca6a7c22014-06-27 13:35:52 -07001396 matrix.preConcat(localMatrix);
1397
Mike Reedf2ae2b22017-05-30 15:22:54 -04001398 // Either we don't stitch tiles, either we have a valid tile size
1399 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1400
Florin Malitab365cf52017-05-30 17:18:01 -04001401 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
1402 skstd::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
1403 fSeed,
1404 fBaseFrequencyX,
1405 fBaseFrequencyY,
1406 matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001407
1408 SkMatrix m = *args.fViewMatrix;
1409 m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
1410 m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
1411
1412 if (fType == kImprovedNoise_Type) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -04001413 GrSamplerState textureParams(GrSamplerState::WrapMode::kRepeat,
1414 GrSamplerState::Filter::kNearest);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001415 sk_sp<GrTextureProxy> permutationsTexture(
1416 GrRefCachedBitmapTextureProxy(args.fContext,
1417 paintingData->getImprovedPermutationsBitmap(),
1418 textureParams, nullptr));
1419 sk_sp<GrTextureProxy> gradientTexture(
1420 GrRefCachedBitmapTextureProxy(args.fContext,
1421 paintingData->getGradientBitmap(),
1422 textureParams, nullptr));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001423 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001424 std::move(permutationsTexture),
1425 std::move(gradientTexture), m);
1426 }
1427
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001428 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001429 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001430 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001431 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1432 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1433 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001434 auto inner =
1435 GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001436 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001437 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001438 }
bsalomonc21b09e2015-08-28 18:46:56 -07001439 // Emit zero.
Brian Osman618d3042016-10-25 10:51:28 -04001440 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001441 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001442 }
1443
Mike Reedf2ae2b22017-05-30 15:22:54 -04001444 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedBitmapProxy(
Robert Phillips1afd4cd2018-01-08 13:40:32 -05001445 args.fContext->contextPriv().proxyProvider(),
1446 paintingData->getPermutationsBitmap());
1447 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedBitmapProxy(
1448 args.fContext->contextPriv().proxyProvider(),
1449 paintingData->getNoiseBitmap());
sugoi@google.come3b4c502013-04-05 13:47:09 +00001450
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001451 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001452 auto inner = GrPerlinNoise2Effect::Make(fType,
1453 fNumOctaves,
1454 fStitchTiles,
1455 std::move(paintingData),
1456 std::move(permutationsProxy),
1457 std::move(noiseProxy),
1458 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001459 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001460 }
bsalomonc21b09e2015-08-28 18:46:56 -07001461 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001462}
1463
1464#endif
1465
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001466#ifndef SK_IGNORE_TO_STRING
Florin Malita14d54c22017-05-18 11:52:59 -04001467void SkPerlinNoiseShaderImpl::toString(SkString* str) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001468 str->append("SkPerlinNoiseShaderImpl: (");
sugoi@google.come3b4c502013-04-05 13:47:09 +00001469
1470 str->append("type: ");
1471 switch (fType) {
1472 case kFractalNoise_Type:
1473 str->append("\"fractal noise\"");
1474 break;
1475 case kTurbulence_Type:
1476 str->append("\"turbulence\"");
1477 break;
1478 default:
1479 str->append("\"unknown\"");
1480 break;
1481 }
1482 str->append(" base frequency: (");
1483 str->appendScalar(fBaseFrequencyX);
1484 str->append(", ");
1485 str->appendScalar(fBaseFrequencyY);
1486 str->append(") number of octaves: ");
1487 str->appendS32(fNumOctaves);
1488 str->append(" seed: ");
1489 str->appendScalar(fSeed);
1490 str->append(" stitch tiles: ");
1491 str->append(fStitchTiles ? "true " : "false ");
1492
1493 this->INHERITED::toString(str);
1494
1495 str->append(")");
1496}
1497#endif
Florin Malita14d54c22017-05-18 11:52:59 -04001498
Mike Reedf2ae2b22017-05-30 15:22:54 -04001499///////////////////////////////////////////////////////////////////////////////////////////////////
1500
1501sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1502 SkScalar baseFrequencyY,
1503 int numOctaves, SkScalar seed,
1504 const SkISize* tileSize) {
1505 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1506 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1507 tileSize));
1508}
1509
1510sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1511 SkScalar baseFrequencyY,
1512 int numOctaves, SkScalar seed,
1513 const SkISize* tileSize) {
1514 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1515 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1516 tileSize));
1517}
1518
1519sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1520 SkScalar baseFrequencyY,
1521 int numOctaves, SkScalar z) {
1522 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1523 baseFrequencyX, baseFrequencyY, numOctaves, z,
1524 nullptr));
1525}
1526
Florin Malita14d54c22017-05-18 11:52:59 -04001527SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPerlinNoiseShader)
1528 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShaderImpl)
1529SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END