blob: c16d99fbf82b6a7ac6909de2d7a58db2db97f246 [file] [log] [blame]
sugoi@google.come3b4c502013-04-05 13:47:09 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/effects/SkPerlinNoiseShader.h"
Herb Derby83e939b2017-02-07 14:25:11 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkColorFilter.h"
11#include "include/core/SkShader.h"
12#include "include/core/SkString.h"
13#include "include/core/SkUnPreMultiply.h"
Ben Wagner729a23f2019-05-17 16:29:34 -040014#include "src/core/SkArenaAlloc.h"
Brian Osman449b1152020-04-15 16:43:00 -040015#include "src/core/SkMatrixProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/core/SkReadBuffer.h"
17#include "src/core/SkWriteBuffer.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000018
19#if SK_SUPPORT_GPU
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040020#include "include/gpu/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/GrRecordingContextPriv.h"
22#include "src/gpu/SkGr.h"
Michael Ludwigf2935c62020-06-26 11:07:23 -040023#include "src/gpu/effects/GrMatrixEffect.h"
Brian Salomon83c2d352020-06-17 11:46:21 -040024#include "src/gpu/effects/GrTextureEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/effects/generated/GrConstColorProcessor.h"
26#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
27#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
28#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
29#include "src/gpu/glsl/GrGLSLUniformHandler.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000030#endif
31
32static const int kBlockSize = 256;
33static const int kBlockMask = kBlockSize - 1;
34static const int kPerlinNoise = 4096;
35static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
36
Mike Reedf2ae2b22017-05-30 15:22:54 -040037static uint8_t improved_noise_permutations[] = {
38 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
39 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
40 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
41 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
42 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
43 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
44 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
45 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
46 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
47 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
48 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
49 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
50 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
51 141, 128, 195, 78, 66, 215, 61, 156, 180,
52 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
53 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
54 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
55 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
56 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
57 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
58 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
59 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
60 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
61 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
62 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
63 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
64 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
65 141, 128, 195, 78, 66, 215, 61, 156, 180
66};
67
68class SkPerlinNoiseShaderImpl : public SkShaderBase {
69public:
Florin Malita83223bc2017-05-31 14:14:05 -040070 struct StitchData {
71 StitchData()
72 : fWidth(0)
73 , fWrapX(0)
74 , fHeight(0)
75 , fWrapY(0)
76 {}
77
Florin Malita102c8cf2018-06-05 17:37:12 -040078 StitchData(SkScalar w, SkScalar h)
Brian Osman788b9162020-02-07 10:36:46 -050079 : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040080 , fWrapX(kPerlinNoise + fWidth)
Brian Osman788b9162020-02-07 10:36:46 -050081 , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040082 , fWrapY(kPerlinNoise + fHeight) {}
83
Florin Malita83223bc2017-05-31 14:14:05 -040084 bool operator==(const StitchData& other) const {
85 return fWidth == other.fWidth &&
86 fWrapX == other.fWrapX &&
87 fHeight == other.fHeight &&
88 fWrapY == other.fWrapY;
89 }
90
91 int fWidth; // How much to subtract to wrap for stitching.
92 int fWrapX; // Minimum value to wrap.
93 int fHeight;
94 int fWrapY;
95 };
96
97 struct PaintingData {
98 PaintingData(const SkISize& tileSize, SkScalar seed,
99 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
100 const SkMatrix& matrix)
101 {
Ethan Nicholas82940152019-01-10 13:58:14 -0500102 SkVector tileVec;
103 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
104 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -0400105
Ethan Nicholas82940152019-01-10 13:58:14 -0500106 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -0500107 if (!matrix.decomposeScale(&scale, nullptr)) {
108 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
109 }
Ethan Nicholas82940152019-01-10 13:58:14 -0500110 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
111 baseFrequencyY * SkScalarInvert(scale.height()));
112 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -0400113 this->init(seed);
114 if (!fTileSize.isEmpty()) {
115 this->stitch();
116 }
117
118 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -0500119 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500120 fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
121 fPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400122
Brian Salomona3a9da72020-06-17 10:52:19 -0400123 info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500124 fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
125 fNoiseBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400126
Greg Daniel7e1912a2018-02-08 09:15:33 -0500127 info = SkImageInfo::MakeA8(256, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500128 fImprovedPermutationsBitmap.installPixels(info, improved_noise_permutations,
129 info.minRowBytes());
130 fImprovedPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400131
Florin Malita83223bc2017-05-31 14:14:05 -0400132 static uint8_t gradients[] = { 2, 2, 1, 0,
133 0, 2, 1, 0,
134 2, 0, 1, 0,
135 0, 0, 1, 0,
136 2, 1, 2, 0,
137 0, 1, 2, 0,
138 2, 1, 0, 0,
139 0, 1, 0, 0,
140 1, 2, 2, 0,
141 1, 0, 2, 0,
142 1, 2, 0, 0,
143 1, 0, 0, 0,
144 2, 2, 1, 0,
145 1, 0, 2, 0,
146 0, 2, 1, 0,
147 1, 0, 0, 0 };
Brian Salomona3a9da72020-06-17 10:52:19 -0400148 info = SkImageInfo::Make(16, 1, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -0500149 fGradientBitmap.installPixels(info, gradients, info.minRowBytes());
150 fGradientBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -0400151 #endif
152 }
153
Brian Salomon4331e462017-07-26 14:58:11 -0400154 #if SK_SUPPORT_GPU
155 PaintingData(const PaintingData& that)
156 : fSeed(that.fSeed)
157 , fTileSize(that.fTileSize)
158 , fBaseFrequency(that.fBaseFrequency)
159 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel6f5441a2020-01-28 17:02:49 -0500160 , fPermutationsBitmap(that.fPermutationsBitmap)
161 , fNoiseBitmap(that.fNoiseBitmap)
162 , fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
163 , fGradientBitmap(that.fGradientBitmap) {
Brian Salomon4331e462017-07-26 14:58:11 -0400164 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
165 memcpy(fNoise, that.fNoise, sizeof(fNoise));
166 memcpy(fGradient, that.fGradient, sizeof(fGradient));
167 }
168 #endif
169
Florin Malita83223bc2017-05-31 14:14:05 -0400170 int fSeed;
171 uint8_t fLatticeSelector[kBlockSize];
172 uint16_t fNoise[4][kBlockSize][2];
173 SkPoint fGradient[4][kBlockSize];
174 SkISize fTileSize;
175 SkVector fBaseFrequency;
176 StitchData fStitchDataInit;
177
178 private:
179
180 #if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500181 SkBitmap fPermutationsBitmap;
182 SkBitmap fNoiseBitmap;
183 SkBitmap fImprovedPermutationsBitmap;
184 SkBitmap fGradientBitmap;
Florin Malita83223bc2017-05-31 14:14:05 -0400185 #endif
186
187 inline int random() {
John Stiles039f6812020-08-10 09:51:42 -0400188 // See https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
189 // m = kRandMaximum, 2**31 - 1 (2147483647)
190 static constexpr int kRandAmplitude = 16807; // 7**5; primitive root of m
191 static constexpr int kRandQ = 127773; // m / a
192 static constexpr int kRandR = 2836; // m % a
Florin Malita83223bc2017-05-31 14:14:05 -0400193
John Stiles039f6812020-08-10 09:51:42 -0400194 int result = kRandAmplitude * (fSeed % kRandQ) - kRandR * (fSeed / kRandQ);
195 if (result <= 0) {
Florin Malita83223bc2017-05-31 14:14:05 -0400196 result += kRandMaximum;
John Stiles039f6812020-08-10 09:51:42 -0400197 }
Florin Malita83223bc2017-05-31 14:14:05 -0400198 fSeed = result;
199 return result;
200 }
201
202 // Only called once. Could be part of the constructor.
203 void init(SkScalar seed)
204 {
Florin Malita83223bc2017-05-31 14:14:05 -0400205 // 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
John Stiles039f6812020-08-10 09:51:42 -0400252 static constexpr SkScalar kHalfMax16bits = 32767.5f;
Florin Malita83223bc2017-05-31 14:14:05 -0400253
254 // Compute gradients from permutated noise data
John Stiles039f6812020-08-10 09:51:42 -0400255 static constexpr SkScalar kInvBlockSizef = 1.0 / SkIntToScalar(kBlockSize);
Florin Malita83223bc2017-05-31 14:14:05 -0400256 for (int channel = 0; channel < 4; ++channel) {
257 for (int i = 0; i < kBlockSize; ++i) {
258 fGradient[channel][i] = SkPoint::Make(
John Stiles039f6812020-08-10 09:51:42 -0400259 (fNoise[channel][i][0] - kBlockSize) * kInvBlockSizef,
260 (fNoise[channel][i][1] - kBlockSize) * kInvBlockSizef);
Florin Malita83223bc2017-05-31 14:14:05 -0400261 fGradient[channel][i].normalize();
262 // Put the normalized gradient back into the noise data
John Stiles039f6812020-08-10 09:51:42 -0400263 fNoise[channel][i][0] =
264 SkScalarRoundToInt((fGradient[channel][i].fX + 1) * kHalfMax16bits);
265 fNoise[channel][i][1] =
266 SkScalarRoundToInt((fGradient[channel][i].fY + 1) * kHalfMax16bits);
Florin Malita83223bc2017-05-31 14:14:05 -0400267 }
268 }
269 }
270
271 // Only called once. Could be part of the constructor.
272 void stitch() {
273 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
274 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
275 SkASSERT(tileWidth > 0 && tileHeight > 0);
276 // When stitching tiled turbulence, the frequencies must be adjusted
277 // so that the tile borders will be continuous.
278 if (fBaseFrequency.fX) {
279 SkScalar lowFrequencx =
280 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
281 SkScalar highFrequencx =
282 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
283 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400284 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
285 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400286 fBaseFrequency.fX = lowFrequencx;
287 } else {
288 fBaseFrequency.fX = highFrequencx;
289 }
290 }
291 if (fBaseFrequency.fY) {
292 SkScalar lowFrequency =
293 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
294 SkScalar highFrequency =
295 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400296 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
297 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400298 fBaseFrequency.fY = lowFrequency;
299 } else {
300 fBaseFrequency.fY = highFrequency;
301 }
302 }
303 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400304 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
305 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400306 }
307
308 public:
309
310#if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500311 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400312
Greg Daniel6f5441a2020-01-28 17:02:49 -0500313 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400314
Greg Daniel6f5441a2020-01-28 17:02:49 -0500315 const SkBitmap& getImprovedPermutationsBitmap() const {
316 return fImprovedPermutationsBitmap;
Greg Daniel7e1912a2018-02-08 09:15:33 -0500317 }
Florin Malita83223bc2017-05-31 14:14:05 -0400318
Greg Daniel6f5441a2020-01-28 17:02:49 -0500319 const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400320#endif
321 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400322
323 /**
324 * About the noise types : the difference between the first 2 is just minor tweaks to the
325 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
326 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
327 * doing :
328 * kFractalNoise_Type : noise * 0.5 + 0.5
329 * kTurbulence_Type : abs(noise)
330 * Very little differences between the 2 types, although you can tell the difference visually.
331 * "Improved" is based on the Improved Perlin Noise algorithm described at
332 * http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
333 * a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
334 * changes to the noise, making it suitable for animated noise.
335 */
336 enum Type {
337 kFractalNoise_Type,
338 kTurbulence_Type,
339 kImprovedNoise_Type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500340 kLast_Type = kImprovedNoise_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400341 };
342
Robert Phillipsbee27322018-01-23 09:58:18 -0500343 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
344
Mike Reedf2ae2b22017-05-30 15:22:54 -0400345 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
346 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
347 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400348
349 class PerlinNoiseShaderContext : public Context {
350 public:
351 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400352
353 void shadeSpan(int x, int y, SkPMColor[], int count) override;
354
355 private:
356 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
357 SkScalar calculateTurbulenceValueForPoint(
358 int channel,
359 StitchData& stitchData, const SkPoint& point) const;
360 SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
361 SkScalar noise2D(int channel,
362 const StitchData& stitchData, const SkPoint& noiseVector) const;
363
Florin Malita83223bc2017-05-31 14:14:05 -0400364 SkMatrix fMatrix;
365 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400366
367 typedef Context INHERITED;
368 };
369
370#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500371 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400372#endif
373
Mike Reedf2ae2b22017-05-30 15:22:54 -0400374protected:
375 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400376#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400377 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400378#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400379
380private:
Mike Klein4fee3232018-10-18 17:27:16 -0400381 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
382
Mike Reedf2ae2b22017-05-30 15:22:54 -0400383 const SkPerlinNoiseShaderImpl::Type fType;
384 const SkScalar fBaseFrequencyX;
385 const SkScalar fBaseFrequencyY;
386 const int fNumOctaves;
387 const SkScalar fSeed;
388 const SkISize fTileSize;
389 const bool fStitchTiles;
390
391 friend class ::SkPerlinNoiseShader;
392
393 typedef SkShaderBase INHERITED;
394};
395
sugoi@google.come3b4c502013-04-05 13:47:09 +0000396namespace {
397
398// noiseValue is the color component's value (or color)
399// limitValue is the maximum perlin noise array index value allowed
400// newValue is the current noise dimension (either width or height)
401inline int checkNoise(int noiseValue, int limitValue, int newValue) {
402 // If the noise value would bring us out of bounds of the current noise array while we are
403 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
404 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
405 if (noiseValue >= limitValue) {
406 noiseValue -= newValue;
407 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000408 return noiseValue;
409}
410
411inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500412 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000413}
414
415} // end namespace
416
Mike Reedf2ae2b22017-05-30 15:22:54 -0400417SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500418 SkScalar baseFrequencyX,
419 SkScalar baseFrequencyY,
420 int numOctaves,
421 SkScalar seed,
422 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000423 : fType(type)
424 , fBaseFrequencyX(baseFrequencyX)
425 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500426 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000427 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700428 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000429 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000430{
Robert Phillipsbee27322018-01-23 09:58:18 -0500431 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400432 SkASSERT(fBaseFrequencyX >= 0);
433 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400434}
435
Florin Malita14d54c22017-05-18 11:52:59 -0400436sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500437 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500438
reed9fa60da2014-08-21 07:59:51 -0700439 SkScalar freqX = buffer.readScalar();
440 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500441 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500442
reed9fa60da2014-08-21 07:59:51 -0700443 SkScalar seed = buffer.readScalar();
444 SkISize tileSize;
445 tileSize.fWidth = buffer.readInt();
446 tileSize.fHeight = buffer.readInt();
447
448 switch (type) {
449 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400450 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700451 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400452 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
453 case kImprovedNoise_Type:
454 return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
reed9fa60da2014-08-21 07:59:51 -0700455 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500456 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500457 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700458 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700459 }
460}
461
Florin Malita14d54c22017-05-18 11:52:59 -0400462void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000463 buffer.writeInt((int) fType);
464 buffer.writeScalar(fBaseFrequencyX);
465 buffer.writeScalar(fBaseFrequencyY);
466 buffer.writeInt(fNumOctaves);
467 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000468 buffer.writeInt(fTileSize.fWidth);
469 buffer.writeInt(fTileSize.fHeight);
470}
471
Florin Malita14d54c22017-05-18 11:52:59 -0400472SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700473 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000474 struct Noise {
475 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700476 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000477 SkScalar noisePositionFractionValue;
478 Noise(SkScalar component)
479 {
480 SkScalar position = component + kPerlinNoise;
481 noisePositionIntegerValue = SkScalarFloorToInt(position);
482 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700483 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000484 }
485 };
486 Noise noiseX(noiseVector.x());
487 Noise noiseY(noiseVector.y());
488 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400489 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000490 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000491 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000492 noiseX.noisePositionIntegerValue =
493 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
494 noiseY.noisePositionIntegerValue =
495 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700496 noiseX.nextNoisePositionIntegerValue =
497 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
498 noiseY.nextNoisePositionIntegerValue =
499 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000500 }
501 noiseX.noisePositionIntegerValue &= kBlockMask;
502 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700503 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
504 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400505 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
506 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700507 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
508 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
509 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
510 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000511 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
512 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400513
Hal Canaryfda46002017-05-08 17:17:47 -0400514 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
515 return 0; // Check for pathological inputs.
516 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400517
sugoi@google.come3b4c502013-04-05 13:47:09 +0000518 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
519 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
520 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400521 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000522 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400523 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000524 SkScalar a = SkScalarInterp(u, v, sx);
525 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400526 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000527 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400528 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000529 SkScalar b = SkScalarInterp(u, v, sx);
530 return SkScalarInterp(a, b, sy);
531}
532
Florin Malita14d54c22017-05-18 11:52:59 -0400533SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700534 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400535 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000536 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000537 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400538 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000539 }
540 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400541 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
542 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000543 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000544 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700545 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700546 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
547 noise : SkScalarAbs(noise);
548 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000549 noiseVector.fX *= 2;
550 noiseVector.fY *= 2;
551 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000552 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000553 // Update stitch values
John Stiles039f6812020-08-10 09:51:42 -0400554 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
Florin Malita102c8cf2018-06-05 17:37:12 -0400555 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000556 }
557 }
558
559 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
560 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000561 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400562 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000563 }
564
565 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700566 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000567 }
568
569 // Clamp result
Brian Osmanaba642c2020-02-06 12:52:25 -0500570 return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000571}
572
Mike Reedf2ae2b22017-05-30 15:22:54 -0400573////////////////////////////////////////////////////////////////////////////////////////////////////
574// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
575static SkScalar fade(SkScalar t) {
576 return t * t * t * (t * (t * 6 - 15) + 10);
577}
578
579static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
580 return a + t * (b - a);
581}
582
583static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
584 int h = hash & 15;
585 SkScalar u = h < 8 ? x : y;
586 SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
587 return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
588}
589
590SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
591 int channel, const SkPoint& point) const {
592 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
593 SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
594 SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
595 // z offset between different channels, chosen arbitrarily
596 static const SkScalar CHANNEL_DELTA = 1000.0f;
597 SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
598 SkScalar result = 0;
599 SkScalar ratio = SK_Scalar1;
600 for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
601 int X = SkScalarFloorToInt(x) & 255;
602 int Y = SkScalarFloorToInt(y) & 255;
603 int Z = SkScalarFloorToInt(z) & 255;
604 SkScalar px = x - SkScalarFloorToScalar(x);
605 SkScalar py = y - SkScalarFloorToScalar(y);
606 SkScalar pz = z - SkScalarFloorToScalar(z);
607 SkScalar u = fade(px);
608 SkScalar v = fade(py);
609 SkScalar w = fade(pz);
610 uint8_t* permutations = improved_noise_permutations;
611 int A = permutations[X] + Y;
612 int AA = permutations[A] + Z;
613 int AB = permutations[A + 1] + Z;
614 int B = permutations[X + 1] + Y;
615 int BA = permutations[B] + Z;
616 int BB = permutations[B + 1] + Z;
617 result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
618 grad(permutations[BA ], px - 1, py , pz )),
619 lerp(u, grad(permutations[AB ], px , py - 1, pz ),
620 grad(permutations[BB ], px - 1, py - 1, pz ))),
621 lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
622 grad(permutations[BA + 1], px - 1, py , pz - 1)),
623 lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
624 grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
625 ratio;
626 x *= 2;
627 y *= 2;
628 ratio *= 2;
629 }
Brian Osmanaba642c2020-02-06 12:52:25 -0500630 result = SkTPin((result + 1.0f) / 2.0f, 0.0f, 1.0f);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400631 return result;
632}
633////////////////////////////////////////////////////////////////////////////////////////////////////
634
Florin Malita14d54c22017-05-18 11:52:59 -0400635SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000636 const SkPoint& point, StitchData& stitchData) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400637 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000638 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000639 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000640 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
641 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
642
643 U8CPU rgba[4];
644 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400645 SkScalar value;
646 if (perlinNoiseShader.fType == kImprovedNoise_Type) {
647 value = calculateImprovedNoiseValueForPoint(channel, newPoint);
648 }
649 else {
650 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
651 }
652 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000653 }
654 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
655}
656
Mike Reede92aae62018-10-17 10:21:51 -0400657#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400658SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400659 SkArenaAlloc* alloc) const {
Mike Reed011d1662019-02-28 17:19:25 -0500660 // should we pay attention to rec's device-colorspace?
Herb Derby83e939b2017-02-07 14:25:11 -0500661 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000662}
Mike Reede92aae62018-10-17 10:21:51 -0400663#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000664
Florin Malita83223bc2017-05-31 14:14:05 -0400665static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
666 const SkShaderBase& shader) {
667 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
668 if (rec.fLocalMatrix) {
669 matrix.preConcat(*rec.fLocalMatrix);
670 }
671
672 return matrix;
673}
674
Florin Malita14d54c22017-05-18 11:52:59 -0400675SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
676 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000677 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400678 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
679 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
680 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000681{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000682 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
683 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400684 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
685 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700686}
687
Florin Malita14d54c22017-05-18 11:52:59 -0400688void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000689 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000690 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
691 StitchData stitchData;
692 for (int i = 0; i < count; ++i) {
693 result[i] = shade(point, stitchData);
694 point.fX += SK_Scalar1;
695 }
696}
697
sugoi@google.come3b4c502013-04-05 13:47:09 +0000698/////////////////////////////////////////////////////////////////////
699
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000700#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000701
egdaniel64c47282015-11-13 06:54:19 -0800702class GrGLPerlinNoise : public GrGLSLFragmentProcessor {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000703public:
robertphillips9cdb9922016-02-03 12:25:40 -0800704 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000705
Mike Reedf2ae2b22017-05-30 15:22:54 -0400706 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000707
wangyixb1daa862015-08-18 11:29:31 -0700708protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400709 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700710
sugoi@google.com4775cba2013-04-17 13:46:56 +0000711private:
egdaniel018fb622015-10-28 07:26:40 -0700712 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700713 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700714
egdaniel64c47282015-11-13 06:54:19 -0800715 typedef GrGLSLFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000716};
717
718/////////////////////////////////////////////////////////////////////
719
Mike Reedf2ae2b22017-05-30 15:22:54 -0400720class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000721public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400722 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -0400723 SkPerlinNoiseShaderImpl::Type type,
724 int numOctaves,
725 bool stitchTiles,
Brian Salomonaff329b2017-08-11 09:40:37 -0400726 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400727 GrSurfaceProxyView permutationsView,
728 GrSurfaceProxyView noiseView,
729 const SkMatrix& matrix,
730 const GrCaps& caps) {
731 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
732 GrSamplerState::WrapMode::kClamp,
733 GrSamplerState::Filter::kNearest};
734 auto permutationsFP =
735 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
736 SkMatrix::I(), kRepeatXSampler, caps);
737 auto noiseFP = GrTextureEffect::Make(std::move(noiseView), kPremul_SkAlphaType,
738 SkMatrix::I(), kRepeatXSampler, caps);
739
Michael Ludwigf2935c62020-06-26 11:07:23 -0400740 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
Brian Salomon83c2d352020-06-17 11:46:21 -0400741 new GrPerlinNoise2Effect(type, numOctaves, stitchTiles, std::move(paintingData),
Michael Ludwigf2935c62020-06-26 11:07:23 -0400742 std::move(permutationsFP), std::move(noiseFP))));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000743 }
744
mtklein36352bf2015-03-25 18:17:31 -0700745 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800746
Brian Salomonaff329b2017-08-11 09:40:37 -0400747 std::unique_ptr<GrFragmentProcessor> clone() const override {
748 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400749 }
750
Mike Reedf2ae2b22017-05-30 15:22:54 -0400751 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000752
Florin Malita14d54c22017-05-18 11:52:59 -0400753 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700754 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700755 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700756 int numOctaves() const { return fNumOctaves; }
senorblancof3b50272014-06-16 10:49:58 -0700757
sugoi@google.come3b4c502013-04-05 13:47:09 +0000758private:
egdaniel57d3b032015-11-13 11:57:27 -0800759 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
robertphillipsbf536af2016-02-04 06:11:53 -0800760 return new GrGLPerlinNoise;
wangyixb1daa862015-08-18 11:29:31 -0700761 }
762
Brian Salomon94efbf52016-11-29 13:43:05 -0500763 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800764 GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700765 GrGLPerlinNoise::GenKey(*this, caps, b);
766 }
767
mtklein36352bf2015-03-25 18:17:31 -0700768 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400769 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700770 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700771 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700772 fNumOctaves == s.fNumOctaves &&
773 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700774 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000775 }
776
Brian Salomon83c2d352020-06-17 11:46:21 -0400777 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type,
778 int numOctaves,
779 bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400780 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400781 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -0400782 std::unique_ptr<GrFragmentProcessor> noiseFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400783 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500784 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500785 , fNumOctaves(numOctaves)
786 , fStitchTiles(stitchTiles)
Florin Malitab365cf52017-05-30 17:18:01 -0400787 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -0400788 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
789 this->registerChild(std::move(noiseFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -0400790 this->setUsesSampleCoordsDirectly();
sugoi@google.come3b4c502013-04-05 13:47:09 +0000791 }
792
Brian Salomon4331e462017-07-26 14:58:11 -0400793 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400794 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -0400795 , fType(that.fType)
Brian Salomon4331e462017-07-26 14:58:11 -0400796 , fNumOctaves(that.fNumOctaves)
797 , fStitchTiles(that.fStitchTiles)
Brian Salomon4331e462017-07-26 14:58:11 -0400798 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -0400799 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -0400800 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -0400801 }
802
Brian Salomonf7dcd762018-07-30 14:48:15 -0400803
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400804 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000805
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400806 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400807 int fNumOctaves;
808 bool fStitchTiles;
Brian Salomon83c2d352020-06-17 11:46:21 -0400809
Florin Malitab365cf52017-05-30 17:18:01 -0400810 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000811
joshualittb0a8a372014-09-23 09:50:21 -0700812 typedef GrFragmentProcessor INHERITED;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000813};
814
815/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400816GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000817
Hal Canary6f6961e2017-01-31 13:50:44 -0500818#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400819std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700820 int numOctaves = d->fRandom->nextRangeU(2, 10);
821 bool stitchTiles = d->fRandom->nextBool();
822 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
823 SkISize tileSize = SkISize::Make(d->fRandom->nextRangeU(4, 4096),
824 d->fRandom->nextRangeU(4, 4096));
825 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
826 0.99f);
827 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
828 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000829
reedfe630452016-03-25 09:08:00 -0700830 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
831 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400832 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700833 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400834 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000835
Brian Osman9f532a32016-10-19 11:12:09 -0400836 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400837 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000838}
Hal Canary6f6961e2017-01-31 13:50:44 -0500839#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000840
wangyix7c157a92015-07-22 15:08:53 -0700841void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400842 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800843
Brian Salomonffd15ea2020-07-01 16:48:20 -0400844 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800845 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000846
Ethan Nicholas16464c32020-04-06 13:53:05 -0400847 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800848 "baseFrequency");
849 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000850
halcanary96fcdcc2015-08-27 07:41:13 -0700851 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800852 if (pne.stitchTiles()) {
Ethan Nicholas16464c32020-04-06 13:53:05 -0400853 fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800854 "stitchData");
855 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000856 }
857
sugoi@google.comd537af52013-06-10 13:59:25 +0000858 // Add noise function
Brian Salomone338c292020-06-16 16:52:17 -0400859 const GrShaderVar gPerlinNoiseArgs[] = {{"chanCoord", kHalf_GrSLType },
860 {"noiseVec ", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000861
Brian Salomone338c292020-06-16 16:52:17 -0400862 const GrShaderVar gPerlinNoiseStitchArgs[] = {{"chanCoord" , kHalf_GrSLType },
863 {"noiseVec" , kHalf2_GrSLType},
864 {"stitchData", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000865
sugoi@google.comd537af52013-06-10 13:59:25 +0000866 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000867
Brian Salomone338c292020-06-16 16:52:17 -0400868 noiseCode.append(
869 R"(half4 floorVal;
870 floorVal.xy = floor(noiseVec);
871 floorVal.zw = floorVal.xy + half2(1);
872 half2 fractVal = fract(noiseVec);
873 // smooth curve : t^2*(3 - 2*t)
874 half2 noiseSmooth = fractVal*fractVal*(half2(3) - 2*fractVal);)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000875
876 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800877 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400878 noiseCode.append(
879 R"(if (floorVal.x >= stitchData.x) { floorVal.x -= stitchData.x; };
880 if (floorVal.y >= stitchData.y) { floorVal.y -= stitchData.y; };
881 if (floorVal.z >= stitchData.x) { floorVal.z -= stitchData.x; };
882 if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000883 }
884
Brian Osman6b5dbb42020-07-15 15:31:05 -0400885 // NOTE: We need to explicitly pass half4(1) as input color here, because the helper function
886 // can't see fInputColor (which is "_input" in the FP's outer function). skbug.com/10506
887 SkString sampleX = this->invokeChild(0, "half4(1)", args, "half2(floorVal.x, 0.5)");
888 SkString sampleY = this->invokeChild(0, "half4(1)", args, "half2(floorVal.z, 0.5)");
Brian Salomon83c2d352020-06-17 11:46:21 -0400889 noiseCode.appendf("half2 latticeIdx = half2(%s.r, %s.r);", sampleX.c_str(), sampleY.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000890
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000891#if defined(SK_BUILD_FOR_ANDROID)
892 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
893 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
894 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
895 // (or 0.484368 here). The following rounding operation prevents these precision issues from
896 // affecting the result of the noise by making sure that we only have multiples of 1/255.
897 // (Note that 1/255 is about 0.003921569, which is the value used here).
Brian Salomone338c292020-06-16 16:52:17 -0400898 noiseCode.append(
899 "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);");
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000900#endif
901
sugoi@google.come3b4c502013-04-05 13:47:09 +0000902 // Get (x,y) coordinates with the permutated x
Brian Salomon83c2d352020-06-17 11:46:21 -0400903 noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000904
Brian Salomone338c292020-06-16 16:52:17 -0400905 noiseCode.append("half2 uv;");
906
907 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
908 // [-1,1] vector and perform a dot product between that vector and the provided vector.
909 // Save it as a string because we will repeat it 4x.
910 static constexpr const char* inc8bit = "0.00390625"; // 1.0 / 256.0
911 SkString dotLattice =
912 SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
913
Brian Osman6b5dbb42020-07-15 15:31:05 -0400914 SkString sampleA = this->invokeChild(1, "half4(1)", args, "half2(bcoords.x, chanCoord)");
915 SkString sampleB = this->invokeChild(1, "half4(1)", args, "half2(bcoords.y, chanCoord)");
916 SkString sampleC = this->invokeChild(1, "half4(1)", args, "half2(bcoords.w, chanCoord)");
917 SkString sampleD = this->invokeChild(1, "half4(1)", args, "half2(bcoords.z, chanCoord)");
Brian Salomon83c2d352020-06-17 11:46:21 -0400918
sugoi@google.come3b4c502013-04-05 13:47:09 +0000919 // Compute u, at offset (0,0)
Brian Salomon83c2d352020-06-17 11:46:21 -0400920 noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
921 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000922
sugoi@google.come3b4c502013-04-05 13:47:09 +0000923 // Compute v, at offset (-1,0)
Brian Salomone338c292020-06-16 16:52:17 -0400924 noiseCode.append("fractVal.x -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400925 noiseCode.appendf("lattice = %s;", sampleB.c_str());
926 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000927
928 // Compute 'a' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400929 noiseCode.append("half2 ab;");
930 noiseCode.append("ab.x = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000931
sugoi@google.come3b4c502013-04-05 13:47:09 +0000932 // Compute v, at offset (-1,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400933 noiseCode.append("fractVal.y -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400934 noiseCode.appendf("lattice = %s;", sampleC.c_str());
935 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000936
sugoi@google.come3b4c502013-04-05 13:47:09 +0000937 // Compute u, at offset (0,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400938 noiseCode.append("fractVal.x += 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400939 noiseCode.appendf("lattice = %s;", sampleD.c_str());
940 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000941
942 // Compute 'b' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400943 noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000944 // Compute the noise as a linear interpolation of 'a' and 'b'
Brian Salomone338c292020-06-16 16:52:17 -0400945 noiseCode.append("return mix(ab.x, ab.y, noiseSmooth.y);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000946
sugoi@google.comd537af52013-06-10 13:59:25 +0000947 SkString noiseFuncName;
robertphillipsbf536af2016-02-04 06:11:53 -0800948 if (pne.stitchTiles()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400949 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800950 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
951 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000952 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400953 fragBuilder->emitFunction(kHalf_GrSLType,
egdaniel4ca2e602015-11-18 08:01:26 -0800954 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
955 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
sugoi@google.comd537af52013-06-10 13:59:25 +0000956 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000957
sugoi@google.comd537af52013-06-10 13:59:25 +0000958 // There are rounding errors if the floor operation is not performed here
Brian Salomone338c292020-06-16 16:52:17 -0400959 fragBuilder->codeAppendf("half2 noiseVec = half2(floor(%s.xy) * %s);",
Michael Ludwige88320b2020-06-24 09:04:56 -0400960 args.fSampleCoord, baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000961
962 // Clear the color accumulator
Brian Salomone338c292020-06-16 16:52:17 -0400963 fragBuilder->codeAppendf("%s = half4(0.0);", args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000964
robertphillipsbf536af2016-02-04 06:11:53 -0800965 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +0000966 // Set up TurbulenceInitial stitch values.
Brian Salomone338c292020-06-16 16:52:17 -0400967 fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000968 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000969
Brian Salomone338c292020-06-16 16:52:17 -0400970 fragBuilder->codeAppendf("half ratio = 1.0;");
sugoi@google.comd537af52013-06-10 13:59:25 +0000971
972 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -0800973 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
Brian Salomone338c292020-06-16 16:52:17 -0400974 fragBuilder->codeAppendf(" %s += ", args.fOutputColor);
Florin Malita14d54c22017-05-18 11:52:59 -0400975 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -0800976 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +0000977 }
Brian Salomone338c292020-06-16 16:52:17 -0400978
Brian Salomon83c2d352020-06-17 11:46:21 -0400979 // There are 4 lines, put y coords at center of each.
980 static constexpr const char* chanCoordR = "0.5";
981 static constexpr const char* chanCoordG = "1.5";
982 static constexpr const char* chanCoordB = "2.5";
983 static constexpr const char* chanCoordA = "3.5";
robertphillipsbf536af2016-02-04 06:11:53 -0800984 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400985 fragBuilder->codeAppendf(R"(
986 half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),"
987 %s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)))",
988 noiseFuncName.c_str(), chanCoordR,
989 noiseFuncName.c_str(), chanCoordG,
990 noiseFuncName.c_str(), chanCoordB,
991 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000992 } else {
Brian Salomone338c292020-06-16 16:52:17 -0400993 fragBuilder->codeAppendf(R"(
994 half4(%s(%s, noiseVec), %s(%s, noiseVec),
995 %s(%s, noiseVec), %s(%s, noiseVec)))",
996 noiseFuncName.c_str(), chanCoordR,
997 noiseFuncName.c_str(), chanCoordG,
998 noiseFuncName.c_str(), chanCoordB,
999 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +00001000 }
Florin Malita14d54c22017-05-18 11:52:59 -04001001 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
Brian Salomone338c292020-06-16 16:52:17 -04001002 fragBuilder->codeAppend(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +00001003 }
Brian Salomone338c292020-06-16 16:52:17 -04001004 fragBuilder->codeAppend(" * ratio;");
sugoi@google.comd537af52013-06-10 13:59:25 +00001005
Brian Salomone338c292020-06-16 16:52:17 -04001006 fragBuilder->codeAppend(R"(noiseVec *= half2(2.0);
1007 ratio *= 0.5;)");
sugoi@google.comd537af52013-06-10 13:59:25 +00001008
robertphillipsbf536af2016-02-04 06:11:53 -08001009 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -04001010 fragBuilder->codeAppend("stitchData *= half2(2.0);");
sugoi@google.comd537af52013-06-10 13:59:25 +00001011 }
Brian Salomone338c292020-06-16 16:52:17 -04001012 fragBuilder->codeAppend("}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +00001013
Florin Malita14d54c22017-05-18 11:52:59 -04001014 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +00001015 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
1016 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
Brian Salomone338c292020-06-16 16:52:17 -04001017 fragBuilder->codeAppendf("%s = %s * half4(0.5) + half4(0.5);",
1018 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001019 }
1020
sugoi@google.come3b4c502013-04-05 13:47:09 +00001021 // Clamp values
Brian Salomone338c292020-06-16 16:52:17 -04001022 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001023
1024 // Pre-multiply the result
Brian Salomone338c292020-06-16 16:52:17 -04001025 fragBuilder->codeAppendf("%s = half4(%s.rgb * %s.aaa, %s.a);\n",
egdaniel4ca2e602015-11-18 08:01:26 -08001026 args.fOutputColor, args.fOutputColor,
1027 args.fOutputColor, args.fOutputColor);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001028}
1029
Brian Salomon94efbf52016-11-29 13:43:05 -05001030void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001031 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001032 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001033
bsalomon63e99f72014-07-21 08:03:14 -07001034 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001035
1036 key = key << 3; // Make room for next 3 bits
1037
1038 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001039 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001040 key |= 0x1;
1041 break;
Florin Malita14d54c22017-05-18 11:52:59 -04001042 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +00001043 key |= 0x2;
1044 break;
1045 default:
1046 // leave key at 0
1047 break;
1048 }
1049
1050 if (turbulence.stitchTiles()) {
1051 key |= 0x4; // Flip the 3rd bit if tile stitching is on
1052 }
1053
bsalomon63e99f72014-07-21 08:03:14 -07001054 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001055}
1056
egdaniel018fb622015-10-28 07:26:40 -07001057void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -04001058 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001059 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -07001060
Mike Reedf2ae2b22017-05-30 15:22:54 -04001061 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +00001062
1063 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -07001064 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001065
sugoi@google.com4775cba2013-04-17 13:46:56 +00001066 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -04001067 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -07001068 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
Brian Salomon81454df2020-06-17 10:59:28 -04001069 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +00001070 }
1071}
1072
sugoi@google.come3b4c502013-04-05 13:47:09 +00001073/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -04001074
1075class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
1076public:
1077 void emitCode(EmitArgs&) override;
1078
1079 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
1080
1081protected:
1082 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
1083
1084private:
1085 GrGLSLProgramDataManager::UniformHandle fZUni;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001086 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
1087
1088 typedef GrGLSLFragmentProcessor INHERITED;
1089};
1090
1091/////////////////////////////////////////////////////////////////////
1092
1093class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
1094public:
Brian Salomonaff329b2017-08-11 09:40:37 -04001095 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -04001096 int octaves,
1097 SkScalar z,
Brian Salomonaff329b2017-08-11 09:40:37 -04001098 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001099 GrSurfaceProxyView permutationsView,
1100 GrSurfaceProxyView gradientView,
1101 const SkMatrix& matrix,
1102 const GrCaps& caps) {
1103 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
1104 GrSamplerState::WrapMode::kClamp,
1105 GrSamplerState::Filter::kNearest};
1106 auto permutationsFP =
1107 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
1108 SkMatrix::I(), kRepeatXSampler, caps);
1109 auto gradientFP = GrTextureEffect::Make(std::move(gradientView), kPremul_SkAlphaType,
1110 SkMatrix::I(), kRepeatXSampler, caps);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001111 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
1112 new GrImprovedPerlinNoiseEffect(octaves, z, std::move(paintingData),
1113 std::move(permutationsFP),
1114 std::move(gradientFP))));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001115 }
1116
Mike Reedf2ae2b22017-05-30 15:22:54 -04001117 const char* name() const override { return "ImprovedPerlinNoise"; }
1118
Brian Salomonaff329b2017-08-11 09:40:37 -04001119 std::unique_ptr<GrFragmentProcessor> clone() const override {
1120 return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -04001121 }
1122
Mike Reedf2ae2b22017-05-30 15:22:54 -04001123 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
1124 SkScalar z() const { return fZ; }
1125 int octaves() const { return fOctaves; }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001126
1127private:
1128 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
1129 return new GrGLImprovedPerlinNoise;
1130 }
1131
1132 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
1133 GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
1134 }
1135
1136 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
John Stiles24a7f072020-08-07 15:59:42 -04001137 const GrImprovedPerlinNoiseEffect& that = sBase.cast<GrImprovedPerlinNoiseEffect>();
1138 return this->z() == that.z() &&
1139 this->octaves() == that.octaves() &&
1140 this->baseFrequency() == that.baseFrequency();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001141 }
1142
Brian Salomon83c2d352020-06-17 11:46:21 -04001143 GrImprovedPerlinNoiseEffect(int octaves,
1144 SkScalar z,
Florin Malitab365cf52017-05-30 17:18:01 -04001145 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -04001146 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -04001147 std::unique_ptr<GrFragmentProcessor> gradientFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001148 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001149 , fOctaves(octaves)
1150 , fZ(z)
Florin Malitab365cf52017-05-30 17:18:01 -04001151 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -04001152 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
1153 this->registerChild(std::move(gradientFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -04001154 this->setUsesSampleCoordsDirectly();
Mike Reedf2ae2b22017-05-30 15:22:54 -04001155 }
1156
Brian Salomon4331e462017-07-26 14:58:11 -04001157 GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
Ethan Nicholasabff9562017-10-09 10:54:08 -04001158 : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
Brian Salomon4331e462017-07-26 14:58:11 -04001159 , fOctaves(that.fOctaves)
1160 , fZ(that.fZ)
John Stiles24a7f072020-08-07 15:59:42 -04001161 , fPaintingData(std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(
1162 *that.fPaintingData)) {
Brian Salomon83c2d352020-06-17 11:46:21 -04001163 this->cloneAndRegisterAllChildProcessors(that);
Michael Ludwigf2935c62020-06-26 11:07:23 -04001164 this->setUsesSampleCoordsDirectly();
Brian Salomon4331e462017-07-26 14:58:11 -04001165 }
1166
Brian Salomon0c26a9d2017-07-06 10:09:38 -04001167 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Mike Reedf2ae2b22017-05-30 15:22:54 -04001168
Mike Reedf2ae2b22017-05-30 15:22:54 -04001169 int fOctaves;
1170 SkScalar fZ;
Brian Salomon83c2d352020-06-17 11:46:21 -04001171
Florin Malitab365cf52017-05-30 17:18:01 -04001172 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001173
1174 typedef GrFragmentProcessor INHERITED;
1175};
1176
1177/////////////////////////////////////////////////////////////////////
1178GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
1179
1180#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -04001181std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
1182 GrProcessorTestData* d) {
Mike Reedf2ae2b22017-05-30 15:22:54 -04001183 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
1184 0.99f);
1185 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
1186 0.99f);
1187 int numOctaves = d->fRandom->nextRangeU(2, 10);
1188 SkScalar z = SkIntToScalar(d->fRandom->nextU());
1189
1190 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
John Stiles24a7f072020-08-07 15:59:42 -04001191 baseFrequencyY,
1192 numOctaves,
1193 z));
Mike Reedf2ae2b22017-05-30 15:22:54 -04001194
1195 GrTest::TestAsFPArgs asFPArgs(d);
1196 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
1197}
1198#endif
1199
1200void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001201 const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
Brian Salomonffd15ea2020-07-01 16:48:20 -04001202 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001203 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001204
Ethan Nicholas16464c32020-04-06 13:53:05 -04001205 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001206 "baseFrequency");
1207 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
1208
Ethan Nicholas16464c32020-04-06 13:53:05 -04001209 fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001210 const char* zUni = uniformHandler->getUniformCStr(fZUni);
1211
1212 // fade function
Nico Webere50efdf2018-10-01 14:40:44 -04001213 const GrShaderVar fadeArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001214 GrShaderVar("t", kHalf3_GrSLType)
Mike Reedf2ae2b22017-05-30 15:22:54 -04001215 };
1216 SkString fadeFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001217 fragBuilder->emitFunction(kHalf3_GrSLType, "fade", SK_ARRAY_COUNT(fadeArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001218 fadeArgs,
1219 "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);",
1220 &fadeFuncName);
1221
1222 // perm function
Nico Webere50efdf2018-10-01 14:40:44 -04001223 const GrShaderVar permArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001224 {"x", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001225 };
Brian Osman6b5dbb42020-07-15 15:31:05 -04001226 SkString samplePerm = this->invokeChild(0, "half4(1)", args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001227 SkString permFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001228 SkString permCode = SkStringPrintf("return %s.r * 255;", samplePerm.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001229 fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001230 permCode.c_str(), &permFuncName);
1231
1232 // grad function
Nico Webere50efdf2018-10-01 14:40:44 -04001233 const GrShaderVar gradArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001234 {"x", kHalf_GrSLType},
1235 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001236 };
Brian Osman6b5dbb42020-07-15 15:31:05 -04001237 SkString sampleGrad = this->invokeChild(1, "half4(1)", args, "float2(x, 0.5)");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001238 SkString gradFuncName;
Brian Salomon83c2d352020-06-17 11:46:21 -04001239 SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));",
1240 sampleGrad.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001241 fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001242 gradCode.c_str(), &gradFuncName);
1243
1244 // lerp function
Nico Webere50efdf2018-10-01 14:40:44 -04001245 const GrShaderVar lerpArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001246 {"a", kHalf_GrSLType},
1247 {"b", kHalf_GrSLType},
1248 {"w", kHalf_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001249 };
1250 SkString lerpFuncName;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001251 fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001252 "return a + w * (b - a);", &lerpFuncName);
1253
1254 // noise function
Brian Salomon83c2d352020-06-17 11:46:21 -04001255 const GrShaderVar noiseArgs[] = {
1256 {"p", kHalf3_GrSLType},
Mike Reedf2ae2b22017-05-30 15:22:54 -04001257 };
1258 SkString noiseFuncName;
1259 SkString noiseCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001260 noiseCode.append("half3 P = mod(floor(p), 256.0);");
Mike Reedf2ae2b22017-05-30 15:22:54 -04001261 noiseCode.append("p -= floor(p);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001262 noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
1263 noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
1264 noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
1265 noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
1266 noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
1267 noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
1268 noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
1269 noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001270 noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
1271 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001272 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 -04001273 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001274 noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001275 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001276 noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
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(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001279 lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
1280 permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001281 noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001282 gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001283 noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001284 lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001285 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 -04001286 gradFuncName.c_str(), permFuncName.c_str());
1287 noiseCode.append("return result;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001288 fragBuilder->emitFunction(kHalf_GrSLType, "noise", SK_ARRAY_COUNT(noiseArgs), noiseArgs,
Mike Reedf2ae2b22017-05-30 15:22:54 -04001289 noiseCode.c_str(), &noiseFuncName);
1290
1291 // noiseOctaves function
Nico Webere50efdf2018-10-01 14:40:44 -04001292 const GrShaderVar noiseOctavesArgs[] = {
Brian Salomon83c2d352020-06-17 11:46:21 -04001293 {"p", kHalf3_GrSLType}
Mike Reedf2ae2b22017-05-30 15:22:54 -04001294 };
1295 SkString noiseOctavesFuncName;
1296 SkString noiseOctavesCode;
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001297 noiseOctavesCode.append("half result = 0.0;");
1298 noiseOctavesCode.append("half ratio = 1.0;");
1299 noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001300 noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
1301 noiseOctavesCode.append("p *= 2.0;");
1302 noiseOctavesCode.append("ratio *= 2.0;");
1303 noiseOctavesCode.append("}");
1304 noiseOctavesCode.append("return (result + 1.0) / 2.0;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001305 fragBuilder->emitFunction(kHalf_GrSLType, "noiseOctaves", SK_ARRAY_COUNT(noiseOctavesArgs),
Mike Reedf2ae2b22017-05-30 15:22:54 -04001306 noiseOctavesArgs, noiseOctavesCode.c_str(), &noiseOctavesFuncName);
1307
Michael Ludwige88320b2020-06-24 09:04:56 -04001308 fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", args.fSampleCoord, baseFrequencyUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001309 fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001310 zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001311 fragBuilder->codeAppendf("half g = %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 b = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001314 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001315 fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001316 noiseOctavesFuncName.c_str(), zUni);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001317 fragBuilder->codeAppendf("%s = half4(r, g, b, a);", args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001318
1319 // Clamp values
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001320 fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001321
1322 // Pre-multiply the result
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001323 fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n",
Mike Reedf2ae2b22017-05-30 15:22:54 -04001324 args.fOutputColor, args.fOutputColor,
1325 args.fOutputColor, args.fOutputColor);
1326}
1327
1328void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
1329 GrProcessorKeyBuilder* b) {
Ethan Nicholasc352f3b2017-06-19 11:25:00 -04001330 const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
1331 b->add32(pne.octaves());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001332}
1333
1334void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
1335 const GrFragmentProcessor& processor) {
1336 INHERITED::onSetData(pdman, processor);
1337
1338 const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
1339
1340 const SkVector& baseFrequency = noise.baseFrequency();
1341 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
1342
Mike Reedf2ae2b22017-05-30 15:22:54 -04001343 pdman.set1f(fZUni, noise.z());
1344}
1345
1346/////////////////////////////////////////////////////////////////////
Brian Salomonaff329b2017-08-11 09:40:37 -04001347std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -05001348 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -07001349 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -08001350
Florin Malita52f02912020-03-09 16:33:17 -04001351 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Brian Osman449b1152020-04-15 16:43:00 -04001352 const auto paintMatrix = SkMatrix::Concat(args.fMatrixProvider.localToDevice(), *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -07001353
Mike Reedf2ae2b22017-05-30 15:22:54 -04001354 // Either we don't stitch tiles, either we have a valid tile size
1355 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
1356
Florin Malitab365cf52017-05-30 17:18:01 -04001357 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -05001358 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -04001359 fSeed,
1360 fBaseFrequencyX,
1361 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -05001362 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001363
Brian Osman449b1152020-04-15 16:43:00 -04001364 SkMatrix m = args.fMatrixProvider.localToDevice();
Florin Malitac6c5ead2018-04-11 15:33:40 -04001365 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
1366 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -04001367
Greg Daniel6f5441a2020-01-28 17:02:49 -05001368 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -04001369 if (fType == kImprovedNoise_Type) {
Greg Daniel7e1912a2018-02-08 09:15:33 -05001370 // Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
1371 // We also know that we will not be using mipmaps. If things things weren't true we should
1372 // go through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001373 const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
1374 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001375 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001376
Greg Daniel6f5441a2020-01-28 17:02:49 -05001377 const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
1378 SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001379 auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
Brian Salomon83c2d352020-06-17 11:46:21 -04001380 return GrImprovedPerlinNoiseEffect::Make(fNumOctaves,
1381 fSeed,
1382 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001383 std::move(permutationsView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001384 std::move(gradientView),
1385 m,
1386 *context->priv().caps());
Mike Reedf2ae2b22017-05-30 15:22:54 -04001387 }
1388
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001389 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001390 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -07001391 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -04001392 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
1393 // color space of the noise. Either way, this case (and the GLSL) need to convert to
1394 // the destination.
John Stiles85894302020-07-13 11:39:52 -04001395 auto inner = GrFragmentProcessor::ModulateRGBA(
1396 /*child=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040));
Mike Reed28eaed22018-02-01 11:24:53 -05001397 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -08001398 }
bsalomonc21b09e2015-08-28 18:46:56 -07001399 // Emit zero.
John Stiles7c196772020-07-13 10:00:16 -04001400 return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +00001401 }
1402
Greg Daniel7e1912a2018-02-08 09:15:33 -05001403 // Need to assert that the textures we'll create are power of 2 so that now copy is needed. We
1404 // also know that we will not be using mipmaps. If things things weren't true we should go
1405 // through GrBitmapTextureMaker to handle needed copies.
Greg Daniel6f5441a2020-01-28 17:02:49 -05001406 const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
1407 SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001408 auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
Greg Daniel7e1912a2018-02-08 09:15:33 -05001409
Greg Daniel6f5441a2020-01-28 17:02:49 -05001410 const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
1411 SkASSERT(SkIsPow2(noiseBitmap.width()) && SkIsPow2(noiseBitmap.height()));
Greg Danielc52db712020-01-28 17:03:46 -05001412 auto noiseView = GrMakeCachedBitmapProxyView(context, noiseBitmap);
sugoi@google.come3b4c502013-04-05 13:47:09 +00001413
Greg Danielc52db712020-01-28 17:03:46 -05001414 if (permutationsView.proxy() && noiseView.proxy()) {
Brian Salomonaff329b2017-08-11 09:40:37 -04001415 auto inner = GrPerlinNoise2Effect::Make(fType,
1416 fNumOctaves,
1417 fStitchTiles,
1418 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -05001419 std::move(permutationsView),
1420 std::move(noiseView),
Brian Salomon83c2d352020-06-17 11:46:21 -04001421 m,
1422 *context->priv().caps());
Mike Reed28eaed22018-02-01 11:24:53 -05001423 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -07001424 }
bsalomonc21b09e2015-08-28 18:46:56 -07001425 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +00001426}
1427
1428#endif
1429
Mike Reedf2ae2b22017-05-30 15:22:54 -04001430///////////////////////////////////////////////////////////////////////////////////////////////////
1431
Mike Reed832aa112018-05-18 11:48:50 -04001432static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
1433 SkScalar seed) {
1434 if (!(baseX >= 0 && baseY >= 0)) {
1435 return false;
1436 }
1437 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1438 return false;
1439 }
1440 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1441 return false;
1442 }
1443 if (!SkScalarIsFinite(seed)) {
1444 return false;
1445 }
1446 return true;
1447}
1448
Mike Reedf2ae2b22017-05-30 15:22:54 -04001449sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1450 SkScalar baseFrequencyY,
1451 int numOctaves, SkScalar seed,
1452 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001453 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1454 return nullptr;
1455 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001456 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1457 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1458 tileSize));
1459}
1460
1461sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1462 SkScalar baseFrequencyY,
1463 int numOctaves, SkScalar seed,
1464 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001465 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1466 return nullptr;
1467 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001468 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1469 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1470 tileSize));
1471}
1472
1473sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
1474 SkScalar baseFrequencyY,
1475 int numOctaves, SkScalar z) {
Mike Reed832aa112018-05-18 11:48:50 -04001476 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
1477 return nullptr;
1478 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001479 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
1480 baseFrequencyX, baseFrequencyY, numOctaves, z,
1481 nullptr));
1482}
1483
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001484void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001485 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001486}