blob: 4bc44a6eefd6b8710cfb34ecc990367025cc6c41 [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 Salomon0bbecb22016-11-17 11:38:22 -0500767 this->addTextureSampler(&fPermutationsSampler);
768 this->addTextureSampler(&fNoiseSampler);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400769 fCoordTransform.reset(matrix);
senorblancof3b50272014-06-16 10:49:58 -0700770 this->addCoordTransform(&fCoordTransform);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000771 }
772
Brian Salomon4331e462017-07-26 14:58:11 -0400773 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400774 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400775 , fType(that.fType)
776 , fCoordTransform(that.fCoordTransform)
777 , fNumOctaves(that.fNumOctaves)
778 , fStitchTiles(that.fStitchTiles)
779 , fPermutationsSampler(that.fPermutationsSampler)
780 , fNoiseSampler(that.fNoiseSampler)
781 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon4331e462017-07-26 14:58:11 -0400782 this->addTextureSampler(&fPermutationsSampler);
783 this->addTextureSampler(&fNoiseSampler);
784 this->addCoordTransform(&fCoordTransform);
785 }
786
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400787 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000788
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400789 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400790 GrCoordTransform fCoordTransform;
791 int fNumOctaves;
792 bool fStitchTiles;
793 TextureSampler fPermutationsSampler;
794 TextureSampler fNoiseSampler;
Florin Malitab365cf52017-05-30 17:18:01 -0400795 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000796
joshualittb0a8a372014-09-23 09:50:21 -0700797 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000798};
799
800/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400801GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000802
Hal Canary6f6961e2017-01-31 13:50:44 -0500803#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400804std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700805 int numOctaves = d->fRandom->nextRangeU(2, 10);
806 bool stitchTiles = d->fRandom->nextBool();
807 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
808 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
809 d->fRandom->nextRangeU(4, 4096));
810 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
811 0.99f);
812 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
813 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000814
reedfe630452016-03-25 09:08:00 -0700815 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
816 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400817 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700818 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400819 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000820
Brian Osman9f532a32016-10-19 11:12:09 -0400821 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400822 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000823}
Hal Canary6f6961e2017-01-31 13:50:44 -0500824#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000825
wangyix7c157a92015-07-22 15:08:53 -0700826void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400827 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800828
Mike Reedf2ae2b22017-05-30 15:22:54 -0400829 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800830 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
bsalomon1a1aa932016-09-12 09:30:36 -0700831 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000832
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400833 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800834 "baseFrequency");
835 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000836
halcanary96fcdcc2015-08-27 07:41:13 -0700837 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800838 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400839 fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800840 "stitchData");
841 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000842 }
843
sugoi@google.comd537af52013-06-10 13:59:25 +0000844 // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8
845 const char* chanCoordR = "0.125";
846 const char* chanCoordG = "0.375";
847 const char* chanCoordB = "0.625";
848 const char* chanCoordA = "0.875";
849 const char* chanCoord = "chanCoord";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000850 const char* stitchData = "stitchData";
851 const char* ratio = "ratio";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000852 const char* noiseVec = "noiseVec";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000853 const char* noiseSmooth = "noiseSmooth";
senorblancoce6a3542014-06-12 11:24:19 -0700854 const char* floorVal = "floorVal";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000855 const char* fractVal = "fractVal";
856 const char* uv = "uv";
857 const char* ab = "ab";
858 const char* latticeIdx = "latticeIdx";
senorblancoce6a3542014-06-12 11:24:19 -0700859 const char* bcoords = "bcoords";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000860 const char* lattice = "lattice";
sugoi@google.come3b4c502013-04-05 13:47:09 +0000861 const char* inc8bit = "0.00390625"; // 1.0 / 256.0
862 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
863 // [-1,1] vector and perform a dot product between that vector and the provided vector.
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400864 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 +0000865
sugoi@google.comd537af52013-06-10 13:59:25 +0000866 // Add noise function
Brian Salomon99938a82016-11-21 13:41:08 -0500867 static const GrShaderVar gPerlinNoiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400868 GrShaderVar(chanCoord, kHalf_GrSLType),
869 GrShaderVar(noiseVec, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000870 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000871
Brian Salomon99938a82016-11-21 13:41:08 -0500872 static const GrShaderVar gPerlinNoiseStitchArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400873 GrShaderVar(chanCoord, kHalf_GrSLType),
874 GrShaderVar(noiseVec, kHalf2_GrSLType),
875 GrShaderVar(stitchData, kHalf2_GrSLType)
sugoi@google.comd537af52013-06-10 13:59:25 +0000876 };
sugoi@google.come3b4c502013-04-05 13:47:09 +0000877
sugoi@google.comd537af52013-06-10 13:59:25 +0000878 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000879
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400880 noiseCode.appendf("\thalf4 %s;\n", floorVal);
senorblancoce6a3542014-06-12 11:24:19 -0700881 noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400882 noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal);
883 noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000884
885 // smooth curve : t * t * (3 - 2 * t)
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400886 noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);",
senorblancoce6a3542014-06-12 11:24:19 -0700887 noiseSmooth, fractVal, fractVal, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000888
889 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800890 if (pne.stitchTiles()) {
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000891 noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400892 floorVal, stitchData, floorVal, stitchData);
commit-bot@chromium.org98393202013-07-04 18:13:05 +0000893 noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400894 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700895 noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400896 floorVal, stitchData, floorVal, stitchData);
senorblancoce6a3542014-06-12 11:24:19 -0700897 noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400898 floorVal, stitchData, floorVal, stitchData);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000899 }
900
901 // Get texture coordinates and normalize
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400902 noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -0400903 floorVal, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000904
905 // Get permutation for x
906 {
907 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400908 xCoords.appendf("half2(%s.x, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000909
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400910 noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700911 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400912 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000913 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000914 }
915
916 // Get permutation for x + 1
917 {
918 SkString xCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400919 xCoords.appendf("half2(%s.z, 0.5)", floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000920
sugoi@google.comd537af52013-06-10 13:59:25 +0000921 noiseCode.appendf("\n\t%s.y = ", latticeIdx);
cdalton3f6f76f2016-04-11 12:18:09 -0700922 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400923 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000924 noiseCode.append(".r;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000925 }
926
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000927#if defined(SK_BUILD_FOR_ANDROID)
928 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
929 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
930 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
931 // (or 0.484368 here). The following rounding operation prevents these precision issues from
932 // affecting the result of the noise by making sure that we only have multiples of 1/255.
933 // (Note that 1/255 is about 0.003921569, which is the value used here).
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400934 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 +0000935 latticeIdx, latticeIdx);
936#endif
937
sugoi@google.come3b4c502013-04-05 13:47:09 +0000938 // Get (x,y) coordinates with the permutated x
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400939 noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000940
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400941 noiseCode.appendf("\n\n\thalf2 %s;", uv);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000942 // Compute u, at offset (0,0)
943 {
944 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400945 latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord);
946 noiseCode.appendf("\n\thalf4 %s = ", lattice);
cdalton3f6f76f2016-04-11 12:18:09 -0700947 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400948 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000949 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
950 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000951 }
952
sugoi@google.comd537af52013-06-10 13:59:25 +0000953 noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000954 // Compute v, at offset (-1,0)
955 {
956 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400957 latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000958 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700959 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400960 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000961 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
962 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000963 }
964
965 // Compute 'a' as a linear interpolation of 'u' and 'v'
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400966 noiseCode.appendf("\n\thalf2 %s;", ab);
sugoi@google.comd537af52013-06-10 13:59:25 +0000967 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 +0000968
sugoi@google.comd537af52013-06-10 13:59:25 +0000969 noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000970 // Compute v, at offset (-1,-1)
971 {
972 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400973 latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000974 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700975 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400976 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000977 noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
978 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000979 }
980
sugoi@google.comd537af52013-06-10 13:59:25 +0000981 noiseCode.appendf("\n\t%s.x += 1.0;", fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000982 // Compute u, at offset (0,-1)
983 {
984 SkString latticeCoords("");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400985 latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord);
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000986 noiseCode.append("\n\tlattice = ");
cdalton3f6f76f2016-04-11 12:18:09 -0700987 fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(),
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400988 kHalf2_GrSLType);
sugoi@google.comd537af52013-06-10 13:59:25 +0000989 noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
990 noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000991 }
992
993 // Compute 'b' as a linear interpolation of 'u' and 'v'
sugoi@google.comd537af52013-06-10 13:59:25 +0000994 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 +0000995 // Compute the noise as a linear interpolation of 'a' and 'b'
sugoi@google.comd537af52013-06-10 13:59:25 +0000996 noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000997
sugoi@google.comd537af52013-06-10 13:59:25 +0000998 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800999 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001000 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001001 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
1002 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001003 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001004 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -08001005 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
1006 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +00001007 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001008
sugoi@google.comd537af52013-06-10 13:59:25 +00001009 // There are rounding errors if the floor operation is not performed here
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001010 fragBuilder->codeAppendf("\n\t\thalf2 %s = floor(%s.xy) * %s;",
egdaniel4ca2e602015-11-18 08:01:26 -08001011 noiseVec, vCoords.c_str(), baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +00001012
1013 // Clear the color accumulator
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001014 fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001015
robertphillipsbf536af2016-02-04 06:11:53 -08001016 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +00001017 // Set up TurbulenceInitial stitch values.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001018 fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001019 }
sugoi@google.come3b4c502013-04-05 13:47:09 +00001020
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001021 fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001022
1023 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -08001024 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
sugoi@google.comd537af52013-06-10 13:59:25 +00001025
Mike Reedf2ae2b22017-05-30 15:22:54 -04001026 fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -04001027 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001028 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +00001029 }
robertphillipsbf536af2016-02-04 06:11:53 -08001030 if (pne.stitchTiles()) {
egdaniel4ca2e602015-11-18 08:01:26 -08001031 fragBuilder->codeAppendf(
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001032 "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 +00001033 "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
1034 noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
1035 noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData,
1036 noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
1037 noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
1038 } else {
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),\n\t\t\t\t%s(%s, %s),"
sugoi@google.comd537af52013-06-10 13:59:25 +00001041 "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
1042 noiseFuncName.c_str(), chanCoordR, noiseVec,
1043 noiseFuncName.c_str(), chanCoordG, noiseVec,
1044 noiseFuncName.c_str(), chanCoordB, noiseVec,
1045 noiseFuncName.c_str(), chanCoordA, noiseVec);
1046 }
Florin Malita14d54c22017-05-18 11:52:59 -04001047 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -08001048 fragBuilder->codeAppendf(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001049 }
egdaniel4ca2e602015-11-18 08:01:26 -08001050 fragBuilder->codeAppendf(" * %s;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001051
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001052 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec);
egdaniel4ca2e602015-11-18 08:01:26 -08001053 fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
sugoi@google.comd537af52013-06-10 13:59:25 +00001054
robertphillipsbf536af2016-02-04 06:11:53 -08001055 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001056 fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData);
sugoi@google.comd537af52013-06-10 13:59:25 +00001057 }
egdaniel4ca2e602015-11-18 08:01:26 -08001058 fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001059
Florin Malita14d54c22017-05-18 11:52:59 -04001060 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001061 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1062 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001063 fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001064 args.fOutputColor,args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001065 }
1066
sugoi@google.come3b4c502013-04-05 13:47:09 +00001067 // Clamp values
egdaniel4ca2e602015-11-18 08:01:26 -08001068 fragBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001069
1070 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001071 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001072 args.fOutputColor, args.fOutputColor,
1073 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001074}
1075
Brian Salomon94efbf52016-11-29 13:43:05 -05001076void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001077 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001078 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001079
bsalomon63e99f72014-07-21 08:03:14 -07001080 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001081
1082 key = key << 3; // Make room for next 3 bits
1083
1084 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001085 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001086 key |= 0x1;
1087 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001088 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001089 key |= 0x2;
1090 break;
1091 default:
1092 // leave key at 0
1093 break;
1094 }
1095
1096 if (turbulence.stitchTiles()) {
1097 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1098 }
1099
bsalomon63e99f72014-07-21 08:03:14 -07001100 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001101}
1102
egdaniel018fb622015-10-28 07:26:40 -07001103void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001104 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001105 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001106
Mike Reedf2ae2b22017-05-30 15:22:54 -04001107 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001108
1109 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001110 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001111
sugoi@google.com4775cba2013-04-17 13:46:56 +00001112 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001113 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001114 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
commit-bot@chromium.org98393202013-07-04 18:13:05 +00001115 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001116 }
1117}
1118
sugoi@google.come3b4c502013-04-05 13:47:09 +00001119/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001120
1121class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1122public:
1123 void emitCode(EmitArgs&) override;
1124
1125 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1126
1127protected:
1128 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1129
1130private:
1131 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001132 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1133
1134 typedef GrGLSLFragmentProcessor INHERITED;
1135};
1136
1137/////////////////////////////////////////////////////////////////////
1138
1139class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1140public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001141 static std::unique_ptr<GrFragmentProcessor> Make(
1142 int octaves, SkScalar z,
1143 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
1144 sk_sp<GrTextureProxy> permutationsProxy, sk_sp<GrTextureProxy> gradientProxy,
1145 const SkMatrix& matrix) {
1146 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(
1147 octaves, z, std::move(paintingData), std::move(permutationsProxy),
1148 std::move(gradientProxy), matrix));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001149 }
1150
Mike Reedf2ae2b22017-05-30 15:22:54 -04001151 const char* name() const override { return "ImprovedPerlinNoise"; }
1152
Brian Salomonaff329b2017-08-11 09:40:37 -04001153 std::unique_ptr<GrFragmentProcessor> clone() const override {
1154 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001155 }
1156
Mike Reedf2ae2b22017-05-30 15:22:54 -04001157 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1158 SkScalar z() const { return fZ; }
1159 int octaves() const { return fOctaves; }
1160 const SkMatrix& matrix() const { return fCoordTransform.getMatrix(); }
1161
1162private:
1163 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1164 return new GrGLImprovedPerlinNoise;
1165 }
1166
1167 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1168 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1169 }
1170
1171 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1172 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1173 return fZ == fZ &&
1174 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1175 }
1176
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001177 GrImprovedPerlinNoiseEffect(int octaves, SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001178 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001179 sk_sp<GrTextureProxy> permutationsProxy,
1180 sk_sp<GrTextureProxy> gradientProxy,
1181 const SkMatrix& matrix)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001182 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001183 , fOctaves(octaves)
1184 , fZ(z)
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001185 , fPermutationsSampler(std::move(permutationsProxy))
1186 , fGradientSampler(std::move(gradientProxy))
Florin Malitab365cf52017-05-30 17:18:01 -04001187 , fPaintingData(std::move(paintingData)) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001188 this->addTextureSampler(&fPermutationsSampler);
1189 this->addTextureSampler(&fGradientSampler);
1190 fCoordTransform.reset(matrix);
1191 this->addCoordTransform(&fCoordTransform);
1192 }
1193
Brian Salomon4331e462017-07-26 14:58:11 -04001194 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001195 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001196 , fCoordTransform(that.fCoordTransform)
1197 , fOctaves(that.fOctaves)
1198 , fZ(that.fZ)
1199 , fPermutationsSampler(that.fPermutationsSampler)
1200 , fGradientSampler(that.fGradientSampler)
1201 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon4331e462017-07-26 14:58:11 -04001202 this->addTextureSampler(&fPermutationsSampler);
1203 this->addTextureSampler(&fGradientSampler);
1204 this->addCoordTransform(&fCoordTransform);
1205 }
1206
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001207 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001208
1209 GrCoordTransform fCoordTransform;
1210 int fOctaves;
1211 SkScalar fZ;
1212 TextureSampler fPermutationsSampler;
1213 TextureSampler fGradientSampler;
Florin Malitab365cf52017-05-30 17:18:01 -04001214 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001215
1216 typedef GrFragmentProcessor INHERITED;
1217};
1218
1219/////////////////////////////////////////////////////////////////////
1220GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1221
1222#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001223std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1224 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001225 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1226 0.99f);
1227 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1228 0.99f);
1229 int numOctaves = d->fRandom->nextRangeU(2, 10);
1230 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1231
1232 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1233 baseFrequencyY,
1234 numOctaves,
1235 z));
1236
1237 GrTest::TestAsFPArgs asFPArgs(d);
1238 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1239}
1240#endif
1241
1242void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001243 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001244 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1245 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1246 SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
1247
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001248 fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001249 "baseFrequency");
1250 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1251
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001252 fZUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001253 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1254
1255 // fade function
1256 static const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001257 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001258 };
1259 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001260 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001261 fadeArgs,
1262 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1263 &fadeFuncName);
1264
1265 // perm function
1266 static const GrShaderVar permArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001267 GrShaderVar("x", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001268 };
1269 SkString permFuncName;
1270 SkString permCode("return ");
1271 // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not
1272 // sure why. Using fract() (here and the next texture lookup) as a workaround.
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001273 fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], "float2(fract(x / 256.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001274 kHalf2_GrSLType);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001275 permCode.append(".r * 255.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001276 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001277 permCode.c_str(), &permFuncName);
1278
1279 // grad function
1280 static const GrShaderVar gradArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001281 GrShaderVar("x", kHalf_GrSLType),
1282 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001283 };
1284 SkString gradFuncName;
1285 SkString gradCode("return dot(");
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001286 fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], "float2(fract(x / 16.0), 0.0)",
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001287 kHalf2_GrSLType);
Ethan Nicholas8aa45692017-09-20 11:24:15 -04001288 gradCode.append(".rgb * 255.0 - float3(1.0), p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001289 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001290 gradCode.c_str(), &gradFuncName);
1291
1292 // lerp function
1293 static const GrShaderVar lerpArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001294 GrShaderVar("a", kHalf_GrSLType),
1295 GrShaderVar("b", kHalf_GrSLType),
1296 GrShaderVar("w", kHalf_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001297 };
1298 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001299 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001300 "return a + w * (b - a);", &lerpFuncName);
1301
1302 // noise function
1303 static const GrShaderVar noiseArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001304 GrShaderVar("p", kHalf3_GrSLType),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001305 };
1306 SkString noiseFuncName;
1307 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001308 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001309 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001310 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1311 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1312 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1313 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1314 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1315 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1316 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1317 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001318 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1319 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001320 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 -04001321 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001322 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001323 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001324 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001325 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001326 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001327 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1328 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001329 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001330 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001331 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001332 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001333 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 -04001334 gradFuncName.c_str(), permFuncName.c_str());
1335 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001336 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001337 noiseCode.c_str(), &noiseFuncName);
1338
1339 // noiseOctaves function
1340 static const GrShaderVar noiseOctavesArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001341 GrShaderVar("p", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001342 };
1343 SkString noiseOctavesFuncName;
1344 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001345 noiseOctavesCode.append("half result = 0.0;");
1346 noiseOctavesCode.append("half ratio = 1.0;");
1347 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001348 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1349 noiseOctavesCode.append("p *= 2.0;");
1350 noiseOctavesCode.append("ratio *= 2.0;");
1351 noiseOctavesCode.append("}");
1352 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001353 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001354 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1355
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001356 fragBuilder->codeAppendf("half2 coords = %s * %s;", vCoords.c_str(), baseFrequencyUni);
1357 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001358 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001359 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001360 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001361 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001362 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001363 fragBuilder->codeAppendf("half a = %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("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001366
1367 // Clamp values
1368 fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor);
1369
1370 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001371 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001372 args.fOutputColor, args.fOutputColor,
1373 args.fOutputColor, args.fOutputColor);
1374}
1375
1376void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1377 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001378 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1379 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001380}
1381
1382void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1383 const GrFragmentProcessor& processor) {
1384 INHERITED::onSetData(pdman, processor);
1385
1386 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1387
1388 const SkVector& baseFrequency = noise.baseFrequency();
1389 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1390
Mike Reedf2ae2b22017-05-30 15:22:54 -04001391 pdman.set1f(fZUni, noise.z());
1392}
1393
1394/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001395std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001396 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001397 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001398
Florin Malitac6c5ead2018-04-11 15:33:40 -04001399 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
1400 const auto matrix = SkMatrix::Concat(*args.fViewMatrix, *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001401
Mike Reedf2ae2b22017-05-30 15:22:54 -04001402 // Either we don't stitch tiles, either we have a valid tile size
1403 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1404
Florin Malitab365cf52017-05-30 17:18:01 -04001405 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
1406 skstd::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
1407 fSeed,
1408 fBaseFrequencyX,
1409 fBaseFrequencyY,
1410 matrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001411
1412 SkMatrix m = *args.fViewMatrix;
Florin Malitac6c5ead2018-04-11 15:33:40 -04001413 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1414 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001415
Greg Daniel7e1912a2018-02-08 09:15:33 -05001416 auto proxyProvider = args.fContext->contextPriv().proxyProvider();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001417 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001418 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1419 // We also know that we will not be using mipmaps. If things things weren't true we should
1420 // go through GrBitmapTextureMaker to handle needed copies.
1421 const sk_sp<SkImage> permutationsImage = paintingData->getImprovedPermutationsImage();
1422 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001423 sk_sp<GrTextureProxy> permutationsTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001424 GrMakeCachedImageProxy(proxyProvider, std::move(permutationsImage)));
1425
1426 const sk_sp<SkImage> gradientImage = paintingData->getGradientImage();
1427 SkASSERT(SkIsPow2(gradientImage->width()) && SkIsPow2(gradientImage->height()));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001428 sk_sp<GrTextureProxy> gradientTexture(
Greg Daniel7e1912a2018-02-08 09:15:33 -05001429 GrMakeCachedImageProxy(proxyProvider, std::move(gradientImage)));
Robert Phillipsfbcef6e2017-06-15 12:07:18 -04001430 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001431 std::move(permutationsTexture),
1432 std::move(gradientTexture), m);
1433 }
1434
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001435 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001436 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001437 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001438 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1439 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1440 // the destination.
Brian Salomonaff329b2017-08-11 09:40:37 -04001441 auto inner =
1442 GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001443 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001444 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001445 }
bsalomonc21b09e2015-08-28 18:46:56 -07001446 // Emit zero.
Brian Osman618d3042016-10-25 10:51:28 -04001447 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001448 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001449 }
1450
Greg Daniel7e1912a2018-02-08 09:15:33 -05001451 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1452 // also know that we will not be using mipmaps. If things things weren't true we should go
1453 // through GrBitmapTextureMaker to handle needed copies.
1454 const sk_sp<SkImage> permutationsImage = paintingData->getPermutationsImage();
1455 SkASSERT(SkIsPow2(permutationsImage->width()) && SkIsPow2(permutationsImage->height()));
1456 sk_sp<GrTextureProxy> permutationsProxy = GrMakeCachedImageProxy(proxyProvider,
1457 std::move(permutationsImage));
1458
1459 const sk_sp<SkImage> noiseImage = paintingData->getNoiseImage();
1460 SkASSERT(SkIsPow2(noiseImage->width()) && SkIsPow2(noiseImage->height()));
1461 sk_sp<GrTextureProxy> noiseProxy = GrMakeCachedImageProxy(proxyProvider,
1462 std::move(noiseImage));
sugoi@google.come3b4c502013-04-05 13:47:09 +00001463
Robert Phillips6f9f7eb2017-02-18 15:15:51 -05001464 if (permutationsProxy && noiseProxy) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001465 auto inner = GrPerlinNoise2Effect::Make(fType,
1466 fNumOctaves,
1467 fStitchTiles,
1468 std::move(paintingData),
1469 std::move(permutationsProxy),
1470 std::move(noiseProxy),
1471 m);
Mike Reed28eaed22018-02-01 11:24:53 -05001472 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001473 }
bsalomonc21b09e2015-08-28 18:46:56 -07001474 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001475}
1476
1477#endif
1478
Mike Reedf2ae2b22017-05-30 15:22:54 -04001479///////////////////////////////////////////////////////////////////////////////////////////////////
1480
Mike Reed832aa112018-05-18 11:48:50 -04001481static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1482 SkScalar seed) {
1483 if (!(baseX >= 0 && baseY >= 0)) {
1484 return false;
1485 }
1486 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1487 return false;
1488 }
1489 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1490 return false;
1491 }
1492 if (!SkScalarIsFinite(seed)) {
1493 return false;
1494 }
1495 return true;
1496}
1497
Mike Reedf2ae2b22017-05-30 15:22:54 -04001498sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1499 SkScalar baseFrequencyY,
1500 int numOctaves, SkScalar seed,
1501 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001502 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1503 return nullptr;
1504 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001505 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1506 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1507 tileSize));
1508}
1509
1510sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1511 SkScalar baseFrequencyY,
1512 int numOctaves, SkScalar seed,
1513 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001514 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1515 return nullptr;
1516 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001517 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1518 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1519 tileSize));
1520}
1521
1522sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1523 SkScalar baseFrequencyY,
1524 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001525 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1526 return nullptr;
1527 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001528 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1529 baseFrequencyX, baseFrequencyY, numOctaves, z,
1530 nullptr));
1531}
1532
Florin Malita14d54c22017-05-18 11:52:59 -04001533SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPerlinNoiseShader)
1534 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPerlinNoiseShaderImpl)
1535SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END