blob: 1f70d500d5a8bdbd51a82b9c33bcda92ce8de30b [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"
bsalomon@google.com77af6802013-10-02 13:04:56 +000022#include "GrCoordTransform.h"
joshualitteb2a6762014-12-04 11:35:33 -080023#include "SkGr.h"
bsalomonc21b09e2015-08-28 18:46:56 -070024#include "effects/GrConstColorProcessor.h"
egdaniel64c47282015-11-13 06:54:19 -080025#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080026#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070027#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080028#include "glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000029#endif
30
31static const int kBlockSize = 256;
32static const int kBlockMask = kBlockSize - 1;
33static const int kPerlinNoise = 4096;
34static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
35
Mike Reedf2ae2b22017-05-30 15:22:54 -040036static uint8_t improved_noise_permutations[] = {
37 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
38 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
39 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
40 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
41 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
42 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
43 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
44 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
45 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
46 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
47 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
48 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
49 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
50 141, 128, 195, 78, 66, 215, 61, 156, 180,
51 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
52 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
53 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
54 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
55 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
56 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
57 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
58 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
59 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
60 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
61 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
62 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
63 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
64 141, 128, 195, 78, 66, 215, 61, 156, 180
65};
66
67class SkPerlinNoiseShaderImpl : public SkShaderBase {
68public:
Florin Malita83223bc2017-05-31 14:14:05 -040069 struct StitchData {
70 StitchData()
71 : fWidth(0)
72 , fWrapX(0)
73 , fHeight(0)
74 , fWrapY(0)
75 {}
76
77 bool operator==(const StitchData& other) const {
78 return fWidth == other.fWidth &&
79 fWrapX == other.fWrapX &&
80 fHeight == other.fHeight &&
81 fWrapY == other.fWrapY;
82 }
83
84 int fWidth; // How much to subtract to wrap for stitching.
85 int fWrapX; // Minimum value to wrap.
86 int fHeight;
87 int fWrapY;
88 };
89
90 struct PaintingData {
91 PaintingData(const SkISize& tileSize, SkScalar seed,
92 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
93 const SkMatrix& matrix)
94 {
95 SkVector vec[2] = {
96 { SkScalarInvert(baseFrequencyX), SkScalarInvert(baseFrequencyY) },
97 { SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight) },
98 };
99 matrix.mapVectors(vec, 2);
100
101 fBaseFrequency.set(SkScalarInvert(vec[0].fX), SkScalarInvert(vec[0].fY));
102 fTileSize.set(SkScalarRoundToInt(vec[1].fX), SkScalarRoundToInt(vec[1].fY));
103 this->init(seed);
104 if (!fTileSize.isEmpty()) {
105 this->stitch();
106 }
107
108 #if SK_SUPPORT_GPU
109 fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1));
110 fPermutationsBitmap.setPixels(fLatticeSelector);
111
112 fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4));
113 fNoiseBitmap.setPixels(fNoise[0][0]);
114
115 fImprovedPermutationsBitmap.setInfo(SkImageInfo::MakeA8(256, 1));
116 fImprovedPermutationsBitmap.setPixels(improved_noise_permutations);
117
118 fGradientBitmap.setInfo(SkImageInfo::MakeN32Premul(16, 1));
119 static uint8_t gradients[] = { 2, 2, 1, 0,
120 0, 2, 1, 0,
121 2, 0, 1, 0,
122 0, 0, 1, 0,
123 2, 1, 2, 0,
124 0, 1, 2, 0,
125 2, 1, 0, 0,
126 0, 1, 0, 0,
127 1, 2, 2, 0,
128 1, 0, 2, 0,
129 1, 2, 0, 0,
130 1, 0, 0, 0,
131 2, 2, 1, 0,
132 1, 0, 2, 0,
133 0, 2, 1, 0,
134 1, 0, 0, 0 };
135 fGradientBitmap.setPixels(gradients);
136 #endif
137 }
138
Brian Salomon4331e462017-07-26 14:58:11 -0400139 #if SK_SUPPORT_GPU
140 PaintingData(const PaintingData& that)
141 : fSeed(that.fSeed)
142 , fTileSize(that.fTileSize)
143 , fBaseFrequency(that.fBaseFrequency)
144 , fStitchDataInit(that.fStitchDataInit)
145 , fPermutationsBitmap(that.fPermutationsBitmap)
146 , fNoiseBitmap(that.fNoiseBitmap)
147 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
148 , fGradientBitmap(that.fGradientBitmap) {
149 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
150 memcpy(fNoise, that.fNoise, sizeof(fNoise));
151 memcpy(fGradient, that.fGradient, sizeof(fGradient));
152 }
153 #endif
154
Florin Malita83223bc2017-05-31 14:14:05 -0400155 int fSeed;
156 uint8_t fLatticeSelector[kBlockSize];
157 uint16_t fNoise[4][kBlockSize][2];
158 SkPoint fGradient[4][kBlockSize];
159 SkISize fTileSize;
160 SkVector fBaseFrequency;
161 StitchData fStitchDataInit;
162
163 private:
164
165 #if SK_SUPPORT_GPU
166 SkBitmap fPermutationsBitmap;
167 SkBitmap fNoiseBitmap;
168 SkBitmap fImprovedPermutationsBitmap;
169 SkBitmap fGradientBitmap;
170 #endif
171
172 inline int random() {
173 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
174 static const int gRandQ = 127773; // m / a
175 static const int gRandR = 2836; // m % a
176
177 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
178 if (result <= 0)
179 result += kRandMaximum;
180 fSeed = result;
181 return result;
182 }
183
184 // Only called once. Could be part of the constructor.
185 void init(SkScalar seed)
186 {
187 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
188
189 // According to the SVG spec, we must truncate (not round) the seed value.
190 fSeed = SkScalarTruncToInt(seed);
191 // The seed value clamp to the range [1, kRandMaximum - 1].
192 if (fSeed <= 0) {
193 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
194 }
195 if (fSeed > kRandMaximum - 1) {
196 fSeed = kRandMaximum - 1;
197 }
198 for (int channel = 0; channel < 4; ++channel) {
199 for (int i = 0; i < kBlockSize; ++i) {
200 fLatticeSelector[i] = i;
201 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
202 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
203 }
204 }
205 for (int i = kBlockSize - 1; i > 0; --i) {
206 int k = fLatticeSelector[i];
207 int j = random() % kBlockSize;
208 SkASSERT(j >= 0);
209 SkASSERT(j < kBlockSize);
210 fLatticeSelector[i] = fLatticeSelector[j];
211 fLatticeSelector[j] = k;
212 }
213
214 // Perform the permutations now
215 {
216 // Copy noise data
217 uint16_t noise[4][kBlockSize][2];
218 for (int i = 0; i < kBlockSize; ++i) {
219 for (int channel = 0; channel < 4; ++channel) {
220 for (int j = 0; j < 2; ++j) {
221 noise[channel][i][j] = fNoise[channel][i][j];
222 }
223 }
224 }
225 // Do permutations on noise data
226 for (int i = 0; i < kBlockSize; ++i) {
227 for (int channel = 0; channel < 4; ++channel) {
228 for (int j = 0; j < 2; ++j) {
229 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
230 }
231 }
232 }
233 }
234
235 // Half of the largest possible value for 16 bit unsigned int
236 static const SkScalar gHalfMax16bits = 32767.5f;
237
238 // Compute gradients from permutated noise data
239 for (int channel = 0; channel < 4; ++channel) {
240 for (int i = 0; i < kBlockSize; ++i) {
241 fGradient[channel][i] = SkPoint::Make(
242 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
243 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
244 fGradient[channel][i].normalize();
245 // Put the normalized gradient back into the noise data
246 fNoise[channel][i][0] = SkScalarRoundToInt(
247 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
248 fNoise[channel][i][1] = SkScalarRoundToInt(
249 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
250 }
251 }
252 }
253
254 // Only called once. Could be part of the constructor.
255 void stitch() {
256 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
257 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
258 SkASSERT(tileWidth > 0 && tileHeight > 0);
259 // When stitching tiled turbulence, the frequencies must be adjusted
260 // so that the tile borders will be continuous.
261 if (fBaseFrequency.fX) {
262 SkScalar lowFrequencx =
263 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
264 SkScalar highFrequencx =
265 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
266 // BaseFrequency should be non-negative according to the standard.
267 if (fBaseFrequency.fX / lowFrequencx < highFrequencx / fBaseFrequency.fX) {
268 fBaseFrequency.fX = lowFrequencx;
269 } else {
270 fBaseFrequency.fX = highFrequencx;
271 }
272 }
273 if (fBaseFrequency.fY) {
274 SkScalar lowFrequency =
275 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
276 SkScalar highFrequency =
277 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
278 if (fBaseFrequency.fY / lowFrequency < highFrequency / fBaseFrequency.fY) {
279 fBaseFrequency.fY = lowFrequency;
280 } else {
281 fBaseFrequency.fY = highFrequency;
282 }
283 }
284 // Set up TurbulenceInitial stitch values.
285 fStitchDataInit.fWidth =
286 SkScalarRoundToInt(tileWidth * fBaseFrequency.fX);
287 fStitchDataInit.fWrapX = kPerlinNoise + fStitchDataInit.fWidth;
288 fStitchDataInit.fHeight =
289 SkScalarRoundToInt(tileHeight * fBaseFrequency.fY);
290 fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight;
291 }
292
293 public:
294
295#if SK_SUPPORT_GPU
296 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
297
298 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
299
300 const SkBitmap& getImprovedPermutationsBitmap() const { return fImprovedPermutationsBitmap; }
301
302 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
303#endif
304 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400305
306 /**
307 * About the noise types : the difference between the first 2 is just minor tweaks to the
308 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
309 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
310 * doing :
311 * kFractalNoise_Type : noise * 0.5 + 0.5
312 * kTurbulence_Type : abs(noise)
313 * Very little differences between the 2 types, although you can tell the difference visually.
314 * "Improved" is based on the Improved Perlin Noise algorithm described at
315 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
316 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
317 * changes to the noise, making it suitable for animated noise.
318 */
319 enum Type {
320 kFractalNoise_Type,
321 kTurbulence_Type,
322 kImprovedNoise_Type,
323 kFirstType = kFractalNoise_Type,
324 kLastType = kImprovedNoise_Type
325 };
326
327 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
328 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
329 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400330
331 class PerlinNoiseShaderContext : public Context {
332 public:
333 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400334
335 void shadeSpan(int x, int y, SkPMColor[], int count) override;
336
337 private:
338 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
339 SkScalar calculateTurbulenceValueForPoint(
340 int channel,
341 StitchData& stitchData, const SkPoint& point) const;
342 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
343 SkScalar noise2D(int channel,
344 const StitchData& stitchData, const SkPoint& noiseVector) const;
345
Florin Malita83223bc2017-05-31 14:14:05 -0400346 SkMatrix fMatrix;
347 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400348
349 typedef Context INHERITED;
350 };
351
352#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -0400353 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400354#endif
355
356 SK_TO_STRING_OVERRIDE()
357 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPerlinNoiseShaderImpl)
358
359protected:
360 void flatten(SkWriteBuffer&) const override;
361 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
362
363private:
364 const SkPerlinNoiseShaderImpl::Type fType;
365 const SkScalar fBaseFrequencyX;
366 const SkScalar fBaseFrequencyY;
367 const int fNumOctaves;
368 const SkScalar fSeed;
369 const SkISize fTileSize;
370 const bool fStitchTiles;
371
372 friend class ::SkPerlinNoiseShader;
373
374 typedef SkShaderBase INHERITED;
375};
376
sugoi@google.come3b4c502013-04-05 13:47:09 +0000377namespace {
378
379// noiseValue is the color component's value (or color)
380// limitValue is the maximum perlin noise array index value allowed
381// newValue is the current noise dimension (either width or height)
382inline int checkNoise(int noiseValue, int limitValue, int newValue) {
383 // If the noise value would bring us out of bounds of the current noise array while we are
384 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
385 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
386 if (noiseValue >= limitValue) {
387 noiseValue -= newValue;
388 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000389 return noiseValue;
390}
391
392inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500393 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000394}
395
396} // end namespace
397
Mike Reedf2ae2b22017-05-30 15:22:54 -0400398SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
399 SkScalar baseFrequencyX,
400 SkScalar baseFrequencyY,
401 int numOctaves,
402 SkScalar seed,
403 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000404 : fType(type)
405 , fBaseFrequencyX(baseFrequencyX)
406 , fBaseFrequencyY(baseFrequencyY)
Mike Reedf2ae2b22017-05-30 15:22:54 -0400407 , fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000408 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700409 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000410 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000411{
Mike Reedf2ae2b22017-05-30 15:22:54 -0400412 SkASSERT(numOctaves >= 0 && numOctaves < 256);
413}
414
Florin Malita14d54c22017-05-18 11:52:59 -0400415sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700416 Type type = (Type)buffer.readInt();
417 SkScalar freqX = buffer.readScalar();
418 SkScalar freqY = buffer.readScalar();
419 int octaves = buffer.readInt();
420 SkScalar seed = buffer.readScalar();
421 SkISize tileSize;
422 tileSize.fWidth = buffer.readInt();
423 tileSize.fHeight = buffer.readInt();
424
425 switch (type) {
426 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400427 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700428 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400429 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
430 case kImprovedNoise_Type:
431 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700432 default:
halcanary96fcdcc2015-08-27 07:41:13 -0700433 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700434 }
435}
436
Florin Malita14d54c22017-05-18 11:52:59 -0400437void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000438 buffer.writeInt((int) fType);
439 buffer.writeScalar(fBaseFrequencyX);
440 buffer.writeScalar(fBaseFrequencyY);
441 buffer.writeInt(fNumOctaves);
442 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000443 buffer.writeInt(fTileSize.fWidth);
444 buffer.writeInt(fTileSize.fHeight);
445}
446
Florin Malita14d54c22017-05-18 11:52:59 -0400447SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700448 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000449 struct Noise {
450 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700451 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000452 SkScalar noisePositionFractionValue;
453 Noise(SkScalar component)
454 {
455 SkScalar position = component + kPerlinNoise;
456 noisePositionIntegerValue = SkScalarFloorToInt(position);
457 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700458 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000459 }
460 };
461 Noise noiseX(noiseVector.x());
462 Noise noiseY(noiseVector.y());
463 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400464 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000465 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000466 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000467 noiseX.noisePositionIntegerValue =
468 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
469 noiseY.noisePositionIntegerValue =
470 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700471 noiseX.nextNoisePositionIntegerValue =
472 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
473 noiseY.nextNoisePositionIntegerValue =
474 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000475 }
476 noiseX.noisePositionIntegerValue &= kBlockMask;
477 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700478 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
479 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400480 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
481 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700482 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
483 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
484 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
485 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000486 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
487 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400488
Hal Canaryfda46002017-05-08 17:17:47 -0400489 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
490 return 0; // Check for pathological inputs.
491 }
Mike Reedf2ae2b22017-05-30 15:22:54 -0400492
sugoi@google.come3b4c502013-04-05 13:47:09 +0000493 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
494 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
495 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400496 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000497 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400498 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000499 SkScalar a = SkScalarInterp(u, v, sx);
500 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400501 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000502 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400503 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000504 SkScalar b = SkScalarInterp(u, v, sx);
505 return SkScalarInterp(a, b, sy);
506}
507
Florin Malita14d54c22017-05-18 11:52:59 -0400508SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700509 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400510 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000511 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000512 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400513 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000514 }
515 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400516 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
517 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000518 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000519 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700520 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700521 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
522 noise : SkScalarAbs(noise);
523 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000524 noiseVector.fX *= 2;
525 noiseVector.fY *= 2;
526 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000527 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000528 // Update stitch values
529 stitchData.fWidth *= 2;
530 stitchData.fWrapX = stitchData.fWidth + kPerlinNoise;
531 stitchData.fHeight *= 2;
532 stitchData.fWrapY = stitchData.fHeight + kPerlinNoise;
533 }
534 }
535
536 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
537 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000538 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400539 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000540 }
541
542 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700543 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000544 }
545
546 // Clamp result
547 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
548}
549
Mike Reedf2ae2b22017-05-30 15:22:54 -0400550////////////////////////////////////////////////////////////////////////////////////////////////////
551// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
552static SkScalar fade(SkScalar t) {
553 return t * t * t * (t * (t * 6 - 15) + 10);
554}
555
556static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
557 return a + t * (b - a);
558}
559
560static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
561 int h = hash & 15;
562 SkScalar u = h < 8 ? x : y;
563 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
564 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
565}
566
567SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
568 int channel, const SkPoint& point) const {
569 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
570 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
571 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
572 // z offset between different channels, chosen arbitrarily
573 static const SkScalar CHANNEL_DELTA = 1000.0f;
574 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
575 SkScalar result = 0;
576 SkScalar ratio = SK_Scalar1;
577 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
578 int X = SkScalarFloorToInt(x) & 255;
579 int Y = SkScalarFloorToInt(y) & 255;
580 int Z = SkScalarFloorToInt(z) & 255;
581 SkScalar px = x - SkScalarFloorToScalar(x);
582 SkScalar py = y - SkScalarFloorToScalar(y);
583 SkScalar pz = z - SkScalarFloorToScalar(z);
584 SkScalar u = fade(px);
585 SkScalar v = fade(py);
586 SkScalar w = fade(pz);
587 uint8_t* permutations = improved_noise_permutations;
588 int A = permutations[X] + Y;
589 int AA = permutations[A] + Z;
590 int AB = permutations[A + 1] + Z;
591 int B = permutations[X + 1] + Y;
592 int BA = permutations[B] + Z;
593 int BB = permutations[B + 1] + Z;
594 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
595 grad(permutations[BA ], px - 1, py , pz )),
596 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
597 grad(permutations[BB ], px - 1, py - 1, pz ))),
598 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
599 grad(permutations[BA + 1], px - 1, py , pz - 1)),
600 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
601 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
602 ratio;
603 x *= 2;
604 y *= 2;
605 ratio *= 2;
606 }
607 result = SkScalarClampMax((result + 1.0f) / 2.0f, 1.0f);
608 return result;
609}
610////////////////////////////////////////////////////////////////////////////////////////////////////
611
Florin Malita14d54c22017-05-18 11:52:59 -0400612SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000613 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400614 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000615 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000616 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000617 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
618 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
619
620 U8CPU rgba[4];
621 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400622 SkScalar value;
623 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
624 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
625 }
626 else {
627 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
628 }
629 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000630 }
631 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
632}
633
Mike Reedf2ae2b22017-05-30 15:22:54 -0400634SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
635 SkArenaAlloc* alloc) const {
Herb Derby83e939b2017-02-07 14:25:11 -0500636 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000637}
638
Florin Malita83223bc2017-05-31 14:14:05 -0400639static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
640 const SkShaderBase& shader) {
641 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
642 if (rec.fLocalMatrix) {
643 matrix.preConcat(*rec.fLocalMatrix);
644 }
645
646 return matrix;
647}
648
Florin Malita14d54c22017-05-18 11:52:59 -0400649SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
650 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000651 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400652 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
653 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
654 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000655{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000656 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
657 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400658 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
659 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700660}
661
Florin Malita14d54c22017-05-18 11:52:59 -0400662void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000663 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000664 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
665 StitchData stitchData;
666 for (int i = 0; i < count; ++i) {
667 result[i] = shade(point, stitchData);
668 point.fX += SK_Scalar1;
669 }
670}
671
sugoi@google.come3b4c502013-04-05 13:47:09 +0000672/////////////////////////////////////////////////////////////////////
673
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000674#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000675
egdaniel64c47282015-11-13 06:54:19 -0800676class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000677public:
robertphillips9cdb9922016-02-03 12:25:40 -0800678 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000679
Mike Reedf2ae2b22017-05-30 15:22:54 -0400680 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000681
wangyixb1daa862015-08-18 11:29:31 -0700682protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400683 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700684
sugoi@google.com4775cba2013-04-17 13:46:56 +0000685private:
egdaniel018fb622015-10-28 07:26:40 -0700686 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700687 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700688
egdaniel64c47282015-11-13 06:54:19 -0800689 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000690};
691
692/////////////////////////////////////////////////////////////////////
693
Mike Reedf2ae2b22017-05-30 15:22:54 -0400694class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000695public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400696 static std::unique_ptr<GrFragmentProcessor> Make(
697 SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
698 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
699 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> noiseProxy,
700 const SkMatrix& matrix) {
701 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
702 type, numOctaves, stitchTiles, std::move(paintingData),
703 std::move(permutationsProxy), std::move(noiseProxy), matrix));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000704 }
705
mtklein36352bf2015-03-25 18:17:31 -0700706 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800707
Brian Salomonaff329b2017-08-11 09:40:37 -0400708 std::unique_ptr<GrFragmentProcessor> clone() const override {
709 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400710 }
711
Mike Reedf2ae2b22017-05-30 15:22:54 -0400712 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000713
Florin Malita14d54c22017-05-18 11:52:59 -0400714 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700715 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700716 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700717 int numOctaves() const { return fNumOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -0400718 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
senorblancof3b50272014-06-16 10:49:58 -0700719
sugoi@google.come3b4c502013-04-05 13:47:09 +0000720private:
egdaniel57d3b032015-11-13 11:57:27 -0800721 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800722 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700723 }
724
Brian Salomon94efbf52016-11-29 13:43:05 -0500725 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800726 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700727 GrGLPerlinNoise::GenKey(*this, caps, b);
728 }
729
mtklein36352bf2015-03-25 18:17:31 -0700730 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400731 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700732 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700733 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700734 fNumOctaves == s.fNumOctaves &&
735 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700736 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000737 }
738
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400739 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400740 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400741 sk_sp<GrTextureProxy> permutationsProxy,
742 sk_sp<GrTextureProxy> noiseProxy,
743 const SkMatrix& matrix)
Brian Salomon587e08f2017-01-27 10:59:27 -0500744 : INHERITED(kNone_OptimizationFlags)
745 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500746 , fNumOctaves(numOctaves)
747 , fStitchTiles(stitchTiles)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400748 , fPermutationsSampler(std::move(permutationsProxy))
749 , fNoiseSampler(std::move(noiseProxy))
Florin Malitab365cf52017-05-30 17:18:01 -0400750 , fPaintingData(std::move(paintingData)) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400751 this->initClassID<GrPerlinNoise2Effect>();
Brian Salomon0bbecb22016-11-17 11:38:22 -0500752 this->addTextureSampler(&fPermutationsSampler);
753 this->addTextureSampler(&fNoiseSampler);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400754 fCoordTransform.reset(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700755 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000756 }
757
Brian Salomon4331e462017-07-26 14:58:11 -0400758 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
759 : INHERITED(kNone_OptimizationFlags)
760 , fType(that.fType)
761 , fCoordTransform(that.fCoordTransform)
762 , fNumOctaves(that.fNumOctaves)
763 , fStitchTiles(that.fStitchTiles)
764 , fPermutationsSampler(that.fPermutationsSampler)
765 , fNoiseSampler(that.fNoiseSampler)
766 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
767 this->initClassID<GrPerlinNoise2Effect>();
768 this->addTextureSampler(&fPermutationsSampler);
769 this->addTextureSampler(&fNoiseSampler);
770 this->addCoordTransform(&fCoordTransform);
771 }
772
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400773 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000774
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400775 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400776 GrCoordTransform fCoordTransform;
777 int fNumOctaves;
778 bool fStitchTiles;
779 TextureSampler fPermutationsSampler;
780 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400781 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000782
joshualittb0a8a372014-09-23 09:50:21 -0700783 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000784};
785
786/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400787GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000788
Hal Canary6f6961e2017-01-31 13:50:44 -0500789#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400790std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700791 int numOctaves = d->fRandom->nextRangeU(2, 10);
792 bool stitchTiles = d->fRandom->nextBool();
793 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
794 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
795 d->fRandom->nextRangeU(4, 4096));
796 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
797 0.99f);
798 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
799 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000800
reedfe630452016-03-25 09:08:00 -0700801 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
802 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400803 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700804 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400805 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000806
Brian Osman9f532a32016-10-19 11:12:09 -0400807 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400808 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000809}
Hal Canary6f6961e2017-01-31 13:50:44 -0500810#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000811
wangyix7c157a92015-07-22 15:08:53 -0700812void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400813 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800814
Mike Reedf2ae2b22017-05-30 15:22:54 -0400815 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800816 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
bsalomon1a1aa932016-09-12 09:30:36 -0700817 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000818
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400819 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800820 "baseFrequency");
821 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000822
halcanary96fcdcc2015-08-27 07:41:13 -0700823 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800824 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400825 fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800826 "stitchData");
827 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000828 }
829
sugoi@google.comd537af52013-06-10 13:59:25 +0000830 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
831 const char* chanCoordR = "0.125";
832 const char* chanCoordG = "0.375";
833 const char* chanCoordB = "0.625";
834 const char* chanCoordA = "0.875";
835 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000836 const char* stitchData = "stitchData";
837 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000838 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000839 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700840 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000841 const char* fractVal = "fractVal";
842 const char* uv = "uv";
843 const char* ab = "ab";
844 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700845 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000846 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000847 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
848 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
849 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400850 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 +0000851
sugoi@google.comd537af52013-06-10 13:59:25 +0000852 // Add noise function
Brian Salomon99938a82016-11-21 13:41:08 -0500853 static const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400854 GrShaderVar(chanCoord, kHalf_GrSLType),
855 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000856 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000857
Brian Salomon99938a82016-11-21 13:41:08 -0500858 static const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400859 GrShaderVar(chanCoord, kHalf_GrSLType),
860 GrShaderVar(noiseVec, kHalf2_GrSLType),
861 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000862 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000863
sugoi@google.comd537af52013-06-10 13:59:25 +0000864 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000865
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400866 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700867 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400868 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
869 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000870
871 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400872 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700873 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000874
875 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800876 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000877 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400878 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000879 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400880 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700881 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400882 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700883 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400884 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000885 }
886
887 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400888 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400889 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000890
891 // Get permutation for x
892 {
893 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400894 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000895
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400896 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700897 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400898 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000899 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000900 }
901
902 // Get permutation for x + 1
903 {
904 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400905 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000906
sugoi@google.comd537af52013-06-10 13:59:25 +0000907 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700908 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400909 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000910 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000911 }
912
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000913#if defined(SK_BUILD_FOR_ANDROID)
914 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
915 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
916 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
917 // (or 0.484368 here). The following rounding operation prevents these precision issues from
918 // affecting the result of the noise by making sure that we only have multiples of 1/255.
919 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400920 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 +0000921 latticeIdx, latticeIdx);
922#endif
923
sugoi@google.come3b4c502013-04-05 13:47:09 +0000924 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400925 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000926
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400927 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000928 // Compute u, at offset (0,0)
929 {
930 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400931 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
932 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700933 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400934 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000935 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
936 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000937 }
938
sugoi@google.comd537af52013-06-10 13:59:25 +0000939 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000940 // Compute v, at offset (-1,0)
941 {
942 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400943 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000944 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700945 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400946 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000947 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
948 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000949 }
950
951 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400952 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000953 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 +0000954
sugoi@google.comd537af52013-06-10 13:59:25 +0000955 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000956 // Compute v, at offset (-1,-1)
957 {
958 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400959 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000960 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700961 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400962 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000963 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
964 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000965 }
966
sugoi@google.comd537af52013-06-10 13:59:25 +0000967 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000968 // Compute u, at offset (0,-1)
969 {
970 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400971 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000972 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700973 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400974 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000975 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
976 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000977 }
978
979 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000980 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 +0000981 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +0000982 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000983
sugoi@google.comd537af52013-06-10 13:59:25 +0000984 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800985 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400986 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800987 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
988 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000989 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400990 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800991 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
992 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000993 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000994
sugoi@google.comd537af52013-06-10 13:59:25 +0000995 // There are rounding errors if the floor operation is not performed here
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400996 fragBuilder->codeAppendf("\n\t\thalf2 %s = floor(%s.xy) * %s;",
egdaniel4ca2e602015-11-18 08:01:26 -0800997 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000998
999 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001000 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001001
robertphillipsbf536af2016-02-04 06:11:53 -08001002 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001003 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001004 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001005 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001006
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001007 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001008
1009 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001010 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001011
Mike Reedf2ae2b22017-05-30 15:22:54 -04001012 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001013 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001014 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001015 }
robertphillipsbf536af2016-02-04 06:11:53 -08001016 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001017 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001018 "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 +00001019 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1020 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1021 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1022 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1023 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1024 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001025 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001026 "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 +00001027 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1028 noiseFuncName.c_str(), chanCoordR, noiseVec,
1029 noiseFuncName.c_str(), chanCoordG, noiseVec,
1030 noiseFuncName.c_str(), chanCoordB, noiseVec,
1031 noiseFuncName.c_str(), chanCoordA, noiseVec);
1032 }
Florin Malita14d54c22017-05-18 11:52:59 -04001033 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001034 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001035 }
egdaniel4ca2e602015-11-18 08:01:26 -08001036 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001037
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001038 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001039 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001040
robertphillipsbf536af2016-02-04 06:11:53 -08001041 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001042 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001043 }
egdaniel4ca2e602015-11-18 08:01:26 -08001044 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001045
Florin Malita14d54c22017-05-18 11:52:59 -04001046 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001047 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1048 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001049 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001050 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001051 }
1052
sugoi@google.come3b4c502013-04-05 13:47:09 +00001053 // Clamp values
egdaniel4ca2e602015-11-18 08:01:26 -08001054 fragBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001055
1056 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001057 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001058 args.fOutputColor, args.fOutputColor,
1059 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001060}
1061
Brian Salomon94efbf52016-11-29 13:43:05 -05001062void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001063 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001064 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001065
bsalomon63e99f72014-07-21 08:03:14 -07001066 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001067
1068 key = key << 3; // Make room for next 3 bits
1069
1070 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001071 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001072 key |= 0x1;
1073 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001074 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001075 key |= 0x2;
1076 break;
1077 default:
1078 // leave key at 0
1079 break;
1080 }
1081
1082 if (turbulence.stitchTiles()) {
1083 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1084 }
1085
bsalomon63e99f72014-07-21 08:03:14 -07001086 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001087}
1088
egdaniel018fb622015-10-28 07:26:40 -07001089void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001090 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001091 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001092
Mike Reedf2ae2b22017-05-30 15:22:54 -04001093 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001094
1095 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001096 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001097
sugoi@google.com4775cba2013-04-17 13:46:56 +00001098 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001099 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001100 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001101 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001102 }
1103}
1104
sugoi@google.come3b4c502013-04-05 13:47:09 +00001105/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001106
1107class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1108public:
1109 void emitCode(EmitArgs&) override;
1110
1111 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1112
1113protected:
1114 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1115
1116private:
1117 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001118 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1119
1120 typedef GrGLSLFragmentProcessor INHERITED;
1121};
1122
1123/////////////////////////////////////////////////////////////////////
1124
1125class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1126public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001127 static std::unique_ptr<GrFragmentProcessor> Make(
1128 int octaves, SkScalar z,
1129 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1130 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1131 const SkMatrix& matrix) {
1132 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1133 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1134 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001135 }
1136
Mike Reedf2ae2b22017-05-30 15:22:54 -04001137 const char* name() const override { return "ImprovedPerlinNoise"; }
1138
Brian Salomonaff329b2017-08-11 09:40:37 -04001139 std::unique_ptr<GrFragmentProcessor> clone() const override {
1140 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001141 }
1142
Mike Reedf2ae2b22017-05-30 15:22:54 -04001143 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1144 SkScalar z() const { return fZ; }
1145 int octaves() const { return fOctaves; }
1146 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
1147
1148private:
1149 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1150 return new GrGLImprovedPerlinNoise;
1151 }
1152
1153 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1154 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1155 }
1156
1157 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1158 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1159 return fZ == fZ &&
1160 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1161 }
1162
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001163 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001164 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001165 sk_sp<GrTextureProxy> permutationsProxy,
1166 sk_sp<GrTextureProxy> gradientProxy,
1167 const SkMatrix& matrix)
1168 : INHERITED(kNone_OptimizationFlags)
1169 , fOctaves(octaves)
1170 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001171 , fPermutationsSampler(std::move(permutationsProxy))
1172 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001173 , fPaintingData(std::move(paintingData)) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001174 this->initClassID<GrImprovedPerlinNoiseEffect>();
1175 this->addTextureSampler(&fPermutationsSampler);
1176 this->addTextureSampler(&fGradientSampler);
1177 fCoordTransform.reset(matrix);
1178 this->addCoordTransform(&fCoordTransform);
1179 }
1180
Brian Salomon4331e462017-07-26 14:58:11 -04001181 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
1182 : INHERITED(kNone_OptimizationFlags)
1183 , fCoordTransform(that.fCoordTransform)
1184 , fOctaves(that.fOctaves)
1185 , fZ(that.fZ)
1186 , fPermutationsSampler(that.fPermutationsSampler)
1187 , fGradientSampler(that.fGradientSampler)
1188 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
1189 this->initClassID<GrImprovedPerlinNoiseEffect>();
1190 this->addTextureSampler(&fPermutationsSampler);
1191 this->addTextureSampler(&fGradientSampler);
1192 this->addCoordTransform(&fCoordTransform);
1193 }
1194
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001195 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001196
1197 GrCoordTransform fCoordTransform;
1198 int fOctaves;
1199 SkScalar fZ;
1200 TextureSampler fPermutationsSampler;
1201 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001202 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001203
1204 typedef GrFragmentProcessor INHERITED;
1205};
1206
1207/////////////////////////////////////////////////////////////////////
1208GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1209
1210#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001211std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1212 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001213 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1214 0.99f);
1215 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1216 0.99f);
1217 int numOctaves = d->fRandom->nextRangeU(2, 10);
1218 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1219
1220 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1221 baseFrequencyY,
1222 numOctaves,
1223 z));
1224
1225 GrTest::TestAsFPArgs asFPArgs(d);
1226 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1227}
1228#endif
1229
1230void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001231 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001232 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1233 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1234 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
1235
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001236 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001237 "baseFrequency");
1238 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1239
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001240 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001241 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1242
1243 // fade function
1244 static const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001245 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001246 };
1247 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001248 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001249 fadeArgs,
1250 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1251 &fadeFuncName);
1252
1253 // perm function
1254 static const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001255 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001256 };
1257 SkString permFuncName;
1258 SkString permCode("return ");
1259 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1260 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001261 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001262 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001263 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001264 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001265 permCode.c_str(), &permFuncName);
1266
1267 // grad function
1268 static const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001269 GrShaderVar("x", kHalf_GrSLType),
1270 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001271 };
1272 SkString gradFuncName;
1273 SkString gradCode("return dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001274 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001275 kHalf2_GrSLType);
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001276 gradCode.append(".rgb * 255.0 - float3(1.0), p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001277 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001278 gradCode.c_str(), &gradFuncName);
1279
1280 // lerp function
1281 static const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001282 GrShaderVar("a", kHalf_GrSLType),
1283 GrShaderVar("b", kHalf_GrSLType),
1284 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001285 };
1286 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001287 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001288 "return a + w * (b - a);", &lerpFuncName);
1289
1290 // noise function
1291 static const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001292 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001293 };
1294 SkString noiseFuncName;
1295 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001296 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001297 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001298 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1299 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1300 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1301 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1302 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1303 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1304 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1305 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001306 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1307 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001308 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 -04001309 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001310 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001311 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001312 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001313 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001314 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001315 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1316 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001317 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001318 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001319 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001320 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001321 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 -04001322 gradFuncName.c_str(), permFuncName.c_str());
1323 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001324 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001325 noiseCode.c_str(), &noiseFuncName);
1326
1327 // noiseOctaves function
1328 static const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001329 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001330 };
1331 SkString noiseOctavesFuncName;
1332 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001333 noiseOctavesCode.append("half result = 0.0;");
1334 noiseOctavesCode.append("half ratio = 1.0;");
1335 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001336 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1337 noiseOctavesCode.append("p *= 2.0;");
1338 noiseOctavesCode.append("ratio *= 2.0;");
1339 noiseOctavesCode.append("}");
1340 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001341 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001342 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1343
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001344 fragBuilder->codeAppendf("half2 coords = %s * %s;", vCoords.c_str(), baseFrequencyUni);
1345 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001346 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001347 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001348 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001349 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001350 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001351 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001352 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001353 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001354
1355 // Clamp values
1356 fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
1357
1358 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001359 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001360 args.fOutputColor, args.fOutputColor,
1361 args.fOutputColor, args.fOutputColor);
1362}
1363
1364void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1365 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001366 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1367 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001368}
1369
1370void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1371 const GrFragmentProcessor& processor) {
1372 INHERITED::onSetData(pdman, processor);
1373
1374 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1375
1376 const SkVector& baseFrequency = noise.baseFrequency();
1377 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1378
Mike Reedf2ae2b22017-05-30 15:22:54 -04001379 pdman.set1f(fZUni, noise.z());
1380}
1381
1382/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001383std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
1384 const AsFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001385 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001386
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001387 SkMatrix localMatrix = this->getLocalMatrix();
brianosman839345d2016-07-22 11:04:53 -07001388 if (args.fLocalMatrix) {
1389 localMatrix.preConcat(*args.fLocalMatrix);
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001390 }
1391
brianosman839345d2016-07-22 11:04:53 -07001392 SkMatrix matrix = *args.fViewMatrix;
senorblancoca6a7c22014-06-27 13:35:52 -07001393 matrix.preConcat(localMatrix);
1394
Mike Reedf2ae2b22017-05-30 15:22:54 -04001395 // Either we don't stitch tiles, either we have a valid tile size
1396 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1397
Florin Malitab365cf52017-05-30 17:18:01 -04001398 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
1399 skstd::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
1400 fSeed,
1401 fBaseFrequencyX,
1402 fBaseFrequencyY,
1403 matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001404
1405 SkMatrix m = *args.fViewMatrix;
1406 m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
1407 m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
1408
1409 if (fType == kImprovedNoise_Type) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -04001410 GrSamplerState textureParams(GrSamplerState::WrapMode::kRepeat,
1411 GrSamplerState::Filter::kNearest);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001412 sk_sp<GrTextureProxy> permutationsTexture(
1413 GrRefCachedBitmapTextureProxy(args.fContext,
1414 paintingData->getImprovedPermutationsBitmap(),
1415 textureParams, nullptr));
1416 sk_sp<GrTextureProxy> gradientTexture(
1417 GrRefCachedBitmapTextureProxy(args.fContext,
1418 paintingData->getGradientBitmap(),
1419 textureParams, nullptr));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001420 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001421 std::move(permutationsTexture),
1422 std::move(gradientTexture), m);
1423 }
1424
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001425 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001426 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001427 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001428 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1429 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1430 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001431 auto inner =
1432 GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040),
1433 GrConstColorProcessor::kModulateRGBA_InputMode);
bungeman06ca8ec2016-06-09 08:01:03 -07001434 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001435 }
bsalomonc21b09e2015-08-28 18:46:56 -07001436 // Emit zero.
Brian Osman618d3042016-10-25 10:51:28 -04001437 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
1438 GrConstColorProcessor::kIgnore_InputMode);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001439 }
1440
Mike Reedf2ae2b22017-05-30 15:22:54 -04001441 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedBitmapProxy(
1442 args.fContext->resourceProvider(),
1443 paintingData->getPermutationsBitmap());
1444 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedBitmapProxy(args.fContext->resourceProvider(),
1445 paintingData->getNoiseBitmap());
sugoi@google.come3b4c502013-04-05 13:47:09 +00001446
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001447 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001448 auto inner = GrPerlinNoise2Effect::Make(fType,
1449 fNumOctaves,
1450 fStitchTiles,
1451 std::move(paintingData),
1452 std::move(permutationsProxy),
1453 std::move(noiseProxy),
1454 m);
bungeman06ca8ec2016-06-09 08:01:03 -07001455 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001456 }
bsalomonc21b09e2015-08-28 18:46:56 -07001457 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001458}
1459
1460#endif
1461
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001462#ifndef SK_IGNORE_TO_STRING
Florin Malita14d54c22017-05-18 11:52:59 -04001463void SkPerlinNoiseShaderImpl::toString(SkString* str) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001464 str->append("SkPerlinNoiseShaderImpl: (");
sugoi@google.come3b4c502013-04-05 13:47:09 +00001465
1466 str->append("type: ");
1467 switch (fType) {
1468 case kFractalNoise_Type:
1469 str->append("\"fractal noise\"");
1470 break;
1471 case kTurbulence_Type:
1472 str->append("\"turbulence\"");
1473 break;
1474 default:
1475 str->append("\"unknown\"");
1476 break;
1477 }
1478 str->append(" base frequency: (");
1479 str->appendScalar(fBaseFrequencyX);
1480 str->append(", ");
1481 str->appendScalar(fBaseFrequencyY);
1482 str->append(") number of octaves: ");
1483 str->appendS32(fNumOctaves);
1484 str->append(" seed: ");
1485 str->appendScalar(fSeed);
1486 str->append(" stitch tiles: ");
1487 str->append(fStitchTiles ? "true " : "false ");
1488
1489 this->INHERITED::toString(str);
1490
1491 str->append(")");
1492}
1493#endif
Florin Malita14d54c22017-05-18 11:52:59 -04001494
Mike Reedf2ae2b22017-05-30 15:22:54 -04001495///////////////////////////////////////////////////////////////////////////////////////////////////
1496
1497sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1498 SkScalar baseFrequencyY,
1499 int numOctaves, SkScalar seed,
1500 const SkISize* tileSize) {
1501 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1502 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1503 tileSize));
1504}
1505
1506sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1507 SkScalar baseFrequencyY,
1508 int numOctaves, SkScalar seed,
1509 const SkISize* tileSize) {
1510 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1511 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1512 tileSize));
1513}
1514
1515sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1516 SkScalar baseFrequencyY,
1517 int numOctaves, SkScalar z) {
1518 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1519 baseFrequencyX, baseFrequencyY, numOctaves, z,
1520 nullptr));
1521}
1522
Florin Malita14d54c22017-05-18 11:52:59 -04001523SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPerlinNoiseShader)
1524 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShaderImpl)
1525SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END