blob: c53baf0fb980570155bb2b0af056ea0135c22d10 [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 {
1135 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1136 return fZ == fZ &&
1137 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1138 }
1139
Brian Salomon83c2d352020-06-17 11:46:21 -04001140 GrImprovedPerlinNoiseEffect(int octaves,
1141 SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001142 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001143 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -04001144 std::unique_ptr<GrFragmentProcessor> gradientFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001145 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001146 , fOctaves(octaves)
1147 , fZ(z)
Florin Malitab365cf52017-05-30 17:18:01 -04001148 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -04001149 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
1150 this->registerChild(std::move(gradientFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -04001151 this->setUsesSampleCoordsDirectly();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001152 }
1153
Brian Salomon4331e462017-07-26 14:58:11 -04001154 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001155 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001156 , fOctaves(that.fOctaves)
1157 , fZ(that.fZ)
Brian Salomon4331e462017-07-26 14:58:11 -04001158 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -04001159 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001160 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -04001161 }
1162
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001163 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001164
Mike Reedf2ae2b22017-05-30 15:22:54 -04001165 int fOctaves;
1166 SkScalar fZ;
Brian Salomon83c2d352020-06-17 11:46:21 -04001167
Florin Malitab365cf52017-05-30 17:18:01 -04001168 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001169
1170 typedef GrFragmentProcessor INHERITED;
1171};
1172
1173/////////////////////////////////////////////////////////////////////
1174GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1175
1176#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001177std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1178 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001179 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1180 0.99f);
1181 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1182 0.99f);
1183 int numOctaves = d->fRandom->nextRangeU(2, 10);
1184 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1185
1186 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1187 baseFrequencyY,
1188 numOctaves,
1189 z));
1190
1191 GrTest::TestAsFPArgs asFPArgs(d);
1192 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1193}
1194#endif
1195
1196void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001197 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Brian Salomonffd15ea2020-07-01 16:48:20 -04001198 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001199 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001200
Ethan Nicholas16464c32020-04-06 13:53:05 -04001201 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001202 "baseFrequency");
1203 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1204
Ethan Nicholas16464c32020-04-06 13:53:05 -04001205 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001206 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1207
1208 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001209 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001210 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001211 };
1212 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001213 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001214 fadeArgs,
1215 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1216 &fadeFuncName);
1217
1218 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001219 const GrShaderVar permArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001220 {"x", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001221 };
Brian Osman6b5dbb42020-07-15 15:31:05 -04001222 SkString samplePerm = this->invokeChild(0, "half4(1)", args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001223 SkString permFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001224 SkString permCode = SkStringPrintf("return %s.r * 255;", samplePerm.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001225 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001226 permCode.c_str(), &permFuncName);
1227
1228 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001229 const GrShaderVar gradArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001230 {"x", kHalf_GrSLType},
1231 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001232 };
Brian Osman6b5dbb42020-07-15 15:31:05 -04001233 SkString sampleGrad = this->invokeChild(1, "half4(1)", args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001234 SkString gradFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001235 SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));",
1236 sampleGrad.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001237 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001238 gradCode.c_str(), &gradFuncName);
1239
1240 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001241 const GrShaderVar lerpArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001242 {"a", kHalf_GrSLType},
1243 {"b", kHalf_GrSLType},
1244 {"w", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001245 };
1246 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001247 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001248 "return a + w * (b - a);", &lerpFuncName);
1249
1250 // noise function
Brian Salomon83c2d352020-06-17 11:46:21 -04001251 const GrShaderVar noiseArgs[] = {
1252 {"p", kHalf3_GrSLType},
Mike Reedf2ae2b22017-05-30 15:22:54 -04001253 };
1254 SkString noiseFuncName;
1255 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001256 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001257 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001258 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1259 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1260 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1261 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1262 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1263 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1264 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1265 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001266 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1267 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001268 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 -04001269 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001270 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
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(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
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(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001275 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1276 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001277 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001278 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001279 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001280 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001281 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 -04001282 gradFuncName.c_str(), permFuncName.c_str());
1283 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001284 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001285 noiseCode.c_str(), &noiseFuncName);
1286
1287 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001288 const GrShaderVar noiseOctavesArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001289 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001290 };
1291 SkString noiseOctavesFuncName;
1292 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001293 noiseOctavesCode.append("half result = 0.0;");
1294 noiseOctavesCode.append("half ratio = 1.0;");
1295 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001296 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1297 noiseOctavesCode.append("p *= 2.0;");
1298 noiseOctavesCode.append("ratio *= 2.0;");
1299 noiseOctavesCode.append("}");
1300 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001301 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001302 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1303
Michael Ludwige88320b2020-06-24 09:04:56 -04001304 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", args.fSampleCoord, baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001305 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001306 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001307 fragBuilder->codeAppendf("half g = %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 b = %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 a = %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("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001314
1315 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001316 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001317
1318 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001319 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001320 args.fOutputColor, args.fOutputColor,
1321 args.fOutputColor, args.fOutputColor);
1322}
1323
1324void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1325 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001326 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1327 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001328}
1329
1330void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1331 const GrFragmentProcessor& processor) {
1332 INHERITED::onSetData(pdman, processor);
1333
1334 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1335
1336 const SkVector& baseFrequency = noise.baseFrequency();
1337 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1338
Mike Reedf2ae2b22017-05-30 15:22:54 -04001339 pdman.set1f(fZUni, noise.z());
1340}
1341
1342/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001343std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001344 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001345 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001346
Florin Malita52f02912020-03-09 16:33:17 -04001347 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Brian Osman449b1152020-04-15 16:43:00 -04001348 const auto paintMatrix = SkMatrix::Concat(args.fMatrixProvider.localToDevice(), *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001349
Mike Reedf2ae2b22017-05-30 15:22:54 -04001350 // Either we don't stitch tiles, either we have a valid tile size
1351 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1352
Florin Malitab365cf52017-05-30 17:18:01 -04001353 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001354 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001355 fSeed,
1356 fBaseFrequencyX,
1357 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001358 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001359
Brian Osman449b1152020-04-15 16:43:00 -04001360 SkMatrix m = args.fMatrixProvider.localToDevice();
Florin Malitac6c5ead2018-04-11 15:33:40 -04001361 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1362 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001363
Greg Daniel6f5441a2020-01-28 17:02:49 -05001364 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001365 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001366 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1367 // We also know that we will not be using mipmaps. If things things weren't true we should
1368 // go through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001369 const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
1370 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001371 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001372
Greg Daniel6f5441a2020-01-28 17:02:49 -05001373 const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
1374 SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001375 auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
Brian Salomon83c2d352020-06-17 11:46:21 -04001376 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves,
1377 fSeed,
1378 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001379 std::move(permutationsView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001380 std::move(gradientView),
1381 m,
1382 *context->priv().caps());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001383 }
1384
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001385 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001386 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001387 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001388 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1389 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1390 // the destination.
John Stiles85894302020-07-13 11:39:52 -04001391 auto inner = GrFragmentProcessor::ModulateRGBA(
1392 /*child=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040));
Mike Reed28eaed22018-02-01 11:24:53 -05001393 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001394 }
bsalomonc21b09e2015-08-28 18:46:56 -07001395 // Emit zero.
John Stiles7c196772020-07-13 10:00:16 -04001396 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT);
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}