blob: 6577a126832125c00b4a5bc719be38ddac99b338 [file] [log] [blame]
sugoi@google.come3b4c502013-04-05 13:47:09 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
sugoi@google.come3b4c502013-04-05 13:47:09 +00008#include "SkPerlinNoiseShader.h"
Herb Derby83e939b2017-02-07 14:25:11 -05009
10#include "SkArenaAlloc.h"
Mike Reedf2ae2b22017-05-30 15:22:54 -040011#include "SkDither.h"
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +000012#include "SkColorFilter.h"
Florin Malitab365cf52017-05-30 17:18:01 -040013#include "SkMakeUnique.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000014#include "SkReadBuffer.h"
Florin Malita14d54c22017-05-18 11:52:59 -040015#include "SkWriteBuffer.h"
Mike Reedf2ae2b22017-05-30 15:22:54 -040016#include "SkShader.h"
17#include "SkUnPreMultiply.h"
18#include "SkString.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000019
20#if SK_SUPPORT_GPU
21#include "GrContext.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050022#include "GrContextPriv.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +000023#include "GrCoordTransform.h"
joshualitteb2a6762014-12-04 11:35:33 -080024#include "SkGr.h"
bsalomonc21b09e2015-08-28 18:46:56 -070025#include "effects/GrConstColorProcessor.h"
egdaniel64c47282015-11-13 06:54:19 -080026#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080027#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070028#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080029#include "glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000030#endif
31
32static const int kBlockSize = 256;
33static const int kBlockMask = kBlockSize - 1;
34static const int kPerlinNoise = 4096;
35static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
36
Mike Reedf2ae2b22017-05-30 15:22:54 -040037static uint8_t improved_noise_permutations[] = {
38 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
39 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
40 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
41 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
42 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
43 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
44 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
45 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
46 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
47 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
48 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
49 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
50 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
51 141, 128, 195, 78, 66, 215, 61, 156, 180,
52 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
53 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
54 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
55 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
56 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
57 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
58 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
59 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
60 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
61 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
62 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
63 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
64 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
65 141, 128, 195, 78, 66, 215, 61, 156, 180
66};
67
68class SkPerlinNoiseShaderImpl : public SkShaderBase {
69public:
Florin Malita83223bc2017-05-31 14:14:05 -040070 struct StitchData {
71 StitchData()
72 : fWidth(0)
73 , fWrapX(0)
74 , fHeight(0)
75 , fWrapY(0)
76 {}
77
78 bool operator==(const StitchData& other) const {
79 return fWidth == other.fWidth &&
80 fWrapX == other.fWrapX &&
81 fHeight == other.fHeight &&
82 fWrapY == other.fWrapY;
83 }
84
85 int fWidth; // How much to subtract to wrap for stitching.
86 int fWrapX; // Minimum value to wrap.
87 int fHeight;
88 int fWrapY;
89 };
90
91 struct PaintingData {
92 PaintingData(const SkISize& tileSize, SkScalar seed,
93 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
94 const SkMatrix& matrix)
95 {
96 SkVector vec[2] = {
97 { SkScalarInvert(baseFrequencyX), SkScalarInvert(baseFrequencyY) },
98 { SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight) },
99 };
100 matrix.mapVectors(vec, 2);
101
102 fBaseFrequency.set(SkScalarInvert(vec[0].fX), SkScalarInvert(vec[0].fY));
103 fTileSize.set(SkScalarRoundToInt(vec[1].fX), SkScalarRoundToInt(vec[1].fY));
104 this->init(seed);
105 if (!fTileSize.isEmpty()) {
106 this->stitch();
107 }
108
109 #if SK_SUPPORT_GPU
110 fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1));
111 fPermutationsBitmap.setPixels(fLatticeSelector);
112
113 fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4));
114 fNoiseBitmap.setPixels(fNoise[0][0]);
115
116 fImprovedPermutationsBitmap.setInfo(SkImageInfo::MakeA8(256, 1));
117 fImprovedPermutationsBitmap.setPixels(improved_noise_permutations);
118
119 fGradientBitmap.setInfo(SkImageInfo::MakeN32Premul(16, 1));
120 static uint8_t gradients[] = { 2, 2, 1, 0,
121 0, 2, 1, 0,
122 2, 0, 1, 0,
123 0, 0, 1, 0,
124 2, 1, 2, 0,
125 0, 1, 2, 0,
126 2, 1, 0, 0,
127 0, 1, 0, 0,
128 1, 2, 2, 0,
129 1, 0, 2, 0,
130 1, 2, 0, 0,
131 1, 0, 0, 0,
132 2, 2, 1, 0,
133 1, 0, 2, 0,
134 0, 2, 1, 0,
135 1, 0, 0, 0 };
136 fGradientBitmap.setPixels(gradients);
137 #endif
138 }
139
Brian Salomon4331e462017-07-26 14:58:11 -0400140 #if SK_SUPPORT_GPU
141 PaintingData(const PaintingData& that)
142 : fSeed(that.fSeed)
143 , fTileSize(that.fTileSize)
144 , fBaseFrequency(that.fBaseFrequency)
145 , fStitchDataInit(that.fStitchDataInit)
146 , fPermutationsBitmap(that.fPermutationsBitmap)
147 , fNoiseBitmap(that.fNoiseBitmap)
148 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
149 , fGradientBitmap(that.fGradientBitmap) {
150 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
151 memcpy(fNoise, that.fNoise, sizeof(fNoise));
152 memcpy(fGradient, that.fGradient, sizeof(fGradient));
153 }
154 #endif
155
Florin Malita83223bc2017-05-31 14:14:05 -0400156 int fSeed;
157 uint8_t fLatticeSelector[kBlockSize];
158 uint16_t fNoise[4][kBlockSize][2];
159 SkPoint fGradient[4][kBlockSize];
160 SkISize fTileSize;
161 SkVector fBaseFrequency;
162 StitchData fStitchDataInit;
163
164 private:
165
166 #if SK_SUPPORT_GPU
167 SkBitmap fPermutationsBitmap;
168 SkBitmap fNoiseBitmap;
169 SkBitmap fImprovedPermutationsBitmap;
170 SkBitmap fGradientBitmap;
171 #endif
172
173 inline int random() {
174 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
175 static const int gRandQ = 127773; // m / a
176 static const int gRandR = 2836; // m % a
177
178 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
179 if (result <= 0)
180 result += kRandMaximum;
181 fSeed = result;
182 return result;
183 }
184
185 // Only called once. Could be part of the constructor.
186 void init(SkScalar seed)
187 {
188 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
189
190 // According to the SVG spec, we must truncate (not round) the seed value.
191 fSeed = SkScalarTruncToInt(seed);
192 // The seed value clamp to the range [1, kRandMaximum - 1].
193 if (fSeed <= 0) {
194 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
195 }
196 if (fSeed > kRandMaximum - 1) {
197 fSeed = kRandMaximum - 1;
198 }
199 for (int channel = 0; channel < 4; ++channel) {
200 for (int i = 0; i < kBlockSize; ++i) {
201 fLatticeSelector[i] = i;
202 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
203 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
204 }
205 }
206 for (int i = kBlockSize - 1; i > 0; --i) {
207 int k = fLatticeSelector[i];
208 int j = random() % kBlockSize;
209 SkASSERT(j >= 0);
210 SkASSERT(j < kBlockSize);
211 fLatticeSelector[i] = fLatticeSelector[j];
212 fLatticeSelector[j] = k;
213 }
214
215 // Perform the permutations now
216 {
217 // Copy noise data
218 uint16_t noise[4][kBlockSize][2];
219 for (int i = 0; i < kBlockSize; ++i) {
220 for (int channel = 0; channel < 4; ++channel) {
221 for (int j = 0; j < 2; ++j) {
222 noise[channel][i][j] = fNoise[channel][i][j];
223 }
224 }
225 }
226 // Do permutations on noise data
227 for (int i = 0; i < kBlockSize; ++i) {
228 for (int channel = 0; channel < 4; ++channel) {
229 for (int j = 0; j < 2; ++j) {
230 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
231 }
232 }
233 }
234 }
235
236 // Half of the largest possible value for 16 bit unsigned int
237 static const SkScalar gHalfMax16bits = 32767.5f;
238
239 // Compute gradients from permutated noise data
240 for (int channel = 0; channel < 4; ++channel) {
241 for (int i = 0; i < kBlockSize; ++i) {
242 fGradient[channel][i] = SkPoint::Make(
243 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
244 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
245 fGradient[channel][i].normalize();
246 // Put the normalized gradient back into the noise data
247 fNoise[channel][i][0] = SkScalarRoundToInt(
248 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
249 fNoise[channel][i][1] = SkScalarRoundToInt(
250 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
251 }
252 }
253 }
254
255 // Only called once. Could be part of the constructor.
256 void stitch() {
257 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
258 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
259 SkASSERT(tileWidth > 0 && tileHeight > 0);
260 // When stitching tiled turbulence, the frequencies must be adjusted
261 // so that the tile borders will be continuous.
262 if (fBaseFrequency.fX) {
263 SkScalar lowFrequencx =
264 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
265 SkScalar highFrequencx =
266 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
267 // BaseFrequency should be non-negative according to the standard.
268 if (fBaseFrequency.fX / lowFrequencx < highFrequencx / fBaseFrequency.fX) {
269 fBaseFrequency.fX = lowFrequencx;
270 } else {
271 fBaseFrequency.fX = highFrequencx;
272 }
273 }
274 if (fBaseFrequency.fY) {
275 SkScalar lowFrequency =
276 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
277 SkScalar highFrequency =
278 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
279 if (fBaseFrequency.fY / lowFrequency < highFrequency / fBaseFrequency.fY) {
280 fBaseFrequency.fY = lowFrequency;
281 } else {
282 fBaseFrequency.fY = highFrequency;
283 }
284 }
285 // Set up TurbulenceInitial stitch values.
286 fStitchDataInit.fWidth =
287 SkScalarRoundToInt(tileWidth * fBaseFrequency.fX);
288 fStitchDataInit.fWrapX = kPerlinNoise + fStitchDataInit.fWidth;
289 fStitchDataInit.fHeight =
290 SkScalarRoundToInt(tileHeight * fBaseFrequency.fY);
291 fStitchDataInit.fWrapY = kPerlinNoise + fStitchDataInit.fHeight;
292 }
293
294 public:
295
296#if SK_SUPPORT_GPU
297 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
298
299 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
300
301 const SkBitmap& getImprovedPermutationsBitmap() const { return fImprovedPermutationsBitmap; }
302
303 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
304#endif
305 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400306
307 /**
308 * About the noise types : the difference between the first 2 is just minor tweaks to the
309 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
310 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
311 * doing :
312 * kFractalNoise_Type : noise * 0.5 + 0.5
313 * kTurbulence_Type : abs(noise)
314 * Very little differences between the 2 types, although you can tell the difference visually.
315 * "Improved" is based on the Improved Perlin Noise algorithm described at
316 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
317 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
318 * changes to the noise, making it suitable for animated noise.
319 */
320 enum Type {
321 kFractalNoise_Type,
322 kTurbulence_Type,
323 kImprovedNoise_Type,
324 kFirstType = kFractalNoise_Type,
325 kLastType = kImprovedNoise_Type
326 };
327
328 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
329 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
330 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400331
332 class PerlinNoiseShaderContext : public Context {
333 public:
334 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400335
336 void shadeSpan(int x, int y, SkPMColor[], int count) override;
337
338 private:
339 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
340 SkScalar calculateTurbulenceValueForPoint(
341 int channel,
342 StitchData& stitchData, const SkPoint& point) const;
343 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
344 SkScalar noise2D(int channel,
345 const StitchData& stitchData, const SkPoint& noiseVector) const;
346
Florin Malita83223bc2017-05-31 14:14:05 -0400347 SkMatrix fMatrix;
348 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400349
350 typedef Context INHERITED;
351 };
352
353#if SK_SUPPORT_GPU
Brian Salomonaff329b2017-08-11 09:40:37 -0400354 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400355#endif
356
357 SK_TO_STRING_OVERRIDE()
358 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPerlinNoiseShaderImpl)
359
360protected:
361 void flatten(SkWriteBuffer&) const override;
362 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
363
364private:
365 const SkPerlinNoiseShaderImpl::Type fType;
366 const SkScalar fBaseFrequencyX;
367 const SkScalar fBaseFrequencyY;
368 const int fNumOctaves;
369 const SkScalar fSeed;
370 const SkISize fTileSize;
371 const bool fStitchTiles;
372
373 friend class ::SkPerlinNoiseShader;
374
375 typedef SkShaderBase INHERITED;
376};
377
sugoi@google.come3b4c502013-04-05 13:47:09 +0000378namespace {
379
380// noiseValue is the color component's value (or color)
381// limitValue is the maximum perlin noise array index value allowed
382// newValue is the current noise dimension (either width or height)
383inline int checkNoise(int noiseValue, int limitValue, int newValue) {
384 // If the noise value would bring us out of bounds of the current noise array while we are
385 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
386 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
387 if (noiseValue >= limitValue) {
388 noiseValue -= newValue;
389 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000390 return noiseValue;
391}
392
393inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500394 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000395}
396
397} // end namespace
398
Mike Reedf2ae2b22017-05-30 15:22:54 -0400399SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
400 SkScalar baseFrequencyX,
401 SkScalar baseFrequencyY,
402 int numOctaves,
403 SkScalar seed,
404 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000405 : fType(type)
406 , fBaseFrequencyX(baseFrequencyX)
407 , fBaseFrequencyY(baseFrequencyY)
Mike Reedf2ae2b22017-05-30 15:22:54 -0400408 , fNumOctaves(numOctaves > 255 ? 255 : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000409 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700410 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000411 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000412{
Mike Reedf2ae2b22017-05-30 15:22:54 -0400413 SkASSERT(numOctaves >= 0 && numOctaves < 256);
414}
415
Florin Malita14d54c22017-05-18 11:52:59 -0400416sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700417 Type type = (Type)buffer.readInt();
418 SkScalar freqX = buffer.readScalar();
419 SkScalar freqY = buffer.readScalar();
420 int octaves = buffer.readInt();
421 SkScalar seed = buffer.readScalar();
422 SkISize tileSize;
423 tileSize.fWidth = buffer.readInt();
424 tileSize.fHeight = buffer.readInt();
425
426 switch (type) {
427 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400428 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700429 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400430 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
431 case kImprovedNoise_Type:
432 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700433 default:
halcanary96fcdcc2015-08-27 07:41:13 -0700434 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700435 }
436}
437
Florin Malita14d54c22017-05-18 11:52:59 -0400438void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000439 buffer.writeInt((int) fType);
440 buffer.writeScalar(fBaseFrequencyX);
441 buffer.writeScalar(fBaseFrequencyY);
442 buffer.writeInt(fNumOctaves);
443 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000444 buffer.writeInt(fTileSize.fWidth);
445 buffer.writeInt(fTileSize.fHeight);
446}
447
Florin Malita14d54c22017-05-18 11:52:59 -0400448SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700449 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000450 struct Noise {
451 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700452 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000453 SkScalar noisePositionFractionValue;
454 Noise(SkScalar component)
455 {
456 SkScalar position = component + kPerlinNoise;
457 noisePositionIntegerValue = SkScalarFloorToInt(position);
458 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700459 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000460 }
461 };
462 Noise noiseX(noiseVector.x());
463 Noise noiseY(noiseVector.y());
464 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400465 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000466 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000467 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000468 noiseX.noisePositionIntegerValue =
469 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
470 noiseY.noisePositionIntegerValue =
471 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700472 noiseX.nextNoisePositionIntegerValue =
473 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
474 noiseY.nextNoisePositionIntegerValue =
475 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000476 }
477 noiseX.noisePositionIntegerValue &= kBlockMask;
478 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700479 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
480 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400481 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
482 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700483 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
484 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
485 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
486 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000487 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
488 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400489
Hal Canaryfda46002017-05-08 17:17:47 -0400490 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
491 return 0; // Check for pathological inputs.
492 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400493
sugoi@google.come3b4c502013-04-05 13:47:09 +0000494 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
495 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
496 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400497 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000498 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400499 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000500 SkScalar a = SkScalarInterp(u, v, sx);
501 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400502 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000503 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400504 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000505 SkScalar b = SkScalarInterp(u, v, sx);
506 return SkScalarInterp(a, b, sy);
507}
508
Florin Malita14d54c22017-05-18 11:52:59 -0400509SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700510 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400511 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000512 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000513 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400514 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000515 }
516 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400517 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
518 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000519 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000520 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700521 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700522 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
523 noise : SkScalarAbs(noise);
524 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000525 noiseVector.fX *= 2;
526 noiseVector.fY *= 2;
527 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000528 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000529 // Update stitch values
530 stitchData.fWidth *= 2;
531 stitchData.fWrapX = stitchData.fWidth + kPerlinNoise;
532 stitchData.fHeight *= 2;
533 stitchData.fWrapY = stitchData.fHeight + kPerlinNoise;
534 }
535 }
536
537 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
538 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000539 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400540 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000541 }
542
543 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700544 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000545 }
546
547 // Clamp result
548 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
549}
550
Mike Reedf2ae2b22017-05-30 15:22:54 -0400551////////////////////////////////////////////////////////////////////////////////////////////////////
552// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
553static SkScalar fade(SkScalar t) {
554 return t * t * t * (t * (t * 6 - 15) + 10);
555}
556
557static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
558 return a + t * (b - a);
559}
560
561static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
562 int h = hash & 15;
563 SkScalar u = h < 8 ? x : y;
564 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
565 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
566}
567
568SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
569 int channel, const SkPoint& point) const {
570 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
571 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
572 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
573 // z offset between different channels, chosen arbitrarily
574 static const SkScalar CHANNEL_DELTA = 1000.0f;
575 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
576 SkScalar result = 0;
577 SkScalar ratio = SK_Scalar1;
578 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
579 int X = SkScalarFloorToInt(x) & 255;
580 int Y = SkScalarFloorToInt(y) & 255;
581 int Z = SkScalarFloorToInt(z) & 255;
582 SkScalar px = x - SkScalarFloorToScalar(x);
583 SkScalar py = y - SkScalarFloorToScalar(y);
584 SkScalar pz = z - SkScalarFloorToScalar(z);
585 SkScalar u = fade(px);
586 SkScalar v = fade(py);
587 SkScalar w = fade(pz);
588 uint8_t* permutations = improved_noise_permutations;
589 int A = permutations[X] + Y;
590 int AA = permutations[A] + Z;
591 int AB = permutations[A + 1] + Z;
592 int B = permutations[X + 1] + Y;
593 int BA = permutations[B] + Z;
594 int BB = permutations[B + 1] + Z;
595 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
596 grad(permutations[BA ], px - 1, py , pz )),
597 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
598 grad(permutations[BB ], px - 1, py - 1, pz ))),
599 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
600 grad(permutations[BA + 1], px - 1, py , pz - 1)),
601 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
602 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
603 ratio;
604 x *= 2;
605 y *= 2;
606 ratio *= 2;
607 }
608 result = SkScalarClampMax((result + 1.0f) / 2.0f, 1.0f);
609 return result;
610}
611////////////////////////////////////////////////////////////////////////////////////////////////////
612
Florin Malita14d54c22017-05-18 11:52:59 -0400613SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000614 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400615 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000616 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000617 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000618 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
619 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
620
621 U8CPU rgba[4];
622 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400623 SkScalar value;
624 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
625 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
626 }
627 else {
628 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
629 }
630 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000631 }
632 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
633}
634
Mike Reedf2ae2b22017-05-30 15:22:54 -0400635SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
636 SkArenaAlloc* alloc) const {
Herb Derby83e939b2017-02-07 14:25:11 -0500637 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000638}
639
Florin Malita83223bc2017-05-31 14:14:05 -0400640static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
641 const SkShaderBase& shader) {
642 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
643 if (rec.fLocalMatrix) {
644 matrix.preConcat(*rec.fLocalMatrix);
645 }
646
647 return matrix;
648}
649
Florin Malita14d54c22017-05-18 11:52:59 -0400650SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
651 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000652 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400653 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
654 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
655 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000656{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000657 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
658 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400659 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
660 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700661}
662
Florin Malita14d54c22017-05-18 11:52:59 -0400663void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000664 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000665 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
666 StitchData stitchData;
667 for (int i = 0; i < count; ++i) {
668 result[i] = shade(point, stitchData);
669 point.fX += SK_Scalar1;
670 }
671}
672
sugoi@google.come3b4c502013-04-05 13:47:09 +0000673/////////////////////////////////////////////////////////////////////
674
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000675#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000676
egdaniel64c47282015-11-13 06:54:19 -0800677class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000678public:
robertphillips9cdb9922016-02-03 12:25:40 -0800679 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000680
Mike Reedf2ae2b22017-05-30 15:22:54 -0400681 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000682
wangyixb1daa862015-08-18 11:29:31 -0700683protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400684 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700685
sugoi@google.com4775cba2013-04-17 13:46:56 +0000686private:
egdaniel018fb622015-10-28 07:26:40 -0700687 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700688 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700689
egdaniel64c47282015-11-13 06:54:19 -0800690 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000691};
692
693/////////////////////////////////////////////////////////////////////
694
Mike Reedf2ae2b22017-05-30 15:22:54 -0400695class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000696public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400697 static std::unique_ptr<GrFragmentProcessor> Make(
698 SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
699 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
700 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> noiseProxy,
701 const SkMatrix& matrix) {
702 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
703 type, numOctaves, stitchTiles, std::move(paintingData),
704 std::move(permutationsProxy), std::move(noiseProxy), matrix));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000705 }
706
mtklein36352bf2015-03-25 18:17:31 -0700707 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800708
Brian Salomonaff329b2017-08-11 09:40:37 -0400709 std::unique_ptr<GrFragmentProcessor> clone() const override {
710 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400711 }
712
Mike Reedf2ae2b22017-05-30 15:22:54 -0400713 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000714
Florin Malita14d54c22017-05-18 11:52:59 -0400715 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700716 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700717 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700718 int numOctaves() const { return fNumOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -0400719 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
senorblancof3b50272014-06-16 10:49:58 -0700720
sugoi@google.come3b4c502013-04-05 13:47:09 +0000721private:
egdaniel57d3b032015-11-13 11:57:27 -0800722 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800723 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700724 }
725
Brian Salomon94efbf52016-11-29 13:43:05 -0500726 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800727 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700728 GrGLPerlinNoise::GenKey(*this, caps, b);
729 }
730
mtklein36352bf2015-03-25 18:17:31 -0700731 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400732 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700733 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700734 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700735 fNumOctaves == s.fNumOctaves &&
736 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700737 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000738 }
739
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400740 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400741 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400742 sk_sp<GrTextureProxy> permutationsProxy,
743 sk_sp<GrTextureProxy> noiseProxy,
744 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400745 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500746 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500747 , fNumOctaves(numOctaves)
748 , fStitchTiles(stitchTiles)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400749 , fPermutationsSampler(std::move(permutationsProxy))
750 , fNoiseSampler(std::move(noiseProxy))
Florin Malitab365cf52017-05-30 17:18:01 -0400751 , fPaintingData(std::move(paintingData)) {
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)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400759 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400760 , 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)) {
Brian Salomon4331e462017-07-26 14:58:11 -0400767 this->addTextureSampler(&fPermutationsSampler);
768 this->addTextureSampler(&fNoiseSampler);
769 this->addCoordTransform(&fCoordTransform);
770 }
771
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400772 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000773
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400774 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400775 GrCoordTransform fCoordTransform;
776 int fNumOctaves;
777 bool fStitchTiles;
778 TextureSampler fPermutationsSampler;
779 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400780 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000781
joshualittb0a8a372014-09-23 09:50:21 -0700782 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000783};
784
785/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400786GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000787
Hal Canary6f6961e2017-01-31 13:50:44 -0500788#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400789std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700790 int numOctaves = d->fRandom->nextRangeU(2, 10);
791 bool stitchTiles = d->fRandom->nextBool();
792 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
793 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
794 d->fRandom->nextRangeU(4, 4096));
795 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
796 0.99f);
797 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
798 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000799
reedfe630452016-03-25 09:08:00 -0700800 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
801 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400802 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700803 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400804 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000805
Brian Osman9f532a32016-10-19 11:12:09 -0400806 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400807 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000808}
Hal Canary6f6961e2017-01-31 13:50:44 -0500809#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000810
wangyix7c157a92015-07-22 15:08:53 -0700811void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400812 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800813
Mike Reedf2ae2b22017-05-30 15:22:54 -0400814 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800815 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
bsalomon1a1aa932016-09-12 09:30:36 -0700816 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000817
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400818 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800819 "baseFrequency");
820 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000821
halcanary96fcdcc2015-08-27 07:41:13 -0700822 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800823 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400824 fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800825 "stitchData");
826 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000827 }
828
sugoi@google.comd537af52013-06-10 13:59:25 +0000829 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
830 const char* chanCoordR = "0.125";
831 const char* chanCoordG = "0.375";
832 const char* chanCoordB = "0.625";
833 const char* chanCoordA = "0.875";
834 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000835 const char* stitchData = "stitchData";
836 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000837 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000838 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700839 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000840 const char* fractVal = "fractVal";
841 const char* uv = "uv";
842 const char* ab = "ab";
843 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700844 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000845 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000846 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
847 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
848 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400849 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 +0000850
sugoi@google.comd537af52013-06-10 13:59:25 +0000851 // Add noise function
Brian Salomon99938a82016-11-21 13:41:08 -0500852 static const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400853 GrShaderVar(chanCoord, kHalf_GrSLType),
854 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000855 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000856
Brian Salomon99938a82016-11-21 13:41:08 -0500857 static const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400858 GrShaderVar(chanCoord, kHalf_GrSLType),
859 GrShaderVar(noiseVec, kHalf2_GrSLType),
860 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000861 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000862
sugoi@google.comd537af52013-06-10 13:59:25 +0000863 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000864
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400865 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700866 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400867 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
868 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000869
870 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400871 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700872 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000873
874 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800875 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000876 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400877 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000878 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400879 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700880 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400881 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700882 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400883 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000884 }
885
886 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400887 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400888 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000889
890 // Get permutation for x
891 {
892 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400893 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000894
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400895 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700896 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400897 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000898 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000899 }
900
901 // Get permutation for x + 1
902 {
903 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400904 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000905
sugoi@google.comd537af52013-06-10 13:59:25 +0000906 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700907 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400908 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000909 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000910 }
911
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000912#if defined(SK_BUILD_FOR_ANDROID)
913 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
914 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
915 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
916 // (or 0.484368 here). The following rounding operation prevents these precision issues from
917 // affecting the result of the noise by making sure that we only have multiples of 1/255.
918 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400919 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 +0000920 latticeIdx, latticeIdx);
921#endif
922
sugoi@google.come3b4c502013-04-05 13:47:09 +0000923 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400924 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000925
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400926 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000927 // Compute u, at offset (0,0)
928 {
929 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400930 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
931 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700932 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400933 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000934 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
935 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000936 }
937
sugoi@google.comd537af52013-06-10 13:59:25 +0000938 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000939 // Compute v, at offset (-1,0)
940 {
941 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400942 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000943 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700944 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400945 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000946 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
947 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000948 }
949
950 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400951 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000952 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 +0000953
sugoi@google.comd537af52013-06-10 13:59:25 +0000954 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000955 // Compute v, at offset (-1,-1)
956 {
957 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400958 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000959 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700960 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400961 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000962 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
963 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000964 }
965
sugoi@google.comd537af52013-06-10 13:59:25 +0000966 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000967 // Compute u, at offset (0,-1)
968 {
969 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400970 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000971 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700972 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400973 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000974 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
975 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000976 }
977
978 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000979 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 +0000980 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +0000981 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000982
sugoi@google.comd537af52013-06-10 13:59:25 +0000983 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800984 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400985 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800986 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
987 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000988 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400989 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800990 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
991 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000992 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000993
sugoi@google.comd537af52013-06-10 13:59:25 +0000994 // There are rounding errors if the floor operation is not performed here
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400995 fragBuilder->codeAppendf("\n\t\thalf2 %s = floor(%s.xy) * %s;",
egdaniel4ca2e602015-11-18 08:01:26 -0800996 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000997
998 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400999 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001000
robertphillipsbf536af2016-02-04 06:11:53 -08001001 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001002 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001003 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001004 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001005
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001006 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001007
1008 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001009 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001010
Mike Reedf2ae2b22017-05-30 15:22:54 -04001011 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001012 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001013 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001014 }
robertphillipsbf536af2016-02-04 06:11:53 -08001015 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001016 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001017 "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 +00001018 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1019 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1020 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1021 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1022 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1023 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001024 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001025 "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 +00001026 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1027 noiseFuncName.c_str(), chanCoordR, noiseVec,
1028 noiseFuncName.c_str(), chanCoordG, noiseVec,
1029 noiseFuncName.c_str(), chanCoordB, noiseVec,
1030 noiseFuncName.c_str(), chanCoordA, noiseVec);
1031 }
Florin Malita14d54c22017-05-18 11:52:59 -04001032 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001033 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001034 }
egdaniel4ca2e602015-11-18 08:01:26 -08001035 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001036
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001037 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001038 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001039
robertphillipsbf536af2016-02-04 06:11:53 -08001040 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001041 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001042 }
egdaniel4ca2e602015-11-18 08:01:26 -08001043 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001044
Florin Malita14d54c22017-05-18 11:52:59 -04001045 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001046 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1047 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001048 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001049 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001050 }
1051
sugoi@google.come3b4c502013-04-05 13:47:09 +00001052 // Clamp values
egdaniel4ca2e602015-11-18 08:01:26 -08001053 fragBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001054
1055 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001056 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001057 args.fOutputColor, args.fOutputColor,
1058 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001059}
1060
Brian Salomon94efbf52016-11-29 13:43:05 -05001061void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001062 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001063 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001064
bsalomon63e99f72014-07-21 08:03:14 -07001065 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001066
1067 key = key << 3; // Make room for next 3 bits
1068
1069 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001070 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001071 key |= 0x1;
1072 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001073 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001074 key |= 0x2;
1075 break;
1076 default:
1077 // leave key at 0
1078 break;
1079 }
1080
1081 if (turbulence.stitchTiles()) {
1082 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1083 }
1084
bsalomon63e99f72014-07-21 08:03:14 -07001085 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001086}
1087
egdaniel018fb622015-10-28 07:26:40 -07001088void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001089 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001090 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001091
Mike Reedf2ae2b22017-05-30 15:22:54 -04001092 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001093
1094 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001095 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001096
sugoi@google.com4775cba2013-04-17 13:46:56 +00001097 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001098 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001099 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001100 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001101 }
1102}
1103
sugoi@google.come3b4c502013-04-05 13:47:09 +00001104/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001105
1106class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1107public:
1108 void emitCode(EmitArgs&) override;
1109
1110 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1111
1112protected:
1113 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1114
1115private:
1116 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001117 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1118
1119 typedef GrGLSLFragmentProcessor INHERITED;
1120};
1121
1122/////////////////////////////////////////////////////////////////////
1123
1124class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1125public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001126 static std::unique_ptr<GrFragmentProcessor> Make(
1127 int octaves, SkScalar z,
1128 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1129 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1130 const SkMatrix& matrix) {
1131 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1132 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1133 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001134 }
1135
Mike Reedf2ae2b22017-05-30 15:22:54 -04001136 const char* name() const override { return "ImprovedPerlinNoise"; }
1137
Brian Salomonaff329b2017-08-11 09:40:37 -04001138 std::unique_ptr<GrFragmentProcessor> clone() const override {
1139 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001140 }
1141
Mike Reedf2ae2b22017-05-30 15:22:54 -04001142 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1143 SkScalar z() const { return fZ; }
1144 int octaves() const { return fOctaves; }
1145 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
1146
1147private:
1148 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1149 return new GrGLImprovedPerlinNoise;
1150 }
1151
1152 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1153 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1154 }
1155
1156 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1157 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1158 return fZ == fZ &&
1159 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1160 }
1161
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001162 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001163 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001164 sk_sp<GrTextureProxy> permutationsProxy,
1165 sk_sp<GrTextureProxy> gradientProxy,
1166 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001167 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001168 , fOctaves(octaves)
1169 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001170 , fPermutationsSampler(std::move(permutationsProxy))
1171 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001172 , fPaintingData(std::move(paintingData)) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001173 this->addTextureSampler(&fPermutationsSampler);
1174 this->addTextureSampler(&fGradientSampler);
1175 fCoordTransform.reset(matrix);
1176 this->addCoordTransform(&fCoordTransform);
1177 }
1178
Brian Salomon4331e462017-07-26 14:58:11 -04001179 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001180 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001181 , fCoordTransform(that.fCoordTransform)
1182 , fOctaves(that.fOctaves)
1183 , fZ(that.fZ)
1184 , fPermutationsSampler(that.fPermutationsSampler)
1185 , fGradientSampler(that.fGradientSampler)
1186 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon4331e462017-07-26 14:58:11 -04001187 this->addTextureSampler(&fPermutationsSampler);
1188 this->addTextureSampler(&fGradientSampler);
1189 this->addCoordTransform(&fCoordTransform);
1190 }
1191
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001192 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001193
1194 GrCoordTransform fCoordTransform;
1195 int fOctaves;
1196 SkScalar fZ;
1197 TextureSampler fPermutationsSampler;
1198 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001199 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001200
1201 typedef GrFragmentProcessor INHERITED;
1202};
1203
1204/////////////////////////////////////////////////////////////////////
1205GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1206
1207#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001208std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1209 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001210 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1211 0.99f);
1212 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1213 0.99f);
1214 int numOctaves = d->fRandom->nextRangeU(2, 10);
1215 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1216
1217 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1218 baseFrequencyY,
1219 numOctaves,
1220 z));
1221
1222 GrTest::TestAsFPArgs asFPArgs(d);
1223 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1224}
1225#endif
1226
1227void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001228 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001229 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1230 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1231 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
1232
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001233 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001234 "baseFrequency");
1235 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1236
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001237 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001238 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1239
1240 // fade function
1241 static const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001242 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001243 };
1244 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001245 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001246 fadeArgs,
1247 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1248 &fadeFuncName);
1249
1250 // perm function
1251 static const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001252 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001253 };
1254 SkString permFuncName;
1255 SkString permCode("return ");
1256 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1257 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001258 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001259 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001260 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001261 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001262 permCode.c_str(), &permFuncName);
1263
1264 // grad function
1265 static const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001266 GrShaderVar("x", kHalf_GrSLType),
1267 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001268 };
1269 SkString gradFuncName;
1270 SkString gradCode("return dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001271 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001272 kHalf2_GrSLType);
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001273 gradCode.append(".rgb * 255.0 - float3(1.0), p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001274 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001275 gradCode.c_str(), &gradFuncName);
1276
1277 // lerp function
1278 static const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001279 GrShaderVar("a", kHalf_GrSLType),
1280 GrShaderVar("b", kHalf_GrSLType),
1281 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001282 };
1283 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001284 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001285 "return a + w * (b - a);", &lerpFuncName);
1286
1287 // noise function
1288 static const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001289 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001290 };
1291 SkString noiseFuncName;
1292 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001293 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001294 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001295 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1296 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1297 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1298 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1299 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1300 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1301 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1302 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001303 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1304 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001305 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 -04001306 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001307 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001308 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001309 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001310 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001311 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001312 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1313 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001314 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001315 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001316 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001317 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001318 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 -04001319 gradFuncName.c_str(), permFuncName.c_str());
1320 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001321 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001322 noiseCode.c_str(), &noiseFuncName);
1323
1324 // noiseOctaves function
1325 static const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001326 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001327 };
1328 SkString noiseOctavesFuncName;
1329 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001330 noiseOctavesCode.append("half result = 0.0;");
1331 noiseOctavesCode.append("half ratio = 1.0;");
1332 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001333 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1334 noiseOctavesCode.append("p *= 2.0;");
1335 noiseOctavesCode.append("ratio *= 2.0;");
1336 noiseOctavesCode.append("}");
1337 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001338 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001339 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1340
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001341 fragBuilder->codeAppendf("half2 coords = %s * %s;", vCoords.c_str(), baseFrequencyUni);
1342 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001343 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001344 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001345 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001346 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001347 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001348 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001349 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001350 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001351
1352 // Clamp values
1353 fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
1354
1355 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001356 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001357 args.fOutputColor, args.fOutputColor,
1358 args.fOutputColor, args.fOutputColor);
1359}
1360
1361void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1362 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001363 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1364 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001365}
1366
1367void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1368 const GrFragmentProcessor& processor) {
1369 INHERITED::onSetData(pdman, processor);
1370
1371 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1372
1373 const SkVector& baseFrequency = noise.baseFrequency();
1374 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1375
Mike Reedf2ae2b22017-05-30 15:22:54 -04001376 pdman.set1f(fZUni, noise.z());
1377}
1378
1379/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001380std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
1381 const AsFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001382 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001383
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001384 SkMatrix localMatrix = this->getLocalMatrix();
brianosman839345d2016-07-22 11:04:53 -07001385 if (args.fLocalMatrix) {
1386 localMatrix.preConcat(*args.fLocalMatrix);
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001387 }
1388
brianosman839345d2016-07-22 11:04:53 -07001389 SkMatrix matrix = *args.fViewMatrix;
senorblancoca6a7c22014-06-27 13:35:52 -07001390 matrix.preConcat(localMatrix);
1391
Mike Reedf2ae2b22017-05-30 15:22:54 -04001392 // Either we don't stitch tiles, either we have a valid tile size
1393 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1394
Florin Malitab365cf52017-05-30 17:18:01 -04001395 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
1396 skstd::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
1397 fSeed,
1398 fBaseFrequencyX,
1399 fBaseFrequencyY,
1400 matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001401
1402 SkMatrix m = *args.fViewMatrix;
1403 m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
1404 m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
1405
1406 if (fType == kImprovedNoise_Type) {
Brian Salomon2bbdcc42017-09-07 12:36:34 -04001407 GrSamplerState textureParams(GrSamplerState::WrapMode::kRepeat,
1408 GrSamplerState::Filter::kNearest);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001409 sk_sp<GrTextureProxy> permutationsTexture(
1410 GrRefCachedBitmapTextureProxy(args.fContext,
1411 paintingData->getImprovedPermutationsBitmap(),
1412 textureParams, nullptr));
1413 sk_sp<GrTextureProxy> gradientTexture(
1414 GrRefCachedBitmapTextureProxy(args.fContext,
1415 paintingData->getGradientBitmap(),
1416 textureParams, nullptr));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001417 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001418 std::move(permutationsTexture),
1419 std::move(gradientTexture), m);
1420 }
1421
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001422 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001423 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001424 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001425 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1426 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1427 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001428 auto inner =
1429 GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001430 GrConstColorProcessor::InputMode::kModulateRGBA);
bungeman06ca8ec2016-06-09 08:01:03 -07001431 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001432 }
bsalomonc21b09e2015-08-28 18:46:56 -07001433 // Emit zero.
Brian Osman618d3042016-10-25 10:51:28 -04001434 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001435 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001436 }
1437
Mike Reedf2ae2b22017-05-30 15:22:54 -04001438 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedBitmapProxy(
Robert Phillips1afd4cd2018-01-08 13:40:32 -05001439 args.fContext->contextPriv().proxyProvider(),
1440 paintingData->getPermutationsBitmap());
1441 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedBitmapProxy(
1442 args.fContext->contextPriv().proxyProvider(),
1443 paintingData->getNoiseBitmap());
sugoi@google.come3b4c502013-04-05 13:47:09 +00001444
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001445 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001446 auto inner = GrPerlinNoise2Effect::Make(fType,
1447 fNumOctaves,
1448 fStitchTiles,
1449 std::move(paintingData),
1450 std::move(permutationsProxy),
1451 std::move(noiseProxy),
1452 m);
bungeman06ca8ec2016-06-09 08:01:03 -07001453 return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001454 }
bsalomonc21b09e2015-08-28 18:46:56 -07001455 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001456}
1457
1458#endif
1459
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +00001460#ifndef SK_IGNORE_TO_STRING
Florin Malita14d54c22017-05-18 11:52:59 -04001461void SkPerlinNoiseShaderImpl::toString(SkString* str) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001462 str->append("SkPerlinNoiseShaderImpl: (");
sugoi@google.come3b4c502013-04-05 13:47:09 +00001463
1464 str->append("type: ");
1465 switch (fType) {
1466 case kFractalNoise_Type:
1467 str->append("\"fractal noise\"");
1468 break;
1469 case kTurbulence_Type:
1470 str->append("\"turbulence\"");
1471 break;
1472 default:
1473 str->append("\"unknown\"");
1474 break;
1475 }
1476 str->append(" base frequency: (");
1477 str->appendScalar(fBaseFrequencyX);
1478 str->append(", ");
1479 str->appendScalar(fBaseFrequencyY);
1480 str->append(") number of octaves: ");
1481 str->appendS32(fNumOctaves);
1482 str->append(" seed: ");
1483 str->appendScalar(fSeed);
1484 str->append(" stitch tiles: ");
1485 str->append(fStitchTiles ? "true " : "false ");
1486
1487 this->INHERITED::toString(str);
1488
1489 str->append(")");
1490}
1491#endif
Florin Malita14d54c22017-05-18 11:52:59 -04001492
Mike Reedf2ae2b22017-05-30 15:22:54 -04001493///////////////////////////////////////////////////////////////////////////////////////////////////
1494
1495sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1496 SkScalar baseFrequencyY,
1497 int numOctaves, SkScalar seed,
1498 const SkISize* tileSize) {
1499 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1500 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1501 tileSize));
1502}
1503
1504sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1505 SkScalar baseFrequencyY,
1506 int numOctaves, SkScalar seed,
1507 const SkISize* tileSize) {
1508 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1509 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1510 tileSize));
1511}
1512
1513sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1514 SkScalar baseFrequencyY,
1515 int numOctaves, SkScalar z) {
1516 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1517 baseFrequencyX, baseFrequencyY, numOctaves, z,
1518 nullptr));
1519}
1520
Florin Malita14d54c22017-05-18 11:52:59 -04001521SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPerlinNoiseShader)
1522 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShaderImpl)
1523SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END