blob: 6c534019da99fea75607e81c07218130f8392153 [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 }
Ben Wagner63fd7602017-10-09 15:45:33 -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)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400744 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500745 , 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)) {
Brian Salomon0bbecb22016-11-17 11:38:22 -0500751 this->addTextureSampler(&fPermutationsSampler);
752 this->addTextureSampler(&fNoiseSampler);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400753 fCoordTransform.reset(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700754 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000755 }
756
Brian Salomon4331e462017-07-26 14:58:11 -0400757 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400758 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400759 , fType(that.fType)
760 , fCoordTransform(that.fCoordTransform)
761 , fNumOctaves(that.fNumOctaves)
762 , fStitchTiles(that.fStitchTiles)
763 , fPermutationsSampler(that.fPermutationsSampler)
764 , fNoiseSampler(that.fNoiseSampler)
765 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon4331e462017-07-26 14:58:11 -0400766 this->addTextureSampler(&fPermutationsSampler);
767 this->addTextureSampler(&fNoiseSampler);
768 this->addCoordTransform(&fCoordTransform);
769 }
770
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400771 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000772
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400773 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400774 GrCoordTransform fCoordTransform;
775 int fNumOctaves;
776 bool fStitchTiles;
777 TextureSampler fPermutationsSampler;
778 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400779 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000780
joshualittb0a8a372014-09-23 09:50:21 -0700781 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000782};
783
784/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400785GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000786
Hal Canary6f6961e2017-01-31 13:50:44 -0500787#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400788std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700789 int numOctaves = d->fRandom->nextRangeU(2, 10);
790 bool stitchTiles = d->fRandom->nextBool();
791 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
792 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
793 d->fRandom->nextRangeU(4, 4096));
794 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
795 0.99f);
796 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
797 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000798
reedfe630452016-03-25 09:08:00 -0700799 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
800 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400801 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700802 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400803 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000804
Brian Osman9f532a32016-10-19 11:12:09 -0400805 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400806 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000807}
Hal Canary6f6961e2017-01-31 13:50:44 -0500808#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000809
wangyix7c157a92015-07-22 15:08:53 -0700810void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400811 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800812
Mike Reedf2ae2b22017-05-30 15:22:54 -0400813 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800814 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
bsalomon1a1aa932016-09-12 09:30:36 -0700815 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000816
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400817 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800818 "baseFrequency");
819 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000820
halcanary96fcdcc2015-08-27 07:41:13 -0700821 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800822 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400823 fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800824 "stitchData");
825 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000826 }
827
sugoi@google.comd537af52013-06-10 13:59:25 +0000828 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
829 const char* chanCoordR = "0.125";
830 const char* chanCoordG = "0.375";
831 const char* chanCoordB = "0.625";
832 const char* chanCoordA = "0.875";
833 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000834 const char* stitchData = "stitchData";
835 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000836 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000837 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700838 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000839 const char* fractVal = "fractVal";
840 const char* uv = "uv";
841 const char* ab = "ab";
842 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700843 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000844 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000845 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
846 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
847 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400848 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 +0000849
sugoi@google.comd537af52013-06-10 13:59:25 +0000850 // Add noise function
Brian Salomon99938a82016-11-21 13:41:08 -0500851 static const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400852 GrShaderVar(chanCoord, kHalf_GrSLType),
853 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000854 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000855
Brian Salomon99938a82016-11-21 13:41:08 -0500856 static const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400857 GrShaderVar(chanCoord, kHalf_GrSLType),
858 GrShaderVar(noiseVec, kHalf2_GrSLType),
859 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000860 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000861
sugoi@google.comd537af52013-06-10 13:59:25 +0000862 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000863
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400864 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700865 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400866 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
867 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000868
869 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400870 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700871 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000872
873 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800874 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000875 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400876 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000877 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400878 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700879 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400880 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700881 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400882 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000883 }
884
885 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400886 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400887 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000888
889 // Get permutation for x
890 {
891 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400892 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000893
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400894 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700895 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400896 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000897 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000898 }
899
900 // Get permutation for x + 1
901 {
902 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400903 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000904
sugoi@google.comd537af52013-06-10 13:59:25 +0000905 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700906 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400907 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000908 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000909 }
910
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000911#if defined(SK_BUILD_FOR_ANDROID)
912 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
913 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
914 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
915 // (or 0.484368 here). The following rounding operation prevents these precision issues from
916 // affecting the result of the noise by making sure that we only have multiples of 1/255.
917 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400918 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 +0000919 latticeIdx, latticeIdx);
920#endif
921
sugoi@google.come3b4c502013-04-05 13:47:09 +0000922 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400923 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000924
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400925 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000926 // Compute u, at offset (0,0)
927 {
928 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400929 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
930 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700931 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400932 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000933 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
934 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000935 }
936
sugoi@google.comd537af52013-06-10 13:59:25 +0000937 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000938 // Compute v, at offset (-1,0)
939 {
940 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400941 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000942 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700943 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400944 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000945 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
946 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000947 }
948
949 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400950 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000951 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 +0000952
sugoi@google.comd537af52013-06-10 13:59:25 +0000953 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000954 // Compute v, at offset (-1,-1)
955 {
956 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400957 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000958 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700959 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400960 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000961 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
962 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000963 }
964
sugoi@google.comd537af52013-06-10 13:59:25 +0000965 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000966 // Compute u, at offset (0,-1)
967 {
968 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400969 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000970 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700971 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400972 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000973 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
974 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000975 }
976
977 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000978 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 +0000979 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +0000980 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000981
sugoi@google.comd537af52013-06-10 13:59:25 +0000982 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800983 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400984 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800985 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
986 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000987 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400988 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800989 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
990 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000991 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000992
sugoi@google.comd537af52013-06-10 13:59:25 +0000993 // There are rounding errors if the floor operation is not performed here
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400994 fragBuilder->codeAppendf("\n\t\thalf2 %s = floor(%s.xy) * %s;",
egdaniel4ca2e602015-11-18 08:01:26 -0800995 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000996
997 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400998 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000999
robertphillipsbf536af2016-02-04 06:11:53 -08001000 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001001 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001002 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001003 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001004
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001005 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001006
1007 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001008 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001009
Mike Reedf2ae2b22017-05-30 15:22:54 -04001010 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001011 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001012 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001013 }
robertphillipsbf536af2016-02-04 06:11:53 -08001014 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001015 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001016 "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 +00001017 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1018 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1019 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1020 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1021 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1022 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001023 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001024 "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 +00001025 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1026 noiseFuncName.c_str(), chanCoordR, noiseVec,
1027 noiseFuncName.c_str(), chanCoordG, noiseVec,
1028 noiseFuncName.c_str(), chanCoordB, noiseVec,
1029 noiseFuncName.c_str(), chanCoordA, noiseVec);
1030 }
Florin Malita14d54c22017-05-18 11:52:59 -04001031 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001032 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001033 }
egdaniel4ca2e602015-11-18 08:01:26 -08001034 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001035
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001036 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001037 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001038
robertphillipsbf536af2016-02-04 06:11:53 -08001039 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001040 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001041 }
egdaniel4ca2e602015-11-18 08:01:26 -08001042 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001043
Florin Malita14d54c22017-05-18 11:52:59 -04001044 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001045 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1046 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001047 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001048 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001049 }
1050
sugoi@google.come3b4c502013-04-05 13:47:09 +00001051 // Clamp values
egdaniel4ca2e602015-11-18 08:01:26 -08001052 fragBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001053
1054 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001055 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001056 args.fOutputColor, args.fOutputColor,
1057 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001058}
1059
Brian Salomon94efbf52016-11-29 13:43:05 -05001060void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001061 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001062 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001063
bsalomon63e99f72014-07-21 08:03:14 -07001064 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001065
1066 key = key << 3; // Make room for next 3 bits
1067
1068 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001069 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001070 key |= 0x1;
1071 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001072 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001073 key |= 0x2;
1074 break;
1075 default:
1076 // leave key at 0
1077 break;
1078 }
1079
1080 if (turbulence.stitchTiles()) {
1081 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1082 }
1083
bsalomon63e99f72014-07-21 08:03:14 -07001084 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001085}
1086
egdaniel018fb622015-10-28 07:26:40 -07001087void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001088 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001089 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001090
Mike Reedf2ae2b22017-05-30 15:22:54 -04001091 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001092
1093 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001094 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001095
sugoi@google.com4775cba2013-04-17 13:46:56 +00001096 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001097 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001098 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001099 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001100 }
1101}
1102
sugoi@google.come3b4c502013-04-05 13:47:09 +00001103/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001104
1105class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1106public:
1107 void emitCode(EmitArgs&) override;
1108
1109 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1110
1111protected:
1112 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1113
1114private:
1115 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001116 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1117
1118 typedef GrGLSLFragmentProcessor INHERITED;
1119};
1120
1121/////////////////////////////////////////////////////////////////////
1122
1123class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1124public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001125 static std::unique_ptr<GrFragmentProcessor> Make(
1126 int octaves, SkScalar z,
1127 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1128 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1129 const SkMatrix& matrix) {
1130 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1131 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1132 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001133 }
1134
Mike Reedf2ae2b22017-05-30 15:22:54 -04001135 const char* name() const override { return "ImprovedPerlinNoise"; }
1136
Brian Salomonaff329b2017-08-11 09:40:37 -04001137 std::unique_ptr<GrFragmentProcessor> clone() const override {
1138 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001139 }
1140
Mike Reedf2ae2b22017-05-30 15:22:54 -04001141 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1142 SkScalar z() const { return fZ; }
1143 int octaves() const { return fOctaves; }
1144 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
1145
1146private:
1147 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1148 return new GrGLImprovedPerlinNoise;
1149 }
1150
1151 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1152 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1153 }
1154
1155 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1156 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1157 return fZ == fZ &&
1158 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1159 }
1160
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001161 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001162 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001163 sk_sp<GrTextureProxy> permutationsProxy,
1164 sk_sp<GrTextureProxy> gradientProxy,
1165 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001166 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001167 , fOctaves(octaves)
1168 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001169 , fPermutationsSampler(std::move(permutationsProxy))
1170 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001171 , fPaintingData(std::move(paintingData)) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001172 this->addTextureSampler(&fPermutationsSampler);
1173 this->addTextureSampler(&fGradientSampler);
1174 fCoordTransform.reset(matrix);
1175 this->addCoordTransform(&fCoordTransform);
1176 }
1177
Brian Salomon4331e462017-07-26 14:58:11 -04001178 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001179 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001180 , fCoordTransform(that.fCoordTransform)
1181 , fOctaves(that.fOctaves)
1182 , fZ(that.fZ)
1183 , fPermutationsSampler(that.fPermutationsSampler)
1184 , fGradientSampler(that.fGradientSampler)
1185 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon4331e462017-07-26 14:58:11 -04001186 this->addTextureSampler(&fPermutationsSampler);
1187 this->addTextureSampler(&fGradientSampler);
1188 this->addCoordTransform(&fCoordTransform);
1189 }
1190
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001191 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001192
1193 GrCoordTransform fCoordTransform;
1194 int fOctaves;
1195 SkScalar fZ;
1196 TextureSampler fPermutationsSampler;
1197 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001198 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001199
1200 typedef GrFragmentProcessor INHERITED;
1201};
1202
1203/////////////////////////////////////////////////////////////////////
1204GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1205
1206#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001207std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1208 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001209 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1210 0.99f);
1211 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1212 0.99f);
1213 int numOctaves = d->fRandom->nextRangeU(2, 10);
1214 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1215
1216 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1217 baseFrequencyY,
1218 numOctaves,
1219 z));
1220
1221 GrTest::TestAsFPArgs asFPArgs(d);
1222 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1223}
1224#endif
1225
1226void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001227 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001228 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1229 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1230 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
1231
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001232 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001233 "baseFrequency");
1234 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1235
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001236 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001237 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1238
1239 // fade function
1240 static const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001241 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001242 };
1243 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001244 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001245 fadeArgs,
1246 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1247 &fadeFuncName);
1248
1249 // perm function
1250 static const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001251 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001252 };
1253 SkString permFuncName;
1254 SkString permCode("return ");
1255 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1256 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001257 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001258 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001259 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001260 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001261 permCode.c_str(), &permFuncName);
1262
1263 // grad function
1264 static const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001265 GrShaderVar("x", kHalf_GrSLType),
1266 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001267 };
1268 SkString gradFuncName;
1269 SkString gradCode("return dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001270 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001271 kHalf2_GrSLType);
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001272 gradCode.append(".rgb * 255.0 - float3(1.0), p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001273 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001274 gradCode.c_str(), &gradFuncName);
1275
1276 // lerp function
1277 static const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001278 GrShaderVar("a", kHalf_GrSLType),
1279 GrShaderVar("b", kHalf_GrSLType),
1280 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001281 };
1282 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001283 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001284 "return a + w * (b - a);", &lerpFuncName);
1285
1286 // noise function
1287 static const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001288 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001289 };
1290 SkString noiseFuncName;
1291 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001292 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001293 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001294 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1295 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1296 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1297 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1298 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1299 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1300 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1301 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001302 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1303 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001304 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 -04001305 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001306 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001307 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001308 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001309 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001310 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001311 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1312 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001313 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
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(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001316 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001317 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 -04001318 gradFuncName.c_str(), permFuncName.c_str());
1319 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001320 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001321 noiseCode.c_str(), &noiseFuncName);
1322
1323 // noiseOctaves function
1324 static const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001325 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001326 };
1327 SkString noiseOctavesFuncName;
1328 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001329 noiseOctavesCode.append("half result = 0.0;");
1330 noiseOctavesCode.append("half ratio = 1.0;");
1331 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001332 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1333 noiseOctavesCode.append("p *= 2.0;");
1334 noiseOctavesCode.append("ratio *= 2.0;");
1335 noiseOctavesCode.append("}");
1336 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001337 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001338 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1339
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001340 fragBuilder->codeAppendf("half2 coords = %s * %s;", vCoords.c_str(), baseFrequencyUni);
1341 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001342 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001343 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001344 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001345 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001346 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001347 fragBuilder->codeAppendf("half a = %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("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001350
1351 // Clamp values
1352 fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
1353
1354 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001355 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001356 args.fOutputColor, args.fOutputColor,
1357 args.fOutputColor, args.fOutputColor);
1358}
1359
1360void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1361 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001362 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1363 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001364}
1365
1366void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1367 const GrFragmentProcessor& processor) {
1368 INHERITED::onSetData(pdman, processor);
1369
1370 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1371
1372 const SkVector& baseFrequency = noise.baseFrequency();
1373 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1374
Mike Reedf2ae2b22017-05-30 15:22:54 -04001375 pdman.set1f(fZUni, noise.z());
1376}
1377
1378/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001379std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
1380 const AsFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001381 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001382
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001383 SkMatrix localMatrix = this->getLocalMatrix();
brianosman839345d2016-07-22 11:04:53 -07001384 if (args.fLocalMatrix) {
1385 localMatrix.preConcat(*args.fLocalMatrix);
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001386 }
1387
brianosman839345d2016-07-22 11:04:53 -07001388 SkMatrix matrix = *args.fViewMatrix;
senorblancoca6a7c22014-06-27 13:35:52 -07001389 matrix.preConcat(localMatrix);
1390
Mike Reedf2ae2b22017-05-30 15:22:54 -04001391 // Either we don't stitch tiles, either we have a valid tile size
1392 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1393
Florin Malitab365cf52017-05-30 17:18:01 -04001394 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
1395 skstd::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
1396 fSeed,
1397 fBaseFrequencyX,
1398 fBaseFrequencyY,
1399 matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001400
1401 SkMatrix m = *args.fViewMatrix;
1402 m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
1403 m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
1404
1405 if (fType == kImprovedNoise_Type) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -04001406 GrSamplerState textureParams(GrSamplerState::WrapMode::kRepeat,
1407 GrSamplerState::Filter::kNearest);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001408 sk_sp<GrTextureProxy> permutationsTexture(
1409 GrRefCachedBitmapTextureProxy(args.fContext,
1410 paintingData->getImprovedPermutationsBitmap(),
1411 textureParams, nullptr));
1412 sk_sp<GrTextureProxy> gradientTexture(
1413 GrRefCachedBitmapTextureProxy(args.fContext,
1414 paintingData->getGradientBitmap(),
1415 textureParams, nullptr));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001416 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001417 std::move(permutationsTexture),
1418 std::move(gradientTexture), m);
1419 }
1420
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001421 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001422 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001423 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001424 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1425 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1426 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001427 auto inner =
1428 GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001429 GrConstColorProcessor::InputMode::kModulateRGBA);
bungeman06ca8ec2016-06-09 08:01:03 -07001430 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001431 }
bsalomonc21b09e2015-08-28 18:46:56 -07001432 // Emit zero.
Brian Osman618d3042016-10-25 10:51:28 -04001433 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001434 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001435 }
1436
Mike Reedf2ae2b22017-05-30 15:22:54 -04001437 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedBitmapProxy(
1438 args.fContext->resourceProvider(),
1439 paintingData->getPermutationsBitmap());
1440 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedBitmapProxy(args.fContext->resourceProvider(),
1441 paintingData->getNoiseBitmap());
sugoi@google.come3b4c502013-04-05 13:47:09 +00001442
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001443 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001444 auto inner = GrPerlinNoise2Effect::Make(fType,
1445 fNumOctaves,
1446 fStitchTiles,
1447 std::move(paintingData),
1448 std::move(permutationsProxy),
1449 std::move(noiseProxy),
1450 m);
bungeman06ca8ec2016-06-09 08:01:03 -07001451 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001452 }
bsalomonc21b09e2015-08-28 18:46:56 -07001453 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001454}
1455
1456#endif
1457
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001458#ifndef SK_IGNORE_TO_STRING
Florin Malita14d54c22017-05-18 11:52:59 -04001459void SkPerlinNoiseShaderImpl::toString(SkString* str) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001460 str->append("SkPerlinNoiseShaderImpl: (");
sugoi@google.come3b4c502013-04-05 13:47:09 +00001461
1462 str->append("type: ");
1463 switch (fType) {
1464 case kFractalNoise_Type:
1465 str->append("\"fractal noise\"");
1466 break;
1467 case kTurbulence_Type:
1468 str->append("\"turbulence\"");
1469 break;
1470 default:
1471 str->append("\"unknown\"");
1472 break;
1473 }
1474 str->append(" base frequency: (");
1475 str->appendScalar(fBaseFrequencyX);
1476 str->append(", ");
1477 str->appendScalar(fBaseFrequencyY);
1478 str->append(") number of octaves: ");
1479 str->appendS32(fNumOctaves);
1480 str->append(" seed: ");
1481 str->appendScalar(fSeed);
1482 str->append(" stitch tiles: ");
1483 str->append(fStitchTiles ? "true " : "false ");
1484
1485 this->INHERITED::toString(str);
1486
1487 str->append(")");
1488}
1489#endif
Florin Malita14d54c22017-05-18 11:52:59 -04001490
Mike Reedf2ae2b22017-05-30 15:22:54 -04001491///////////////////////////////////////////////////////////////////////////////////////////////////
1492
1493sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1494 SkScalar baseFrequencyY,
1495 int numOctaves, SkScalar seed,
1496 const SkISize* tileSize) {
1497 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1498 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1499 tileSize));
1500}
1501
1502sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1503 SkScalar baseFrequencyY,
1504 int numOctaves, SkScalar seed,
1505 const SkISize* tileSize) {
1506 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1507 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1508 tileSize));
1509}
1510
1511sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1512 SkScalar baseFrequencyY,
1513 int numOctaves, SkScalar z) {
1514 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1515 baseFrequencyX, baseFrequencyY, numOctaves, z,
1516 nullptr));
1517}
1518
Florin Malita14d54c22017-05-18 11:52:59 -04001519SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPerlinNoiseShader)
1520 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShaderImpl)
1521SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END