blob: 5dd53de8cedfcc82ba1a78a93586a8dc03926551 [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 Osman6b5dbb42020-07-15 15:31:05 -0400883 // NOTE: We need to explicitly pass half4(1) as input color here, because the helper function
884 // can't see fInputColor (which is "_input" in the FP's outer function). skbug.com/10506
885 SkString sampleX = this->invokeChild(0, "half4(1)", args, "half2(floorVal.x, 0.5)");
886 SkString sampleY = this->invokeChild(0, "half4(1)", args, "half2(floorVal.z, 0.5)");
Brian Salomon83c2d352020-06-17 11:46:21 -0400887 noiseCode.appendf("half2 latticeIdx = half2(%s.r, %s.r);", sampleX.c_str(), sampleY.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000888
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000889#if defined(SK_BUILD_FOR_ANDROID)
890 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
891 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
892 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
893 // (or 0.484368 here). The following rounding operation prevents these precision issues from
894 // affecting the result of the noise by making sure that we only have multiples of 1/255.
895 // (Note that 1/255 is about 0.003921569, which is the value used here).
Brian Salomone338c292020-06-16 16:52:17 -0400896 noiseCode.append(
897 "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);");
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000898#endif
899
sugoi@google.come3b4c502013-04-05 13:47:09 +0000900 // Get (x,y) coordinates with the permutated x
Brian Salomon83c2d352020-06-17 11:46:21 -0400901 noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000902
Brian Salomone338c292020-06-16 16:52:17 -0400903 noiseCode.append("half2 uv;");
904
905 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
906 // [-1,1] vector and perform a dot product between that vector and the provided vector.
907 // Save it as a string because we will repeat it 4x.
908 static constexpr const char* inc8bit = "0.00390625"; // 1.0 / 256.0
909 SkString dotLattice =
910 SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
911
Brian Osman6b5dbb42020-07-15 15:31:05 -0400912 SkString sampleA = this->invokeChild(1, "half4(1)", args, "half2(bcoords.x, chanCoord)");
913 SkString sampleB = this->invokeChild(1, "half4(1)", args, "half2(bcoords.y, chanCoord)");
914 SkString sampleC = this->invokeChild(1, "half4(1)", args, "half2(bcoords.w, chanCoord)");
915 SkString sampleD = this->invokeChild(1, "half4(1)", args, "half2(bcoords.z, chanCoord)");
Brian Salomon83c2d352020-06-17 11:46:21 -0400916
sugoi@google.come3b4c502013-04-05 13:47:09 +0000917 // Compute u, at offset (0,0)
Brian Salomon83c2d352020-06-17 11:46:21 -0400918 noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
919 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000920
sugoi@google.come3b4c502013-04-05 13:47:09 +0000921 // Compute v, at offset (-1,0)
Brian Salomone338c292020-06-16 16:52:17 -0400922 noiseCode.append("fractVal.x -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400923 noiseCode.appendf("lattice = %s;", sampleB.c_str());
924 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000925
926 // Compute 'a' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400927 noiseCode.append("half2 ab;");
928 noiseCode.append("ab.x = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000929
sugoi@google.come3b4c502013-04-05 13:47:09 +0000930 // Compute v, at offset (-1,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400931 noiseCode.append("fractVal.y -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400932 noiseCode.appendf("lattice = %s;", sampleC.c_str());
933 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000934
sugoi@google.come3b4c502013-04-05 13:47:09 +0000935 // Compute u, at offset (0,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400936 noiseCode.append("fractVal.x += 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400937 noiseCode.appendf("lattice = %s;", sampleD.c_str());
938 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000939
940 // Compute 'b' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400941 noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000942 // Compute the noise as a linear interpolation of 'a' and 'b'
Brian Salomone338c292020-06-16 16:52:17 -0400943 noiseCode.append("return mix(ab.x, ab.y, noiseSmooth.y);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000944
sugoi@google.comd537af52013-06-10 13:59:25 +0000945 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800946 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400947 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800948 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
949 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000950 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400951 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800952 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
953 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000954 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000955
sugoi@google.comd537af52013-06-10 13:59:25 +0000956 // There are rounding errors if the floor operation is not performed here
Brian Salomone338c292020-06-16 16:52:17 -0400957 fragBuilder->codeAppendf("half2 noiseVec = half2(floor(%s.xy) * %s);",
Michael Ludwige88320b2020-06-24 09:04:56 -0400958 args.fSampleCoord, baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000959
960 // Clear the color accumulator
Brian Salomone338c292020-06-16 16:52:17 -0400961 fragBuilder->codeAppendf("%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000962
robertphillipsbf536af2016-02-04 06:11:53 -0800963 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +0000964 // Set up TurbulenceInitial stitch values.
Brian Salomone338c292020-06-16 16:52:17 -0400965 fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000966 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000967
Brian Salomone338c292020-06-16 16:52:17 -0400968 fragBuilder->codeAppendf("half ratio = 1.0;");
sugoi@google.comd537af52013-06-10 13:59:25 +0000969
970 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -0800971 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
Brian Salomone338c292020-06-16 16:52:17 -0400972 fragBuilder->codeAppendf(" %s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -0400973 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -0800974 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +0000975 }
Brian Salomone338c292020-06-16 16:52:17 -0400976
Brian Salomon83c2d352020-06-17 11:46:21 -0400977 // There are 4 lines, put y coords at center of each.
978 static constexpr const char* chanCoordR = "0.5";
979 static constexpr const char* chanCoordG = "1.5";
980 static constexpr const char* chanCoordB = "2.5";
981 static constexpr const char* chanCoordA = "3.5";
robertphillipsbf536af2016-02-04 06:11:53 -0800982 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400983 fragBuilder->codeAppendf(R"(
984 half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),"
985 %s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)))",
986 noiseFuncName.c_str(), chanCoordR,
987 noiseFuncName.c_str(), chanCoordG,
988 noiseFuncName.c_str(), chanCoordB,
989 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000990 } else {
Brian Salomone338c292020-06-16 16:52:17 -0400991 fragBuilder->codeAppendf(R"(
992 half4(%s(%s, noiseVec), %s(%s, noiseVec),
993 %s(%s, noiseVec), %s(%s, noiseVec)))",
994 noiseFuncName.c_str(), chanCoordR,
995 noiseFuncName.c_str(), chanCoordG,
996 noiseFuncName.c_str(), chanCoordB,
997 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000998 }
Florin Malita14d54c22017-05-18 11:52:59 -0400999 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
Brian Salomone338c292020-06-16 16:52:17 -04001000 fragBuilder->codeAppend(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001001 }
Brian Salomone338c292020-06-16 16:52:17 -04001002 fragBuilder->codeAppend(" * ratio;");
sugoi@google.comd537af52013-06-10 13:59:25 +00001003
Brian Salomone338c292020-06-16 16:52:17 -04001004 fragBuilder->codeAppend(R"(noiseVec *= half2(2.0);
1005 ratio *= 0.5;)");
sugoi@google.comd537af52013-06-10 13:59:25 +00001006
robertphillipsbf536af2016-02-04 06:11:53 -08001007 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -04001008 fragBuilder->codeAppend("stitchData *= half2(2.0);");
sugoi@google.comd537af52013-06-10 13:59:25 +00001009 }
Brian Salomone338c292020-06-16 16:52:17 -04001010 fragBuilder->codeAppend("}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001011
Florin Malita14d54c22017-05-18 11:52:59 -04001012 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001013 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1014 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Brian Salomone338c292020-06-16 16:52:17 -04001015 fragBuilder->codeAppendf("%s = %s * half4(0.5) + half4(0.5);",
1016 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001017 }
1018
sugoi@google.come3b4c502013-04-05 13:47:09 +00001019 // Clamp values
Brian Salomone338c292020-06-16 16:52:17 -04001020 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001021
1022 // Pre-multiply the result
Brian Salomone338c292020-06-16 16:52:17 -04001023 fragBuilder->codeAppendf("%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001024 args.fOutputColor, args.fOutputColor,
1025 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001026}
1027
Brian Salomon94efbf52016-11-29 13:43:05 -05001028void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001029 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001030 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001031
bsalomon63e99f72014-07-21 08:03:14 -07001032 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001033
1034 key = key << 3; // Make room for next 3 bits
1035
1036 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001037 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001038 key |= 0x1;
1039 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001040 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001041 key |= 0x2;
1042 break;
1043 default:
1044 // leave key at 0
1045 break;
1046 }
1047
1048 if (turbulence.stitchTiles()) {
1049 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1050 }
1051
bsalomon63e99f72014-07-21 08:03:14 -07001052 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001053}
1054
egdaniel018fb622015-10-28 07:26:40 -07001055void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001056 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001057 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001058
Mike Reedf2ae2b22017-05-30 15:22:54 -04001059 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001060
1061 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001062 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001063
sugoi@google.com4775cba2013-04-17 13:46:56 +00001064 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001065 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001066 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
Brian Salomon81454df2020-06-17 10:59:28 -04001067 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001068 }
1069}
1070
sugoi@google.come3b4c502013-04-05 13:47:09 +00001071/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001072
1073class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1074public:
1075 void emitCode(EmitArgs&) override;
1076
1077 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1078
1079protected:
1080 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1081
1082private:
1083 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001084 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1085
1086 typedef GrGLSLFragmentProcessor INHERITED;
1087};
1088
1089/////////////////////////////////////////////////////////////////////
1090
1091class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1092public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001093 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -04001094 int octaves,
1095 SkScalar z,
Brian Salomonaff329b2017-08-11 09:40:37 -04001096 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001097 GrSurfaceProxyView permutationsView,
1098 GrSurfaceProxyView gradientView,
1099 const SkMatrix& matrix,
1100 const GrCaps& caps) {
1101 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
1102 GrSamplerState::WrapMode::kClamp,
1103 GrSamplerState::Filter::kNearest};
1104 auto permutationsFP =
1105 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
1106 SkMatrix::I(), kRepeatXSampler, caps);
1107 auto gradientFP = GrTextureEffect::Make(std::move(gradientView), kPremul_SkAlphaType,
1108 SkMatrix::I(), kRepeatXSampler, caps);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001109 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
1110 new GrImprovedPerlinNoiseEffect(octaves, z, std::move(paintingData),
1111 std::move(permutationsFP),
1112 std::move(gradientFP))));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001113 }
1114
Mike Reedf2ae2b22017-05-30 15:22:54 -04001115 const char* name() const override { return "ImprovedPerlinNoise"; }
1116
Brian Salomonaff329b2017-08-11 09:40:37 -04001117 std::unique_ptr<GrFragmentProcessor> clone() const override {
1118 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001119 }
1120
Mike Reedf2ae2b22017-05-30 15:22:54 -04001121 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1122 SkScalar z() const { return fZ; }
1123 int octaves() const { return fOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001124
1125private:
1126 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1127 return new GrGLImprovedPerlinNoise;
1128 }
1129
1130 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1131 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1132 }
1133
1134 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
John Stiles24a7f072020-08-07 15:59:42 -04001135 const GrImprovedPerlinNoiseEffect& that = sBase.cast<GrImprovedPerlinNoiseEffect>();
1136 return this->z() == that.z() &&
1137 this->octaves() == that.octaves() &&
1138 this->baseFrequency() == that.baseFrequency();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001139 }
1140
Brian Salomon83c2d352020-06-17 11:46:21 -04001141 GrImprovedPerlinNoiseEffect(int octaves,
1142 SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001143 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001144 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -04001145 std::unique_ptr<GrFragmentProcessor> gradientFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001146 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001147 , fOctaves(octaves)
1148 , fZ(z)
Florin Malitab365cf52017-05-30 17:18:01 -04001149 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -04001150 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
1151 this->registerChild(std::move(gradientFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -04001152 this->setUsesSampleCoordsDirectly();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001153 }
1154
Brian Salomon4331e462017-07-26 14:58:11 -04001155 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001156 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001157 , fOctaves(that.fOctaves)
1158 , fZ(that.fZ)
John Stiles24a7f072020-08-07 15:59:42 -04001159 , fPaintingData(std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(
1160 *that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -04001161 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001162 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -04001163 }
1164
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001165 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001166
Mike Reedf2ae2b22017-05-30 15:22:54 -04001167 int fOctaves;
1168 SkScalar fZ;
Brian Salomon83c2d352020-06-17 11:46:21 -04001169
Florin Malitab365cf52017-05-30 17:18:01 -04001170 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001171
1172 typedef GrFragmentProcessor INHERITED;
1173};
1174
1175/////////////////////////////////////////////////////////////////////
1176GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1177
1178#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001179std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1180 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001181 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1182 0.99f);
1183 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1184 0.99f);
1185 int numOctaves = d->fRandom->nextRangeU(2, 10);
1186 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1187
1188 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
John Stiles24a7f072020-08-07 15:59:42 -04001189 baseFrequencyY,
1190 numOctaves,
1191 z));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001192
1193 GrTest::TestAsFPArgs asFPArgs(d);
1194 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1195}
1196#endif
1197
1198void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001199 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Brian Salomonffd15ea2020-07-01 16:48:20 -04001200 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001201 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001202
Ethan Nicholas16464c32020-04-06 13:53:05 -04001203 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001204 "baseFrequency");
1205 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1206
Ethan Nicholas16464c32020-04-06 13:53:05 -04001207 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001208 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1209
1210 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001211 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001212 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001213 };
1214 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001215 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001216 fadeArgs,
1217 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1218 &fadeFuncName);
1219
1220 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001221 const GrShaderVar permArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001222 {"x", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001223 };
Brian Osman6b5dbb42020-07-15 15:31:05 -04001224 SkString samplePerm = this->invokeChild(0, "half4(1)", args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001225 SkString permFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001226 SkString permCode = SkStringPrintf("return %s.r * 255;", samplePerm.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001227 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001228 permCode.c_str(), &permFuncName);
1229
1230 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001231 const GrShaderVar gradArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001232 {"x", kHalf_GrSLType},
1233 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001234 };
Brian Osman6b5dbb42020-07-15 15:31:05 -04001235 SkString sampleGrad = this->invokeChild(1, "half4(1)", args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001236 SkString gradFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001237 SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));",
1238 sampleGrad.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001239 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001240 gradCode.c_str(), &gradFuncName);
1241
1242 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001243 const GrShaderVar lerpArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001244 {"a", kHalf_GrSLType},
1245 {"b", kHalf_GrSLType},
1246 {"w", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001247 };
1248 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001249 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001250 "return a + w * (b - a);", &lerpFuncName);
1251
1252 // noise function
Brian Salomon83c2d352020-06-17 11:46:21 -04001253 const GrShaderVar noiseArgs[] = {
1254 {"p", kHalf3_GrSLType},
Mike Reedf2ae2b22017-05-30 15:22:54 -04001255 };
1256 SkString noiseFuncName;
1257 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001258 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001259 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001260 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1261 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1262 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1263 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1264 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1265 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1266 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1267 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001268 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1269 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001270 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 -04001271 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001272 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001273 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001274 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001275 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001276 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001277 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1278 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001279 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001280 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001281 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001282 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001283 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 -04001284 gradFuncName.c_str(), permFuncName.c_str());
1285 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001286 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001287 noiseCode.c_str(), &noiseFuncName);
1288
1289 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001290 const GrShaderVar noiseOctavesArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001291 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001292 };
1293 SkString noiseOctavesFuncName;
1294 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001295 noiseOctavesCode.append("half result = 0.0;");
1296 noiseOctavesCode.append("half ratio = 1.0;");
1297 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001298 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1299 noiseOctavesCode.append("p *= 2.0;");
1300 noiseOctavesCode.append("ratio *= 2.0;");
1301 noiseOctavesCode.append("}");
1302 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001303 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001304 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1305
Michael Ludwige88320b2020-06-24 09:04:56 -04001306 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", args.fSampleCoord, baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001307 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001308 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001309 fragBuilder->codeAppendf("half g = %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("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001312 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001313 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001314 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001315 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001316
1317 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001318 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001319
1320 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001321 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001322 args.fOutputColor, args.fOutputColor,
1323 args.fOutputColor, args.fOutputColor);
1324}
1325
1326void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1327 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001328 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1329 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001330}
1331
1332void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1333 const GrFragmentProcessor& processor) {
1334 INHERITED::onSetData(pdman, processor);
1335
1336 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1337
1338 const SkVector& baseFrequency = noise.baseFrequency();
1339 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1340
Mike Reedf2ae2b22017-05-30 15:22:54 -04001341 pdman.set1f(fZUni, noise.z());
1342}
1343
1344/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001345std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001346 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001347 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001348
Florin Malita52f02912020-03-09 16:33:17 -04001349 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Brian Osman449b1152020-04-15 16:43:00 -04001350 const auto paintMatrix = SkMatrix::Concat(args.fMatrixProvider.localToDevice(), *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001351
Mike Reedf2ae2b22017-05-30 15:22:54 -04001352 // Either we don't stitch tiles, either we have a valid tile size
1353 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1354
Florin Malitab365cf52017-05-30 17:18:01 -04001355 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001356 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001357 fSeed,
1358 fBaseFrequencyX,
1359 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001360 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001361
Brian Osman449b1152020-04-15 16:43:00 -04001362 SkMatrix m = args.fMatrixProvider.localToDevice();
Florin Malitac6c5ead2018-04-11 15:33:40 -04001363 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1364 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001365
Greg Daniel6f5441a2020-01-28 17:02:49 -05001366 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001367 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001368 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1369 // We also know that we will not be using mipmaps. If things things weren't true we should
1370 // go through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001371 const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
1372 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001373 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001374
Greg Daniel6f5441a2020-01-28 17:02:49 -05001375 const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
1376 SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001377 auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
Brian Salomon83c2d352020-06-17 11:46:21 -04001378 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves,
1379 fSeed,
1380 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001381 std::move(permutationsView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001382 std::move(gradientView),
1383 m,
1384 *context->priv().caps());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001385 }
1386
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001387 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001388 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001389 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001390 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1391 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1392 // the destination.
John Stiles85894302020-07-13 11:39:52 -04001393 auto inner = GrFragmentProcessor::ModulateRGBA(
1394 /*child=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040));
Mike Reed28eaed22018-02-01 11:24:53 -05001395 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001396 }
bsalomonc21b09e2015-08-28 18:46:56 -07001397 // Emit zero.
John Stiles7c196772020-07-13 10:00:16 -04001398 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001399 }
1400
Greg Daniel7e1912a2018-02-08 09:15:33 -05001401 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1402 // also know that we will not be using mipmaps. If things things weren't true we should go
1403 // through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001404 const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
1405 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001406 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001407
Greg Daniel6f5441a2020-01-28 17:02:49 -05001408 const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
1409 SkASSERT(SkIsPow2(noiseBitmap.width()) && SkIsPow2(noiseBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001410 auto noiseView = GrMakeCachedBitmapProxyView(context, noiseBitmap);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001411
Greg Danielc52db712020-01-28 17:03:46 -05001412 if (permutationsView.proxy() && noiseView.proxy()) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001413 auto inner = GrPerlinNoise2Effect::Make(fType,
1414 fNumOctaves,
1415 fStitchTiles,
1416 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001417 std::move(permutationsView),
1418 std::move(noiseView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001419 m,
1420 *context->priv().caps());
Mike Reed28eaed22018-02-01 11:24:53 -05001421 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001422 }
bsalomonc21b09e2015-08-28 18:46:56 -07001423 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001424}
1425
1426#endif
1427
Mike Reedf2ae2b22017-05-30 15:22:54 -04001428///////////////////////////////////////////////////////////////////////////////////////////////////
1429
Mike Reed832aa112018-05-18 11:48:50 -04001430static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1431 SkScalar seed) {
1432 if (!(baseX >= 0 && baseY >= 0)) {
1433 return false;
1434 }
1435 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1436 return false;
1437 }
1438 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1439 return false;
1440 }
1441 if (!SkScalarIsFinite(seed)) {
1442 return false;
1443 }
1444 return true;
1445}
1446
Mike Reedf2ae2b22017-05-30 15:22:54 -04001447sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1448 SkScalar baseFrequencyY,
1449 int numOctaves, SkScalar seed,
1450 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001451 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1452 return nullptr;
1453 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001454 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1455 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1456 tileSize));
1457}
1458
1459sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1460 SkScalar baseFrequencyY,
1461 int numOctaves, SkScalar seed,
1462 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001463 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1464 return nullptr;
1465 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001466 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1467 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1468 tileSize));
1469}
1470
1471sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1472 SkScalar baseFrequencyY,
1473 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001474 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1475 return nullptr;
1476 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001477 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1478 baseFrequencyX, baseFrequencyY, numOctaves, z,
1479 nullptr));
1480}
1481
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001482void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001483 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001484}