blob: 6cd2603163fd9f659c509ca2762b4f56cbe1c04a [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/effects/SkPerlinNoiseShader.h"
Herb Derby83e939b2017-02-07 14:25:11 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkColorFilter.h"
11#include "include/core/SkShader.h"
12#include "include/core/SkString.h"
13#include "include/core/SkUnPreMultiply.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040014#include "src/core/SkArenaAlloc.h"
Brian Osman449b1152020-04-15 16:43:00 -040015#include "src/core/SkMatrixProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/core/SkReadBuffer.h"
17#include "src/core/SkWriteBuffer.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000018
19#if SK_SUPPORT_GPU
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040020#include "include/gpu/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/GrRecordingContextPriv.h"
22#include "src/gpu/SkGr.h"
Michael Ludwigf2935c62020-06-26 11:07:23 -040023#include "src/gpu/effects/GrMatrixEffect.h"
Brian Salomon83c2d352020-06-17 11:46:21 -040024#include "src/gpu/effects/GrTextureEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/effects/generated/GrConstColorProcessor.h"
26#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
27#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
28#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
29#include "src/gpu/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)
Brian Osman788b9162020-02-07 10:36:46 -050079 : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040080 , fWrapX(kPerlinNoise + fWidth)
Brian Osman788b9162020-02-07 10:36:46 -050081 , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040082 , 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 {
Ethan Nicholas82940152019-01-10 13:58:14 -0500102 SkVector tileVec;
103 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
104 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -0400105
Ethan Nicholas82940152019-01-10 13:58:14 -0500106 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -0500107 if (!matrix.decomposeScale(&scale, nullptr)) {
108 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
109 }
Ethan Nicholas82940152019-01-10 13:58:14 -0500110 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
111 baseFrequencyY * SkScalarInvert(scale.height()));
112 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -0400113 this->init(seed);
114 if (!fTileSize.isEmpty()) {
115 this->stitch();
116 }
117
118 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500119 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500120 fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
121 fPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400122
Brian Salomona3a9da72020-06-17 10:52:19 -0400123 info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500124 fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
125 fNoiseBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400126
Greg Daniel7e1912a2018-02-08 09:15:33 -0500127 info = SkImageInfo::MakeA8(256, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500128 fImprovedPermutationsBitmap.installPixels(info, improved_noise_permutations,
129 info.minRowBytes());
130 fImprovedPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400131
Florin Malita83223bc2017-05-31 14:14:05 -0400132 static uint8_t gradients[] = { 2, 2, 1, 0,
133 0, 2, 1, 0,
134 2, 0, 1, 0,
135 0, 0, 1, 0,
136 2, 1, 2, 0,
137 0, 1, 2, 0,
138 2, 1, 0, 0,
139 0, 1, 0, 0,
140 1, 2, 2, 0,
141 1, 0, 2, 0,
142 1, 2, 0, 0,
143 1, 0, 0, 0,
144 2, 2, 1, 0,
145 1, 0, 2, 0,
146 0, 2, 1, 0,
147 1, 0, 0, 0 };
Brian Salomona3a9da72020-06-17 10:52:19 -0400148 info = SkImageInfo::Make(16, 1, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500149 fGradientBitmap.installPixels(info, gradients, info.minRowBytes());
150 fGradientBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400151 #endif
152 }
153
Brian Salomon4331e462017-07-26 14:58:11 -0400154 #if SK_SUPPORT_GPU
155 PaintingData(const PaintingData& that)
156 : fSeed(that.fSeed)
157 , fTileSize(that.fTileSize)
158 , fBaseFrequency(that.fBaseFrequency)
159 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel6f5441a2020-01-28 17:02:49 -0500160 , fPermutationsBitmap(that.fPermutationsBitmap)
161 , fNoiseBitmap(that.fNoiseBitmap)
162 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
163 , fGradientBitmap(that.fGradientBitmap) {
Brian Salomon4331e462017-07-26 14:58:11 -0400164 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
165 memcpy(fNoise, that.fNoise, sizeof(fNoise));
166 memcpy(fGradient, that.fGradient, sizeof(fGradient));
167 }
168 #endif
169
Florin Malita83223bc2017-05-31 14:14:05 -0400170 int fSeed;
171 uint8_t fLatticeSelector[kBlockSize];
172 uint16_t fNoise[4][kBlockSize][2];
173 SkPoint fGradient[4][kBlockSize];
174 SkISize fTileSize;
175 SkVector fBaseFrequency;
176 StitchData fStitchDataInit;
177
178 private:
179
180 #if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500181 SkBitmap fPermutationsBitmap;
182 SkBitmap fNoiseBitmap;
183 SkBitmap fImprovedPermutationsBitmap;
184 SkBitmap fGradientBitmap;
Florin Malita83223bc2017-05-31 14:14:05 -0400185 #endif
186
187 inline int random() {
188 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
189 static const int gRandQ = 127773; // m / a
190 static const int gRandR = 2836; // m % a
191
192 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
193 if (result <= 0)
194 result += kRandMaximum;
195 fSeed = result;
196 return result;
197 }
198
199 // Only called once. Could be part of the constructor.
200 void init(SkScalar seed)
201 {
202 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
203
204 // According to the SVG spec, we must truncate (not round) the seed value.
205 fSeed = SkScalarTruncToInt(seed);
206 // The seed value clamp to the range [1, kRandMaximum - 1].
207 if (fSeed <= 0) {
208 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
209 }
210 if (fSeed > kRandMaximum - 1) {
211 fSeed = kRandMaximum - 1;
212 }
213 for (int channel = 0; channel < 4; ++channel) {
214 for (int i = 0; i < kBlockSize; ++i) {
215 fLatticeSelector[i] = i;
216 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
217 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
218 }
219 }
220 for (int i = kBlockSize - 1; i > 0; --i) {
221 int k = fLatticeSelector[i];
222 int j = random() % kBlockSize;
223 SkASSERT(j >= 0);
224 SkASSERT(j < kBlockSize);
225 fLatticeSelector[i] = fLatticeSelector[j];
226 fLatticeSelector[j] = k;
227 }
228
229 // Perform the permutations now
230 {
231 // Copy noise data
232 uint16_t noise[4][kBlockSize][2];
233 for (int i = 0; i < kBlockSize; ++i) {
234 for (int channel = 0; channel < 4; ++channel) {
235 for (int j = 0; j < 2; ++j) {
236 noise[channel][i][j] = fNoise[channel][i][j];
237 }
238 }
239 }
240 // Do permutations on noise data
241 for (int i = 0; i < kBlockSize; ++i) {
242 for (int channel = 0; channel < 4; ++channel) {
243 for (int j = 0; j < 2; ++j) {
244 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
245 }
246 }
247 }
248 }
249
250 // Half of the largest possible value for 16 bit unsigned int
251 static const SkScalar gHalfMax16bits = 32767.5f;
252
253 // Compute gradients from permutated noise data
254 for (int channel = 0; channel < 4; ++channel) {
255 for (int i = 0; i < kBlockSize; ++i) {
256 fGradient[channel][i] = SkPoint::Make(
257 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
258 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
259 fGradient[channel][i].normalize();
260 // Put the normalized gradient back into the noise data
261 fNoise[channel][i][0] = SkScalarRoundToInt(
262 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
263 fNoise[channel][i][1] = SkScalarRoundToInt(
264 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
265 }
266 }
267 }
268
269 // Only called once. Could be part of the constructor.
270 void stitch() {
271 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
272 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
273 SkASSERT(tileWidth > 0 && tileHeight > 0);
274 // When stitching tiled turbulence, the frequencies must be adjusted
275 // so that the tile borders will be continuous.
276 if (fBaseFrequency.fX) {
277 SkScalar lowFrequencx =
278 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
279 SkScalar highFrequencx =
280 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
281 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400282 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
283 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400284 fBaseFrequency.fX = lowFrequencx;
285 } else {
286 fBaseFrequency.fX = highFrequencx;
287 }
288 }
289 if (fBaseFrequency.fY) {
290 SkScalar lowFrequency =
291 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
292 SkScalar highFrequency =
293 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400294 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
295 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400296 fBaseFrequency.fY = lowFrequency;
297 } else {
298 fBaseFrequency.fY = highFrequency;
299 }
300 }
301 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400302 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
303 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400304 }
305
306 public:
307
308#if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500309 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400310
Greg Daniel6f5441a2020-01-28 17:02:49 -0500311 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400312
Greg Daniel6f5441a2020-01-28 17:02:49 -0500313 const SkBitmap& getImprovedPermutationsBitmap() const {
314 return fImprovedPermutationsBitmap;
Greg Daniel7e1912a2018-02-08 09:15:33 -0500315 }
Florin Malita83223bc2017-05-31 14:14:05 -0400316
Greg Daniel6f5441a2020-01-28 17:02:49 -0500317 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400318#endif
319 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400320
321 /**
322 * About the noise types : the difference between the first 2 is just minor tweaks to the
323 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
324 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
325 * doing :
326 * kFractalNoise_Type : noise * 0.5 + 0.5
327 * kTurbulence_Type : abs(noise)
328 * Very little differences between the 2 types, although you can tell the difference visually.
329 * "Improved" is based on the Improved Perlin Noise algorithm described at
330 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
331 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
332 * changes to the noise, making it suitable for animated noise.
333 */
334 enum Type {
335 kFractalNoise_Type,
336 kTurbulence_Type,
337 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500338 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400339 };
340
Robert Phillipsbee27322018-01-23 09:58:18 -0500341 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
342
Mike Reedf2ae2b22017-05-30 15:22:54 -0400343 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
344 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
345 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400346
347 class PerlinNoiseShaderContext : public Context {
348 public:
349 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400350
351 void shadeSpan(int x, int y, SkPMColor[], int count) override;
352
353 private:
354 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
355 SkScalar calculateTurbulenceValueForPoint(
356 int channel,
357 StitchData& stitchData, const SkPoint& point) const;
358 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
359 SkScalar noise2D(int channel,
360 const StitchData& stitchData, const SkPoint& noiseVector) const;
361
Florin Malita83223bc2017-05-31 14:14:05 -0400362 SkMatrix fMatrix;
363 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400364
365 typedef Context INHERITED;
366 };
367
368#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500369 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400370#endif
371
Mike Reedf2ae2b22017-05-30 15:22:54 -0400372protected:
373 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400374#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400375 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400376#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400377
378private:
Mike Klein4fee3232018-10-18 17:27:16 -0400379 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
380
Mike Reedf2ae2b22017-05-30 15:22:54 -0400381 const SkPerlinNoiseShaderImpl::Type fType;
382 const SkScalar fBaseFrequencyX;
383 const SkScalar fBaseFrequencyY;
384 const int fNumOctaves;
385 const SkScalar fSeed;
386 const SkISize fTileSize;
387 const bool fStitchTiles;
388
389 friend class ::SkPerlinNoiseShader;
390
391 typedef SkShaderBase INHERITED;
392};
393
sugoi@google.come3b4c502013-04-05 13:47:09 +0000394namespace {
395
396// noiseValue is the color component's value (or color)
397// limitValue is the maximum perlin noise array index value allowed
398// newValue is the current noise dimension (either width or height)
399inline int checkNoise(int noiseValue, int limitValue, int newValue) {
400 // If the noise value would bring us out of bounds of the current noise array while we are
401 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
402 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
403 if (noiseValue >= limitValue) {
404 noiseValue -= newValue;
405 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000406 return noiseValue;
407}
408
409inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500410 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000411}
412
413} // end namespace
414
Mike Reedf2ae2b22017-05-30 15:22:54 -0400415SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500416 SkScalar baseFrequencyX,
417 SkScalar baseFrequencyY,
418 int numOctaves,
419 SkScalar seed,
420 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000421 : fType(type)
422 , fBaseFrequencyX(baseFrequencyX)
423 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500424 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000425 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700426 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000427 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000428{
Robert Phillipsbee27322018-01-23 09:58:18 -0500429 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400430 SkASSERT(fBaseFrequencyX >= 0);
431 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400432}
433
Florin Malita14d54c22017-05-18 11:52:59 -0400434sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500435 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500436
reed9fa60da2014-08-21 07:59:51 -0700437 SkScalar freqX = buffer.readScalar();
438 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500439 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500440
reed9fa60da2014-08-21 07:59:51 -0700441 SkScalar seed = buffer.readScalar();
442 SkISize tileSize;
443 tileSize.fWidth = buffer.readInt();
444 tileSize.fHeight = buffer.readInt();
445
446 switch (type) {
447 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400448 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700449 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400450 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
451 case kImprovedNoise_Type:
452 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700453 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500454 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500455 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700456 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700457 }
458}
459
Florin Malita14d54c22017-05-18 11:52:59 -0400460void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000461 buffer.writeInt((int) fType);
462 buffer.writeScalar(fBaseFrequencyX);
463 buffer.writeScalar(fBaseFrequencyY);
464 buffer.writeInt(fNumOctaves);
465 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000466 buffer.writeInt(fTileSize.fWidth);
467 buffer.writeInt(fTileSize.fHeight);
468}
469
Florin Malita14d54c22017-05-18 11:52:59 -0400470SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700471 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000472 struct Noise {
473 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700474 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000475 SkScalar noisePositionFractionValue;
476 Noise(SkScalar component)
477 {
478 SkScalar position = component + kPerlinNoise;
479 noisePositionIntegerValue = SkScalarFloorToInt(position);
480 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700481 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000482 }
483 };
484 Noise noiseX(noiseVector.x());
485 Noise noiseY(noiseVector.y());
486 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400487 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000488 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000489 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000490 noiseX.noisePositionIntegerValue =
491 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
492 noiseY.noisePositionIntegerValue =
493 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700494 noiseX.nextNoisePositionIntegerValue =
495 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
496 noiseY.nextNoisePositionIntegerValue =
497 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000498 }
499 noiseX.noisePositionIntegerValue &= kBlockMask;
500 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700501 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
502 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400503 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
504 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700505 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
506 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
507 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
508 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000509 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
510 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400511
Hal Canaryfda46002017-05-08 17:17:47 -0400512 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
513 return 0; // Check for pathological inputs.
514 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400515
sugoi@google.come3b4c502013-04-05 13:47:09 +0000516 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
517 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
518 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400519 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000520 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400521 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000522 SkScalar a = SkScalarInterp(u, v, sx);
523 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400524 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000525 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400526 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000527 SkScalar b = SkScalarInterp(u, v, sx);
528 return SkScalarInterp(a, b, sy);
529}
530
Florin Malita14d54c22017-05-18 11:52:59 -0400531SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700532 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400533 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000534 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000535 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400536 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000537 }
538 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400539 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
540 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000541 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000542 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700543 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700544 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
545 noise : SkScalarAbs(noise);
546 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000547 noiseVector.fX *= 2;
548 noiseVector.fY *= 2;
549 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000550 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000551 // Update stitch values
Florin Malita102c8cf2018-06-05 17:37:12 -0400552 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
553 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000554 }
555 }
556
557 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
558 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000559 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400560 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000561 }
562
563 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700564 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000565 }
566
567 // Clamp result
Brian Osmanaba642c2020-02-06 12:52:25 -0500568 return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000569}
570
Mike Reedf2ae2b22017-05-30 15:22:54 -0400571////////////////////////////////////////////////////////////////////////////////////////////////////
572// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
573static SkScalar fade(SkScalar t) {
574 return t * t * t * (t * (t * 6 - 15) + 10);
575}
576
577static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
578 return a + t * (b - a);
579}
580
581static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
582 int h = hash & 15;
583 SkScalar u = h < 8 ? x : y;
584 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
585 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
586}
587
588SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
589 int channel, const SkPoint& point) const {
590 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
591 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
592 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
593 // z offset between different channels, chosen arbitrarily
594 static const SkScalar CHANNEL_DELTA = 1000.0f;
595 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
596 SkScalar result = 0;
597 SkScalar ratio = SK_Scalar1;
598 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
599 int X = SkScalarFloorToInt(x) & 255;
600 int Y = SkScalarFloorToInt(y) & 255;
601 int Z = SkScalarFloorToInt(z) & 255;
602 SkScalar px = x - SkScalarFloorToScalar(x);
603 SkScalar py = y - SkScalarFloorToScalar(y);
604 SkScalar pz = z - SkScalarFloorToScalar(z);
605 SkScalar u = fade(px);
606 SkScalar v = fade(py);
607 SkScalar w = fade(pz);
608 uint8_t* permutations = improved_noise_permutations;
609 int A = permutations[X] + Y;
610 int AA = permutations[A] + Z;
611 int AB = permutations[A + 1] + Z;
612 int B = permutations[X + 1] + Y;
613 int BA = permutations[B] + Z;
614 int BB = permutations[B + 1] + Z;
615 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
616 grad(permutations[BA ], px - 1, py , pz )),
617 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
618 grad(permutations[BB ], px - 1, py - 1, pz ))),
619 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
620 grad(permutations[BA + 1], px - 1, py , pz - 1)),
621 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
622 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
623 ratio;
624 x *= 2;
625 y *= 2;
626 ratio *= 2;
627 }
Brian Osmanaba642c2020-02-06 12:52:25 -0500628 result = SkTPin((result + 1.0f) / 2.0f, 0.0f, 1.0f);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400629 return result;
630}
631////////////////////////////////////////////////////////////////////////////////////////////////////
632
Florin Malita14d54c22017-05-18 11:52:59 -0400633SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000634 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400635 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000636 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000637 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000638 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
639 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
640
641 U8CPU rgba[4];
642 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400643 SkScalar value;
644 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
645 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
646 }
647 else {
648 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
649 }
650 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000651 }
652 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
653}
654
Mike Reede92aae62018-10-17 10:21:51 -0400655#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400656SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400657 SkArenaAlloc* alloc) const {
Mike Reed011d1662019-02-28 17:19:25 -0500658 // should we pay attention to rec's device-colorspace?
Herb Derby83e939b2017-02-07 14:25:11 -0500659 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000660}
Mike Reede92aae62018-10-17 10:21:51 -0400661#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000662
Florin Malita83223bc2017-05-31 14:14:05 -0400663static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
664 const SkShaderBase& shader) {
665 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
666 if (rec.fLocalMatrix) {
667 matrix.preConcat(*rec.fLocalMatrix);
668 }
669
670 return matrix;
671}
672
Florin Malita14d54c22017-05-18 11:52:59 -0400673SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
674 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000675 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400676 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
677 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
678 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000679{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000680 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
681 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400682 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
683 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700684}
685
Florin Malita14d54c22017-05-18 11:52:59 -0400686void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000687 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000688 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
689 StitchData stitchData;
690 for (int i = 0; i < count; ++i) {
691 result[i] = shade(point, stitchData);
692 point.fX += SK_Scalar1;
693 }
694}
695
sugoi@google.come3b4c502013-04-05 13:47:09 +0000696/////////////////////////////////////////////////////////////////////
697
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000698#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000699
egdaniel64c47282015-11-13 06:54:19 -0800700class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000701public:
robertphillips9cdb9922016-02-03 12:25:40 -0800702 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000703
Mike Reedf2ae2b22017-05-30 15:22:54 -0400704 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000705
wangyixb1daa862015-08-18 11:29:31 -0700706protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400707 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700708
sugoi@google.com4775cba2013-04-17 13:46:56 +0000709private:
egdaniel018fb622015-10-28 07:26:40 -0700710 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700711 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700712
egdaniel64c47282015-11-13 06:54:19 -0800713 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000714};
715
716/////////////////////////////////////////////////////////////////////
717
Mike Reedf2ae2b22017-05-30 15:22:54 -0400718class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000719public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400720 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -0400721 SkPerlinNoiseShaderImpl::Type type,
722 int numOctaves,
723 bool stitchTiles,
Brian Salomonaff329b2017-08-11 09:40:37 -0400724 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400725 GrSurfaceProxyView permutationsView,
726 GrSurfaceProxyView noiseView,
727 const SkMatrix& matrix,
728 const GrCaps& caps) {
729 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
730 GrSamplerState::WrapMode::kClamp,
731 GrSamplerState::Filter::kNearest};
732 auto permutationsFP =
733 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
734 SkMatrix::I(), kRepeatXSampler, caps);
735 auto noiseFP = GrTextureEffect::Make(std::move(noiseView), kPremul_SkAlphaType,
736 SkMatrix::I(), kRepeatXSampler, caps);
737
Michael Ludwigf2935c62020-06-26 11:07:23 -0400738 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
Brian Salomon83c2d352020-06-17 11:46:21 -0400739 new GrPerlinNoise2Effect(type, numOctaves, stitchTiles, std::move(paintingData),
Michael Ludwigf2935c62020-06-26 11:07:23 -0400740 std::move(permutationsFP), std::move(noiseFP))));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000741 }
742
mtklein36352bf2015-03-25 18:17:31 -0700743 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800744
Brian Salomonaff329b2017-08-11 09:40:37 -0400745 std::unique_ptr<GrFragmentProcessor> clone() const override {
746 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400747 }
748
Mike Reedf2ae2b22017-05-30 15:22:54 -0400749 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000750
Florin Malita14d54c22017-05-18 11:52:59 -0400751 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700752 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700753 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700754 int numOctaves() const { return fNumOctaves; }
senorblancof3b50272014-06-16 10:49:58 -0700755
sugoi@google.come3b4c502013-04-05 13:47:09 +0000756private:
egdaniel57d3b032015-11-13 11:57:27 -0800757 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800758 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700759 }
760
Brian Salomon94efbf52016-11-29 13:43:05 -0500761 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800762 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700763 GrGLPerlinNoise::GenKey(*this, caps, b);
764 }
765
mtklein36352bf2015-03-25 18:17:31 -0700766 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400767 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700768 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700769 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700770 fNumOctaves == s.fNumOctaves &&
771 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700772 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000773 }
774
Brian Salomon83c2d352020-06-17 11:46:21 -0400775 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type,
776 int numOctaves,
777 bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400778 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400779 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -0400780 std::unique_ptr<GrFragmentProcessor> noiseFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400781 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500782 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500783 , fNumOctaves(numOctaves)
784 , fStitchTiles(stitchTiles)
Florin Malitab365cf52017-05-30 17:18:01 -0400785 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -0400786 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
787 this->registerChild(std::move(noiseFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -0400788 this->setUsesSampleCoordsDirectly();
sugoi@google.come3b4c502013-04-05 13:47:09 +0000789 }
790
Brian Salomon4331e462017-07-26 14:58:11 -0400791 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400792 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400793 , fType(that.fType)
Brian Salomon4331e462017-07-26 14:58:11 -0400794 , fNumOctaves(that.fNumOctaves)
795 , fStitchTiles(that.fStitchTiles)
Brian Salomon4331e462017-07-26 14:58:11 -0400796 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -0400797 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -0400798 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -0400799 }
800
Brian Salomonf7dcd762018-07-30 14:48:15 -0400801
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400802 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000803
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400804 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400805 int fNumOctaves;
806 bool fStitchTiles;
Brian Salomon83c2d352020-06-17 11:46:21 -0400807
Florin Malitab365cf52017-05-30 17:18:01 -0400808 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000809
joshualittb0a8a372014-09-23 09:50:21 -0700810 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000811};
812
813/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400814GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000815
Hal Canary6f6961e2017-01-31 13:50:44 -0500816#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400817std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700818 int numOctaves = d->fRandom->nextRangeU(2, 10);
819 bool stitchTiles = d->fRandom->nextBool();
820 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
821 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
822 d->fRandom->nextRangeU(4, 4096));
823 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
824 0.99f);
825 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
826 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000827
reedfe630452016-03-25 09:08:00 -0700828 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
829 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400830 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700831 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400832 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000833
Brian Osman9f532a32016-10-19 11:12:09 -0400834 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400835 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000836}
Hal Canary6f6961e2017-01-31 13:50:44 -0500837#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000838
wangyix7c157a92015-07-22 15:08:53 -0700839void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400840 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800841
Brian Salomonffd15ea2020-07-01 16:48:20 -0400842 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800843 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000844
Ethan Nicholas16464c32020-04-06 13:53:05 -0400845 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800846 "baseFrequency");
847 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000848
halcanary96fcdcc2015-08-27 07:41:13 -0700849 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800850 if (pne.stitchTiles()) {
Ethan Nicholas16464c32020-04-06 13:53:05 -0400851 fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800852 "stitchData");
853 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000854 }
855
sugoi@google.comd537af52013-06-10 13:59:25 +0000856 // Add noise function
Brian Salomone338c292020-06-16 16:52:17 -0400857 const GrShaderVar gPerlinNoiseArgs[] = {{"chanCoord", kHalf_GrSLType },
858 {"noiseVec ", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000859
Brian Salomone338c292020-06-16 16:52:17 -0400860 const GrShaderVar gPerlinNoiseStitchArgs[] = {{"chanCoord" , kHalf_GrSLType },
861 {"noiseVec" , kHalf2_GrSLType},
862 {"stitchData", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000863
sugoi@google.comd537af52013-06-10 13:59:25 +0000864 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000865
Brian Salomone338c292020-06-16 16:52:17 -0400866 noiseCode.append(
867 R"(half4 floorVal;
868 floorVal.xy = floor(noiseVec);
869 floorVal.zw = floorVal.xy + half2(1);
870 half2 fractVal = fract(noiseVec);
871 // smooth curve : t^2*(3 - 2*t)
872 half2 noiseSmooth = fractVal*fractVal*(half2(3) - 2*fractVal);)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000873
874 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800875 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400876 noiseCode.append(
877 R"(if (floorVal.x >= stitchData.x) { floorVal.x -= stitchData.x; };
878 if (floorVal.y >= stitchData.y) { floorVal.y -= stitchData.y; };
879 if (floorVal.z >= stitchData.x) { floorVal.z -= stitchData.x; };
880 if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000881 }
882
Brian Salomon83c2d352020-06-17 11:46:21 -0400883 SkString sampleX = this->invokeChild(0, args, "half2(floorVal.x, 0.5)");
884 SkString sampleY = this->invokeChild(0, args, "half2(floorVal.z, 0.5)");
885 noiseCode.appendf("half2 latticeIdx = half2(%s.r, %s.r);", sampleX.c_str(), sampleY.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000886
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000887#if defined(SK_BUILD_FOR_ANDROID)
888 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
889 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
890 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
891 // (or 0.484368 here). The following rounding operation prevents these precision issues from
892 // affecting the result of the noise by making sure that we only have multiples of 1/255.
893 // (Note that 1/255 is about 0.003921569, which is the value used here).
Brian Salomone338c292020-06-16 16:52:17 -0400894 noiseCode.append(
895 "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);");
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000896#endif
897
sugoi@google.come3b4c502013-04-05 13:47:09 +0000898 // Get (x,y) coordinates with the permutated x
Brian Salomon83c2d352020-06-17 11:46:21 -0400899 noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000900
Brian Salomone338c292020-06-16 16:52:17 -0400901 noiseCode.append("half2 uv;");
902
903 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
904 // [-1,1] vector and perform a dot product between that vector and the provided vector.
905 // Save it as a string because we will repeat it 4x.
906 static constexpr const char* inc8bit = "0.00390625"; // 1.0 / 256.0
907 SkString dotLattice =
908 SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
909
Brian Salomon83c2d352020-06-17 11:46:21 -0400910 SkString sampleA = this->invokeChild(1, args, "half2(bcoords.x, chanCoord)");
911 SkString sampleB = this->invokeChild(1, args, "half2(bcoords.y, chanCoord)");
912 SkString sampleC = this->invokeChild(1, args, "half2(bcoords.w, chanCoord)");
913 SkString sampleD = this->invokeChild(1, args, "half2(bcoords.z, chanCoord)");
914
sugoi@google.come3b4c502013-04-05 13:47:09 +0000915 // Compute u, at offset (0,0)
Brian Salomon83c2d352020-06-17 11:46:21 -0400916 noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
917 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000918
sugoi@google.come3b4c502013-04-05 13:47:09 +0000919 // Compute v, at offset (-1,0)
Brian Salomone338c292020-06-16 16:52:17 -0400920 noiseCode.append("fractVal.x -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400921 noiseCode.appendf("lattice = %s;", sampleB.c_str());
922 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000923
924 // Compute 'a' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400925 noiseCode.append("half2 ab;");
926 noiseCode.append("ab.x = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000927
sugoi@google.come3b4c502013-04-05 13:47:09 +0000928 // Compute v, at offset (-1,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400929 noiseCode.append("fractVal.y -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400930 noiseCode.appendf("lattice = %s;", sampleC.c_str());
931 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000932
sugoi@google.come3b4c502013-04-05 13:47:09 +0000933 // Compute u, at offset (0,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400934 noiseCode.append("fractVal.x += 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400935 noiseCode.appendf("lattice = %s;", sampleD.c_str());
936 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000937
938 // Compute 'b' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400939 noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000940 // Compute the noise as a linear interpolation of 'a' and 'b'
Brian Salomone338c292020-06-16 16:52:17 -0400941 noiseCode.append("return mix(ab.x, ab.y, noiseSmooth.y);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000942
sugoi@google.comd537af52013-06-10 13:59:25 +0000943 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800944 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400945 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800946 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
947 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000948 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400949 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800950 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
951 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000952 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000953
sugoi@google.comd537af52013-06-10 13:59:25 +0000954 // There are rounding errors if the floor operation is not performed here
Brian Salomone338c292020-06-16 16:52:17 -0400955 fragBuilder->codeAppendf("half2 noiseVec = half2(floor(%s.xy) * %s);",
Michael Ludwige88320b2020-06-24 09:04:56 -0400956 args.fSampleCoord, baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000957
958 // Clear the color accumulator
Brian Salomone338c292020-06-16 16:52:17 -0400959 fragBuilder->codeAppendf("%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000960
robertphillipsbf536af2016-02-04 06:11:53 -0800961 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +0000962 // Set up TurbulenceInitial stitch values.
Brian Salomone338c292020-06-16 16:52:17 -0400963 fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000964 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000965
Brian Salomone338c292020-06-16 16:52:17 -0400966 fragBuilder->codeAppendf("half ratio = 1.0;");
sugoi@google.comd537af52013-06-10 13:59:25 +0000967
968 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -0800969 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
Brian Salomone338c292020-06-16 16:52:17 -0400970 fragBuilder->codeAppendf(" %s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -0400971 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -0800972 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +0000973 }
Brian Salomone338c292020-06-16 16:52:17 -0400974
Brian Salomon83c2d352020-06-17 11:46:21 -0400975 // There are 4 lines, put y coords at center of each.
976 static constexpr const char* chanCoordR = "0.5";
977 static constexpr const char* chanCoordG = "1.5";
978 static constexpr const char* chanCoordB = "2.5";
979 static constexpr const char* chanCoordA = "3.5";
robertphillipsbf536af2016-02-04 06:11:53 -0800980 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400981 fragBuilder->codeAppendf(R"(
982 half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),"
983 %s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)))",
984 noiseFuncName.c_str(), chanCoordR,
985 noiseFuncName.c_str(), chanCoordG,
986 noiseFuncName.c_str(), chanCoordB,
987 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000988 } else {
Brian Salomone338c292020-06-16 16:52:17 -0400989 fragBuilder->codeAppendf(R"(
990 half4(%s(%s, noiseVec), %s(%s, noiseVec),
991 %s(%s, noiseVec), %s(%s, noiseVec)))",
992 noiseFuncName.c_str(), chanCoordR,
993 noiseFuncName.c_str(), chanCoordG,
994 noiseFuncName.c_str(), chanCoordB,
995 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000996 }
Florin Malita14d54c22017-05-18 11:52:59 -0400997 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
Brian Salomone338c292020-06-16 16:52:17 -0400998 fragBuilder->codeAppend(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +0000999 }
Brian Salomone338c292020-06-16 16:52:17 -04001000 fragBuilder->codeAppend(" * ratio;");
sugoi@google.comd537af52013-06-10 13:59:25 +00001001
Brian Salomone338c292020-06-16 16:52:17 -04001002 fragBuilder->codeAppend(R"(noiseVec *= half2(2.0);
1003 ratio *= 0.5;)");
sugoi@google.comd537af52013-06-10 13:59:25 +00001004
robertphillipsbf536af2016-02-04 06:11:53 -08001005 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -04001006 fragBuilder->codeAppend("stitchData *= half2(2.0);");
sugoi@google.comd537af52013-06-10 13:59:25 +00001007 }
Brian Salomone338c292020-06-16 16:52:17 -04001008 fragBuilder->codeAppend("}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001009
Florin Malita14d54c22017-05-18 11:52:59 -04001010 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001011 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1012 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Brian Salomone338c292020-06-16 16:52:17 -04001013 fragBuilder->codeAppendf("%s = %s * half4(0.5) + half4(0.5);",
1014 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001015 }
1016
sugoi@google.come3b4c502013-04-05 13:47:09 +00001017 // Clamp values
Brian Salomone338c292020-06-16 16:52:17 -04001018 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001019
1020 // Pre-multiply the result
Brian Salomone338c292020-06-16 16:52:17 -04001021 fragBuilder->codeAppendf("%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001022 args.fOutputColor, args.fOutputColor,
1023 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001024}
1025
Brian Salomon94efbf52016-11-29 13:43:05 -05001026void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001027 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001028 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001029
bsalomon63e99f72014-07-21 08:03:14 -07001030 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001031
1032 key = key << 3; // Make room for next 3 bits
1033
1034 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001035 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001036 key |= 0x1;
1037 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001038 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001039 key |= 0x2;
1040 break;
1041 default:
1042 // leave key at 0
1043 break;
1044 }
1045
1046 if (turbulence.stitchTiles()) {
1047 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1048 }
1049
bsalomon63e99f72014-07-21 08:03:14 -07001050 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001051}
1052
egdaniel018fb622015-10-28 07:26:40 -07001053void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001054 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001055 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001056
Mike Reedf2ae2b22017-05-30 15:22:54 -04001057 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001058
1059 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001060 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001061
sugoi@google.com4775cba2013-04-17 13:46:56 +00001062 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001063 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001064 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
Brian Salomon81454df2020-06-17 10:59:28 -04001065 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001066 }
1067}
1068
sugoi@google.come3b4c502013-04-05 13:47:09 +00001069/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001070
1071class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1072public:
1073 void emitCode(EmitArgs&) override;
1074
1075 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1076
1077protected:
1078 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1079
1080private:
1081 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001082 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1083
1084 typedef GrGLSLFragmentProcessor INHERITED;
1085};
1086
1087/////////////////////////////////////////////////////////////////////
1088
1089class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1090public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001091 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -04001092 int octaves,
1093 SkScalar z,
Brian Salomonaff329b2017-08-11 09:40:37 -04001094 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001095 GrSurfaceProxyView permutationsView,
1096 GrSurfaceProxyView gradientView,
1097 const SkMatrix& matrix,
1098 const GrCaps& caps) {
1099 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
1100 GrSamplerState::WrapMode::kClamp,
1101 GrSamplerState::Filter::kNearest};
1102 auto permutationsFP =
1103 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
1104 SkMatrix::I(), kRepeatXSampler, caps);
1105 auto gradientFP = GrTextureEffect::Make(std::move(gradientView), kPremul_SkAlphaType,
1106 SkMatrix::I(), kRepeatXSampler, caps);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001107 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
1108 new GrImprovedPerlinNoiseEffect(octaves, z, std::move(paintingData),
1109 std::move(permutationsFP),
1110 std::move(gradientFP))));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001111 }
1112
Mike Reedf2ae2b22017-05-30 15:22:54 -04001113 const char* name() const override { return "ImprovedPerlinNoise"; }
1114
Brian Salomonaff329b2017-08-11 09:40:37 -04001115 std::unique_ptr<GrFragmentProcessor> clone() const override {
1116 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001117 }
1118
Mike Reedf2ae2b22017-05-30 15:22:54 -04001119 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1120 SkScalar z() const { return fZ; }
1121 int octaves() const { return fOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001122
1123private:
1124 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1125 return new GrGLImprovedPerlinNoise;
1126 }
1127
1128 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1129 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1130 }
1131
1132 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1133 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1134 return fZ == fZ &&
1135 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1136 }
1137
Brian Salomon83c2d352020-06-17 11:46:21 -04001138 GrImprovedPerlinNoiseEffect(int octaves,
1139 SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001140 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001141 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -04001142 std::unique_ptr<GrFragmentProcessor> gradientFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001143 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001144 , fOctaves(octaves)
1145 , fZ(z)
Florin Malitab365cf52017-05-30 17:18:01 -04001146 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -04001147 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
1148 this->registerChild(std::move(gradientFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -04001149 this->setUsesSampleCoordsDirectly();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001150 }
1151
Brian Salomon4331e462017-07-26 14:58:11 -04001152 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001153 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001154 , fOctaves(that.fOctaves)
1155 , fZ(that.fZ)
Brian Salomon4331e462017-07-26 14:58:11 -04001156 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -04001157 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001158 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -04001159 }
1160
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001161 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001162
Mike Reedf2ae2b22017-05-30 15:22:54 -04001163 int fOctaves;
1164 SkScalar fZ;
Brian Salomon83c2d352020-06-17 11:46:21 -04001165
Florin Malitab365cf52017-05-30 17:18:01 -04001166 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001167
1168 typedef GrFragmentProcessor INHERITED;
1169};
1170
1171/////////////////////////////////////////////////////////////////////
1172GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1173
1174#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001175std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1176 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001177 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1178 0.99f);
1179 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1180 0.99f);
1181 int numOctaves = d->fRandom->nextRangeU(2, 10);
1182 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1183
1184 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1185 baseFrequencyY,
1186 numOctaves,
1187 z));
1188
1189 GrTest::TestAsFPArgs asFPArgs(d);
1190 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1191}
1192#endif
1193
1194void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001195 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Brian Salomonffd15ea2020-07-01 16:48:20 -04001196 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001197 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001198
Ethan Nicholas16464c32020-04-06 13:53:05 -04001199 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001200 "baseFrequency");
1201 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1202
Ethan Nicholas16464c32020-04-06 13:53:05 -04001203 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001204 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1205
1206 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001207 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001208 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001209 };
1210 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001211 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001212 fadeArgs,
1213 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1214 &fadeFuncName);
1215
1216 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001217 const GrShaderVar permArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001218 {"x", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001219 };
Brian Salomon83c2d352020-06-17 11:46:21 -04001220 SkString samplePerm = this->invokeChild(0, args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001221 SkString permFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001222 SkString permCode = SkStringPrintf("return %s.r * 255;", samplePerm.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001223 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001224 permCode.c_str(), &permFuncName);
1225
1226 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001227 const GrShaderVar gradArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001228 {"x", kHalf_GrSLType},
1229 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001230 };
Brian Salomon83c2d352020-06-17 11:46:21 -04001231 SkString sampleGrad = this->invokeChild(1, args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001232 SkString gradFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001233 SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));",
1234 sampleGrad.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001235 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001236 gradCode.c_str(), &gradFuncName);
1237
1238 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001239 const GrShaderVar lerpArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001240 {"a", kHalf_GrSLType},
1241 {"b", kHalf_GrSLType},
1242 {"w", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001243 };
1244 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001245 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001246 "return a + w * (b - a);", &lerpFuncName);
1247
1248 // noise function
Brian Salomon83c2d352020-06-17 11:46:21 -04001249 const GrShaderVar noiseArgs[] = {
1250 {"p", kHalf3_GrSLType},
Mike Reedf2ae2b22017-05-30 15:22:54 -04001251 };
1252 SkString noiseFuncName;
1253 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001254 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001255 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001256 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1257 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1258 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1259 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1260 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1261 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1262 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1263 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001264 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1265 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001266 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 -04001267 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001268 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001269 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001270 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001271 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001272 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001273 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1274 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001275 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001276 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001277 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001278 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001279 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 -04001280 gradFuncName.c_str(), permFuncName.c_str());
1281 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001282 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001283 noiseCode.c_str(), &noiseFuncName);
1284
1285 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001286 const GrShaderVar noiseOctavesArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001287 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001288 };
1289 SkString noiseOctavesFuncName;
1290 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001291 noiseOctavesCode.append("half result = 0.0;");
1292 noiseOctavesCode.append("half ratio = 1.0;");
1293 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001294 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1295 noiseOctavesCode.append("p *= 2.0;");
1296 noiseOctavesCode.append("ratio *= 2.0;");
1297 noiseOctavesCode.append("}");
1298 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001299 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001300 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1301
Michael Ludwige88320b2020-06-24 09:04:56 -04001302 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", args.fSampleCoord, baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001303 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001304 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001305 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001306 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001307 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001308 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001309 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001310 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001311 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001312
1313 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001314 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001315
1316 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001317 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001318 args.fOutputColor, args.fOutputColor,
1319 args.fOutputColor, args.fOutputColor);
1320}
1321
1322void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1323 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001324 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1325 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001326}
1327
1328void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1329 const GrFragmentProcessor& processor) {
1330 INHERITED::onSetData(pdman, processor);
1331
1332 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1333
1334 const SkVector& baseFrequency = noise.baseFrequency();
1335 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1336
Mike Reedf2ae2b22017-05-30 15:22:54 -04001337 pdman.set1f(fZUni, noise.z());
1338}
1339
1340/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001341std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001342 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001343 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001344
Florin Malita52f02912020-03-09 16:33:17 -04001345 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Brian Osman449b1152020-04-15 16:43:00 -04001346 const auto paintMatrix = SkMatrix::Concat(args.fMatrixProvider.localToDevice(), *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001347
Mike Reedf2ae2b22017-05-30 15:22:54 -04001348 // Either we don't stitch tiles, either we have a valid tile size
1349 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1350
Florin Malitab365cf52017-05-30 17:18:01 -04001351 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001352 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001353 fSeed,
1354 fBaseFrequencyX,
1355 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001356 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001357
Brian Osman449b1152020-04-15 16:43:00 -04001358 SkMatrix m = args.fMatrixProvider.localToDevice();
Florin Malitac6c5ead2018-04-11 15:33:40 -04001359 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1360 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001361
Greg Daniel6f5441a2020-01-28 17:02:49 -05001362 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001363 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001364 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1365 // We also know that we will not be using mipmaps. If things things weren't true we should
1366 // go through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001367 const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
1368 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001369 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001370
Greg Daniel6f5441a2020-01-28 17:02:49 -05001371 const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
1372 SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001373 auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
Brian Salomon83c2d352020-06-17 11:46:21 -04001374 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves,
1375 fSeed,
1376 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001377 std::move(permutationsView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001378 std::move(gradientView),
1379 m,
1380 *context->priv().caps());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001381 }
1382
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001383 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001384 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001385 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001386 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1387 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1388 // the destination.
John Stilese3a39f72020-06-15 13:58:48 -04001389 auto inner = GrConstColorProcessor::Make(
1390 /*inputFP=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040),
1391 GrConstColorProcessor::InputMode::kModulateRGBA);
Mike Reed28eaed22018-02-01 11:24:53 -05001392 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001393 }
bsalomonc21b09e2015-08-28 18:46:56 -07001394 // Emit zero.
John Stilese3a39f72020-06-15 13:58:48 -04001395 return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT,
Ethan Nicholase9d172a2017-11-20 12:12:24 -05001396 GrConstColorProcessor::InputMode::kIgnore);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001397 }
1398
Greg Daniel7e1912a2018-02-08 09:15:33 -05001399 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1400 // also know that we will not be using mipmaps. If things things weren't true we should go
1401 // through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001402 const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
1403 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001404 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001405
Greg Daniel6f5441a2020-01-28 17:02:49 -05001406 const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
1407 SkASSERT(SkIsPow2(noiseBitmap.width()) && SkIsPow2(noiseBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001408 auto noiseView = GrMakeCachedBitmapProxyView(context, noiseBitmap);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001409
Greg Danielc52db712020-01-28 17:03:46 -05001410 if (permutationsView.proxy() && noiseView.proxy()) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001411 auto inner = GrPerlinNoise2Effect::Make(fType,
1412 fNumOctaves,
1413 fStitchTiles,
1414 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001415 std::move(permutationsView),
1416 std::move(noiseView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001417 m,
1418 *context->priv().caps());
Mike Reed28eaed22018-02-01 11:24:53 -05001419 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001420 }
bsalomonc21b09e2015-08-28 18:46:56 -07001421 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001422}
1423
1424#endif
1425
Mike Reedf2ae2b22017-05-30 15:22:54 -04001426///////////////////////////////////////////////////////////////////////////////////////////////////
1427
Mike Reed832aa112018-05-18 11:48:50 -04001428static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1429 SkScalar seed) {
1430 if (!(baseX >= 0 && baseY >= 0)) {
1431 return false;
1432 }
1433 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1434 return false;
1435 }
1436 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1437 return false;
1438 }
1439 if (!SkScalarIsFinite(seed)) {
1440 return false;
1441 }
1442 return true;
1443}
1444
Mike Reedf2ae2b22017-05-30 15:22:54 -04001445sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1446 SkScalar baseFrequencyY,
1447 int numOctaves, SkScalar seed,
1448 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001449 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1450 return nullptr;
1451 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001452 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1453 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1454 tileSize));
1455}
1456
1457sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1458 SkScalar baseFrequencyY,
1459 int numOctaves, SkScalar seed,
1460 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001461 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1462 return nullptr;
1463 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001464 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1465 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1466 tileSize));
1467}
1468
1469sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1470 SkScalar baseFrequencyY,
1471 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001472 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1473 return nullptr;
1474 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001475 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1476 baseFrequencyX, baseFrequencyY, numOctaves, z,
1477 nullptr));
1478}
1479
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001480void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001481 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001482}