blob: 5dd8090618846bcc0a48e5bd123abf5389cd2ec8 [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"
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +000011#include "SkColorFilter.h"
Florin Malitab365cf52017-05-30 17:18:01 -040012#include "SkMakeUnique.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
Mike Reedf2ae2b22017-05-30 15:22:54 -040014#include "SkShader.h"
Mike Reedf2ae2b22017-05-30 15:22:54 -040015#include "SkString.h"
Greg Daniel7e1912a2018-02-08 09:15:33 -050016#include "SkUnPreMultiply.h"
17#include "SkWriteBuffer.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000018
19#if SK_SUPPORT_GPU
20#include "GrContext.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050021#include "GrContextPriv.h"
bsalomon@google.com77af6802013-10-02 13:04:56 +000022#include "GrCoordTransform.h"
joshualitteb2a6762014-12-04 11:35:33 -080023#include "SkGr.h"
bsalomonc21b09e2015-08-28 18:46:56 -070024#include "effects/GrConstColorProcessor.h"
egdaniel64c47282015-11-13 06:54:19 -080025#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080026#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070027#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080028#include "glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000029#endif
30
31static const int kBlockSize = 256;
32static const int kBlockMask = kBlockSize - 1;
33static const int kPerlinNoise = 4096;
34static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
35
Mike Reedf2ae2b22017-05-30 15:22:54 -040036static uint8_t improved_noise_permutations[] = {
37 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
38 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
39 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
40 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
41 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
42 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
43 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
44 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
45 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
46 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
47 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
48 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
49 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
50 141, 128, 195, 78, 66, 215, 61, 156, 180,
51 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
52 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
53 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
54 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
55 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
56 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
57 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
58 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
59 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
60 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
61 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
62 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
63 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
64 141, 128, 195, 78, 66, 215, 61, 156, 180
65};
66
67class SkPerlinNoiseShaderImpl : public SkShaderBase {
68public:
Florin Malita83223bc2017-05-31 14:14:05 -040069 struct StitchData {
70 StitchData()
71 : fWidth(0)
72 , fWrapX(0)
73 , fHeight(0)
74 , fWrapY(0)
75 {}
76
Florin Malita102c8cf2018-06-05 17:37:12 -040077 StitchData(SkScalar w, SkScalar h)
78 : fWidth(SkTMin(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
79 , fWrapX(kPerlinNoise + fWidth)
80 , fHeight(SkTMin(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
81 , fWrapY(kPerlinNoise + fHeight) {}
82
Florin Malita83223bc2017-05-31 14:14:05 -040083 bool operator==(const StitchData& other) const {
84 return fWidth == other.fWidth &&
85 fWrapX == other.fWrapX &&
86 fHeight == other.fHeight &&
87 fWrapY == other.fWrapY;
88 }
89
90 int fWidth; // How much to subtract to wrap for stitching.
91 int fWrapX; // Minimum value to wrap.
92 int fHeight;
93 int fWrapY;
94 };
95
96 struct PaintingData {
97 PaintingData(const SkISize& tileSize, SkScalar seed,
98 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
99 const SkMatrix& matrix)
100 {
Ethan Nicholas82940152019-01-10 13:58:14 -0500101 SkVector tileVec;
102 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
103 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -0400104
Ethan Nicholas82940152019-01-10 13:58:14 -0500105 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -0500106 if (!matrix.decomposeScale(&scale, nullptr)) {
107 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
108 }
Ethan Nicholas82940152019-01-10 13:58:14 -0500109 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
110 baseFrequencyY * SkScalarInvert(scale.height()));
111 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -0400112 this->init(seed);
113 if (!fTileSize.isEmpty()) {
114 this->stitch();
115 }
116
117 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500118 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
119 SkPixmap permutationsPixmap(info, fLatticeSelector, info.minRowBytes());
120 fPermutationsImage = SkImage::MakeFromRaster(permutationsPixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400121
Greg Daniel7e1912a2018-02-08 09:15:33 -0500122 info = SkImageInfo::MakeN32Premul(kBlockSize, 4);
123 SkPixmap noisePixmap(info, fNoise[0][0], info.minRowBytes());
124 fNoiseImage = SkImage::MakeFromRaster(noisePixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400125
Greg Daniel7e1912a2018-02-08 09:15:33 -0500126 info = SkImageInfo::MakeA8(256, 1);
127 SkPixmap impPermutationsPixmap(info, improved_noise_permutations, info.minRowBytes());
128 fImprovedPermutationsImage = SkImage::MakeFromRaster(impPermutationsPixmap, nullptr,
129 nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400130
Florin Malita83223bc2017-05-31 14:14:05 -0400131 static uint8_t gradients[] = { 2, 2, 1, 0,
132 0, 2, 1, 0,
133 2, 0, 1, 0,
134 0, 0, 1, 0,
135 2, 1, 2, 0,
136 0, 1, 2, 0,
137 2, 1, 0, 0,
138 0, 1, 0, 0,
139 1, 2, 2, 0,
140 1, 0, 2, 0,
141 1, 2, 0, 0,
142 1, 0, 0, 0,
143 2, 2, 1, 0,
144 1, 0, 2, 0,
145 0, 2, 1, 0,
146 1, 0, 0, 0 };
Greg Daniel7e1912a2018-02-08 09:15:33 -0500147 info = SkImageInfo::MakeN32Premul(16, 1);
148 SkPixmap gradPixmap(info, gradients, info.minRowBytes());
149 fGradientImage = SkImage::MakeFromRaster(gradPixmap, nullptr, nullptr);
Florin Malita83223bc2017-05-31 14:14:05 -0400150 #endif
151 }
152
Brian Salomon4331e462017-07-26 14:58:11 -0400153 #if SK_SUPPORT_GPU
154 PaintingData(const PaintingData& that)
155 : fSeed(that.fSeed)
156 , fTileSize(that.fTileSize)
157 , fBaseFrequency(that.fBaseFrequency)
158 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel7e1912a2018-02-08 09:15:33 -0500159 , fPermutationsImage(that.fPermutationsImage)
160 , fNoiseImage(that.fNoiseImage)
161 , fImprovedPermutationsImage(that.fImprovedPermutationsImage)
162 , fGradientImage(that.fGradientImage) {
Brian Salomon4331e462017-07-26 14:58:11 -0400163 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
164 memcpy(fNoise, that.fNoise, sizeof(fNoise));
165 memcpy(fGradient, that.fGradient, sizeof(fGradient));
166 }
167 #endif
168
Florin Malita83223bc2017-05-31 14:14:05 -0400169 int fSeed;
170 uint8_t fLatticeSelector[kBlockSize];
171 uint16_t fNoise[4][kBlockSize][2];
172 SkPoint fGradient[4][kBlockSize];
173 SkISize fTileSize;
174 SkVector fBaseFrequency;
175 StitchData fStitchDataInit;
176
177 private:
178
179 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500180 sk_sp<SkImage> fPermutationsImage;
181 sk_sp<SkImage> fNoiseImage;
182 sk_sp<SkImage> fImprovedPermutationsImage;
183 sk_sp<SkImage> fGradientImage;
Florin Malita83223bc2017-05-31 14:14:05 -0400184 #endif
185
186 inline int random() {
187 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
188 static const int gRandQ = 127773; // m / a
189 static const int gRandR = 2836; // m % a
190
191 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
192 if (result <= 0)
193 result += kRandMaximum;
194 fSeed = result;
195 return result;
196 }
197
198 // Only called once. Could be part of the constructor.
199 void init(SkScalar seed)
200 {
201 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
202
203 // According to the SVG spec, we must truncate (not round) the seed value.
204 fSeed = SkScalarTruncToInt(seed);
205 // The seed value clamp to the range [1, kRandMaximum - 1].
206 if (fSeed <= 0) {
207 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
208 }
209 if (fSeed > kRandMaximum - 1) {
210 fSeed = kRandMaximum - 1;
211 }
212 for (int channel = 0; channel < 4; ++channel) {
213 for (int i = 0; i < kBlockSize; ++i) {
214 fLatticeSelector[i] = i;
215 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
216 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
217 }
218 }
219 for (int i = kBlockSize - 1; i > 0; --i) {
220 int k = fLatticeSelector[i];
221 int j = random() % kBlockSize;
222 SkASSERT(j >= 0);
223 SkASSERT(j < kBlockSize);
224 fLatticeSelector[i] = fLatticeSelector[j];
225 fLatticeSelector[j] = k;
226 }
227
228 // Perform the permutations now
229 {
230 // Copy noise data
231 uint16_t noise[4][kBlockSize][2];
232 for (int i = 0; i < kBlockSize; ++i) {
233 for (int channel = 0; channel < 4; ++channel) {
234 for (int j = 0; j < 2; ++j) {
235 noise[channel][i][j] = fNoise[channel][i][j];
236 }
237 }
238 }
239 // Do permutations on noise data
240 for (int i = 0; i < kBlockSize; ++i) {
241 for (int channel = 0; channel < 4; ++channel) {
242 for (int j = 0; j < 2; ++j) {
243 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
244 }
245 }
246 }
247 }
248
249 // Half of the largest possible value for 16 bit unsigned int
250 static const SkScalar gHalfMax16bits = 32767.5f;
251
252 // Compute gradients from permutated noise data
253 for (int channel = 0; channel < 4; ++channel) {
254 for (int i = 0; i < kBlockSize; ++i) {
255 fGradient[channel][i] = SkPoint::Make(
256 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
257 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
258 fGradient[channel][i].normalize();
259 // Put the normalized gradient back into the noise data
260 fNoise[channel][i][0] = SkScalarRoundToInt(
261 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
262 fNoise[channel][i][1] = SkScalarRoundToInt(
263 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
264 }
265 }
266 }
267
268 // Only called once. Could be part of the constructor.
269 void stitch() {
270 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
271 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
272 SkASSERT(tileWidth > 0 && tileHeight > 0);
273 // When stitching tiled turbulence, the frequencies must be adjusted
274 // so that the tile borders will be continuous.
275 if (fBaseFrequency.fX) {
276 SkScalar lowFrequencx =
277 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
278 SkScalar highFrequencx =
279 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
280 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400281 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
282 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400283 fBaseFrequency.fX = lowFrequencx;
284 } else {
285 fBaseFrequency.fX = highFrequencx;
286 }
287 }
288 if (fBaseFrequency.fY) {
289 SkScalar lowFrequency =
290 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
291 SkScalar highFrequency =
292 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400293 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
294 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400295 fBaseFrequency.fY = lowFrequency;
296 } else {
297 fBaseFrequency.fY = highFrequency;
298 }
299 }
300 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400301 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
302 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400303 }
304
305 public:
306
307#if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500308 const sk_sp<SkImage> getPermutationsImage() const { return fPermutationsImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400309
Greg Daniel7e1912a2018-02-08 09:15:33 -0500310 const sk_sp<SkImage> getNoiseImage() const { return fNoiseImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400311
Greg Daniel7e1912a2018-02-08 09:15:33 -0500312 const sk_sp<SkImage> getImprovedPermutationsImage() const {
313 return fImprovedPermutationsImage;
314 }
Florin Malita83223bc2017-05-31 14:14:05 -0400315
Greg Daniel7e1912a2018-02-08 09:15:33 -0500316 const sk_sp<SkImage> getGradientImage() const { return fGradientImage; }
Florin Malita83223bc2017-05-31 14:14:05 -0400317#endif
318 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400319
320 /**
321 * About the noise types : the difference between the first 2 is just minor tweaks to the
322 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
323 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
324 * doing :
325 * kFractalNoise_Type : noise * 0.5 + 0.5
326 * kTurbulence_Type : abs(noise)
327 * Very little differences between the 2 types, although you can tell the difference visually.
328 * "Improved" is based on the Improved Perlin Noise algorithm described at
329 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
330 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
331 * changes to the noise, making it suitable for animated noise.
332 */
333 enum Type {
334 kFractalNoise_Type,
335 kTurbulence_Type,
336 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500337 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400338 };
339
Robert Phillipsbee27322018-01-23 09:58:18 -0500340 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
341
Mike Reedf2ae2b22017-05-30 15:22:54 -0400342 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
343 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
344 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400345
346 class PerlinNoiseShaderContext : public Context {
347 public:
348 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400349
350 void shadeSpan(int x, int y, SkPMColor[], int count) override;
351
352 private:
353 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
354 SkScalar calculateTurbulenceValueForPoint(
355 int channel,
356 StitchData& stitchData, const SkPoint& point) const;
357 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
358 SkScalar noise2D(int channel,
359 const StitchData& stitchData, const SkPoint& noiseVector) const;
360
Florin Malita83223bc2017-05-31 14:14:05 -0400361 SkMatrix fMatrix;
362 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400363
364 typedef Context INHERITED;
365 };
366
367#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500368 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400369#endif
370
Mike Reedf2ae2b22017-05-30 15:22:54 -0400371protected:
372 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400373#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400374 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400375#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400376
377private:
Mike Klein4fee3232018-10-18 17:27:16 -0400378 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
379
Mike Reedf2ae2b22017-05-30 15:22:54 -0400380 const SkPerlinNoiseShaderImpl::Type fType;
381 const SkScalar fBaseFrequencyX;
382 const SkScalar fBaseFrequencyY;
383 const int fNumOctaves;
384 const SkScalar fSeed;
385 const SkISize fTileSize;
386 const bool fStitchTiles;
387
388 friend class ::SkPerlinNoiseShader;
389
390 typedef SkShaderBase INHERITED;
391};
392
sugoi@google.come3b4c502013-04-05 13:47:09 +0000393namespace {
394
395// noiseValue is the color component's value (or color)
396// limitValue is the maximum perlin noise array index value allowed
397// newValue is the current noise dimension (either width or height)
398inline int checkNoise(int noiseValue, int limitValue, int newValue) {
399 // If the noise value would bring us out of bounds of the current noise array while we are
400 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
401 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
402 if (noiseValue >= limitValue) {
403 noiseValue -= newValue;
404 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000405 return noiseValue;
406}
407
408inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500409 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000410}
411
412} // end namespace
413
Mike Reedf2ae2b22017-05-30 15:22:54 -0400414SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500415 SkScalar baseFrequencyX,
416 SkScalar baseFrequencyY,
417 int numOctaves,
418 SkScalar seed,
419 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000420 : fType(type)
421 , fBaseFrequencyX(baseFrequencyX)
422 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500423 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000424 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700425 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000426 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000427{
Robert Phillipsbee27322018-01-23 09:58:18 -0500428 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400429 SkASSERT(fBaseFrequencyX >= 0);
430 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400431}
432
Florin Malita14d54c22017-05-18 11:52:59 -0400433sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500434 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500435
reed9fa60da2014-08-21 07:59:51 -0700436 SkScalar freqX = buffer.readScalar();
437 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500438 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500439
reed9fa60da2014-08-21 07:59:51 -0700440 SkScalar seed = buffer.readScalar();
441 SkISize tileSize;
442 tileSize.fWidth = buffer.readInt();
443 tileSize.fHeight = buffer.readInt();
444
445 switch (type) {
446 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400447 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700448 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400449 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
450 case kImprovedNoise_Type:
451 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700452 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500453 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500454 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700455 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700456 }
457}
458
Florin Malita14d54c22017-05-18 11:52:59 -0400459void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000460 buffer.writeInt((int) fType);
461 buffer.writeScalar(fBaseFrequencyX);
462 buffer.writeScalar(fBaseFrequencyY);
463 buffer.writeInt(fNumOctaves);
464 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000465 buffer.writeInt(fTileSize.fWidth);
466 buffer.writeInt(fTileSize.fHeight);
467}
468
Florin Malita14d54c22017-05-18 11:52:59 -0400469SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700470 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000471 struct Noise {
472 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700473 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000474 SkScalar noisePositionFractionValue;
475 Noise(SkScalar component)
476 {
477 SkScalar position = component + kPerlinNoise;
478 noisePositionIntegerValue = SkScalarFloorToInt(position);
479 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700480 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000481 }
482 };
483 Noise noiseX(noiseVector.x());
484 Noise noiseY(noiseVector.y());
485 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400486 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000487 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000488 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000489 noiseX.noisePositionIntegerValue =
490 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
491 noiseY.noisePositionIntegerValue =
492 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700493 noiseX.nextNoisePositionIntegerValue =
494 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
495 noiseY.nextNoisePositionIntegerValue =
496 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000497 }
498 noiseX.noisePositionIntegerValue &= kBlockMask;
499 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700500 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
501 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400502 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
503 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700504 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
505 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
506 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
507 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000508 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
509 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400510
Hal Canaryfda46002017-05-08 17:17:47 -0400511 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
512 return 0; // Check for pathological inputs.
513 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400514
sugoi@google.come3b4c502013-04-05 13:47:09 +0000515 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
516 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
517 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400518 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000519 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400520 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000521 SkScalar a = SkScalarInterp(u, v, sx);
522 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400523 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000524 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400525 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000526 SkScalar b = SkScalarInterp(u, v, sx);
527 return SkScalarInterp(a, b, sy);
528}
529
Florin Malita14d54c22017-05-18 11:52:59 -0400530SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700531 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400532 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000533 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000534 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400535 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000536 }
537 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400538 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
539 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000540 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000541 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700542 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700543 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
544 noise : SkScalarAbs(noise);
545 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000546 noiseVector.fX *= 2;
547 noiseVector.fY *= 2;
548 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000549 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000550 // Update stitch values
Florin Malita102c8cf2018-06-05 17:37:12 -0400551 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
552 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000553 }
554 }
555
556 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
557 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000558 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400559 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000560 }
561
562 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700563 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000564 }
565
566 // Clamp result
567 return SkScalarPin(turbulenceFunctionResult, 0, SK_Scalar1);
568}
569
Mike Reedf2ae2b22017-05-30 15:22:54 -0400570////////////////////////////////////////////////////////////////////////////////////////////////////
571// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
572static SkScalar fade(SkScalar t) {
573 return t * t * t * (t * (t * 6 - 15) + 10);
574}
575
576static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
577 return a + t * (b - a);
578}
579
580static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
581 int h = hash & 15;
582 SkScalar u = h < 8 ? x : y;
583 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
584 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
585}
586
587SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
588 int channel, const SkPoint& point) const {
589 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
590 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
591 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
592 // z offset between different channels, chosen arbitrarily
593 static const SkScalar CHANNEL_DELTA = 1000.0f;
594 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
595 SkScalar result = 0;
596 SkScalar ratio = SK_Scalar1;
597 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
598 int X = SkScalarFloorToInt(x) & 255;
599 int Y = SkScalarFloorToInt(y) & 255;
600 int Z = SkScalarFloorToInt(z) & 255;
601 SkScalar px = x - SkScalarFloorToScalar(x);
602 SkScalar py = y - SkScalarFloorToScalar(y);
603 SkScalar pz = z - SkScalarFloorToScalar(z);
604 SkScalar u = fade(px);
605 SkScalar v = fade(py);
606 SkScalar w = fade(pz);
607 uint8_t* permutations = improved_noise_permutations;
608 int A = permutations[X] + Y;
609 int AA = permutations[A] + Z;
610 int AB = permutations[A + 1] + Z;
611 int B = permutations[X + 1] + Y;
612 int BA = permutations[B] + Z;
613 int BB = permutations[B + 1] + Z;
614 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
615 grad(permutations[BA ], px - 1, py , pz )),
616 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
617 grad(permutations[BB ], px - 1, py - 1, pz ))),
618 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
619 grad(permutations[BA + 1], px - 1, py , pz - 1)),
620 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
621 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
622 ratio;
623 x *= 2;
624 y *= 2;
625 ratio *= 2;
626 }
627 result = SkScalarClampMax((result + 1.0f) / 2.0f, 1.0f);
628 return result;
629}
630////////////////////////////////////////////////////////////////////////////////////////////////////
631
Florin Malita14d54c22017-05-18 11:52:59 -0400632SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000633 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400634 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000635 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000636 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000637 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
638 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
639
640 U8CPU rgba[4];
641 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400642 SkScalar value;
643 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
644 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
645 }
646 else {
647 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
648 }
649 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000650 }
651 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
652}
653
Mike Reede92aae62018-10-17 10:21:51 -0400654#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400655SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400656 SkArenaAlloc* alloc) const {
Herb Derby83e939b2017-02-07 14:25:11 -0500657 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000658}
Mike Reede92aae62018-10-17 10:21:51 -0400659#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000660
Florin Malita83223bc2017-05-31 14:14:05 -0400661static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
662 const SkShaderBase& shader) {
663 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
664 if (rec.fLocalMatrix) {
665 matrix.preConcat(*rec.fLocalMatrix);
666 }
667
668 return matrix;
669}
670
Florin Malita14d54c22017-05-18 11:52:59 -0400671SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
672 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000673 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400674 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
675 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
676 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000677{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000678 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
679 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400680 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
681 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700682}
683
Florin Malita14d54c22017-05-18 11:52:59 -0400684void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000685 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000686 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
687 StitchData stitchData;
688 for (int i = 0; i < count; ++i) {
689 result[i] = shade(point, stitchData);
690 point.fX += SK_Scalar1;
691 }
692}
693
sugoi@google.come3b4c502013-04-05 13:47:09 +0000694/////////////////////////////////////////////////////////////////////
695
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000696#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000697
egdaniel64c47282015-11-13 06:54:19 -0800698class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000699public:
robertphillips9cdb9922016-02-03 12:25:40 -0800700 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000701
Mike Reedf2ae2b22017-05-30 15:22:54 -0400702 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000703
wangyixb1daa862015-08-18 11:29:31 -0700704protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400705 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700706
sugoi@google.com4775cba2013-04-17 13:46:56 +0000707private:
egdaniel018fb622015-10-28 07:26:40 -0700708 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700709 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700710
egdaniel64c47282015-11-13 06:54:19 -0800711 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000712};
713
714/////////////////////////////////////////////////////////////////////
715
Mike Reedf2ae2b22017-05-30 15:22:54 -0400716class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000717public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400718 static std::unique_ptr<GrFragmentProcessor> Make(
719 SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
720 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
721 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> noiseProxy,
722 const SkMatrix& matrix) {
723 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(
724 type, numOctaves, stitchTiles, std::move(paintingData),
725 std::move(permutationsProxy), std::move(noiseProxy), matrix));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000726 }
727
mtklein36352bf2015-03-25 18:17:31 -0700728 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800729
Brian Salomonaff329b2017-08-11 09:40:37 -0400730 std::unique_ptr<GrFragmentProcessor> clone() const override {
731 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400732 }
733
Mike Reedf2ae2b22017-05-30 15:22:54 -0400734 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000735
Florin Malita14d54c22017-05-18 11:52:59 -0400736 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700737 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700738 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700739 int numOctaves() const { return fNumOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -0400740 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
senorblancof3b50272014-06-16 10:49:58 -0700741
sugoi@google.come3b4c502013-04-05 13:47:09 +0000742private:
egdaniel57d3b032015-11-13 11:57:27 -0800743 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800744 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700745 }
746
Brian Salomon94efbf52016-11-29 13:43:05 -0500747 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800748 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700749 GrGLPerlinNoise::GenKey(*this, caps, b);
750 }
751
mtklein36352bf2015-03-25 18:17:31 -0700752 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400753 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700754 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700755 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700756 fNumOctaves == s.fNumOctaves &&
757 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700758 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000759 }
760
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400761 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400762 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400763 sk_sp<GrTextureProxy> permutationsProxy,
764 sk_sp<GrTextureProxy> noiseProxy,
765 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400766 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500767 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500768 , fNumOctaves(numOctaves)
769 , fStitchTiles(stitchTiles)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400770 , fPermutationsSampler(std::move(permutationsProxy))
771 , fNoiseSampler(std::move(noiseProxy))
Florin Malitab365cf52017-05-30 17:18:01 -0400772 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400773 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -0500774 fCoordTransform = GrCoordTransform(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700775 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000776 }
777
Brian Salomon4331e462017-07-26 14:58:11 -0400778 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400779 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400780 , fType(that.fType)
781 , fCoordTransform(that.fCoordTransform)
782 , fNumOctaves(that.fNumOctaves)
783 , fStitchTiles(that.fStitchTiles)
784 , fPermutationsSampler(that.fPermutationsSampler)
785 , fNoiseSampler(that.fNoiseSampler)
786 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -0400787 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -0400788 this->addCoordTransform(&fCoordTransform);
789 }
790
Brian Salomonf7dcd762018-07-30 14:48:15 -0400791 const TextureSampler& onTextureSampler(int i) const override {
792 return IthTextureSampler(i, fPermutationsSampler, fNoiseSampler);
793 }
794
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400795 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000796
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400797 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400798 GrCoordTransform fCoordTransform;
799 int fNumOctaves;
800 bool fStitchTiles;
801 TextureSampler fPermutationsSampler;
802 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400803 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000804
joshualittb0a8a372014-09-23 09:50:21 -0700805 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000806};
807
808/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400809GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000810
Hal Canary6f6961e2017-01-31 13:50:44 -0500811#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400812std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700813 int numOctaves = d->fRandom->nextRangeU(2, 10);
814 bool stitchTiles = d->fRandom->nextBool();
815 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
816 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
817 d->fRandom->nextRangeU(4, 4096));
818 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
819 0.99f);
820 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
821 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000822
reedfe630452016-03-25 09:08:00 -0700823 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
824 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400825 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700826 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400827 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000828
Brian Osman9f532a32016-10-19 11:12:09 -0400829 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400830 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000831}
Hal Canary6f6961e2017-01-31 13:50:44 -0500832#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000833
wangyix7c157a92015-07-22 15:08:53 -0700834void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400835 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800836
Mike Reedf2ae2b22017-05-30 15:22:54 -0400837 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800838 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
bsalomon1a1aa932016-09-12 09:30:36 -0700839 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000840
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400841 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800842 "baseFrequency");
843 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000844
halcanary96fcdcc2015-08-27 07:41:13 -0700845 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800846 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400847 fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800848 "stitchData");
849 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000850 }
851
sugoi@google.comd537af52013-06-10 13:59:25 +0000852 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
853 const char* chanCoordR = "0.125";
854 const char* chanCoordG = "0.375";
855 const char* chanCoordB = "0.625";
856 const char* chanCoordA = "0.875";
857 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000858 const char* stitchData = "stitchData";
859 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000860 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000861 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700862 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000863 const char* fractVal = "fractVal";
864 const char* uv = "uv";
865 const char* ab = "ab";
866 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700867 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000868 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000869 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
870 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
871 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400872 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 +0000873
sugoi@google.comd537af52013-06-10 13:59:25 +0000874 // Add noise function
Nico Webere50efdf2018-10-01 14:40:44 -0400875 const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400876 GrShaderVar(chanCoord, kHalf_GrSLType),
877 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000878 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000879
Nico Webere50efdf2018-10-01 14:40:44 -0400880 const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400881 GrShaderVar(chanCoord, kHalf_GrSLType),
882 GrShaderVar(noiseVec, kHalf2_GrSLType),
883 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000884 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000885
sugoi@google.comd537af52013-06-10 13:59:25 +0000886 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000887
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400888 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700889 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400890 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
891 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000892
893 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400894 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700895 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000896
897 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800898 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000899 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400900 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000901 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400902 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700903 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400904 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700905 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400906 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000907 }
908
909 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400910 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400911 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000912
913 // Get permutation for x
914 {
915 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400916 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000917
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400918 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700919 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400920 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000921 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000922 }
923
924 // Get permutation for x + 1
925 {
926 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400927 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000928
sugoi@google.comd537af52013-06-10 13:59:25 +0000929 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700930 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400931 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000932 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000933 }
934
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000935#if defined(SK_BUILD_FOR_ANDROID)
936 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
937 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
938 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
939 // (or 0.484368 here). The following rounding operation prevents these precision issues from
940 // affecting the result of the noise by making sure that we only have multiples of 1/255.
941 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400942 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 +0000943 latticeIdx, latticeIdx);
944#endif
945
sugoi@google.come3b4c502013-04-05 13:47:09 +0000946 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400947 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000948
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400949 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000950 // Compute u, at offset (0,0)
951 {
952 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400953 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
954 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700955 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400956 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000957 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
958 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000959 }
960
sugoi@google.comd537af52013-06-10 13:59:25 +0000961 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000962 // Compute v, at offset (-1,0)
963 {
964 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400965 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000966 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700967 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400968 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000969 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
970 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000971 }
972
973 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400974 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000975 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 +0000976
sugoi@google.comd537af52013-06-10 13:59:25 +0000977 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000978 // Compute v, at offset (-1,-1)
979 {
980 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400981 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000982 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700983 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400984 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000985 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
986 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000987 }
988
sugoi@google.comd537af52013-06-10 13:59:25 +0000989 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000990 // Compute u, at offset (0,-1)
991 {
992 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400993 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000994 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700995 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400996 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000997 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
998 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000999 }
1000
1001 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +00001002 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 +00001003 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +00001004 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001005
sugoi@google.comd537af52013-06-10 13:59:25 +00001006 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -08001007 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001008 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001009 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
1010 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001011 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001012 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001013 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
1014 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001015 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001016
sugoi@google.comd537af52013-06-10 13:59:25 +00001017 // There are rounding errors if the floor operation is not performed here
Ethan Nicholase1f55022019-02-05 17:17:40 -05001018 fragBuilder->codeAppendf("\n\t\thalf2 %s = half2(floor(%s.xy) * %s);",
egdaniel4ca2e602015-11-18 08:01:26 -08001019 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001020
1021 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001022 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001023
robertphillipsbf536af2016-02-04 06:11:53 -08001024 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001025 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001026 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001027 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001028
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001029 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001030
1031 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001032 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001033
Mike Reedf2ae2b22017-05-30 15:22:54 -04001034 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001035 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001036 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001037 }
robertphillipsbf536af2016-02-04 06:11:53 -08001038 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001039 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001040 "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 +00001041 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1042 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1043 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1044 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1045 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1046 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001047 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001048 "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 +00001049 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1050 noiseFuncName.c_str(), chanCoordR, noiseVec,
1051 noiseFuncName.c_str(), chanCoordG, noiseVec,
1052 noiseFuncName.c_str(), chanCoordB, noiseVec,
1053 noiseFuncName.c_str(), chanCoordA, noiseVec);
1054 }
Florin Malita14d54c22017-05-18 11:52:59 -04001055 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001056 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001057 }
egdaniel4ca2e602015-11-18 08:01:26 -08001058 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001059
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001060 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001061 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001062
robertphillipsbf536af2016-02-04 06:11:53 -08001063 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001064 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001065 }
egdaniel4ca2e602015-11-18 08:01:26 -08001066 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001067
Florin Malita14d54c22017-05-18 11:52:59 -04001068 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001069 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1070 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001071 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001072 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001073 }
1074
sugoi@google.come3b4c502013-04-05 13:47:09 +00001075 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001076 fragBuilder->codeAppendf("\n\t\t%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001077
1078 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001079 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001080 args.fOutputColor, args.fOutputColor,
1081 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001082}
1083
Brian Salomon94efbf52016-11-29 13:43:05 -05001084void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001085 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001086 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001087
bsalomon63e99f72014-07-21 08:03:14 -07001088 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001089
1090 key = key << 3; // Make room for next 3 bits
1091
1092 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001093 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001094 key |= 0x1;
1095 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001096 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001097 key |= 0x2;
1098 break;
1099 default:
1100 // leave key at 0
1101 break;
1102 }
1103
1104 if (turbulence.stitchTiles()) {
1105 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1106 }
1107
bsalomon63e99f72014-07-21 08:03:14 -07001108 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001109}
1110
egdaniel018fb622015-10-28 07:26:40 -07001111void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001112 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001113 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001114
Mike Reedf2ae2b22017-05-30 15:22:54 -04001115 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001116
1117 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001118 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001119
sugoi@google.com4775cba2013-04-17 13:46:56 +00001120 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001121 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001122 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001123 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001124 }
1125}
1126
sugoi@google.come3b4c502013-04-05 13:47:09 +00001127/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001128
1129class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1130public:
1131 void emitCode(EmitArgs&) override;
1132
1133 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1134
1135protected:
1136 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1137
1138private:
1139 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001140 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1141
1142 typedef GrGLSLFragmentProcessor INHERITED;
1143};
1144
1145/////////////////////////////////////////////////////////////////////
1146
1147class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1148public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001149 static std::unique_ptr<GrFragmentProcessor> Make(
1150 int octaves, SkScalar z,
1151 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1152 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1153 const SkMatrix& matrix) {
1154 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1155 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1156 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001157 }
1158
Mike Reedf2ae2b22017-05-30 15:22:54 -04001159 const char* name() const override { return "ImprovedPerlinNoise"; }
1160
Brian Salomonaff329b2017-08-11 09:40:37 -04001161 std::unique_ptr<GrFragmentProcessor> clone() const override {
1162 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001163 }
1164
Mike Reedf2ae2b22017-05-30 15:22:54 -04001165 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1166 SkScalar z() const { return fZ; }
1167 int octaves() const { return fOctaves; }
1168 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
1169
1170private:
1171 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1172 return new GrGLImprovedPerlinNoise;
1173 }
1174
1175 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1176 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1177 }
1178
1179 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1180 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1181 return fZ == fZ &&
1182 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1183 }
1184
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001185 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001186 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001187 sk_sp<GrTextureProxy> permutationsProxy,
1188 sk_sp<GrTextureProxy> gradientProxy,
1189 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001190 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001191 , fOctaves(octaves)
1192 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001193 , fPermutationsSampler(std::move(permutationsProxy))
1194 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001195 , fPaintingData(std::move(paintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001196 this->setTextureSamplerCnt(2);
Brian Salomon246bc3d2018-12-06 15:33:02 -05001197 fCoordTransform = GrCoordTransform(matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001198 this->addCoordTransform(&fCoordTransform);
1199 }
1200
Brian Salomon4331e462017-07-26 14:58:11 -04001201 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001202 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001203 , fCoordTransform(that.fCoordTransform)
1204 , fOctaves(that.fOctaves)
1205 , fZ(that.fZ)
1206 , fPermutationsSampler(that.fPermutationsSampler)
1207 , fGradientSampler(that.fGradientSampler)
1208 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomonf7dcd762018-07-30 14:48:15 -04001209 this->setTextureSamplerCnt(2);
Brian Salomon4331e462017-07-26 14:58:11 -04001210 this->addCoordTransform(&fCoordTransform);
1211 }
1212
Brian Salomonf7dcd762018-07-30 14:48:15 -04001213 const TextureSampler& onTextureSampler(int i) const override {
1214 return IthTextureSampler(i, fPermutationsSampler, fGradientSampler);
1215 }
1216
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001217 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001218
1219 GrCoordTransform fCoordTransform;
1220 int fOctaves;
1221 SkScalar fZ;
1222 TextureSampler fPermutationsSampler;
1223 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001224 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001225
1226 typedef GrFragmentProcessor INHERITED;
1227};
1228
1229/////////////////////////////////////////////////////////////////////
1230GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1231
1232#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001233std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1234 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001235 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1236 0.99f);
1237 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1238 0.99f);
1239 int numOctaves = d->fRandom->nextRangeU(2, 10);
1240 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1241
1242 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1243 baseFrequencyY,
1244 numOctaves,
1245 z));
1246
1247 GrTest::TestAsFPArgs asFPArgs(d);
1248 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1249}
1250#endif
1251
1252void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001253 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001254 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1255 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1256 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
1257
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001258 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001259 "baseFrequency");
1260 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1261
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001262 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001263 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1264
1265 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001266 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001267 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001268 };
1269 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001270 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001271 fadeArgs,
1272 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1273 &fadeFuncName);
1274
1275 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001276 const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001277 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001278 };
1279 SkString permFuncName;
1280 SkString permCode("return ");
1281 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1282 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001283 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001284 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001285 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001286 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001287 permCode.c_str(), &permFuncName);
1288
1289 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001290 const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001291 GrShaderVar("x", kHalf_GrSLType),
1292 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001293 };
1294 SkString gradFuncName;
Ethan Nicholase1f55022019-02-05 17:17:40 -05001295 SkString gradCode("return half(dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001296 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001297 kHalf2_GrSLType);
Ethan Nicholase1f55022019-02-05 17:17:40 -05001298 gradCode.append(".rgb * 255.0 - float3(1.0), p));");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001299 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001300 gradCode.c_str(), &gradFuncName);
1301
1302 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001303 const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001304 GrShaderVar("a", kHalf_GrSLType),
1305 GrShaderVar("b", kHalf_GrSLType),
1306 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001307 };
1308 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001309 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001310 "return a + w * (b - a);", &lerpFuncName);
1311
1312 // noise function
Nico Webere50efdf2018-10-01 14:40:44 -04001313 const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001314 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001315 };
1316 SkString noiseFuncName;
1317 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001318 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001319 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001320 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1321 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1322 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1323 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1324 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1325 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1326 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1327 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001328 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1329 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001330 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 -04001331 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001332 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001333 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001334 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001335 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001336 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001337 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1338 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001339 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001340 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001341 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001342 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001343 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 -04001344 gradFuncName.c_str(), permFuncName.c_str());
1345 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001346 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001347 noiseCode.c_str(), &noiseFuncName);
1348
1349 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001350 const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001351 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001352 };
1353 SkString noiseOctavesFuncName;
1354 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001355 noiseOctavesCode.append("half result = 0.0;");
1356 noiseOctavesCode.append("half ratio = 1.0;");
1357 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001358 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1359 noiseOctavesCode.append("p *= 2.0;");
1360 noiseOctavesCode.append("ratio *= 2.0;");
1361 noiseOctavesCode.append("}");
1362 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001363 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001364 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1365
Ethan Nicholase1f55022019-02-05 17:17:40 -05001366 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", vCoords.c_str(), baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001367 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001368 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001369 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001370 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001371 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001372 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001373 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001374 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001375 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001376
1377 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001378 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001379
1380 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001381 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001382 args.fOutputColor, args.fOutputColor,
1383 args.fOutputColor, args.fOutputColor);
1384}
1385
1386void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1387 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001388 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1389 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001390}
1391
1392void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1393 const GrFragmentProcessor& processor) {
1394 INHERITED::onSetData(pdman, processor);
1395
1396 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1397
1398 const SkVector& baseFrequency = noise.baseFrequency();
1399 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1400
Mike Reedf2ae2b22017-05-30 15:22:54 -04001401 pdman.set1f(fZUni, noise.z());
1402}
1403
1404/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001405std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001406 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001407 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001408
Florin Malitac6c5ead2018-04-11 15:33:40 -04001409 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
Ethan Nicholas82940152019-01-10 13:58:14 -05001410 const auto paintMatrix = SkMatrix::Concat(*args.fViewMatrix, *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001411
Mike Reedf2ae2b22017-05-30 15:22:54 -04001412 // Either we don't stitch tiles, either we have a valid tile size
1413 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1414
Florin Malitab365cf52017-05-30 17:18:01 -04001415 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
1416 skstd::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
1417 fSeed,
1418 fBaseFrequencyX,
1419 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001420 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001421
1422 SkMatrix m = *args.fViewMatrix;
Florin Malitac6c5ead2018-04-11 15:33:40 -04001423 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1424 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001425
Robert Phillips9da87e02019-02-04 13:26:26 -05001426 auto proxyProvider = args.fContext->priv().proxyProvider();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001427 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001428 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1429 // We also know that we will not be using mipmaps. If things things weren't true we should
1430 // go through GrBitmapTextureMaker to handle needed copies.
1431 const sk_sp<SkImage> permutationsImage = paintingData->getImprovedPermutationsImage();
1432 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001433 sk_sp<GrTextureProxy> permutationsTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001434 GrMakeCachedImageProxy(proxyProvider, std::move(permutationsImage)));
1435
1436 const sk_sp<SkImage> gradientImage = paintingData->getGradientImage();
1437 SkASSERT(SkIsPow2(gradientImage->width()) && SkIsPow2(gradientImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001438 sk_sp<GrTextureProxy> gradientTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001439 GrMakeCachedImageProxy(proxyProvider, std::move(gradientImage)));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001440 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001441 std::move(permutationsTexture),
1442 std::move(gradientTexture), m);
1443 }
1444
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001445 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001446 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001447 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001448 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1449 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1450 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001451 auto inner =
Brian Osmancb3d0872018-10-16 15:19:28 -04001452 GrConstColorProcessor::Make(SkPMColor4f::FromBytes_RGBA(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001453 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001454 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001455 }
bsalomonc21b09e2015-08-28 18:46:56 -07001456 // Emit zero.
Brian Osmanf28e55d2018-10-03 16:35:54 -04001457 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001458 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001459 }
1460
Greg Daniel7e1912a2018-02-08 09:15:33 -05001461 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1462 // also know that we will not be using mipmaps. If things things weren't true we should go
1463 // through GrBitmapTextureMaker to handle needed copies.
1464 const sk_sp<SkImage> permutationsImage = paintingData->getPermutationsImage();
1465 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
1466 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedImageProxy(proxyProvider,
1467 std::move(permutationsImage));
1468
1469 const sk_sp<SkImage> noiseImage = paintingData->getNoiseImage();
1470 SkASSERT(SkIsPow2(noiseImage->width()) && SkIsPow2(noiseImage->height()));
1471 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedImageProxy(proxyProvider,
1472 std::move(noiseImage));
sugoi@google.come3b4c502013-04-05 13:47:09 +00001473
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001474 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001475 auto inner = GrPerlinNoise2Effect::Make(fType,
1476 fNumOctaves,
1477 fStitchTiles,
1478 std::move(paintingData),
1479 std::move(permutationsProxy),
1480 std::move(noiseProxy),
1481 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001482 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001483 }
bsalomonc21b09e2015-08-28 18:46:56 -07001484 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001485}
1486
1487#endif
1488
Mike Reedf2ae2b22017-05-30 15:22:54 -04001489///////////////////////////////////////////////////////////////////////////////////////////////////
1490
Mike Reed832aa112018-05-18 11:48:50 -04001491static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1492 SkScalar seed) {
1493 if (!(baseX >= 0 && baseY >= 0)) {
1494 return false;
1495 }
1496 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1497 return false;
1498 }
1499 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1500 return false;
1501 }
1502 if (!SkScalarIsFinite(seed)) {
1503 return false;
1504 }
1505 return true;
1506}
1507
Mike Reedf2ae2b22017-05-30 15:22:54 -04001508sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1509 SkScalar baseFrequencyY,
1510 int numOctaves, SkScalar seed,
1511 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001512 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1513 return nullptr;
1514 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001515 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1516 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1517 tileSize));
1518}
1519
1520sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1521 SkScalar baseFrequencyY,
1522 int numOctaves, SkScalar seed,
1523 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001524 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1525 return nullptr;
1526 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001527 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1528 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1529 tileSize));
1530}
1531
1532sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1533 SkScalar baseFrequencyY,
1534 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001535 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1536 return nullptr;
1537 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001538 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1539 baseFrequencyX, baseFrequencyY, numOctaves, z,
1540 nullptr));
1541}
1542
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001543void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001544 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001545}