blob: 1dc538c4f3bd36c331dae922d59b2f53ccc5712c [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 Reedac9f0c92020-12-23 10:11:33 -050010#include "include/core/SkBitmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkColorFilter.h"
12#include "include/core/SkShader.h"
13#include "include/core/SkString.h"
14#include "include/core/SkUnPreMultiply.h"
Mike Klein8aa0edf2020-10-16 11:04:18 -050015#include "include/private/SkTPin.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040016#include "src/core/SkArenaAlloc.h"
Brian Osman449b1152020-04-15 16:43:00 -040017#include "src/core/SkMatrixProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/core/SkReadBuffer.h"
19#include "src/core/SkWriteBuffer.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000020
21#if SK_SUPPORT_GPU
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040022#include "include/gpu/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/gpu/GrRecordingContextPriv.h"
24#include "src/gpu/SkGr.h"
Michael Ludwigf2935c62020-06-26 11:07:23 -040025#include "src/gpu/effects/GrMatrixEffect.h"
Brian Salomon83c2d352020-06-17 11:46:21 -040026#include "src/gpu/effects/GrTextureEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/gpu/effects/generated/GrConstColorProcessor.h"
28#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
29#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
30#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
31#include "src/gpu/glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000032#endif
33
34static const int kBlockSize = 256;
35static const int kBlockMask = kBlockSize - 1;
36static const int kPerlinNoise = 4096;
37static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
38
Mike Reedf2ae2b22017-05-30 15:22:54 -040039static uint8_t improved_noise_permutations[] = {
40 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
41 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
42 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
43 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
44 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
45 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
46 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
47 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
48 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
49 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
50 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
51 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
52 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
53 141, 128, 195, 78, 66, 215, 61, 156, 180,
54 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
55 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
56 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
57 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
58 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
59 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
60 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
61 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
62 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
63 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
64 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
65 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
66 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
67 141, 128, 195, 78, 66, 215, 61, 156, 180
68};
69
70class SkPerlinNoiseShaderImpl : public SkShaderBase {
71public:
Florin Malita83223bc2017-05-31 14:14:05 -040072 struct StitchData {
73 StitchData()
74 : fWidth(0)
75 , fWrapX(0)
76 , fHeight(0)
77 , fWrapY(0)
78 {}
79
Florin Malita102c8cf2018-06-05 17:37:12 -040080 StitchData(SkScalar w, SkScalar h)
Brian Osman788b9162020-02-07 10:36:46 -050081 : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040082 , fWrapX(kPerlinNoise + fWidth)
Brian Osman788b9162020-02-07 10:36:46 -050083 , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040084 , fWrapY(kPerlinNoise + fHeight) {}
85
Florin Malita83223bc2017-05-31 14:14:05 -040086 bool operator==(const StitchData& other) const {
87 return fWidth == other.fWidth &&
88 fWrapX == other.fWrapX &&
89 fHeight == other.fHeight &&
90 fWrapY == other.fWrapY;
91 }
92
93 int fWidth; // How much to subtract to wrap for stitching.
94 int fWrapX; // Minimum value to wrap.
95 int fHeight;
96 int fWrapY;
97 };
98
99 struct PaintingData {
100 PaintingData(const SkISize& tileSize, SkScalar seed,
101 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
102 const SkMatrix& matrix)
103 {
Ethan Nicholas82940152019-01-10 13:58:14 -0500104 SkVector tileVec;
105 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
106 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -0400107
Ethan Nicholas82940152019-01-10 13:58:14 -0500108 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -0500109 if (!matrix.decomposeScale(&scale, nullptr)) {
110 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
111 }
Ethan Nicholas82940152019-01-10 13:58:14 -0500112 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
113 baseFrequencyY * SkScalarInvert(scale.height()));
114 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -0400115 this->init(seed);
116 if (!fTileSize.isEmpty()) {
117 this->stitch();
118 }
119
120 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500121 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500122 fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
123 fPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400124
Brian Salomona3a9da72020-06-17 10:52:19 -0400125 info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500126 fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
127 fNoiseBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400128
Greg Daniel7e1912a2018-02-08 09:15:33 -0500129 info = SkImageInfo::MakeA8(256, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500130 fImprovedPermutationsBitmap.installPixels(info, improved_noise_permutations,
131 info.minRowBytes());
132 fImprovedPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400133
Florin Malita83223bc2017-05-31 14:14:05 -0400134 static uint8_t gradients[] = { 2, 2, 1, 0,
135 0, 2, 1, 0,
136 2, 0, 1, 0,
137 0, 0, 1, 0,
138 2, 1, 2, 0,
139 0, 1, 2, 0,
140 2, 1, 0, 0,
141 0, 1, 0, 0,
142 1, 2, 2, 0,
143 1, 0, 2, 0,
144 1, 2, 0, 0,
145 1, 0, 0, 0,
146 2, 2, 1, 0,
147 1, 0, 2, 0,
148 0, 2, 1, 0,
149 1, 0, 0, 0 };
Brian Salomona3a9da72020-06-17 10:52:19 -0400150 info = SkImageInfo::Make(16, 1, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500151 fGradientBitmap.installPixels(info, gradients, info.minRowBytes());
152 fGradientBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400153 #endif
154 }
155
Brian Salomon4331e462017-07-26 14:58:11 -0400156 #if SK_SUPPORT_GPU
157 PaintingData(const PaintingData& that)
158 : fSeed(that.fSeed)
159 , fTileSize(that.fTileSize)
160 , fBaseFrequency(that.fBaseFrequency)
161 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel6f5441a2020-01-28 17:02:49 -0500162 , fPermutationsBitmap(that.fPermutationsBitmap)
163 , fNoiseBitmap(that.fNoiseBitmap)
164 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
165 , fGradientBitmap(that.fGradientBitmap) {
Brian Salomon4331e462017-07-26 14:58:11 -0400166 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
167 memcpy(fNoise, that.fNoise, sizeof(fNoise));
168 memcpy(fGradient, that.fGradient, sizeof(fGradient));
169 }
170 #endif
171
Florin Malita83223bc2017-05-31 14:14:05 -0400172 int fSeed;
173 uint8_t fLatticeSelector[kBlockSize];
174 uint16_t fNoise[4][kBlockSize][2];
175 SkPoint fGradient[4][kBlockSize];
176 SkISize fTileSize;
177 SkVector fBaseFrequency;
178 StitchData fStitchDataInit;
179
180 private:
181
182 #if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500183 SkBitmap fPermutationsBitmap;
184 SkBitmap fNoiseBitmap;
185 SkBitmap fImprovedPermutationsBitmap;
186 SkBitmap fGradientBitmap;
Florin Malita83223bc2017-05-31 14:14:05 -0400187 #endif
188
189 inline int random() {
John Stiles039f6812020-08-10 09:51:42 -0400190 // See https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
191 // m = kRandMaximum, 2**31 - 1 (2147483647)
192 static constexpr int kRandAmplitude = 16807; // 7**5; primitive root of m
193 static constexpr int kRandQ = 127773; // m / a
194 static constexpr int kRandR = 2836; // m % a
Florin Malita83223bc2017-05-31 14:14:05 -0400195
John Stiles039f6812020-08-10 09:51:42 -0400196 int result = kRandAmplitude * (fSeed % kRandQ) - kRandR * (fSeed / kRandQ);
197 if (result <= 0) {
Florin Malita83223bc2017-05-31 14:14:05 -0400198 result += kRandMaximum;
John Stiles039f6812020-08-10 09:51:42 -0400199 }
Florin Malita83223bc2017-05-31 14:14:05 -0400200 fSeed = result;
201 return result;
202 }
203
204 // Only called once. Could be part of the constructor.
205 void init(SkScalar seed)
206 {
Florin Malita83223bc2017-05-31 14:14:05 -0400207 // According to the SVG spec, we must truncate (not round) the seed value.
208 fSeed = SkScalarTruncToInt(seed);
209 // The seed value clamp to the range [1, kRandMaximum - 1].
210 if (fSeed <= 0) {
211 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
212 }
213 if (fSeed > kRandMaximum - 1) {
214 fSeed = kRandMaximum - 1;
215 }
216 for (int channel = 0; channel < 4; ++channel) {
217 for (int i = 0; i < kBlockSize; ++i) {
218 fLatticeSelector[i] = i;
219 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
220 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
221 }
222 }
223 for (int i = kBlockSize - 1; i > 0; --i) {
224 int k = fLatticeSelector[i];
225 int j = random() % kBlockSize;
226 SkASSERT(j >= 0);
227 SkASSERT(j < kBlockSize);
228 fLatticeSelector[i] = fLatticeSelector[j];
229 fLatticeSelector[j] = k;
230 }
231
232 // Perform the permutations now
233 {
234 // Copy noise data
235 uint16_t noise[4][kBlockSize][2];
236 for (int i = 0; i < kBlockSize; ++i) {
237 for (int channel = 0; channel < 4; ++channel) {
238 for (int j = 0; j < 2; ++j) {
239 noise[channel][i][j] = fNoise[channel][i][j];
240 }
241 }
242 }
243 // Do permutations on noise data
244 for (int i = 0; i < kBlockSize; ++i) {
245 for (int channel = 0; channel < 4; ++channel) {
246 for (int j = 0; j < 2; ++j) {
247 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
248 }
249 }
250 }
251 }
252
253 // Half of the largest possible value for 16 bit unsigned int
John Stiles039f6812020-08-10 09:51:42 -0400254 static constexpr SkScalar kHalfMax16bits = 32767.5f;
Florin Malita83223bc2017-05-31 14:14:05 -0400255
256 // Compute gradients from permutated noise data
John Stiles039f6812020-08-10 09:51:42 -0400257 static constexpr SkScalar kInvBlockSizef = 1.0 / SkIntToScalar(kBlockSize);
Florin Malita83223bc2017-05-31 14:14:05 -0400258 for (int channel = 0; channel < 4; ++channel) {
259 for (int i = 0; i < kBlockSize; ++i) {
260 fGradient[channel][i] = SkPoint::Make(
John Stiles039f6812020-08-10 09:51:42 -0400261 (fNoise[channel][i][0] - kBlockSize) * kInvBlockSizef,
262 (fNoise[channel][i][1] - kBlockSize) * kInvBlockSizef);
Florin Malita83223bc2017-05-31 14:14:05 -0400263 fGradient[channel][i].normalize();
264 // Put the normalized gradient back into the noise data
John Stiles039f6812020-08-10 09:51:42 -0400265 fNoise[channel][i][0] =
266 SkScalarRoundToInt((fGradient[channel][i].fX + 1) * kHalfMax16bits);
267 fNoise[channel][i][1] =
268 SkScalarRoundToInt((fGradient[channel][i].fY + 1) * kHalfMax16bits);
Florin Malita83223bc2017-05-31 14:14:05 -0400269 }
270 }
271 }
272
273 // Only called once. Could be part of the constructor.
274 void stitch() {
275 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
276 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
277 SkASSERT(tileWidth > 0 && tileHeight > 0);
278 // When stitching tiled turbulence, the frequencies must be adjusted
279 // so that the tile borders will be continuous.
280 if (fBaseFrequency.fX) {
281 SkScalar lowFrequencx =
282 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
283 SkScalar highFrequencx =
284 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
285 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400286 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
287 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400288 fBaseFrequency.fX = lowFrequencx;
289 } else {
290 fBaseFrequency.fX = highFrequencx;
291 }
292 }
293 if (fBaseFrequency.fY) {
294 SkScalar lowFrequency =
295 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
296 SkScalar highFrequency =
297 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400298 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
299 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400300 fBaseFrequency.fY = lowFrequency;
301 } else {
302 fBaseFrequency.fY = highFrequency;
303 }
304 }
305 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400306 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
307 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400308 }
309
310 public:
311
312#if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500313 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400314
Greg Daniel6f5441a2020-01-28 17:02:49 -0500315 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400316
Greg Daniel6f5441a2020-01-28 17:02:49 -0500317 const SkBitmap& getImprovedPermutationsBitmap() const {
318 return fImprovedPermutationsBitmap;
Greg Daniel7e1912a2018-02-08 09:15:33 -0500319 }
Florin Malita83223bc2017-05-31 14:14:05 -0400320
Greg Daniel6f5441a2020-01-28 17:02:49 -0500321 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400322#endif
323 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400324
325 /**
326 * About the noise types : the difference between the first 2 is just minor tweaks to the
327 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
328 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
329 * doing :
330 * kFractalNoise_Type : noise * 0.5 + 0.5
331 * kTurbulence_Type : abs(noise)
332 * Very little differences between the 2 types, although you can tell the difference visually.
333 * "Improved" is based on the Improved Perlin Noise algorithm described at
334 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
335 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
336 * changes to the noise, making it suitable for animated noise.
337 */
338 enum Type {
339 kFractalNoise_Type,
340 kTurbulence_Type,
341 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500342 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400343 };
344
Robert Phillipsbee27322018-01-23 09:58:18 -0500345 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
346
Mike Reedf2ae2b22017-05-30 15:22:54 -0400347 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
348 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
349 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400350
351 class PerlinNoiseShaderContext : public Context {
352 public:
353 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400354
355 void shadeSpan(int x, int y, SkPMColor[], int count) override;
356
357 private:
358 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
359 SkScalar calculateTurbulenceValueForPoint(
360 int channel,
361 StitchData& stitchData, const SkPoint& point) const;
362 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
363 SkScalar noise2D(int channel,
364 const StitchData& stitchData, const SkPoint& noiseVector) const;
365
Florin Malita83223bc2017-05-31 14:14:05 -0400366 SkMatrix fMatrix;
367 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400368
John Stiles7571f9e2020-09-02 22:42:33 -0400369 using INHERITED = Context;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400370 };
371
372#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500373 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400374#endif
375
Mike Reedf2ae2b22017-05-30 15:22:54 -0400376protected:
377 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400378#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400379 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400380#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400381
382private:
Mike Klein4fee3232018-10-18 17:27:16 -0400383 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
384
Mike Reedf2ae2b22017-05-30 15:22:54 -0400385 const SkPerlinNoiseShaderImpl::Type fType;
386 const SkScalar fBaseFrequencyX;
387 const SkScalar fBaseFrequencyY;
388 const int fNumOctaves;
389 const SkScalar fSeed;
390 const SkISize fTileSize;
391 const bool fStitchTiles;
392
393 friend class ::SkPerlinNoiseShader;
394
John Stiles7571f9e2020-09-02 22:42:33 -0400395 using INHERITED = SkShaderBase;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400396};
397
sugoi@google.come3b4c502013-04-05 13:47:09 +0000398namespace {
399
400// noiseValue is the color component's value (or color)
401// limitValue is the maximum perlin noise array index value allowed
402// newValue is the current noise dimension (either width or height)
403inline int checkNoise(int noiseValue, int limitValue, int newValue) {
404 // If the noise value would bring us out of bounds of the current noise array while we are
405 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
406 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
407 if (noiseValue >= limitValue) {
408 noiseValue -= newValue;
409 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000410 return noiseValue;
411}
412
413inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500414 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000415}
416
417} // end namespace
418
Mike Reedf2ae2b22017-05-30 15:22:54 -0400419SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500420 SkScalar baseFrequencyX,
421 SkScalar baseFrequencyY,
422 int numOctaves,
423 SkScalar seed,
424 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000425 : fType(type)
426 , fBaseFrequencyX(baseFrequencyX)
427 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500428 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000429 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700430 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000431 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000432{
Robert Phillipsbee27322018-01-23 09:58:18 -0500433 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400434 SkASSERT(fBaseFrequencyX >= 0);
435 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400436}
437
Florin Malita14d54c22017-05-18 11:52:59 -0400438sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500439 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500440
reed9fa60da2014-08-21 07:59:51 -0700441 SkScalar freqX = buffer.readScalar();
442 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500443 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500444
reed9fa60da2014-08-21 07:59:51 -0700445 SkScalar seed = buffer.readScalar();
446 SkISize tileSize;
447 tileSize.fWidth = buffer.readInt();
448 tileSize.fHeight = buffer.readInt();
449
450 switch (type) {
451 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400452 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700453 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400454 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
455 case kImprovedNoise_Type:
456 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700457 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500458 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500459 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700460 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700461 }
462}
463
Florin Malita14d54c22017-05-18 11:52:59 -0400464void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000465 buffer.writeInt((int) fType);
466 buffer.writeScalar(fBaseFrequencyX);
467 buffer.writeScalar(fBaseFrequencyY);
468 buffer.writeInt(fNumOctaves);
469 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000470 buffer.writeInt(fTileSize.fWidth);
471 buffer.writeInt(fTileSize.fHeight);
472}
473
Florin Malita14d54c22017-05-18 11:52:59 -0400474SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700475 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000476 struct Noise {
477 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700478 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000479 SkScalar noisePositionFractionValue;
480 Noise(SkScalar component)
481 {
482 SkScalar position = component + kPerlinNoise;
483 noisePositionIntegerValue = SkScalarFloorToInt(position);
484 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700485 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000486 }
487 };
488 Noise noiseX(noiseVector.x());
489 Noise noiseY(noiseVector.y());
490 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400491 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000492 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000493 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000494 noiseX.noisePositionIntegerValue =
495 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
496 noiseY.noisePositionIntegerValue =
497 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700498 noiseX.nextNoisePositionIntegerValue =
499 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
500 noiseY.nextNoisePositionIntegerValue =
501 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000502 }
503 noiseX.noisePositionIntegerValue &= kBlockMask;
504 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700505 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
506 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400507 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
508 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700509 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
510 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
511 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
512 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000513 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
514 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400515
Hal Canaryfda46002017-05-08 17:17:47 -0400516 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
517 return 0; // Check for pathological inputs.
518 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400519
sugoi@google.come3b4c502013-04-05 13:47:09 +0000520 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
521 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
522 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400523 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000524 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400525 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000526 SkScalar a = SkScalarInterp(u, v, sx);
527 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400528 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000529 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400530 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000531 SkScalar b = SkScalarInterp(u, v, sx);
532 return SkScalarInterp(a, b, sy);
533}
534
Florin Malita14d54c22017-05-18 11:52:59 -0400535SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700536 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400537 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000538 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000539 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400540 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000541 }
542 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400543 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
544 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000545 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000546 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700547 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700548 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
549 noise : SkScalarAbs(noise);
550 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000551 noiseVector.fX *= 2;
552 noiseVector.fY *= 2;
553 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000554 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000555 // Update stitch values
John Stiles039f6812020-08-10 09:51:42 -0400556 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
Florin Malita102c8cf2018-06-05 17:37:12 -0400557 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000558 }
559 }
560
561 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
562 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000563 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400564 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000565 }
566
567 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700568 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000569 }
570
571 // Clamp result
Brian Osmanaba642c2020-02-06 12:52:25 -0500572 return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000573}
574
Mike Reedf2ae2b22017-05-30 15:22:54 -0400575////////////////////////////////////////////////////////////////////////////////////////////////////
576// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
577static SkScalar fade(SkScalar t) {
578 return t * t * t * (t * (t * 6 - 15) + 10);
579}
580
581static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
582 return a + t * (b - a);
583}
584
585static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
586 int h = hash & 15;
587 SkScalar u = h < 8 ? x : y;
588 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
589 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
590}
591
592SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
593 int channel, const SkPoint& point) const {
594 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
595 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
596 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
597 // z offset between different channels, chosen arbitrarily
598 static const SkScalar CHANNEL_DELTA = 1000.0f;
599 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
600 SkScalar result = 0;
601 SkScalar ratio = SK_Scalar1;
602 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
603 int X = SkScalarFloorToInt(x) & 255;
604 int Y = SkScalarFloorToInt(y) & 255;
605 int Z = SkScalarFloorToInt(z) & 255;
606 SkScalar px = x - SkScalarFloorToScalar(x);
607 SkScalar py = y - SkScalarFloorToScalar(y);
608 SkScalar pz = z - SkScalarFloorToScalar(z);
609 SkScalar u = fade(px);
610 SkScalar v = fade(py);
611 SkScalar w = fade(pz);
612 uint8_t* permutations = improved_noise_permutations;
613 int A = permutations[X] + Y;
614 int AA = permutations[A] + Z;
615 int AB = permutations[A + 1] + Z;
616 int B = permutations[X + 1] + Y;
617 int BA = permutations[B] + Z;
618 int BB = permutations[B + 1] + Z;
619 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
620 grad(permutations[BA ], px - 1, py , pz )),
621 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
622 grad(permutations[BB ], px - 1, py - 1, pz ))),
623 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
624 grad(permutations[BA + 1], px - 1, py , pz - 1)),
625 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
626 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
627 ratio;
628 x *= 2;
629 y *= 2;
630 ratio *= 2;
631 }
Brian Osmanaba642c2020-02-06 12:52:25 -0500632 result = SkTPin((result + 1.0f) / 2.0f, 0.0f, 1.0f);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400633 return result;
634}
635////////////////////////////////////////////////////////////////////////////////////////////////////
636
Florin Malita14d54c22017-05-18 11:52:59 -0400637SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000638 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400639 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000640 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000641 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000642 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
643 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
644
645 U8CPU rgba[4];
646 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400647 SkScalar value;
648 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
649 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
650 }
651 else {
652 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
653 }
654 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000655 }
656 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
657}
658
Mike Reede92aae62018-10-17 10:21:51 -0400659#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400660SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400661 SkArenaAlloc* alloc) const {
Mike Reed011d1662019-02-28 17:19:25 -0500662 // should we pay attention to rec's device-colorspace?
Herb Derby83e939b2017-02-07 14:25:11 -0500663 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000664}
Mike Reede92aae62018-10-17 10:21:51 -0400665#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000666
Florin Malita83223bc2017-05-31 14:14:05 -0400667static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
668 const SkShaderBase& shader) {
669 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
670 if (rec.fLocalMatrix) {
671 matrix.preConcat(*rec.fLocalMatrix);
672 }
673
674 return matrix;
675}
676
Florin Malita14d54c22017-05-18 11:52:59 -0400677SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
678 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000679 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400680 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
681 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
682 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000683{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000684 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
685 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400686 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
687 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700688}
689
Florin Malita14d54c22017-05-18 11:52:59 -0400690void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000691 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000692 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
693 StitchData stitchData;
694 for (int i = 0; i < count; ++i) {
695 result[i] = shade(point, stitchData);
696 point.fX += SK_Scalar1;
697 }
698}
699
sugoi@google.come3b4c502013-04-05 13:47:09 +0000700/////////////////////////////////////////////////////////////////////
701
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000702#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000703
egdaniel64c47282015-11-13 06:54:19 -0800704class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000705public:
robertphillips9cdb9922016-02-03 12:25:40 -0800706 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000707
Mike Reedf2ae2b22017-05-30 15:22:54 -0400708 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000709
wangyixb1daa862015-08-18 11:29:31 -0700710protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400711 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700712
sugoi@google.com4775cba2013-04-17 13:46:56 +0000713private:
egdaniel018fb622015-10-28 07:26:40 -0700714 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700715 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700716
John Stiles7571f9e2020-09-02 22:42:33 -0400717 using INHERITED = GrGLSLFragmentProcessor;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000718};
719
720/////////////////////////////////////////////////////////////////////
721
Mike Reedf2ae2b22017-05-30 15:22:54 -0400722class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000723public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400724 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -0400725 SkPerlinNoiseShaderImpl::Type type,
726 int numOctaves,
727 bool stitchTiles,
Brian Salomonaff329b2017-08-11 09:40:37 -0400728 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400729 GrSurfaceProxyView permutationsView,
730 GrSurfaceProxyView noiseView,
731 const SkMatrix& matrix,
732 const GrCaps& caps) {
733 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
734 GrSamplerState::WrapMode::kClamp,
735 GrSamplerState::Filter::kNearest};
736 auto permutationsFP =
737 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
738 SkMatrix::I(), kRepeatXSampler, caps);
739 auto noiseFP = GrTextureEffect::Make(std::move(noiseView), kPremul_SkAlphaType,
740 SkMatrix::I(), kRepeatXSampler, caps);
741
Michael Ludwigf2935c62020-06-26 11:07:23 -0400742 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
Brian Salomon83c2d352020-06-17 11:46:21 -0400743 new GrPerlinNoise2Effect(type, numOctaves, stitchTiles, std::move(paintingData),
Michael Ludwigf2935c62020-06-26 11:07:23 -0400744 std::move(permutationsFP), std::move(noiseFP))));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000745 }
746
mtklein36352bf2015-03-25 18:17:31 -0700747 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800748
Brian Salomonaff329b2017-08-11 09:40:37 -0400749 std::unique_ptr<GrFragmentProcessor> clone() const override {
750 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400751 }
752
Mike Reedf2ae2b22017-05-30 15:22:54 -0400753 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000754
Florin Malita14d54c22017-05-18 11:52:59 -0400755 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700756 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700757 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700758 int numOctaves() const { return fNumOctaves; }
senorblancof3b50272014-06-16 10:49:58 -0700759
sugoi@google.come3b4c502013-04-05 13:47:09 +0000760private:
egdaniel57d3b032015-11-13 11:57:27 -0800761 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800762 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700763 }
764
John Stiles1cf2c8d2020-08-13 22:58:04 -0400765 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700766 GrGLPerlinNoise::GenKey(*this, caps, b);
767 }
768
mtklein36352bf2015-03-25 18:17:31 -0700769 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400770 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700771 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700772 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700773 fNumOctaves == s.fNumOctaves &&
774 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700775 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000776 }
777
Brian Salomon83c2d352020-06-17 11:46:21 -0400778 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type,
779 int numOctaves,
780 bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400781 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400782 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -0400783 std::unique_ptr<GrFragmentProcessor> noiseFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400784 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500785 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500786 , fNumOctaves(numOctaves)
787 , fStitchTiles(stitchTiles)
Florin Malitab365cf52017-05-30 17:18:01 -0400788 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -0400789 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
790 this->registerChild(std::move(noiseFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -0400791 this->setUsesSampleCoordsDirectly();
sugoi@google.come3b4c502013-04-05 13:47:09 +0000792 }
793
Brian Salomon4331e462017-07-26 14:58:11 -0400794 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400795 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400796 , fType(that.fType)
Brian Salomon4331e462017-07-26 14:58:11 -0400797 , fNumOctaves(that.fNumOctaves)
798 , fStitchTiles(that.fStitchTiles)
Brian Salomon4331e462017-07-26 14:58:11 -0400799 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -0400800 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -0400801 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -0400802 }
803
Brian Salomonf7dcd762018-07-30 14:48:15 -0400804
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400805 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000806
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400807 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400808 int fNumOctaves;
809 bool fStitchTiles;
Brian Salomon83c2d352020-06-17 11:46:21 -0400810
Florin Malitab365cf52017-05-30 17:18:01 -0400811 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000812
John Stiles7571f9e2020-09-02 22:42:33 -0400813 using INHERITED = GrFragmentProcessor;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000814};
815
816/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400817GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000818
Hal Canary6f6961e2017-01-31 13:50:44 -0500819#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400820std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700821 int numOctaves = d->fRandom->nextRangeU(2, 10);
822 bool stitchTiles = d->fRandom->nextBool();
823 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
824 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
825 d->fRandom->nextRangeU(4, 4096));
826 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
827 0.99f);
828 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
829 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000830
reedfe630452016-03-25 09:08:00 -0700831 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
832 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400833 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700834 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400835 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000836
Brian Osman9f532a32016-10-19 11:12:09 -0400837 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400838 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000839}
Hal Canary6f6961e2017-01-31 13:50:44 -0500840#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000841
wangyix7c157a92015-07-22 15:08:53 -0700842void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400843 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800844
Brian Salomonffd15ea2020-07-01 16:48:20 -0400845 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800846 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000847
Ethan Nicholas16464c32020-04-06 13:53:05 -0400848 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800849 "baseFrequency");
850 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000851
halcanary96fcdcc2015-08-27 07:41:13 -0700852 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800853 if (pne.stitchTiles()) {
Ethan Nicholas16464c32020-04-06 13:53:05 -0400854 fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800855 "stitchData");
856 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000857 }
858
sugoi@google.comd537af52013-06-10 13:59:25 +0000859 // Add noise function
Brian Salomone338c292020-06-16 16:52:17 -0400860 const GrShaderVar gPerlinNoiseArgs[] = {{"chanCoord", kHalf_GrSLType },
861 {"noiseVec ", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000862
Brian Salomone338c292020-06-16 16:52:17 -0400863 const GrShaderVar gPerlinNoiseStitchArgs[] = {{"chanCoord" , kHalf_GrSLType },
864 {"noiseVec" , kHalf2_GrSLType},
865 {"stitchData", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000866
sugoi@google.comd537af52013-06-10 13:59:25 +0000867 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000868
Brian Salomone338c292020-06-16 16:52:17 -0400869 noiseCode.append(
870 R"(half4 floorVal;
871 floorVal.xy = floor(noiseVec);
872 floorVal.zw = floorVal.xy + half2(1);
873 half2 fractVal = fract(noiseVec);
874 // smooth curve : t^2*(3 - 2*t)
875 half2 noiseSmooth = fractVal*fractVal*(half2(3) - 2*fractVal);)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000876
877 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800878 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400879 noiseCode.append(
880 R"(if (floorVal.x >= stitchData.x) { floorVal.x -= stitchData.x; };
881 if (floorVal.y >= stitchData.y) { floorVal.y -= stitchData.y; };
882 if (floorVal.z >= stitchData.x) { floorVal.z -= stitchData.x; };
883 if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000884 }
885
Brian Osman6b5dbb42020-07-15 15:31:05 -0400886 // NOTE: We need to explicitly pass half4(1) as input color here, because the helper function
887 // can't see fInputColor (which is "_input" in the FP's outer function). skbug.com/10506
888 SkString sampleX = this->invokeChild(0, "half4(1)", args, "half2(floorVal.x, 0.5)");
889 SkString sampleY = this->invokeChild(0, "half4(1)", args, "half2(floorVal.z, 0.5)");
Brian Salomonb43d6992021-01-05 14:37:40 -0500890 noiseCode.appendf("half2 latticeIdx = half2(%s.a, %s.a);", sampleX.c_str(), sampleY.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000891
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000892#if defined(SK_BUILD_FOR_ANDROID)
893 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
894 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
895 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
896 // (or 0.484368 here). The following rounding operation prevents these precision issues from
897 // affecting the result of the noise by making sure that we only have multiples of 1/255.
898 // (Note that 1/255 is about 0.003921569, which is the value used here).
Brian Salomone338c292020-06-16 16:52:17 -0400899 noiseCode.append(
900 "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);");
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000901#endif
902
sugoi@google.come3b4c502013-04-05 13:47:09 +0000903 // Get (x,y) coordinates with the permutated x
Brian Salomon83c2d352020-06-17 11:46:21 -0400904 noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000905
Brian Salomone338c292020-06-16 16:52:17 -0400906 noiseCode.append("half2 uv;");
907
908 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
909 // [-1,1] vector and perform a dot product between that vector and the provided vector.
910 // Save it as a string because we will repeat it 4x.
911 static constexpr const char* inc8bit = "0.00390625"; // 1.0 / 256.0
912 SkString dotLattice =
913 SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
914
Brian Osman6b5dbb42020-07-15 15:31:05 -0400915 SkString sampleA = this->invokeChild(1, "half4(1)", args, "half2(bcoords.x, chanCoord)");
916 SkString sampleB = this->invokeChild(1, "half4(1)", args, "half2(bcoords.y, chanCoord)");
917 SkString sampleC = this->invokeChild(1, "half4(1)", args, "half2(bcoords.w, chanCoord)");
918 SkString sampleD = this->invokeChild(1, "half4(1)", args, "half2(bcoords.z, chanCoord)");
Brian Salomon83c2d352020-06-17 11:46:21 -0400919
sugoi@google.come3b4c502013-04-05 13:47:09 +0000920 // Compute u, at offset (0,0)
Brian Salomon83c2d352020-06-17 11:46:21 -0400921 noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
922 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000923
sugoi@google.come3b4c502013-04-05 13:47:09 +0000924 // Compute v, at offset (-1,0)
Brian Salomone338c292020-06-16 16:52:17 -0400925 noiseCode.append("fractVal.x -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400926 noiseCode.appendf("lattice = %s;", sampleB.c_str());
927 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000928
929 // Compute 'a' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400930 noiseCode.append("half2 ab;");
931 noiseCode.append("ab.x = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000932
sugoi@google.come3b4c502013-04-05 13:47:09 +0000933 // Compute v, at offset (-1,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400934 noiseCode.append("fractVal.y -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400935 noiseCode.appendf("lattice = %s;", sampleC.c_str());
936 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000937
sugoi@google.come3b4c502013-04-05 13:47:09 +0000938 // Compute u, at offset (0,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400939 noiseCode.append("fractVal.x += 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400940 noiseCode.appendf("lattice = %s;", sampleD.c_str());
941 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000942
943 // Compute 'b' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400944 noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000945 // Compute the noise as a linear interpolation of 'a' and 'b'
Brian Salomone338c292020-06-16 16:52:17 -0400946 noiseCode.append("return mix(ab.x, ab.y, noiseSmooth.y);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000947
John Stiles6b58a332020-10-26 17:53:06 -0400948 SkString noiseFuncName = fragBuilder->getMangledFunctionName("noiseFuncName");
robertphillipsbf536af2016-02-04 06:11:53 -0800949 if (pne.stitchTiles()) {
John Stiles6b58a332020-10-26 17:53:06 -0400950 fragBuilder->emitFunction(kHalf_GrSLType, noiseFuncName.c_str(),
John Stilesfdf61482020-10-27 09:45:40 -0400951 {gPerlinNoiseStitchArgs, SK_ARRAY_COUNT(gPerlinNoiseStitchArgs)},
John Stiles6b58a332020-10-26 17:53:06 -0400952 noiseCode.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000953 } else {
John Stiles6b58a332020-10-26 17:53:06 -0400954 fragBuilder->emitFunction(kHalf_GrSLType, noiseFuncName.c_str(),
John Stilesfdf61482020-10-27 09:45:40 -0400955 {gPerlinNoiseArgs, SK_ARRAY_COUNT(gPerlinNoiseArgs)},
John Stiles6b58a332020-10-26 17:53:06 -0400956 noiseCode.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000957 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000958
sugoi@google.comd537af52013-06-10 13:59:25 +0000959 // There are rounding errors if the floor operation is not performed here
Brian Salomone338c292020-06-16 16:52:17 -0400960 fragBuilder->codeAppendf("half2 noiseVec = half2(floor(%s.xy) * %s);",
Michael Ludwige88320b2020-06-24 09:04:56 -0400961 args.fSampleCoord, baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000962
963 // Clear the color accumulator
John Stilesd1eab8b2020-12-15 09:47:26 -0500964 fragBuilder->codeAppendf("half4 color = half4(0);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000965
robertphillipsbf536af2016-02-04 06:11:53 -0800966 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +0000967 // Set up TurbulenceInitial stitch values.
Brian Salomone338c292020-06-16 16:52:17 -0400968 fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000969 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000970
Brian Salomone338c292020-06-16 16:52:17 -0400971 fragBuilder->codeAppendf("half ratio = 1.0;");
sugoi@google.comd537af52013-06-10 13:59:25 +0000972
973 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -0800974 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
John Stilesd1eab8b2020-12-15 09:47:26 -0500975 fragBuilder->codeAppendf(" color += ");
Florin Malita14d54c22017-05-18 11:52:59 -0400976 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -0800977 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +0000978 }
Brian Salomone338c292020-06-16 16:52:17 -0400979
Brian Salomon83c2d352020-06-17 11:46:21 -0400980 // There are 4 lines, put y coords at center of each.
981 static constexpr const char* chanCoordR = "0.5";
982 static constexpr const char* chanCoordG = "1.5";
983 static constexpr const char* chanCoordB = "2.5";
984 static constexpr const char* chanCoordA = "3.5";
robertphillipsbf536af2016-02-04 06:11:53 -0800985 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400986 fragBuilder->codeAppendf(R"(
987 half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),"
988 %s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)))",
989 noiseFuncName.c_str(), chanCoordR,
990 noiseFuncName.c_str(), chanCoordG,
991 noiseFuncName.c_str(), chanCoordB,
992 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000993 } else {
Brian Salomone338c292020-06-16 16:52:17 -0400994 fragBuilder->codeAppendf(R"(
995 half4(%s(%s, noiseVec), %s(%s, noiseVec),
996 %s(%s, noiseVec), %s(%s, noiseVec)))",
997 noiseFuncName.c_str(), chanCoordR,
998 noiseFuncName.c_str(), chanCoordG,
999 noiseFuncName.c_str(), chanCoordB,
1000 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +00001001 }
Florin Malita14d54c22017-05-18 11:52:59 -04001002 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
Brian Salomone338c292020-06-16 16:52:17 -04001003 fragBuilder->codeAppend(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001004 }
Brian Salomone338c292020-06-16 16:52:17 -04001005 fragBuilder->codeAppend(" * ratio;");
sugoi@google.comd537af52013-06-10 13:59:25 +00001006
Brian Salomone338c292020-06-16 16:52:17 -04001007 fragBuilder->codeAppend(R"(noiseVec *= half2(2.0);
1008 ratio *= 0.5;)");
sugoi@google.comd537af52013-06-10 13:59:25 +00001009
robertphillipsbf536af2016-02-04 06:11:53 -08001010 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -04001011 fragBuilder->codeAppend("stitchData *= half2(2.0);");
sugoi@google.comd537af52013-06-10 13:59:25 +00001012 }
Brian Salomone338c292020-06-16 16:52:17 -04001013 fragBuilder->codeAppend("}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001014
Florin Malita14d54c22017-05-18 11:52:59 -04001015 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001016 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1017 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
John Stilesd1eab8b2020-12-15 09:47:26 -05001018 fragBuilder->codeAppendf("color = color * half4(0.5) + half4(0.5);");
sugoi@google.come3b4c502013-04-05 13:47:09 +00001019 }
1020
sugoi@google.come3b4c502013-04-05 13:47:09 +00001021 // Clamp values
John Stilesd1eab8b2020-12-15 09:47:26 -05001022 fragBuilder->codeAppendf("color = saturate(color);");
sugoi@google.come3b4c502013-04-05 13:47:09 +00001023
1024 // Pre-multiply the result
John Stilesd1eab8b2020-12-15 09:47:26 -05001025 fragBuilder->codeAppendf("return half4(color.rgb * color.aaa, color.a);");
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
John Stiles7571f9e2020-09-02 22:42:33 -04001086 using INHERITED = GrGLSLFragmentProcessor;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001087};
1088
1089/////////////////////////////////////////////////////////////////////
1090
1091class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1092public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001093 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -04001094 int octaves,
1095 SkScalar z,
Brian Salomonaff329b2017-08-11 09:40:37 -04001096 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001097 GrSurfaceProxyView permutationsView,
1098 GrSurfaceProxyView gradientView,
1099 const SkMatrix& matrix,
1100 const GrCaps& caps) {
1101 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
1102 GrSamplerState::WrapMode::kClamp,
1103 GrSamplerState::Filter::kNearest};
1104 auto permutationsFP =
1105 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
1106 SkMatrix::I(), kRepeatXSampler, caps);
1107 auto gradientFP = GrTextureEffect::Make(std::move(gradientView), kPremul_SkAlphaType,
1108 SkMatrix::I(), kRepeatXSampler, caps);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001109 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
1110 new GrImprovedPerlinNoiseEffect(octaves, z, std::move(paintingData),
1111 std::move(permutationsFP),
1112 std::move(gradientFP))));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001113 }
1114
Mike Reedf2ae2b22017-05-30 15:22:54 -04001115 const char* name() const override { return "ImprovedPerlinNoise"; }
1116
Brian Salomonaff329b2017-08-11 09:40:37 -04001117 std::unique_ptr<GrFragmentProcessor> clone() const override {
1118 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001119 }
1120
Mike Reedf2ae2b22017-05-30 15:22:54 -04001121 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1122 SkScalar z() const { return fZ; }
1123 int octaves() const { return fOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001124
1125private:
1126 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1127 return new GrGLImprovedPerlinNoise;
1128 }
1129
1130 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1131 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1132 }
1133
1134 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
John Stiles24a7f072020-08-07 15:59:42 -04001135 const GrImprovedPerlinNoiseEffect& that = sBase.cast<GrImprovedPerlinNoiseEffect>();
1136 return this->z() == that.z() &&
1137 this->octaves() == that.octaves() &&
1138 this->baseFrequency() == that.baseFrequency();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001139 }
1140
Brian Salomon83c2d352020-06-17 11:46:21 -04001141 GrImprovedPerlinNoiseEffect(int octaves,
1142 SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001143 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001144 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -04001145 std::unique_ptr<GrFragmentProcessor> gradientFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001146 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001147 , fOctaves(octaves)
1148 , fZ(z)
Florin Malitab365cf52017-05-30 17:18:01 -04001149 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -04001150 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
1151 this->registerChild(std::move(gradientFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -04001152 this->setUsesSampleCoordsDirectly();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001153 }
1154
Brian Salomon4331e462017-07-26 14:58:11 -04001155 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001156 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001157 , fOctaves(that.fOctaves)
1158 , fZ(that.fZ)
John Stiles24a7f072020-08-07 15:59:42 -04001159 , fPaintingData(std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(
1160 *that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -04001161 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001162 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -04001163 }
1164
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001165 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001166
Mike Reedf2ae2b22017-05-30 15:22:54 -04001167 int fOctaves;
1168 SkScalar fZ;
Brian Salomon83c2d352020-06-17 11:46:21 -04001169
Florin Malitab365cf52017-05-30 17:18:01 -04001170 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001171
John Stiles7571f9e2020-09-02 22:42:33 -04001172 using INHERITED = GrFragmentProcessor;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001173};
1174
1175/////////////////////////////////////////////////////////////////////
1176GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1177
1178#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001179std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1180 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001181 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1182 0.99f);
1183 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1184 0.99f);
1185 int numOctaves = d->fRandom->nextRangeU(2, 10);
1186 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1187
1188 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
John Stiles24a7f072020-08-07 15:59:42 -04001189 baseFrequencyY,
1190 numOctaves,
1191 z));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001192
1193 GrTest::TestAsFPArgs asFPArgs(d);
1194 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1195}
1196#endif
1197
1198void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001199 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Brian Salomonffd15ea2020-07-01 16:48:20 -04001200 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001201 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001202
Ethan Nicholas16464c32020-04-06 13:53:05 -04001203 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001204 "baseFrequency");
1205 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1206
Ethan Nicholas16464c32020-04-06 13:53:05 -04001207 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001208 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1209
1210 // fade function
John Stiles6b58a332020-10-26 17:53:06 -04001211 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001212 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001213 };
John Stiles6b58a332020-10-26 17:53:06 -04001214 SkString fadeFuncName = fragBuilder->getMangledFunctionName("fade");
1215 fragBuilder->emitFunction(kHalf3_GrSLType, fadeFuncName.c_str(),
John Stilesfdf61482020-10-27 09:45:40 -04001216 {fadeArgs, SK_ARRAY_COUNT(fadeArgs)},
John Stiles6b58a332020-10-26 17:53:06 -04001217 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001218
1219 // perm function
John Stiles6b58a332020-10-26 17:53:06 -04001220 const GrShaderVar permArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001221 {"x", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001222 };
Brian Osman6b5dbb42020-07-15 15:31:05 -04001223 SkString samplePerm = this->invokeChild(0, "half4(1)", args, "float2(x, 0.5)");
John Stiles6b58a332020-10-26 17:53:06 -04001224 SkString permFuncName = fragBuilder->getMangledFunctionName("perm");
John Stiles9730dc42021-01-06 23:30:09 +00001225 SkString permCode = SkStringPrintf("return %s.r * 255;", samplePerm.c_str());
John Stilesfdf61482020-10-27 09:45:40 -04001226 fragBuilder->emitFunction(kHalf_GrSLType, permFuncName.c_str(),
1227 {permArgs, SK_ARRAY_COUNT(permArgs)}, permCode.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001228
1229 // grad function
John Stiles6b58a332020-10-26 17:53:06 -04001230 const GrShaderVar gradArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001231 {"x", kHalf_GrSLType},
1232 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001233 };
Brian Osman6b5dbb42020-07-15 15:31:05 -04001234 SkString sampleGrad = this->invokeChild(1, "half4(1)", args, "float2(x, 0.5)");
John Stiles6b58a332020-10-26 17:53:06 -04001235 SkString gradFuncName = fragBuilder->getMangledFunctionName("grad");
Brian Salomon83c2d352020-06-17 11:46:21 -04001236 SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));",
1237 sampleGrad.c_str());
John Stilesfdf61482020-10-27 09:45:40 -04001238 fragBuilder->emitFunction(kHalf_GrSLType, gradFuncName.c_str(),
1239 {gradArgs, SK_ARRAY_COUNT(gradArgs)}, gradCode.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001240
1241 // lerp function
John Stiles6b58a332020-10-26 17:53:06 -04001242 const GrShaderVar lerpArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001243 {"a", kHalf_GrSLType},
1244 {"b", kHalf_GrSLType},
1245 {"w", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001246 };
John Stiles6b58a332020-10-26 17:53:06 -04001247 SkString lerpFuncName = fragBuilder->getMangledFunctionName("lerp");
John Stilesfdf61482020-10-27 09:45:40 -04001248 fragBuilder->emitFunction(kHalf_GrSLType, lerpFuncName.c_str(),
1249 {lerpArgs, SK_ARRAY_COUNT(lerpArgs)}, "return a + w * (b - a);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001250
1251 // noise function
Brian Salomon83c2d352020-06-17 11:46:21 -04001252 const GrShaderVar noiseArgs[] = {
1253 {"p", kHalf3_GrSLType},
Mike Reedf2ae2b22017-05-30 15:22:54 -04001254 };
John Stiles6b58a332020-10-26 17:53:06 -04001255 SkString noiseFuncName = fragBuilder->getMangledFunctionName("noise");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001256 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001257 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001258 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001259 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1260 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1261 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1262 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1263 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1264 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1265 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1266 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001267 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1268 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001269 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 -04001270 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001271 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
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(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001274 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001275 noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001276 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1277 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001278 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001279 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001280 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001281 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001282 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 -04001283 gradFuncName.c_str(), permFuncName.c_str());
1284 noiseCode.append("return result;");
John Stilesfdf61482020-10-27 09:45:40 -04001285 fragBuilder->emitFunction(kHalf_GrSLType, noiseFuncName.c_str(),
1286 {noiseArgs, SK_ARRAY_COUNT(noiseArgs)}, noiseCode.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001287
1288 // noiseOctaves function
John Stiles6b58a332020-10-26 17:53:06 -04001289 const GrShaderVar noiseOctavesArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001290 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001291 };
John Stiles6b58a332020-10-26 17:53:06 -04001292 SkString noiseOctavesFuncName = fragBuilder->getMangledFunctionName("noiseOctaves");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001293 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001294 noiseOctavesCode.append("half result = 0.0;");
1295 noiseOctavesCode.append("half ratio = 1.0;");
1296 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001297 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1298 noiseOctavesCode.append("p *= 2.0;");
1299 noiseOctavesCode.append("ratio *= 2.0;");
1300 noiseOctavesCode.append("}");
1301 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
John Stiles6b58a332020-10-26 17:53:06 -04001302 fragBuilder->emitFunction(kHalf_GrSLType, noiseOctavesFuncName.c_str(),
John Stilesfdf61482020-10-27 09:45:40 -04001303 {noiseOctavesArgs, SK_ARRAY_COUNT(noiseOctavesArgs)},
John Stiles6b58a332020-10-26 17:53:06 -04001304 noiseOctavesCode.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001305
Michael Ludwige88320b2020-06-24 09:04:56 -04001306 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", args.fSampleCoord, baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001307 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001308 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001309 fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001310 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001311 fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001312 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001313 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001314 noiseOctavesFuncName.c_str(), zUni);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001315
1316 // Clamp values
John Stilesd1eab8b2020-12-15 09:47:26 -05001317 fragBuilder->codeAppendf("half4 color = saturate(half4(r, g, b, a));");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001318
1319 // Pre-multiply the result
John Stilesd1eab8b2020-12-15 09:47:26 -05001320 fragBuilder->codeAppendf("return half4(color.rgb * color.aaa, color.a);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001321}
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 Stiles85894302020-07-13 11:39:52 -04001390 auto inner = GrFragmentProcessor::ModulateRGBA(
1391 /*child=*/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}