blob: e8b04d55991f240f28b502f7a6cd05c1fc559c28 [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"
Mike Reedf2ae2b22017-05-30 15:22:54 -040015#include "SkShader.h"
Mike Reedf2ae2b22017-05-30 15:22:54 -040016#include "SkString.h"
Greg Daniel7e1912a2018-02-08 09:15:33 -050017#include "SkUnPreMultiply.h"
18#include "SkWriteBuffer.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
Florin Malita102c8cf2018-06-05 17:37:12 -040078 StitchData(SkScalar w, SkScalar h)
79 : fWidth(SkTMin(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
80 , fWrapX(kPerlinNoise + fWidth)
81 , fHeight(SkTMin(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
82 , fWrapY(kPerlinNoise + fHeight) {}
83
Florin Malita83223bc2017-05-31 14:14:05 -040084 bool operator==(const StitchData& other) const {
85 return fWidth == other.fWidth &&
86 fWrapX == other.fWrapX &&
87 fHeight == other.fHeight &&
88 fWrapY == other.fWrapY;
89 }
90
91 int fWidth; // How much to subtract to wrap for stitching.
92 int fWrapX; // Minimum value to wrap.
93 int fHeight;
94 int fWrapY;
95 };
96
97 struct PaintingData {
98 PaintingData(const SkISize& tileSize, SkScalar seed,
99 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
100 const SkMatrix& matrix)
101 {
102 SkVector vec[2] = {
103 { SkScalarInvert(baseFrequencyX), SkScalarInvert(baseFrequencyY) },
104 { SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight) },
105 };
106 matrix.mapVectors(vec, 2);
107
108 fBaseFrequency.set(SkScalarInvert(vec[0].fX), SkScalarInvert(vec[0].fY));
109 fTileSize.set(SkScalarRoundToInt(vec[1].fX), SkScalarRoundToInt(vec[1].fY));
110 this->init(seed);
111 if (!fTileSize.isEmpty()) {
112 this->stitch();
113 }
114
115 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500116 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
117 SkPixmap permutationsPixmap(info, fLatticeSelector, info.minRowBytes());
118 fPermutationsImage = SkImage::MakeFromRaster(permutationsPixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400119
Greg Daniel7e1912a2018-02-08 09:15:33 -0500120 info = SkImageInfo::MakeN32Premul(kBlockSize, 4);
121 SkPixmap noisePixmap(info, fNoise[0][0], info.minRowBytes());
122 fNoiseImage = SkImage::MakeFromRaster(noisePixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400123
Greg Daniel7e1912a2018-02-08 09:15:33 -0500124 info = SkImageInfo::MakeA8(256, 1);
125 SkPixmap impPermutationsPixmap(info, improved_noise_permutations, info.minRowBytes());
126 fImprovedPermutationsImage = SkImage::MakeFromRaster(impPermutationsPixmap, nullptr,
127 nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400128
Florin Malita83223bc2017-05-31 14:14:05 -0400129 static uint8_t gradients[] = { 2, 2, 1, 0,
130 0, 2, 1, 0,
131 2, 0, 1, 0,
132 0, 0, 1, 0,
133 2, 1, 2, 0,
134 0, 1, 2, 0,
135 2, 1, 0, 0,
136 0, 1, 0, 0,
137 1, 2, 2, 0,
138 1, 0, 2, 0,
139 1, 2, 0, 0,
140 1, 0, 0, 0,
141 2, 2, 1, 0,
142 1, 0, 2, 0,
143 0, 2, 1, 0,
144 1, 0, 0, 0 };
Greg Daniel7e1912a2018-02-08 09:15:33 -0500145 info = SkImageInfo::MakeN32Premul(16, 1);
146 SkPixmap gradPixmap(info, gradients, info.minRowBytes());
147 fGradientImage = SkImage::MakeFromRaster(gradPixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400148 #endif
149 }
150
Brian Salomon4331e462017-07-26 14:58:11 -0400151 #if SK_SUPPORT_GPU
152 PaintingData(const PaintingData& that)
153 : fSeed(that.fSeed)
154 , fTileSize(that.fTileSize)
155 , fBaseFrequency(that.fBaseFrequency)
156 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel7e1912a2018-02-08 09:15:33 -0500157 , fPermutationsImage(that.fPermutationsImage)
158 , fNoiseImage(that.fNoiseImage)
159 , fImprovedPermutationsImage(that.fImprovedPermutationsImage)
160 , fGradientImage(that.fGradientImage) {
Brian Salomon4331e462017-07-26 14:58:11 -0400161 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
162 memcpy(fNoise, that.fNoise, sizeof(fNoise));
163 memcpy(fGradient, that.fGradient, sizeof(fGradient));
164 }
165 #endif
166
Florin Malita83223bc2017-05-31 14:14:05 -0400167 int fSeed;
168 uint8_t fLatticeSelector[kBlockSize];
169 uint16_t fNoise[4][kBlockSize][2];
170 SkPoint fGradient[4][kBlockSize];
171 SkISize fTileSize;
172 SkVector fBaseFrequency;
173 StitchData fStitchDataInit;
174
175 private:
176
177 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500178 sk_sp<SkImage> fPermutationsImage;
179 sk_sp<SkImage> fNoiseImage;
180 sk_sp<SkImage> fImprovedPermutationsImage;
181 sk_sp<SkImage> fGradientImage;
Florin Malita83223bc2017-05-31 14:14:05 -0400182 #endif
183
184 inline int random() {
185 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
186 static const int gRandQ = 127773; // m / a
187 static const int gRandR = 2836; // m % a
188
189 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
190 if (result <= 0)
191 result += kRandMaximum;
192 fSeed = result;
193 return result;
194 }
195
196 // Only called once. Could be part of the constructor.
197 void init(SkScalar seed)
198 {
199 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
200
201 // According to the SVG spec, we must truncate (not round) the seed value.
202 fSeed = SkScalarTruncToInt(seed);
203 // The seed value clamp to the range [1, kRandMaximum - 1].
204 if (fSeed <= 0) {
205 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
206 }
207 if (fSeed > kRandMaximum - 1) {
208 fSeed = kRandMaximum - 1;
209 }
210 for (int channel = 0; channel < 4; ++channel) {
211 for (int i = 0; i < kBlockSize; ++i) {
212 fLatticeSelector[i] = i;
213 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
214 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
215 }
216 }
217 for (int i = kBlockSize - 1; i > 0; --i) {
218 int k = fLatticeSelector[i];
219 int j = random() % kBlockSize;
220 SkASSERT(j >= 0);
221 SkASSERT(j < kBlockSize);
222 fLatticeSelector[i] = fLatticeSelector[j];
223 fLatticeSelector[j] = k;
224 }
225
226 // Perform the permutations now
227 {
228 // Copy noise data
229 uint16_t noise[4][kBlockSize][2];
230 for (int i = 0; i < kBlockSize; ++i) {
231 for (int channel = 0; channel < 4; ++channel) {
232 for (int j = 0; j < 2; ++j) {
233 noise[channel][i][j] = fNoise[channel][i][j];
234 }
235 }
236 }
237 // Do permutations on noise data
238 for (int i = 0; i < kBlockSize; ++i) {
239 for (int channel = 0; channel < 4; ++channel) {
240 for (int j = 0; j < 2; ++j) {
241 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
242 }
243 }
244 }
245 }
246
247 // Half of the largest possible value for 16 bit unsigned int
248 static const SkScalar gHalfMax16bits = 32767.5f;
249
250 // Compute gradients from permutated noise data
251 for (int channel = 0; channel < 4; ++channel) {
252 for (int i = 0; i < kBlockSize; ++i) {
253 fGradient[channel][i] = SkPoint::Make(
254 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
255 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
256 fGradient[channel][i].normalize();
257 // Put the normalized gradient back into the noise data
258 fNoise[channel][i][0] = SkScalarRoundToInt(
259 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
260 fNoise[channel][i][1] = SkScalarRoundToInt(
261 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
262 }
263 }
264 }
265
266 // Only called once. Could be part of the constructor.
267 void stitch() {
268 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
269 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
270 SkASSERT(tileWidth > 0 && tileHeight > 0);
271 // When stitching tiled turbulence, the frequencies must be adjusted
272 // so that the tile borders will be continuous.
273 if (fBaseFrequency.fX) {
274 SkScalar lowFrequencx =
275 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
276 SkScalar highFrequencx =
277 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
278 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400279 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
280 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400281 fBaseFrequency.fX = lowFrequencx;
282 } else {
283 fBaseFrequency.fX = highFrequencx;
284 }
285 }
286 if (fBaseFrequency.fY) {
287 SkScalar lowFrequency =
288 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
289 SkScalar highFrequency =
290 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400291 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
292 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400293 fBaseFrequency.fY = lowFrequency;
294 } else {
295 fBaseFrequency.fY = highFrequency;
296 }
297 }
298 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400299 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
300 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400301 }
302
303 public:
304
305#if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500306 const sk_sp<SkImage> getPermutationsImage() const { return fPermutationsImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400307
Greg Daniel7e1912a2018-02-08 09:15:33 -0500308 const sk_sp<SkImage> getNoiseImage() const { return fNoiseImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400309
Greg Daniel7e1912a2018-02-08 09:15:33 -0500310 const sk_sp<SkImage> getImprovedPermutationsImage() const {
311 return fImprovedPermutationsImage;
312 }
Florin Malita83223bc2017-05-31 14:14:05 -0400313
Greg Daniel7e1912a2018-02-08 09:15:33 -0500314 const sk_sp<SkImage> getGradientImage() const { return fGradientImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400315#endif
316 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400317
318 /**
319 * About the noise types : the difference between the first 2 is just minor tweaks to the
320 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
321 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
322 * doing :
323 * kFractalNoise_Type : noise * 0.5 + 0.5
324 * kTurbulence_Type : abs(noise)
325 * Very little differences between the 2 types, although you can tell the difference visually.
326 * "Improved" is based on the Improved Perlin Noise algorithm described at
327 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
328 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
329 * changes to the noise, making it suitable for animated noise.
330 */
331 enum Type {
332 kFractalNoise_Type,
333 kTurbulence_Type,
334 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500335 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400336 };
337
Robert Phillipsbee27322018-01-23 09:58:18 -0500338 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
339
Mike Reedf2ae2b22017-05-30 15:22:54 -0400340 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
341 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
342 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400343
344 class PerlinNoiseShaderContext : public Context {
345 public:
346 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400347
348 void shadeSpan(int x, int y, SkPMColor[], int count) override;
349
350 private:
351 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
352 SkScalar calculateTurbulenceValueForPoint(
353 int channel,
354 StitchData& stitchData, const SkPoint& point) const;
355 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
356 SkScalar noise2D(int channel,
357 const StitchData& stitchData, const SkPoint& noiseVector) const;
358
Florin Malita83223bc2017-05-31 14:14:05 -0400359 SkMatrix fMatrix;
360 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400361
362 typedef Context INHERITED;
363 };
364
365#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500366 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400367#endif
368
Mike Reedf2ae2b22017-05-30 15:22:54 -0400369 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPerlinNoiseShaderImpl)
370
371protected:
372 void flatten(SkWriteBuffer&) const override;
373 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
374
375private:
376 const SkPerlinNoiseShaderImpl::Type fType;
377 const SkScalar fBaseFrequencyX;
378 const SkScalar fBaseFrequencyY;
379 const int fNumOctaves;
380 const SkScalar fSeed;
381 const SkISize fTileSize;
382 const bool fStitchTiles;
383
384 friend class ::SkPerlinNoiseShader;
385
386 typedef SkShaderBase INHERITED;
387};
388
sugoi@google.come3b4c502013-04-05 13:47:09 +0000389namespace {
390
391// noiseValue is the color component's value (or color)
392// limitValue is the maximum perlin noise array index value allowed
393// newValue is the current noise dimension (either width or height)
394inline int checkNoise(int noiseValue, int limitValue, int newValue) {
395 // If the noise value would bring us out of bounds of the current noise array while we are
396 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
397 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
398 if (noiseValue >= limitValue) {
399 noiseValue -= newValue;
400 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000401 return noiseValue;
402}
403
404inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500405 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000406}
407
408} // end namespace
409
Mike Reedf2ae2b22017-05-30 15:22:54 -0400410SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500411 SkScalar baseFrequencyX,
412 SkScalar baseFrequencyY,
413 int numOctaves,
414 SkScalar seed,
415 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000416 : fType(type)
417 , fBaseFrequencyX(baseFrequencyX)
418 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500419 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000420 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700421 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000422 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000423{
Robert Phillipsbee27322018-01-23 09:58:18 -0500424 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400425 SkASSERT(fBaseFrequencyX >= 0);
426 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400427}
428
Florin Malita14d54c22017-05-18 11:52:59 -0400429sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500430 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500431
reed9fa60da2014-08-21 07:59:51 -0700432 SkScalar freqX = buffer.readScalar();
433 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500434 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500435
reed9fa60da2014-08-21 07:59:51 -0700436 SkScalar seed = buffer.readScalar();
437 SkISize tileSize;
438 tileSize.fWidth = buffer.readInt();
439 tileSize.fHeight = buffer.readInt();
440
441 switch (type) {
442 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400443 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700444 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400445 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
446 case kImprovedNoise_Type:
447 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700448 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500449 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500450 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700451 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700452 }
453}
454
Florin Malita14d54c22017-05-18 11:52:59 -0400455void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000456 buffer.writeInt((int) fType);
457 buffer.writeScalar(fBaseFrequencyX);
458 buffer.writeScalar(fBaseFrequencyY);
459 buffer.writeInt(fNumOctaves);
460 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000461 buffer.writeInt(fTileSize.fWidth);
462 buffer.writeInt(fTileSize.fHeight);
463}
464
Florin Malita14d54c22017-05-18 11:52:59 -0400465SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700466 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000467 struct Noise {
468 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700469 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000470 SkScalar noisePositionFractionValue;
471 Noise(SkScalar component)
472 {
473 SkScalar position = component + kPerlinNoise;
474 noisePositionIntegerValue = SkScalarFloorToInt(position);
475 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700476 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000477 }
478 };
479 Noise noiseX(noiseVector.x());
480 Noise noiseY(noiseVector.y());
481 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400482 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000483 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000484 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000485 noiseX.noisePositionIntegerValue =
486 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
487 noiseY.noisePositionIntegerValue =
488 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700489 noiseX.nextNoisePositionIntegerValue =
490 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
491 noiseY.nextNoisePositionIntegerValue =
492 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000493 }
494 noiseX.noisePositionIntegerValue &= kBlockMask;
495 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700496 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
497 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400498 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
499 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700500 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
501 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
502 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
503 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000504 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
505 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400506
Hal Canaryfda46002017-05-08 17:17:47 -0400507 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
508 return 0; // Check for pathological inputs.
509 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400510
sugoi@google.come3b4c502013-04-05 13:47:09 +0000511 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
512 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
513 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400514 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000515 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400516 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000517 SkScalar a = SkScalarInterp(u, v, sx);
518 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400519 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000520 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400521 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000522 SkScalar b = SkScalarInterp(u, v, sx);
523 return SkScalarInterp(a, b, sy);
524}
525
Florin Malita14d54c22017-05-18 11:52:59 -0400526SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700527 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400528 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000529 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000530 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400531 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000532 }
533 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400534 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
535 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000536 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000537 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700538 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700539 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
540 noise : SkScalarAbs(noise);
541 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000542 noiseVector.fX *= 2;
543 noiseVector.fY *= 2;
544 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000545 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000546 // Update stitch values
Florin Malita102c8cf2018-06-05 17:37:12 -0400547 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
548 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000549 }
550 }
551
552 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
553 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000554 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400555 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000556 }
557
558 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700559 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000560 }
561
562 // Clamp result
563 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
564}
565
Mike Reedf2ae2b22017-05-30 15:22:54 -0400566////////////////////////////////////////////////////////////////////////////////////////////////////
567// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
568static SkScalar fade(SkScalar t) {
569 return t * t * t * (t * (t * 6 - 15) + 10);
570}
571
572static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
573 return a + t * (b - a);
574}
575
576static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
577 int h = hash & 15;
578 SkScalar u = h < 8 ? x : y;
579 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
580 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
581}
582
583SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
584 int channel, const SkPoint& point) const {
585 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
586 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
587 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
588 // z offset between different channels, chosen arbitrarily
589 static const SkScalar CHANNEL_DELTA = 1000.0f;
590 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
591 SkScalar result = 0;
592 SkScalar ratio = SK_Scalar1;
593 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
594 int X = SkScalarFloorToInt(x) & 255;
595 int Y = SkScalarFloorToInt(y) & 255;
596 int Z = SkScalarFloorToInt(z) & 255;
597 SkScalar px = x - SkScalarFloorToScalar(x);
598 SkScalar py = y - SkScalarFloorToScalar(y);
599 SkScalar pz = z - SkScalarFloorToScalar(z);
600 SkScalar u = fade(px);
601 SkScalar v = fade(py);
602 SkScalar w = fade(pz);
603 uint8_t* permutations = improved_noise_permutations;
604 int A = permutations[X] + Y;
605 int AA = permutations[A] + Z;
606 int AB = permutations[A + 1] + Z;
607 int B = permutations[X + 1] + Y;
608 int BA = permutations[B] + Z;
609 int BB = permutations[B + 1] + Z;
610 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
611 grad(permutations[BA ], px - 1, py , pz )),
612 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
613 grad(permutations[BB ], px - 1, py - 1, pz ))),
614 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
615 grad(permutations[BA + 1], px - 1, py , pz - 1)),
616 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
617 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
618 ratio;
619 x *= 2;
620 y *= 2;
621 ratio *= 2;
622 }
623 result = SkScalarClampMax((result + 1.0f) / 2.0f, 1.0f);
624 return result;
625}
626////////////////////////////////////////////////////////////////////////////////////////////////////
627
Florin Malita14d54c22017-05-18 11:52:59 -0400628SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000629 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400630 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000631 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000632 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000633 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
634 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
635
636 U8CPU rgba[4];
637 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400638 SkScalar value;
639 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
640 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
641 }
642 else {
643 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
644 }
645 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000646 }
647 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
648}
649
Mike Reedf2ae2b22017-05-30 15:22:54 -0400650SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400651 SkArenaAlloc* alloc) const {
Herb Derby83e939b2017-02-07 14:25:11 -0500652 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000653}
654
Florin Malita83223bc2017-05-31 14:14:05 -0400655static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
656 const SkShaderBase& shader) {
657 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
658 if (rec.fLocalMatrix) {
659 matrix.preConcat(*rec.fLocalMatrix);
660 }
661
662 return matrix;
663}
664
Florin Malita14d54c22017-05-18 11:52:59 -0400665SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
666 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000667 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400668 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
669 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
670 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000671{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000672 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
673 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400674 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
675 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700676}
677
Florin Malita14d54c22017-05-18 11:52:59 -0400678void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000679 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000680 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
681 StitchData stitchData;
682 for (int i = 0; i < count; ++i) {
683 result[i] = shade(point, stitchData);
684 point.fX += SK_Scalar1;
685 }
686}
687
sugoi@google.come3b4c502013-04-05 13:47:09 +0000688/////////////////////////////////////////////////////////////////////
689
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000690#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000691
egdaniel64c47282015-11-13 06:54:19 -0800692class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000693public:
robertphillips9cdb9922016-02-03 12:25:40 -0800694 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000695
Mike Reedf2ae2b22017-05-30 15:22:54 -0400696 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000697
wangyixb1daa862015-08-18 11:29:31 -0700698protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400699 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700700
sugoi@google.com4775cba2013-04-17 13:46:56 +0000701private:
egdaniel018fb622015-10-28 07:26:40 -0700702 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700703 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700704
egdaniel64c47282015-11-13 06:54:19 -0800705 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000706};
707
708/////////////////////////////////////////////////////////////////////
709
Mike Reedf2ae2b22017-05-30 15:22:54 -0400710class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000711public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400712 static std::unique_ptr<GrFragmentProcessor> Make(
713 SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
714 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
715 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> noiseProxy,
716 const SkMatrix& matrix) {
717 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
718 type, numOctaves, stitchTiles, std::move(paintingData),
719 std::move(permutationsProxy), std::move(noiseProxy), matrix));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000720 }
721
mtklein36352bf2015-03-25 18:17:31 -0700722 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800723
Brian Salomonaff329b2017-08-11 09:40:37 -0400724 std::unique_ptr<GrFragmentProcessor> clone() const override {
725 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400726 }
727
Mike Reedf2ae2b22017-05-30 15:22:54 -0400728 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000729
Florin Malita14d54c22017-05-18 11:52:59 -0400730 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700731 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700732 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700733 int numOctaves() const { return fNumOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -0400734 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
senorblancof3b50272014-06-16 10:49:58 -0700735
sugoi@google.come3b4c502013-04-05 13:47:09 +0000736private:
egdaniel57d3b032015-11-13 11:57:27 -0800737 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800738 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700739 }
740
Brian Salomon94efbf52016-11-29 13:43:05 -0500741 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800742 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700743 GrGLPerlinNoise::GenKey(*this, caps, b);
744 }
745
mtklein36352bf2015-03-25 18:17:31 -0700746 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400747 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700748 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700749 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700750 fNumOctaves == s.fNumOctaves &&
751 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700752 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000753 }
754
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400755 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400756 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400757 sk_sp<GrTextureProxy> permutationsProxy,
758 sk_sp<GrTextureProxy> noiseProxy,
759 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400760 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500761 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500762 , fNumOctaves(numOctaves)
763 , fStitchTiles(stitchTiles)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400764 , fPermutationsSampler(std::move(permutationsProxy))
765 , fNoiseSampler(std::move(noiseProxy))
Florin Malitab365cf52017-05-30 17:18:01 -0400766 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400767 this->setTextureSamplerCnt(2);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400768 fCoordTransform.reset(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700769 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000770 }
771
Brian Salomon4331e462017-07-26 14:58:11 -0400772 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400773 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400774 , fType(that.fType)
775 , fCoordTransform(that.fCoordTransform)
776 , fNumOctaves(that.fNumOctaves)
777 , fStitchTiles(that.fStitchTiles)
778 , fPermutationsSampler(that.fPermutationsSampler)
779 , fNoiseSampler(that.fNoiseSampler)
780 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400781 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -0400782 this->addCoordTransform(&fCoordTransform);
783 }
784
Brian Salomonf7dcd762018-07-30 14:48:15 -0400785 const TextureSampler& onTextureSampler(int i) const override {
786 return IthTextureSampler(i, fPermutationsSampler, fNoiseSampler);
787 }
788
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400789 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000790
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400791 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400792 GrCoordTransform fCoordTransform;
793 int fNumOctaves;
794 bool fStitchTiles;
795 TextureSampler fPermutationsSampler;
796 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400797 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000798
joshualittb0a8a372014-09-23 09:50:21 -0700799 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000800};
801
802/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400803GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000804
Hal Canary6f6961e2017-01-31 13:50:44 -0500805#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400806std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700807 int numOctaves = d->fRandom->nextRangeU(2, 10);
808 bool stitchTiles = d->fRandom->nextBool();
809 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
810 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
811 d->fRandom->nextRangeU(4, 4096));
812 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
813 0.99f);
814 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
815 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000816
reedfe630452016-03-25 09:08:00 -0700817 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
818 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400819 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700820 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400821 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000822
Brian Osman9f532a32016-10-19 11:12:09 -0400823 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400824 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000825}
Hal Canary6f6961e2017-01-31 13:50:44 -0500826#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000827
wangyix7c157a92015-07-22 15:08:53 -0700828void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400829 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800830
Mike Reedf2ae2b22017-05-30 15:22:54 -0400831 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800832 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
bsalomon1a1aa932016-09-12 09:30:36 -0700833 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000834
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400835 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800836 "baseFrequency");
837 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000838
halcanary96fcdcc2015-08-27 07:41:13 -0700839 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800840 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400841 fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800842 "stitchData");
843 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000844 }
845
sugoi@google.comd537af52013-06-10 13:59:25 +0000846 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
847 const char* chanCoordR = "0.125";
848 const char* chanCoordG = "0.375";
849 const char* chanCoordB = "0.625";
850 const char* chanCoordA = "0.875";
851 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000852 const char* stitchData = "stitchData";
853 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000854 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000855 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700856 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000857 const char* fractVal = "fractVal";
858 const char* uv = "uv";
859 const char* ab = "ab";
860 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700861 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000862 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000863 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
864 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
865 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400866 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 +0000867
sugoi@google.comd537af52013-06-10 13:59:25 +0000868 // Add noise function
Brian Salomon99938a82016-11-21 13:41:08 -0500869 static const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400870 GrShaderVar(chanCoord, kHalf_GrSLType),
871 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000872 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000873
Brian Salomon99938a82016-11-21 13:41:08 -0500874 static const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400875 GrShaderVar(chanCoord, kHalf_GrSLType),
876 GrShaderVar(noiseVec, kHalf2_GrSLType),
877 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000878 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000879
sugoi@google.comd537af52013-06-10 13:59:25 +0000880 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000881
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400882 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700883 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400884 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
885 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000886
887 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400888 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700889 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000890
891 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800892 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000893 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400894 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000895 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400896 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700897 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400898 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700899 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400900 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000901 }
902
903 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400904 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400905 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000906
907 // Get permutation for x
908 {
909 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400910 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000911
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400912 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700913 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400914 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000915 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000916 }
917
918 // Get permutation for x + 1
919 {
920 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400921 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000922
sugoi@google.comd537af52013-06-10 13:59:25 +0000923 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700924 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400925 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000926 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000927 }
928
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000929#if defined(SK_BUILD_FOR_ANDROID)
930 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
931 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
932 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
933 // (or 0.484368 here). The following rounding operation prevents these precision issues from
934 // affecting the result of the noise by making sure that we only have multiples of 1/255.
935 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400936 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 +0000937 latticeIdx, latticeIdx);
938#endif
939
sugoi@google.come3b4c502013-04-05 13:47:09 +0000940 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400941 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000942
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400943 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000944 // Compute u, at offset (0,0)
945 {
946 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400947 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
948 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700949 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400950 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000951 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
952 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000953 }
954
sugoi@google.comd537af52013-06-10 13:59:25 +0000955 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000956 // Compute v, at offset (-1,0)
957 {
958 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400959 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000960 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700961 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400962 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000963 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
964 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000965 }
966
967 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400968 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000969 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 +0000970
sugoi@google.comd537af52013-06-10 13:59:25 +0000971 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000972 // Compute v, at offset (-1,-1)
973 {
974 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400975 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000976 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700977 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400978 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000979 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
980 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000981 }
982
sugoi@google.comd537af52013-06-10 13:59:25 +0000983 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000984 // Compute u, at offset (0,-1)
985 {
986 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400987 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000988 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700989 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400990 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000991 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
992 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000993 }
994
995 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000996 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 +0000997 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +0000998 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000999
sugoi@google.comd537af52013-06-10 13:59:25 +00001000 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -08001001 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001002 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001003 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
1004 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001005 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001006 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001007 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
1008 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001009 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001010
sugoi@google.comd537af52013-06-10 13:59:25 +00001011 // There are rounding errors if the floor operation is not performed here
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001012 fragBuilder->codeAppendf("\n\t\thalf2 %s = floor(%s.xy) * %s;",
egdaniel4ca2e602015-11-18 08:01:26 -08001013 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001014
1015 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001016 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001017
robertphillipsbf536af2016-02-04 06:11:53 -08001018 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001019 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001020 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001021 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001022
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001023 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001024
1025 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001026 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001027
Mike Reedf2ae2b22017-05-30 15:22:54 -04001028 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001029 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001030 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001031 }
robertphillipsbf536af2016-02-04 06:11:53 -08001032 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001033 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001034 "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 +00001035 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1036 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1037 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1038 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1039 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1040 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001041 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001042 "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 +00001043 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1044 noiseFuncName.c_str(), chanCoordR, noiseVec,
1045 noiseFuncName.c_str(), chanCoordG, noiseVec,
1046 noiseFuncName.c_str(), chanCoordB, noiseVec,
1047 noiseFuncName.c_str(), chanCoordA, noiseVec);
1048 }
Florin Malita14d54c22017-05-18 11:52:59 -04001049 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001050 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001051 }
egdaniel4ca2e602015-11-18 08:01:26 -08001052 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001053
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001054 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001055 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001056
robertphillipsbf536af2016-02-04 06:11:53 -08001057 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001058 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001059 }
egdaniel4ca2e602015-11-18 08:01:26 -08001060 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001061
Florin Malita14d54c22017-05-18 11:52:59 -04001062 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001063 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1064 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001065 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001066 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001067 }
1068
sugoi@google.come3b4c502013-04-05 13:47:09 +00001069 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001070 fragBuilder->codeAppendf("\n\t\t%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001071
1072 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001073 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001074 args.fOutputColor, args.fOutputColor,
1075 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001076}
1077
Brian Salomon94efbf52016-11-29 13:43:05 -05001078void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001079 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001080 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001081
bsalomon63e99f72014-07-21 08:03:14 -07001082 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001083
1084 key = key << 3; // Make room for next 3 bits
1085
1086 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001087 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001088 key |= 0x1;
1089 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001090 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001091 key |= 0x2;
1092 break;
1093 default:
1094 // leave key at 0
1095 break;
1096 }
1097
1098 if (turbulence.stitchTiles()) {
1099 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1100 }
1101
bsalomon63e99f72014-07-21 08:03:14 -07001102 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001103}
1104
egdaniel018fb622015-10-28 07:26:40 -07001105void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001106 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001107 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001108
Mike Reedf2ae2b22017-05-30 15:22:54 -04001109 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001110
1111 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001112 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001113
sugoi@google.com4775cba2013-04-17 13:46:56 +00001114 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001115 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001116 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001117 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001118 }
1119}
1120
sugoi@google.come3b4c502013-04-05 13:47:09 +00001121/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001122
1123class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1124public:
1125 void emitCode(EmitArgs&) override;
1126
1127 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1128
1129protected:
1130 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1131
1132private:
1133 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001134 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1135
1136 typedef GrGLSLFragmentProcessor INHERITED;
1137};
1138
1139/////////////////////////////////////////////////////////////////////
1140
1141class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1142public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001143 static std::unique_ptr<GrFragmentProcessor> Make(
1144 int octaves, SkScalar z,
1145 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1146 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1147 const SkMatrix& matrix) {
1148 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1149 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1150 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001151 }
1152
Mike Reedf2ae2b22017-05-30 15:22:54 -04001153 const char* name() const override { return "ImprovedPerlinNoise"; }
1154
Brian Salomonaff329b2017-08-11 09:40:37 -04001155 std::unique_ptr<GrFragmentProcessor> clone() const override {
1156 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001157 }
1158
Mike Reedf2ae2b22017-05-30 15:22:54 -04001159 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1160 SkScalar z() const { return fZ; }
1161 int octaves() const { return fOctaves; }
1162 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
1163
1164private:
1165 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1166 return new GrGLImprovedPerlinNoise;
1167 }
1168
1169 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1170 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1171 }
1172
1173 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1174 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1175 return fZ == fZ &&
1176 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1177 }
1178
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001179 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001180 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001181 sk_sp<GrTextureProxy> permutationsProxy,
1182 sk_sp<GrTextureProxy> gradientProxy,
1183 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001184 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001185 , fOctaves(octaves)
1186 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001187 , fPermutationsSampler(std::move(permutationsProxy))
1188 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001189 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001190 this->setTextureSamplerCnt(2);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001191 fCoordTransform.reset(matrix);
1192 this->addCoordTransform(&fCoordTransform);
1193 }
1194
Brian Salomon4331e462017-07-26 14:58:11 -04001195 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001196 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001197 , fCoordTransform(that.fCoordTransform)
1198 , fOctaves(that.fOctaves)
1199 , fZ(that.fZ)
1200 , fPermutationsSampler(that.fPermutationsSampler)
1201 , fGradientSampler(that.fGradientSampler)
1202 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001203 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -04001204 this->addCoordTransform(&fCoordTransform);
1205 }
1206
Brian Salomonf7dcd762018-07-30 14:48:15 -04001207 const TextureSampler& onTextureSampler(int i) const override {
1208 return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
1209 }
1210
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001211 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001212
1213 GrCoordTransform fCoordTransform;
1214 int fOctaves;
1215 SkScalar fZ;
1216 TextureSampler fPermutationsSampler;
1217 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001218 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001219
1220 typedef GrFragmentProcessor INHERITED;
1221};
1222
1223/////////////////////////////////////////////////////////////////////
1224GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1225
1226#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001227std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1228 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001229 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1230 0.99f);
1231 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1232 0.99f);
1233 int numOctaves = d->fRandom->nextRangeU(2, 10);
1234 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1235
1236 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1237 baseFrequencyY,
1238 numOctaves,
1239 z));
1240
1241 GrTest::TestAsFPArgs asFPArgs(d);
1242 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1243}
1244#endif
1245
1246void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001247 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001248 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1249 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1250 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
1251
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001252 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001253 "baseFrequency");
1254 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1255
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001256 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001257 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1258
1259 // fade function
1260 static const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001261 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001262 };
1263 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001264 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001265 fadeArgs,
1266 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1267 &fadeFuncName);
1268
1269 // perm function
1270 static const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001271 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001272 };
1273 SkString permFuncName;
1274 SkString permCode("return ");
1275 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1276 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001277 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001278 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001279 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001280 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001281 permCode.c_str(), &permFuncName);
1282
1283 // grad function
1284 static const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001285 GrShaderVar("x", kHalf_GrSLType),
1286 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001287 };
1288 SkString gradFuncName;
1289 SkString gradCode("return dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001290 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001291 kHalf2_GrSLType);
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001292 gradCode.append(".rgb * 255.0 - float3(1.0), p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001293 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001294 gradCode.c_str(), &gradFuncName);
1295
1296 // lerp function
1297 static const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001298 GrShaderVar("a", kHalf_GrSLType),
1299 GrShaderVar("b", kHalf_GrSLType),
1300 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001301 };
1302 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001303 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001304 "return a + w * (b - a);", &lerpFuncName);
1305
1306 // noise function
1307 static const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001308 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001309 };
1310 SkString noiseFuncName;
1311 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001312 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001313 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001314 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1315 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1316 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1317 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1318 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1319 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1320 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1321 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001322 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1323 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001324 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 -04001325 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001326 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001327 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001328 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001329 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001330 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001331 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1332 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001333 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001334 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001335 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001336 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001337 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 -04001338 gradFuncName.c_str(), permFuncName.c_str());
1339 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001340 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001341 noiseCode.c_str(), &noiseFuncName);
1342
1343 // noiseOctaves function
1344 static const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001345 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001346 };
1347 SkString noiseOctavesFuncName;
1348 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001349 noiseOctavesCode.append("half result = 0.0;");
1350 noiseOctavesCode.append("half ratio = 1.0;");
1351 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001352 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1353 noiseOctavesCode.append("p *= 2.0;");
1354 noiseOctavesCode.append("ratio *= 2.0;");
1355 noiseOctavesCode.append("}");
1356 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001357 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001358 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1359
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001360 fragBuilder->codeAppendf("half2 coords = %s * %s;", vCoords.c_str(), baseFrequencyUni);
1361 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001362 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001363 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001364 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001365 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001366 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001367 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001368 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001369 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001370
1371 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001372 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001373
1374 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001375 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001376 args.fOutputColor, args.fOutputColor,
1377 args.fOutputColor, args.fOutputColor);
1378}
1379
1380void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1381 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001382 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1383 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001384}
1385
1386void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1387 const GrFragmentProcessor& processor) {
1388 INHERITED::onSetData(pdman, processor);
1389
1390 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1391
1392 const SkVector& baseFrequency = noise.baseFrequency();
1393 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1394
Mike Reedf2ae2b22017-05-30 15:22:54 -04001395 pdman.set1f(fZUni, noise.z());
1396}
1397
1398/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001399std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001400 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001401 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001402
Florin Malitac6c5ead2018-04-11 15:33:40 -04001403 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
1404 const auto matrix = SkMatrix::Concat(*args.fViewMatrix, *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001405
Mike Reedf2ae2b22017-05-30 15:22:54 -04001406 // Either we don't stitch tiles, either we have a valid tile size
1407 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1408
Florin Malitab365cf52017-05-30 17:18:01 -04001409 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
1410 skstd::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
1411 fSeed,
1412 fBaseFrequencyX,
1413 fBaseFrequencyY,
1414 matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001415
1416 SkMatrix m = *args.fViewMatrix;
Florin Malitac6c5ead2018-04-11 15:33:40 -04001417 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1418 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001419
Greg Daniel7e1912a2018-02-08 09:15:33 -05001420 auto proxyProvider = args.fContext->contextPriv().proxyProvider();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001421 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001422 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1423 // We also know that we will not be using mipmaps. If things things weren't true we should
1424 // go through GrBitmapTextureMaker to handle needed copies.
1425 const sk_sp<SkImage> permutationsImage = paintingData->getImprovedPermutationsImage();
1426 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001427 sk_sp<GrTextureProxy> permutationsTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001428 GrMakeCachedImageProxy(proxyProvider, std::move(permutationsImage)));
1429
1430 const sk_sp<SkImage> gradientImage = paintingData->getGradientImage();
1431 SkASSERT(SkIsPow2(gradientImage->width()) && SkIsPow2(gradientImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001432 sk_sp<GrTextureProxy> gradientTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001433 GrMakeCachedImageProxy(proxyProvider, std::move(gradientImage)));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001434 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001435 std::move(permutationsTexture),
1436 std::move(gradientTexture), m);
1437 }
1438
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001439 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001440 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001441 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001442 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1443 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1444 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001445 auto inner =
1446 GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001447 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001448 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001449 }
bsalomonc21b09e2015-08-28 18:46:56 -07001450 // Emit zero.
Brian Osman618d3042016-10-25 10:51:28 -04001451 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001452 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001453 }
1454
Greg Daniel7e1912a2018-02-08 09:15:33 -05001455 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1456 // also know that we will not be using mipmaps. If things things weren't true we should go
1457 // through GrBitmapTextureMaker to handle needed copies.
1458 const sk_sp<SkImage> permutationsImage = paintingData->getPermutationsImage();
1459 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
1460 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedImageProxy(proxyProvider,
1461 std::move(permutationsImage));
1462
1463 const sk_sp<SkImage> noiseImage = paintingData->getNoiseImage();
1464 SkASSERT(SkIsPow2(noiseImage->width()) && SkIsPow2(noiseImage->height()));
1465 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedImageProxy(proxyProvider,
1466 std::move(noiseImage));
sugoi@google.come3b4c502013-04-05 13:47:09 +00001467
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001468 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001469 auto inner = GrPerlinNoise2Effect::Make(fType,
1470 fNumOctaves,
1471 fStitchTiles,
1472 std::move(paintingData),
1473 std::move(permutationsProxy),
1474 std::move(noiseProxy),
1475 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001476 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001477 }
bsalomonc21b09e2015-08-28 18:46:56 -07001478 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001479}
1480
1481#endif
1482
Mike Reedf2ae2b22017-05-30 15:22:54 -04001483///////////////////////////////////////////////////////////////////////////////////////////////////
1484
Mike Reed832aa112018-05-18 11:48:50 -04001485static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1486 SkScalar seed) {
1487 if (!(baseX >= 0 && baseY >= 0)) {
1488 return false;
1489 }
1490 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1491 return false;
1492 }
1493 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1494 return false;
1495 }
1496 if (!SkScalarIsFinite(seed)) {
1497 return false;
1498 }
1499 return true;
1500}
1501
Mike Reedf2ae2b22017-05-30 15:22:54 -04001502sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1503 SkScalar baseFrequencyY,
1504 int numOctaves, SkScalar seed,
1505 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001506 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1507 return nullptr;
1508 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001509 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1510 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1511 tileSize));
1512}
1513
1514sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1515 SkScalar baseFrequencyY,
1516 int numOctaves, SkScalar seed,
1517 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001518 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1519 return nullptr;
1520 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001521 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1522 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1523 tileSize));
1524}
1525
1526sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1527 SkScalar baseFrequencyY,
1528 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001529 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1530 return nullptr;
1531 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001532 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1533 baseFrequencyX, baseFrequencyY, numOctaves, z,
1534 nullptr));
1535}
1536
Florin Malita14d54c22017-05-18 11:52:59 -04001537SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPerlinNoiseShader)
1538 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShaderImpl)
1539SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END