blob: f3632ab5a8f2754a55447566acc06361e26328d3 [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"
John Stiles7c196772020-07-13 10:00:16 -040026#include "src/gpu/effects/generated/GrModulateRGBAEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
28#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
29#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
30#include "src/gpu/glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000031#endif
32
33static const int kBlockSize = 256;
34static const int kBlockMask = kBlockSize - 1;
35static const int kPerlinNoise = 4096;
36static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
37
Mike Reedf2ae2b22017-05-30 15:22:54 -040038static uint8_t improved_noise_permutations[] = {
39 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
40 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
41 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
42 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
43 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
44 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
45 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
46 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
47 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
48 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
49 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
50 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
51 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
52 141, 128, 195, 78, 66, 215, 61, 156, 180,
53 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
54 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
55 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
56 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
57 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
58 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
59 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
60 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
61 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
62 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
63 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
64 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
65 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
66 141, 128, 195, 78, 66, 215, 61, 156, 180
67};
68
69class SkPerlinNoiseShaderImpl : public SkShaderBase {
70public:
Florin Malita83223bc2017-05-31 14:14:05 -040071 struct StitchData {
72 StitchData()
73 : fWidth(0)
74 , fWrapX(0)
75 , fHeight(0)
76 , fWrapY(0)
77 {}
78
Florin Malita102c8cf2018-06-05 17:37:12 -040079 StitchData(SkScalar w, SkScalar h)
Brian Osman788b9162020-02-07 10:36:46 -050080 : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040081 , fWrapX(kPerlinNoise + fWidth)
Brian Osman788b9162020-02-07 10:36:46 -050082 , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040083 , fWrapY(kPerlinNoise + fHeight) {}
84
Florin Malita83223bc2017-05-31 14:14:05 -040085 bool operator==(const StitchData& other) const {
86 return fWidth == other.fWidth &&
87 fWrapX == other.fWrapX &&
88 fHeight == other.fHeight &&
89 fWrapY == other.fWrapY;
90 }
91
92 int fWidth; // How much to subtract to wrap for stitching.
93 int fWrapX; // Minimum value to wrap.
94 int fHeight;
95 int fWrapY;
96 };
97
98 struct PaintingData {
99 PaintingData(const SkISize& tileSize, SkScalar seed,
100 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
101 const SkMatrix& matrix)
102 {
Ethan Nicholas82940152019-01-10 13:58:14 -0500103 SkVector tileVec;
104 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
105 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -0400106
Ethan Nicholas82940152019-01-10 13:58:14 -0500107 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -0500108 if (!matrix.decomposeScale(&scale, nullptr)) {
109 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
110 }
Ethan Nicholas82940152019-01-10 13:58:14 -0500111 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
112 baseFrequencyY * SkScalarInvert(scale.height()));
113 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -0400114 this->init(seed);
115 if (!fTileSize.isEmpty()) {
116 this->stitch();
117 }
118
119 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500120 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500121 fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
122 fPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400123
Brian Salomona3a9da72020-06-17 10:52:19 -0400124 info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500125 fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
126 fNoiseBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400127
Greg Daniel7e1912a2018-02-08 09:15:33 -0500128 info = SkImageInfo::MakeA8(256, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500129 fImprovedPermutationsBitmap.installPixels(info, improved_noise_permutations,
130 info.minRowBytes());
131 fImprovedPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400132
Florin Malita83223bc2017-05-31 14:14:05 -0400133 static uint8_t gradients[] = { 2, 2, 1, 0,
134 0, 2, 1, 0,
135 2, 0, 1, 0,
136 0, 0, 1, 0,
137 2, 1, 2, 0,
138 0, 1, 2, 0,
139 2, 1, 0, 0,
140 0, 1, 0, 0,
141 1, 2, 2, 0,
142 1, 0, 2, 0,
143 1, 2, 0, 0,
144 1, 0, 0, 0,
145 2, 2, 1, 0,
146 1, 0, 2, 0,
147 0, 2, 1, 0,
148 1, 0, 0, 0 };
Brian Salomona3a9da72020-06-17 10:52:19 -0400149 info = SkImageInfo::Make(16, 1, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500150 fGradientBitmap.installPixels(info, gradients, info.minRowBytes());
151 fGradientBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400152 #endif
153 }
154
Brian Salomon4331e462017-07-26 14:58:11 -0400155 #if SK_SUPPORT_GPU
156 PaintingData(const PaintingData& that)
157 : fSeed(that.fSeed)
158 , fTileSize(that.fTileSize)
159 , fBaseFrequency(that.fBaseFrequency)
160 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel6f5441a2020-01-28 17:02:49 -0500161 , fPermutationsBitmap(that.fPermutationsBitmap)
162 , fNoiseBitmap(that.fNoiseBitmap)
163 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
164 , fGradientBitmap(that.fGradientBitmap) {
Brian Salomon4331e462017-07-26 14:58:11 -0400165 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
166 memcpy(fNoise, that.fNoise, sizeof(fNoise));
167 memcpy(fGradient, that.fGradient, sizeof(fGradient));
168 }
169 #endif
170
Florin Malita83223bc2017-05-31 14:14:05 -0400171 int fSeed;
172 uint8_t fLatticeSelector[kBlockSize];
173 uint16_t fNoise[4][kBlockSize][2];
174 SkPoint fGradient[4][kBlockSize];
175 SkISize fTileSize;
176 SkVector fBaseFrequency;
177 StitchData fStitchDataInit;
178
179 private:
180
181 #if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500182 SkBitmap fPermutationsBitmap;
183 SkBitmap fNoiseBitmap;
184 SkBitmap fImprovedPermutationsBitmap;
185 SkBitmap fGradientBitmap;
Florin Malita83223bc2017-05-31 14:14:05 -0400186 #endif
187
188 inline int random() {
189 static const int gRandAmplitude = 16807; // 7**5; primitive root of m
190 static const int gRandQ = 127773; // m / a
191 static const int gRandR = 2836; // m % a
192
193 int result = gRandAmplitude * (fSeed % gRandQ) - gRandR * (fSeed / gRandQ);
194 if (result <= 0)
195 result += kRandMaximum;
196 fSeed = result;
197 return result;
198 }
199
200 // Only called once. Could be part of the constructor.
201 void init(SkScalar seed)
202 {
203 static const SkScalar gInvBlockSizef = SkScalarInvert(SkIntToScalar(kBlockSize));
204
205 // According to the SVG spec, we must truncate (not round) the seed value.
206 fSeed = SkScalarTruncToInt(seed);
207 // The seed value clamp to the range [1, kRandMaximum - 1].
208 if (fSeed <= 0) {
209 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
210 }
211 if (fSeed > kRandMaximum - 1) {
212 fSeed = kRandMaximum - 1;
213 }
214 for (int channel = 0; channel < 4; ++channel) {
215 for (int i = 0; i < kBlockSize; ++i) {
216 fLatticeSelector[i] = i;
217 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
218 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
219 }
220 }
221 for (int i = kBlockSize - 1; i > 0; --i) {
222 int k = fLatticeSelector[i];
223 int j = random() % kBlockSize;
224 SkASSERT(j >= 0);
225 SkASSERT(j < kBlockSize);
226 fLatticeSelector[i] = fLatticeSelector[j];
227 fLatticeSelector[j] = k;
228 }
229
230 // Perform the permutations now
231 {
232 // Copy noise data
233 uint16_t noise[4][kBlockSize][2];
234 for (int i = 0; i < kBlockSize; ++i) {
235 for (int channel = 0; channel < 4; ++channel) {
236 for (int j = 0; j < 2; ++j) {
237 noise[channel][i][j] = fNoise[channel][i][j];
238 }
239 }
240 }
241 // Do permutations on noise data
242 for (int i = 0; i < kBlockSize; ++i) {
243 for (int channel = 0; channel < 4; ++channel) {
244 for (int j = 0; j < 2; ++j) {
245 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
246 }
247 }
248 }
249 }
250
251 // Half of the largest possible value for 16 bit unsigned int
252 static const SkScalar gHalfMax16bits = 32767.5f;
253
254 // Compute gradients from permutated noise data
255 for (int channel = 0; channel < 4; ++channel) {
256 for (int i = 0; i < kBlockSize; ++i) {
257 fGradient[channel][i] = SkPoint::Make(
258 (fNoise[channel][i][0] - kBlockSize) * gInvBlockSizef,
259 (fNoise[channel][i][1] - kBlockSize) * gInvBlockSizef);
260 fGradient[channel][i].normalize();
261 // Put the normalized gradient back into the noise data
262 fNoise[channel][i][0] = SkScalarRoundToInt(
263 (fGradient[channel][i].fX + 1) * gHalfMax16bits);
264 fNoise[channel][i][1] = SkScalarRoundToInt(
265 (fGradient[channel][i].fY + 1) * gHalfMax16bits);
266 }
267 }
268 }
269
270 // Only called once. Could be part of the constructor.
271 void stitch() {
272 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
273 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
274 SkASSERT(tileWidth > 0 && tileHeight > 0);
275 // When stitching tiled turbulence, the frequencies must be adjusted
276 // so that the tile borders will be continuous.
277 if (fBaseFrequency.fX) {
278 SkScalar lowFrequencx =
279 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
280 SkScalar highFrequencx =
281 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
282 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400283 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
284 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400285 fBaseFrequency.fX = lowFrequencx;
286 } else {
287 fBaseFrequency.fX = highFrequencx;
288 }
289 }
290 if (fBaseFrequency.fY) {
291 SkScalar lowFrequency =
292 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
293 SkScalar highFrequency =
294 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400295 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
296 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400297 fBaseFrequency.fY = lowFrequency;
298 } else {
299 fBaseFrequency.fY = highFrequency;
300 }
301 }
302 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400303 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
304 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400305 }
306
307 public:
308
309#if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500310 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400311
Greg Daniel6f5441a2020-01-28 17:02:49 -0500312 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400313
Greg Daniel6f5441a2020-01-28 17:02:49 -0500314 const SkBitmap& getImprovedPermutationsBitmap() const {
315 return fImprovedPermutationsBitmap;
Greg Daniel7e1912a2018-02-08 09:15:33 -0500316 }
Florin Malita83223bc2017-05-31 14:14:05 -0400317
Greg Daniel6f5441a2020-01-28 17:02:49 -0500318 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400319#endif
320 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400321
322 /**
323 * About the noise types : the difference between the first 2 is just minor tweaks to the
324 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
325 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
326 * doing :
327 * kFractalNoise_Type : noise * 0.5 + 0.5
328 * kTurbulence_Type : abs(noise)
329 * Very little differences between the 2 types, although you can tell the difference visually.
330 * "Improved" is based on the Improved Perlin Noise algorithm described at
331 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
332 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
333 * changes to the noise, making it suitable for animated noise.
334 */
335 enum Type {
336 kFractalNoise_Type,
337 kTurbulence_Type,
338 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500339 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400340 };
341
Robert Phillipsbee27322018-01-23 09:58:18 -0500342 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
343
Mike Reedf2ae2b22017-05-30 15:22:54 -0400344 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
345 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
346 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400347
348 class PerlinNoiseShaderContext : public Context {
349 public:
350 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400351
352 void shadeSpan(int x, int y, SkPMColor[], int count) override;
353
354 private:
355 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
356 SkScalar calculateTurbulenceValueForPoint(
357 int channel,
358 StitchData& stitchData, const SkPoint& point) const;
359 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
360 SkScalar noise2D(int channel,
361 const StitchData& stitchData, const SkPoint& noiseVector) const;
362
Florin Malita83223bc2017-05-31 14:14:05 -0400363 SkMatrix fMatrix;
364 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400365
366 typedef Context INHERITED;
367 };
368
369#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500370 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400371#endif
372
Mike Reedf2ae2b22017-05-30 15:22:54 -0400373protected:
374 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400375#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400376 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400377#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400378
379private:
Mike Klein4fee3232018-10-18 17:27:16 -0400380 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
381
Mike Reedf2ae2b22017-05-30 15:22:54 -0400382 const SkPerlinNoiseShaderImpl::Type fType;
383 const SkScalar fBaseFrequencyX;
384 const SkScalar fBaseFrequencyY;
385 const int fNumOctaves;
386 const SkScalar fSeed;
387 const SkISize fTileSize;
388 const bool fStitchTiles;
389
390 friend class ::SkPerlinNoiseShader;
391
392 typedef SkShaderBase INHERITED;
393};
394
sugoi@google.come3b4c502013-04-05 13:47:09 +0000395namespace {
396
397// noiseValue is the color component's value (or color)
398// limitValue is the maximum perlin noise array index value allowed
399// newValue is the current noise dimension (either width or height)
400inline int checkNoise(int noiseValue, int limitValue, int newValue) {
401 // If the noise value would bring us out of bounds of the current noise array while we are
402 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
403 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
404 if (noiseValue >= limitValue) {
405 noiseValue -= newValue;
406 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000407 return noiseValue;
408}
409
410inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500411 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000412}
413
414} // end namespace
415
Mike Reedf2ae2b22017-05-30 15:22:54 -0400416SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500417 SkScalar baseFrequencyX,
418 SkScalar baseFrequencyY,
419 int numOctaves,
420 SkScalar seed,
421 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000422 : fType(type)
423 , fBaseFrequencyX(baseFrequencyX)
424 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500425 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000426 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700427 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000428 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000429{
Robert Phillipsbee27322018-01-23 09:58:18 -0500430 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400431 SkASSERT(fBaseFrequencyX >= 0);
432 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400433}
434
Florin Malita14d54c22017-05-18 11:52:59 -0400435sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500436 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500437
reed9fa60da2014-08-21 07:59:51 -0700438 SkScalar freqX = buffer.readScalar();
439 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500440 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500441
reed9fa60da2014-08-21 07:59:51 -0700442 SkScalar seed = buffer.readScalar();
443 SkISize tileSize;
444 tileSize.fWidth = buffer.readInt();
445 tileSize.fHeight = buffer.readInt();
446
447 switch (type) {
448 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400449 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700450 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400451 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
452 case kImprovedNoise_Type:
453 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700454 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500455 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500456 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700457 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700458 }
459}
460
Florin Malita14d54c22017-05-18 11:52:59 -0400461void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000462 buffer.writeInt((int) fType);
463 buffer.writeScalar(fBaseFrequencyX);
464 buffer.writeScalar(fBaseFrequencyY);
465 buffer.writeInt(fNumOctaves);
466 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000467 buffer.writeInt(fTileSize.fWidth);
468 buffer.writeInt(fTileSize.fHeight);
469}
470
Florin Malita14d54c22017-05-18 11:52:59 -0400471SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700472 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000473 struct Noise {
474 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700475 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000476 SkScalar noisePositionFractionValue;
477 Noise(SkScalar component)
478 {
479 SkScalar position = component + kPerlinNoise;
480 noisePositionIntegerValue = SkScalarFloorToInt(position);
481 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700482 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000483 }
484 };
485 Noise noiseX(noiseVector.x());
486 Noise noiseY(noiseVector.y());
487 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400488 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000489 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000490 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000491 noiseX.noisePositionIntegerValue =
492 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
493 noiseY.noisePositionIntegerValue =
494 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700495 noiseX.nextNoisePositionIntegerValue =
496 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
497 noiseY.nextNoisePositionIntegerValue =
498 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000499 }
500 noiseX.noisePositionIntegerValue &= kBlockMask;
501 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700502 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
503 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400504 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
505 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700506 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
507 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
508 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
509 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000510 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
511 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400512
Hal Canaryfda46002017-05-08 17:17:47 -0400513 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
514 return 0; // Check for pathological inputs.
515 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400516
sugoi@google.come3b4c502013-04-05 13:47:09 +0000517 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
518 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
519 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400520 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000521 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400522 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000523 SkScalar a = SkScalarInterp(u, v, sx);
524 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400525 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000526 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400527 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000528 SkScalar b = SkScalarInterp(u, v, sx);
529 return SkScalarInterp(a, b, sy);
530}
531
Florin Malita14d54c22017-05-18 11:52:59 -0400532SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700533 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400534 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000535 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000536 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400537 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000538 }
539 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400540 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
541 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000542 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000543 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700544 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700545 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
546 noise : SkScalarAbs(noise);
547 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000548 noiseVector.fX *= 2;
549 noiseVector.fY *= 2;
550 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000551 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000552 // Update stitch values
Florin Malita102c8cf2018-06-05 17:37:12 -0400553 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
554 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000555 }
556 }
557
558 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
559 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000560 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400561 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000562 }
563
564 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700565 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000566 }
567
568 // Clamp result
Brian Osmanaba642c2020-02-06 12:52:25 -0500569 return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000570}
571
Mike Reedf2ae2b22017-05-30 15:22:54 -0400572////////////////////////////////////////////////////////////////////////////////////////////////////
573// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
574static SkScalar fade(SkScalar t) {
575 return t * t * t * (t * (t * 6 - 15) + 10);
576}
577
578static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
579 return a + t * (b - a);
580}
581
582static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
583 int h = hash & 15;
584 SkScalar u = h < 8 ? x : y;
585 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
586 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
587}
588
589SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
590 int channel, const SkPoint& point) const {
591 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
592 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
593 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
594 // z offset between different channels, chosen arbitrarily
595 static const SkScalar CHANNEL_DELTA = 1000.0f;
596 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
597 SkScalar result = 0;
598 SkScalar ratio = SK_Scalar1;
599 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
600 int X = SkScalarFloorToInt(x) & 255;
601 int Y = SkScalarFloorToInt(y) & 255;
602 int Z = SkScalarFloorToInt(z) & 255;
603 SkScalar px = x - SkScalarFloorToScalar(x);
604 SkScalar py = y - SkScalarFloorToScalar(y);
605 SkScalar pz = z - SkScalarFloorToScalar(z);
606 SkScalar u = fade(px);
607 SkScalar v = fade(py);
608 SkScalar w = fade(pz);
609 uint8_t* permutations = improved_noise_permutations;
610 int A = permutations[X] + Y;
611 int AA = permutations[A] + Z;
612 int AB = permutations[A + 1] + Z;
613 int B = permutations[X + 1] + Y;
614 int BA = permutations[B] + Z;
615 int BB = permutations[B + 1] + Z;
616 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
617 grad(permutations[BA ], px - 1, py , pz )),
618 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
619 grad(permutations[BB ], px - 1, py - 1, pz ))),
620 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
621 grad(permutations[BA + 1], px - 1, py , pz - 1)),
622 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
623 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
624 ratio;
625 x *= 2;
626 y *= 2;
627 ratio *= 2;
628 }
Brian Osmanaba642c2020-02-06 12:52:25 -0500629 result = SkTPin((result + 1.0f) / 2.0f, 0.0f, 1.0f);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400630 return result;
631}
632////////////////////////////////////////////////////////////////////////////////////////////////////
633
Florin Malita14d54c22017-05-18 11:52:59 -0400634SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000635 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400636 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000637 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000638 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000639 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
640 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
641
642 U8CPU rgba[4];
643 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400644 SkScalar value;
645 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
646 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
647 }
648 else {
649 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
650 }
651 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000652 }
653 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
654}
655
Mike Reede92aae62018-10-17 10:21:51 -0400656#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400657SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400658 SkArenaAlloc* alloc) const {
Mike Reed011d1662019-02-28 17:19:25 -0500659 // should we pay attention to rec's device-colorspace?
Herb Derby83e939b2017-02-07 14:25:11 -0500660 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000661}
Mike Reede92aae62018-10-17 10:21:51 -0400662#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000663
Florin Malita83223bc2017-05-31 14:14:05 -0400664static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
665 const SkShaderBase& shader) {
666 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
667 if (rec.fLocalMatrix) {
668 matrix.preConcat(*rec.fLocalMatrix);
669 }
670
671 return matrix;
672}
673
Florin Malita14d54c22017-05-18 11:52:59 -0400674SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
675 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000676 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400677 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
678 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
679 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000680{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000681 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
682 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400683 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
684 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700685}
686
Florin Malita14d54c22017-05-18 11:52:59 -0400687void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000688 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000689 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
690 StitchData stitchData;
691 for (int i = 0; i < count; ++i) {
692 result[i] = shade(point, stitchData);
693 point.fX += SK_Scalar1;
694 }
695}
696
sugoi@google.come3b4c502013-04-05 13:47:09 +0000697/////////////////////////////////////////////////////////////////////
698
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000699#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000700
egdaniel64c47282015-11-13 06:54:19 -0800701class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000702public:
robertphillips9cdb9922016-02-03 12:25:40 -0800703 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000704
Mike Reedf2ae2b22017-05-30 15:22:54 -0400705 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000706
wangyixb1daa862015-08-18 11:29:31 -0700707protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400708 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700709
sugoi@google.com4775cba2013-04-17 13:46:56 +0000710private:
egdaniel018fb622015-10-28 07:26:40 -0700711 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700712 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700713
egdaniel64c47282015-11-13 06:54:19 -0800714 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000715};
716
717/////////////////////////////////////////////////////////////////////
718
Mike Reedf2ae2b22017-05-30 15:22:54 -0400719class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000720public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400721 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -0400722 SkPerlinNoiseShaderImpl::Type type,
723 int numOctaves,
724 bool stitchTiles,
Brian Salomonaff329b2017-08-11 09:40:37 -0400725 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400726 GrSurfaceProxyView permutationsView,
727 GrSurfaceProxyView noiseView,
728 const SkMatrix& matrix,
729 const GrCaps& caps) {
730 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
731 GrSamplerState::WrapMode::kClamp,
732 GrSamplerState::Filter::kNearest};
733 auto permutationsFP =
734 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
735 SkMatrix::I(), kRepeatXSampler, caps);
736 auto noiseFP = GrTextureEffect::Make(std::move(noiseView), kPremul_SkAlphaType,
737 SkMatrix::I(), kRepeatXSampler, caps);
738
Michael Ludwigf2935c62020-06-26 11:07:23 -0400739 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
Brian Salomon83c2d352020-06-17 11:46:21 -0400740 new GrPerlinNoise2Effect(type, numOctaves, stitchTiles, std::move(paintingData),
Michael Ludwigf2935c62020-06-26 11:07:23 -0400741 std::move(permutationsFP), std::move(noiseFP))));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000742 }
743
mtklein36352bf2015-03-25 18:17:31 -0700744 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800745
Brian Salomonaff329b2017-08-11 09:40:37 -0400746 std::unique_ptr<GrFragmentProcessor> clone() const override {
747 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400748 }
749
Mike Reedf2ae2b22017-05-30 15:22:54 -0400750 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000751
Florin Malita14d54c22017-05-18 11:52:59 -0400752 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700753 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700754 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700755 int numOctaves() const { return fNumOctaves; }
senorblancof3b50272014-06-16 10:49:58 -0700756
sugoi@google.come3b4c502013-04-05 13:47:09 +0000757private:
egdaniel57d3b032015-11-13 11:57:27 -0800758 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800759 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700760 }
761
Brian Salomon94efbf52016-11-29 13:43:05 -0500762 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800763 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700764 GrGLPerlinNoise::GenKey(*this, caps, b);
765 }
766
mtklein36352bf2015-03-25 18:17:31 -0700767 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400768 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700769 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700770 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700771 fNumOctaves == s.fNumOctaves &&
772 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700773 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000774 }
775
Brian Salomon83c2d352020-06-17 11:46:21 -0400776 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type,
777 int numOctaves,
778 bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400779 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400780 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -0400781 std::unique_ptr<GrFragmentProcessor> noiseFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400782 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500783 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500784 , fNumOctaves(numOctaves)
785 , fStitchTiles(stitchTiles)
Florin Malitab365cf52017-05-30 17:18:01 -0400786 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -0400787 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
788 this->registerChild(std::move(noiseFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -0400789 this->setUsesSampleCoordsDirectly();
sugoi@google.come3b4c502013-04-05 13:47:09 +0000790 }
791
Brian Salomon4331e462017-07-26 14:58:11 -0400792 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400793 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400794 , fType(that.fType)
Brian Salomon4331e462017-07-26 14:58:11 -0400795 , fNumOctaves(that.fNumOctaves)
796 , fStitchTiles(that.fStitchTiles)
Brian Salomon4331e462017-07-26 14:58:11 -0400797 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -0400798 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -0400799 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -0400800 }
801
Brian Salomonf7dcd762018-07-30 14:48:15 -0400802
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400803 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000804
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400805 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400806 int fNumOctaves;
807 bool fStitchTiles;
Brian Salomon83c2d352020-06-17 11:46:21 -0400808
Florin Malitab365cf52017-05-30 17:18:01 -0400809 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000810
joshualittb0a8a372014-09-23 09:50:21 -0700811 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000812};
813
814/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400815GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000816
Hal Canary6f6961e2017-01-31 13:50:44 -0500817#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400818std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700819 int numOctaves = d->fRandom->nextRangeU(2, 10);
820 bool stitchTiles = d->fRandom->nextBool();
821 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
822 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
823 d->fRandom->nextRangeU(4, 4096));
824 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
825 0.99f);
826 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
827 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000828
reedfe630452016-03-25 09:08:00 -0700829 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
830 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400831 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700832 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400833 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000834
Brian Osman9f532a32016-10-19 11:12:09 -0400835 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400836 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000837}
Hal Canary6f6961e2017-01-31 13:50:44 -0500838#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000839
wangyix7c157a92015-07-22 15:08:53 -0700840void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400841 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800842
Brian Salomonffd15ea2020-07-01 16:48:20 -0400843 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800844 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000845
Ethan Nicholas16464c32020-04-06 13:53:05 -0400846 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800847 "baseFrequency");
848 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000849
halcanary96fcdcc2015-08-27 07:41:13 -0700850 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800851 if (pne.stitchTiles()) {
Ethan Nicholas16464c32020-04-06 13:53:05 -0400852 fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800853 "stitchData");
854 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000855 }
856
sugoi@google.comd537af52013-06-10 13:59:25 +0000857 // Add noise function
Brian Salomone338c292020-06-16 16:52:17 -0400858 const GrShaderVar gPerlinNoiseArgs[] = {{"chanCoord", kHalf_GrSLType },
859 {"noiseVec ", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000860
Brian Salomone338c292020-06-16 16:52:17 -0400861 const GrShaderVar gPerlinNoiseStitchArgs[] = {{"chanCoord" , kHalf_GrSLType },
862 {"noiseVec" , kHalf2_GrSLType},
863 {"stitchData", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000864
sugoi@google.comd537af52013-06-10 13:59:25 +0000865 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000866
Brian Salomone338c292020-06-16 16:52:17 -0400867 noiseCode.append(
868 R"(half4 floorVal;
869 floorVal.xy = floor(noiseVec);
870 floorVal.zw = floorVal.xy + half2(1);
871 half2 fractVal = fract(noiseVec);
872 // smooth curve : t^2*(3 - 2*t)
873 half2 noiseSmooth = fractVal*fractVal*(half2(3) - 2*fractVal);)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000874
875 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800876 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400877 noiseCode.append(
878 R"(if (floorVal.x >= stitchData.x) { floorVal.x -= stitchData.x; };
879 if (floorVal.y >= stitchData.y) { floorVal.y -= stitchData.y; };
880 if (floorVal.z >= stitchData.x) { floorVal.z -= stitchData.x; };
881 if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000882 }
883
Brian Salomon83c2d352020-06-17 11:46:21 -0400884 SkString sampleX = this->invokeChild(0, args, "half2(floorVal.x, 0.5)");
885 SkString sampleY = this->invokeChild(0, args, "half2(floorVal.z, 0.5)");
886 noiseCode.appendf("half2 latticeIdx = half2(%s.r, %s.r);", sampleX.c_str(), sampleY.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000887
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000888#if defined(SK_BUILD_FOR_ANDROID)
889 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
890 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
891 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
892 // (or 0.484368 here). The following rounding operation prevents these precision issues from
893 // affecting the result of the noise by making sure that we only have multiples of 1/255.
894 // (Note that 1/255 is about 0.003921569, which is the value used here).
Brian Salomone338c292020-06-16 16:52:17 -0400895 noiseCode.append(
896 "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);");
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000897#endif
898
sugoi@google.come3b4c502013-04-05 13:47:09 +0000899 // Get (x,y) coordinates with the permutated x
Brian Salomon83c2d352020-06-17 11:46:21 -0400900 noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000901
Brian Salomone338c292020-06-16 16:52:17 -0400902 noiseCode.append("half2 uv;");
903
904 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
905 // [-1,1] vector and perform a dot product between that vector and the provided vector.
906 // Save it as a string because we will repeat it 4x.
907 static constexpr const char* inc8bit = "0.00390625"; // 1.0 / 256.0
908 SkString dotLattice =
909 SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
910
Brian Salomon83c2d352020-06-17 11:46:21 -0400911 SkString sampleA = this->invokeChild(1, args, "half2(bcoords.x, chanCoord)");
912 SkString sampleB = this->invokeChild(1, args, "half2(bcoords.y, chanCoord)");
913 SkString sampleC = this->invokeChild(1, args, "half2(bcoords.w, chanCoord)");
914 SkString sampleD = this->invokeChild(1, args, "half2(bcoords.z, chanCoord)");
915
sugoi@google.come3b4c502013-04-05 13:47:09 +0000916 // Compute u, at offset (0,0)
Brian Salomon83c2d352020-06-17 11:46:21 -0400917 noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
918 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000919
sugoi@google.come3b4c502013-04-05 13:47:09 +0000920 // Compute v, at offset (-1,0)
Brian Salomone338c292020-06-16 16:52:17 -0400921 noiseCode.append("fractVal.x -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400922 noiseCode.appendf("lattice = %s;", sampleB.c_str());
923 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000924
925 // Compute 'a' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400926 noiseCode.append("half2 ab;");
927 noiseCode.append("ab.x = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000928
sugoi@google.come3b4c502013-04-05 13:47:09 +0000929 // Compute v, at offset (-1,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400930 noiseCode.append("fractVal.y -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400931 noiseCode.appendf("lattice = %s;", sampleC.c_str());
932 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000933
sugoi@google.come3b4c502013-04-05 13:47:09 +0000934 // Compute u, at offset (0,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400935 noiseCode.append("fractVal.x += 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400936 noiseCode.appendf("lattice = %s;", sampleD.c_str());
937 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000938
939 // Compute 'b' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400940 noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000941 // Compute the noise as a linear interpolation of 'a' and 'b'
Brian Salomone338c292020-06-16 16:52:17 -0400942 noiseCode.append("return mix(ab.x, ab.y, noiseSmooth.y);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000943
sugoi@google.comd537af52013-06-10 13:59:25 +0000944 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800945 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400946 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800947 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
948 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000949 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400950 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800951 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
952 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000953 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000954
sugoi@google.comd537af52013-06-10 13:59:25 +0000955 // There are rounding errors if the floor operation is not performed here
Brian Salomone338c292020-06-16 16:52:17 -0400956 fragBuilder->codeAppendf("half2 noiseVec = half2(floor(%s.xy) * %s);",
Michael Ludwige88320b2020-06-24 09:04:56 -0400957 args.fSampleCoord, baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000958
959 // Clear the color accumulator
Brian Salomone338c292020-06-16 16:52:17 -0400960 fragBuilder->codeAppendf("%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000961
robertphillipsbf536af2016-02-04 06:11:53 -0800962 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +0000963 // Set up TurbulenceInitial stitch values.
Brian Salomone338c292020-06-16 16:52:17 -0400964 fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000965 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000966
Brian Salomone338c292020-06-16 16:52:17 -0400967 fragBuilder->codeAppendf("half ratio = 1.0;");
sugoi@google.comd537af52013-06-10 13:59:25 +0000968
969 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -0800970 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
Brian Salomone338c292020-06-16 16:52:17 -0400971 fragBuilder->codeAppendf(" %s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -0400972 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -0800973 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +0000974 }
Brian Salomone338c292020-06-16 16:52:17 -0400975
Brian Salomon83c2d352020-06-17 11:46:21 -0400976 // There are 4 lines, put y coords at center of each.
977 static constexpr const char* chanCoordR = "0.5";
978 static constexpr const char* chanCoordG = "1.5";
979 static constexpr const char* chanCoordB = "2.5";
980 static constexpr const char* chanCoordA = "3.5";
robertphillipsbf536af2016-02-04 06:11:53 -0800981 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400982 fragBuilder->codeAppendf(R"(
983 half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),"
984 %s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)))",
985 noiseFuncName.c_str(), chanCoordR,
986 noiseFuncName.c_str(), chanCoordG,
987 noiseFuncName.c_str(), chanCoordB,
988 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000989 } else {
Brian Salomone338c292020-06-16 16:52:17 -0400990 fragBuilder->codeAppendf(R"(
991 half4(%s(%s, noiseVec), %s(%s, noiseVec),
992 %s(%s, noiseVec), %s(%s, noiseVec)))",
993 noiseFuncName.c_str(), chanCoordR,
994 noiseFuncName.c_str(), chanCoordG,
995 noiseFuncName.c_str(), chanCoordB,
996 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000997 }
Florin Malita14d54c22017-05-18 11:52:59 -0400998 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
Brian Salomone338c292020-06-16 16:52:17 -0400999 fragBuilder->codeAppend(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001000 }
Brian Salomone338c292020-06-16 16:52:17 -04001001 fragBuilder->codeAppend(" * ratio;");
sugoi@google.comd537af52013-06-10 13:59:25 +00001002
Brian Salomone338c292020-06-16 16:52:17 -04001003 fragBuilder->codeAppend(R"(noiseVec *= half2(2.0);
1004 ratio *= 0.5;)");
sugoi@google.comd537af52013-06-10 13:59:25 +00001005
robertphillipsbf536af2016-02-04 06:11:53 -08001006 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -04001007 fragBuilder->codeAppend("stitchData *= half2(2.0);");
sugoi@google.comd537af52013-06-10 13:59:25 +00001008 }
Brian Salomone338c292020-06-16 16:52:17 -04001009 fragBuilder->codeAppend("}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001010
Florin Malita14d54c22017-05-18 11:52:59 -04001011 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001012 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1013 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Brian Salomone338c292020-06-16 16:52:17 -04001014 fragBuilder->codeAppendf("%s = %s * half4(0.5) + half4(0.5);",
1015 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001016 }
1017
sugoi@google.come3b4c502013-04-05 13:47:09 +00001018 // Clamp values
Brian Salomone338c292020-06-16 16:52:17 -04001019 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001020
1021 // Pre-multiply the result
Brian Salomone338c292020-06-16 16:52:17 -04001022 fragBuilder->codeAppendf("%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001023 args.fOutputColor, args.fOutputColor,
1024 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001025}
1026
Brian Salomon94efbf52016-11-29 13:43:05 -05001027void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001028 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001029 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001030
bsalomon63e99f72014-07-21 08:03:14 -07001031 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001032
1033 key = key << 3; // Make room for next 3 bits
1034
1035 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001036 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001037 key |= 0x1;
1038 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001039 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001040 key |= 0x2;
1041 break;
1042 default:
1043 // leave key at 0
1044 break;
1045 }
1046
1047 if (turbulence.stitchTiles()) {
1048 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1049 }
1050
bsalomon63e99f72014-07-21 08:03:14 -07001051 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001052}
1053
egdaniel018fb622015-10-28 07:26:40 -07001054void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001055 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001056 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001057
Mike Reedf2ae2b22017-05-30 15:22:54 -04001058 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001059
1060 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001061 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001062
sugoi@google.com4775cba2013-04-17 13:46:56 +00001063 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001064 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001065 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
Brian Salomon81454df2020-06-17 10:59:28 -04001066 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001067 }
1068}
1069
sugoi@google.come3b4c502013-04-05 13:47:09 +00001070/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001071
1072class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1073public:
1074 void emitCode(EmitArgs&) override;
1075
1076 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1077
1078protected:
1079 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1080
1081private:
1082 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001083 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1084
1085 typedef GrGLSLFragmentProcessor INHERITED;
1086};
1087
1088/////////////////////////////////////////////////////////////////////
1089
1090class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1091public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001092 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -04001093 int octaves,
1094 SkScalar z,
Brian Salomonaff329b2017-08-11 09:40:37 -04001095 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001096 GrSurfaceProxyView permutationsView,
1097 GrSurfaceProxyView gradientView,
1098 const SkMatrix& matrix,
1099 const GrCaps& caps) {
1100 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
1101 GrSamplerState::WrapMode::kClamp,
1102 GrSamplerState::Filter::kNearest};
1103 auto permutationsFP =
1104 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
1105 SkMatrix::I(), kRepeatXSampler, caps);
1106 auto gradientFP = GrTextureEffect::Make(std::move(gradientView), kPremul_SkAlphaType,
1107 SkMatrix::I(), kRepeatXSampler, caps);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001108 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
1109 new GrImprovedPerlinNoiseEffect(octaves, z, std::move(paintingData),
1110 std::move(permutationsFP),
1111 std::move(gradientFP))));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001112 }
1113
Mike Reedf2ae2b22017-05-30 15:22:54 -04001114 const char* name() const override { return "ImprovedPerlinNoise"; }
1115
Brian Salomonaff329b2017-08-11 09:40:37 -04001116 std::unique_ptr<GrFragmentProcessor> clone() const override {
1117 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001118 }
1119
Mike Reedf2ae2b22017-05-30 15:22:54 -04001120 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1121 SkScalar z() const { return fZ; }
1122 int octaves() const { return fOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001123
1124private:
1125 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1126 return new GrGLImprovedPerlinNoise;
1127 }
1128
1129 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1130 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1131 }
1132
1133 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
1134 const GrImprovedPerlinNoiseEffect& s = sBase.cast<GrImprovedPerlinNoiseEffect>();
1135 return fZ == fZ &&
1136 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency;
1137 }
1138
Brian Salomon83c2d352020-06-17 11:46:21 -04001139 GrImprovedPerlinNoiseEffect(int octaves,
1140 SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001141 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001142 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -04001143 std::unique_ptr<GrFragmentProcessor> gradientFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001144 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001145 , fOctaves(octaves)
1146 , fZ(z)
Florin Malitab365cf52017-05-30 17:18:01 -04001147 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -04001148 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
1149 this->registerChild(std::move(gradientFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -04001150 this->setUsesSampleCoordsDirectly();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001151 }
1152
Brian Salomon4331e462017-07-26 14:58:11 -04001153 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001154 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001155 , fOctaves(that.fOctaves)
1156 , fZ(that.fZ)
Brian Salomon4331e462017-07-26 14:58:11 -04001157 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -04001158 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001159 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -04001160 }
1161
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001162 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001163
Mike Reedf2ae2b22017-05-30 15:22:54 -04001164 int fOctaves;
1165 SkScalar fZ;
Brian Salomon83c2d352020-06-17 11:46:21 -04001166
Florin Malitab365cf52017-05-30 17:18:01 -04001167 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001168
1169 typedef GrFragmentProcessor INHERITED;
1170};
1171
1172/////////////////////////////////////////////////////////////////////
1173GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1174
1175#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001176std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1177 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001178 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1179 0.99f);
1180 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1181 0.99f);
1182 int numOctaves = d->fRandom->nextRangeU(2, 10);
1183 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1184
1185 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
1186 baseFrequencyY,
1187 numOctaves,
1188 z));
1189
1190 GrTest::TestAsFPArgs asFPArgs(d);
1191 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1192}
1193#endif
1194
1195void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001196 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Brian Salomonffd15ea2020-07-01 16:48:20 -04001197 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001198 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001199
Ethan Nicholas16464c32020-04-06 13:53:05 -04001200 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001201 "baseFrequency");
1202 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1203
Ethan Nicholas16464c32020-04-06 13:53:05 -04001204 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001205 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1206
1207 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001208 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001209 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001210 };
1211 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001212 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001213 fadeArgs,
1214 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1215 &fadeFuncName);
1216
1217 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001218 const GrShaderVar permArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001219 {"x", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001220 };
Brian Salomon83c2d352020-06-17 11:46:21 -04001221 SkString samplePerm = this->invokeChild(0, args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001222 SkString permFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001223 SkString permCode = SkStringPrintf("return %s.r * 255;", samplePerm.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001224 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001225 permCode.c_str(), &permFuncName);
1226
1227 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001228 const GrShaderVar gradArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001229 {"x", kHalf_GrSLType},
1230 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001231 };
Brian Salomon83c2d352020-06-17 11:46:21 -04001232 SkString sampleGrad = this->invokeChild(1, args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001233 SkString gradFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001234 SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));",
1235 sampleGrad.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001236 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001237 gradCode.c_str(), &gradFuncName);
1238
1239 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001240 const GrShaderVar lerpArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001241 {"a", kHalf_GrSLType},
1242 {"b", kHalf_GrSLType},
1243 {"w", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001244 };
1245 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001246 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001247 "return a + w * (b - a);", &lerpFuncName);
1248
1249 // noise function
Brian Salomon83c2d352020-06-17 11:46:21 -04001250 const GrShaderVar noiseArgs[] = {
1251 {"p", kHalf3_GrSLType},
Mike Reedf2ae2b22017-05-30 15:22:54 -04001252 };
1253 SkString noiseFuncName;
1254 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001255 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001256 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001257 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1258 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1259 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1260 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1261 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1262 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1263 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1264 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001265 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1266 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001267 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 -04001268 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001269 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001270 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001271 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001272 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001273 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001274 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1275 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001276 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001277 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001278 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001279 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001280 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 -04001281 gradFuncName.c_str(), permFuncName.c_str());
1282 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001283 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001284 noiseCode.c_str(), &noiseFuncName);
1285
1286 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001287 const GrShaderVar noiseOctavesArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001288 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001289 };
1290 SkString noiseOctavesFuncName;
1291 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001292 noiseOctavesCode.append("half result = 0.0;");
1293 noiseOctavesCode.append("half ratio = 1.0;");
1294 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001295 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1296 noiseOctavesCode.append("p *= 2.0;");
1297 noiseOctavesCode.append("ratio *= 2.0;");
1298 noiseOctavesCode.append("}");
1299 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001300 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001301 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1302
Michael Ludwige88320b2020-06-24 09:04:56 -04001303 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", args.fSampleCoord, baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001304 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001305 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001306 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001307 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001308 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001309 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001310 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001311 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001312 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001313
1314 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001315 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001316
1317 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001318 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001319 args.fOutputColor, args.fOutputColor,
1320 args.fOutputColor, args.fOutputColor);
1321}
1322
1323void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1324 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001325 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1326 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001327}
1328
1329void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1330 const GrFragmentProcessor& processor) {
1331 INHERITED::onSetData(pdman, processor);
1332
1333 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1334
1335 const SkVector& baseFrequency = noise.baseFrequency();
1336 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1337
Mike Reedf2ae2b22017-05-30 15:22:54 -04001338 pdman.set1f(fZUni, noise.z());
1339}
1340
1341/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001342std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001343 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001344 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001345
Florin Malita52f02912020-03-09 16:33:17 -04001346 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Brian Osman449b1152020-04-15 16:43:00 -04001347 const auto paintMatrix = SkMatrix::Concat(args.fMatrixProvider.localToDevice(), *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001348
Mike Reedf2ae2b22017-05-30 15:22:54 -04001349 // Either we don't stitch tiles, either we have a valid tile size
1350 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1351
Florin Malitab365cf52017-05-30 17:18:01 -04001352 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001353 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001354 fSeed,
1355 fBaseFrequencyX,
1356 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001357 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001358
Brian Osman449b1152020-04-15 16:43:00 -04001359 SkMatrix m = args.fMatrixProvider.localToDevice();
Florin Malitac6c5ead2018-04-11 15:33:40 -04001360 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1361 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001362
Greg Daniel6f5441a2020-01-28 17:02:49 -05001363 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001364 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001365 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1366 // We also know that we will not be using mipmaps. If things things weren't true we should
1367 // go through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001368 const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
1369 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001370 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001371
Greg Daniel6f5441a2020-01-28 17:02:49 -05001372 const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
1373 SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001374 auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
Brian Salomon83c2d352020-06-17 11:46:21 -04001375 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves,
1376 fSeed,
1377 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001378 std::move(permutationsView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001379 std::move(gradientView),
1380 m,
1381 *context->priv().caps());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001382 }
1383
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001384 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001385 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001386 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001387 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1388 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1389 // the destination.
John Stiles7c196772020-07-13 10:00:16 -04001390 auto inner = GrModulateRGBAEffect::Make(
1391 /*inputFP=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040));
Mike Reed28eaed22018-02-01 11:24:53 -05001392 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001393 }
bsalomonc21b09e2015-08-28 18:46:56 -07001394 // Emit zero.
John Stiles7c196772020-07-13 10:00:16 -04001395 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001396 }
1397
Greg Daniel7e1912a2018-02-08 09:15:33 -05001398 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1399 // also know that we will not be using mipmaps. If things things weren't true we should go
1400 // through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001401 const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
1402 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001403 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001404
Greg Daniel6f5441a2020-01-28 17:02:49 -05001405 const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
1406 SkASSERT(SkIsPow2(noiseBitmap.width()) && SkIsPow2(noiseBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001407 auto noiseView = GrMakeCachedBitmapProxyView(context, noiseBitmap);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001408
Greg Danielc52db712020-01-28 17:03:46 -05001409 if (permutationsView.proxy() && noiseView.proxy()) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001410 auto inner = GrPerlinNoise2Effect::Make(fType,
1411 fNumOctaves,
1412 fStitchTiles,
1413 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001414 std::move(permutationsView),
1415 std::move(noiseView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001416 m,
1417 *context->priv().caps());
Mike Reed28eaed22018-02-01 11:24:53 -05001418 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001419 }
bsalomonc21b09e2015-08-28 18:46:56 -07001420 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001421}
1422
1423#endif
1424
Mike Reedf2ae2b22017-05-30 15:22:54 -04001425///////////////////////////////////////////////////////////////////////////////////////////////////
1426
Mike Reed832aa112018-05-18 11:48:50 -04001427static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1428 SkScalar seed) {
1429 if (!(baseX >= 0 && baseY >= 0)) {
1430 return false;
1431 }
1432 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1433 return false;
1434 }
1435 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1436 return false;
1437 }
1438 if (!SkScalarIsFinite(seed)) {
1439 return false;
1440 }
1441 return true;
1442}
1443
Mike Reedf2ae2b22017-05-30 15:22:54 -04001444sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1445 SkScalar baseFrequencyY,
1446 int numOctaves, SkScalar seed,
1447 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001448 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1449 return nullptr;
1450 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001451 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1452 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1453 tileSize));
1454}
1455
1456sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1457 SkScalar baseFrequencyY,
1458 int numOctaves, SkScalar seed,
1459 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001460 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1461 return nullptr;
1462 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001463 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1464 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1465 tileSize));
1466}
1467
1468sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1469 SkScalar baseFrequencyY,
1470 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001471 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1472 return nullptr;
1473 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001474 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1475 baseFrequencyX, baseFrequencyY, numOctaves, z,
1476 nullptr));
1477}
1478
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001479void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001480 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001481}