blob: 796802a3e95dcf7fc1f5f738a80a1b4584b7072c [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"
Mike Kleine7541d92021-01-13 13:53:05 -060019#include "src/core/SkVM.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/core/SkWriteBuffer.h"
sugoi@google.come3b4c502013-04-05 13:47:09 +000021
22#if SK_SUPPORT_GPU
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040023#include "include/gpu/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/GrRecordingContextPriv.h"
25#include "src/gpu/SkGr.h"
Michael Ludwigf2935c62020-06-26 11:07:23 -040026#include "src/gpu/effects/GrMatrixEffect.h"
Brian Salomon83c2d352020-06-17 11:46:21 -040027#include "src/gpu/effects/GrTextureEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050028#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 -040039class SkPerlinNoiseShaderImpl : public SkShaderBase {
40public:
Florin Malita83223bc2017-05-31 14:14:05 -040041 struct StitchData {
42 StitchData()
43 : fWidth(0)
44 , fWrapX(0)
45 , fHeight(0)
46 , fWrapY(0)
47 {}
48
Florin Malita102c8cf2018-06-05 17:37:12 -040049 StitchData(SkScalar w, SkScalar h)
Brian Osman788b9162020-02-07 10:36:46 -050050 : fWidth(std::min(SkScalarRoundToInt(w), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040051 , fWrapX(kPerlinNoise + fWidth)
Brian Osman788b9162020-02-07 10:36:46 -050052 , fHeight(std::min(SkScalarRoundToInt(h), SK_MaxS32 - kPerlinNoise))
Florin Malita102c8cf2018-06-05 17:37:12 -040053 , fWrapY(kPerlinNoise + fHeight) {}
54
Florin Malita83223bc2017-05-31 14:14:05 -040055 bool operator==(const StitchData& other) const {
56 return fWidth == other.fWidth &&
57 fWrapX == other.fWrapX &&
58 fHeight == other.fHeight &&
59 fWrapY == other.fWrapY;
60 }
61
62 int fWidth; // How much to subtract to wrap for stitching.
63 int fWrapX; // Minimum value to wrap.
64 int fHeight;
65 int fWrapY;
66 };
67
68 struct PaintingData {
69 PaintingData(const SkISize& tileSize, SkScalar seed,
70 SkScalar baseFrequencyX, SkScalar baseFrequencyY,
71 const SkMatrix& matrix)
72 {
Ethan Nicholas82940152019-01-10 13:58:14 -050073 SkVector tileVec;
74 matrix.mapVector(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight),
75 &tileVec);
Florin Malita83223bc2017-05-31 14:14:05 -040076
Ethan Nicholas82940152019-01-10 13:58:14 -050077 SkSize scale;
Ethan Nicholas2ee498c2019-01-11 15:32:05 -050078 if (!matrix.decomposeScale(&scale, nullptr)) {
79 scale.set(SK_ScalarNearlyZero, SK_ScalarNearlyZero);
80 }
Ethan Nicholas82940152019-01-10 13:58:14 -050081 fBaseFrequency.set(baseFrequencyX * SkScalarInvert(scale.width()),
82 baseFrequencyY * SkScalarInvert(scale.height()));
83 fTileSize.set(SkScalarRoundToInt(tileVec.fX), SkScalarRoundToInt(tileVec.fY));
Florin Malita83223bc2017-05-31 14:14:05 -040084 this->init(seed);
85 if (!fTileSize.isEmpty()) {
86 this->stitch();
87 }
88
89 #if SK_SUPPORT_GPU
Greg Daniel7e1912a2018-02-08 09:15:33 -050090 SkImageInfo info = SkImageInfo::MakeA8(kBlockSize, 1);
Greg Daniel6f5441a2020-01-28 17:02:49 -050091 fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes());
92 fPermutationsBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -040093
Brian Salomona3a9da72020-06-17 10:52:19 -040094 info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Greg Daniel6f5441a2020-01-28 17:02:49 -050095 fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
96 fNoiseBitmap.setImmutable();
Florin Malita83223bc2017-05-31 14:14:05 -040097 #endif
98 }
99
Brian Salomon4331e462017-07-26 14:58:11 -0400100 #if SK_SUPPORT_GPU
101 PaintingData(const PaintingData& that)
102 : fSeed(that.fSeed)
103 , fTileSize(that.fTileSize)
104 , fBaseFrequency(that.fBaseFrequency)
105 , fStitchDataInit(that.fStitchDataInit)
Greg Daniel6f5441a2020-01-28 17:02:49 -0500106 , fPermutationsBitmap(that.fPermutationsBitmap)
Brian Salomon4878b3e2021-01-08 18:11:33 -0500107 , fNoiseBitmap(that.fNoiseBitmap) {
Brian Salomon4331e462017-07-26 14:58:11 -0400108 memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
109 memcpy(fNoise, that.fNoise, sizeof(fNoise));
110 memcpy(fGradient, that.fGradient, sizeof(fGradient));
111 }
112 #endif
113
Florin Malita83223bc2017-05-31 14:14:05 -0400114 int fSeed;
115 uint8_t fLatticeSelector[kBlockSize];
116 uint16_t fNoise[4][kBlockSize][2];
117 SkPoint fGradient[4][kBlockSize];
118 SkISize fTileSize;
119 SkVector fBaseFrequency;
120 StitchData fStitchDataInit;
121
122 private:
123
124 #if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500125 SkBitmap fPermutationsBitmap;
126 SkBitmap fNoiseBitmap;
Florin Malita83223bc2017-05-31 14:14:05 -0400127 #endif
128
129 inline int random() {
John Stiles039f6812020-08-10 09:51:42 -0400130 // See https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
131 // m = kRandMaximum, 2**31 - 1 (2147483647)
132 static constexpr int kRandAmplitude = 16807; // 7**5; primitive root of m
133 static constexpr int kRandQ = 127773; // m / a
134 static constexpr int kRandR = 2836; // m % a
Florin Malita83223bc2017-05-31 14:14:05 -0400135
John Stiles039f6812020-08-10 09:51:42 -0400136 int result = kRandAmplitude * (fSeed % kRandQ) - kRandR * (fSeed / kRandQ);
137 if (result <= 0) {
Florin Malita83223bc2017-05-31 14:14:05 -0400138 result += kRandMaximum;
John Stiles039f6812020-08-10 09:51:42 -0400139 }
Florin Malita83223bc2017-05-31 14:14:05 -0400140 fSeed = result;
141 return result;
142 }
143
144 // Only called once. Could be part of the constructor.
145 void init(SkScalar seed)
146 {
Florin Malita83223bc2017-05-31 14:14:05 -0400147 // According to the SVG spec, we must truncate (not round) the seed value.
148 fSeed = SkScalarTruncToInt(seed);
149 // The seed value clamp to the range [1, kRandMaximum - 1].
150 if (fSeed <= 0) {
151 fSeed = -(fSeed % (kRandMaximum - 1)) + 1;
152 }
153 if (fSeed > kRandMaximum - 1) {
154 fSeed = kRandMaximum - 1;
155 }
156 for (int channel = 0; channel < 4; ++channel) {
157 for (int i = 0; i < kBlockSize; ++i) {
158 fLatticeSelector[i] = i;
159 fNoise[channel][i][0] = (random() % (2 * kBlockSize));
160 fNoise[channel][i][1] = (random() % (2 * kBlockSize));
161 }
162 }
163 for (int i = kBlockSize - 1; i > 0; --i) {
164 int k = fLatticeSelector[i];
165 int j = random() % kBlockSize;
166 SkASSERT(j >= 0);
167 SkASSERT(j < kBlockSize);
168 fLatticeSelector[i] = fLatticeSelector[j];
169 fLatticeSelector[j] = k;
170 }
171
172 // Perform the permutations now
173 {
174 // Copy noise data
175 uint16_t noise[4][kBlockSize][2];
176 for (int i = 0; i < kBlockSize; ++i) {
177 for (int channel = 0; channel < 4; ++channel) {
178 for (int j = 0; j < 2; ++j) {
179 noise[channel][i][j] = fNoise[channel][i][j];
180 }
181 }
182 }
183 // Do permutations on noise data
184 for (int i = 0; i < kBlockSize; ++i) {
185 for (int channel = 0; channel < 4; ++channel) {
186 for (int j = 0; j < 2; ++j) {
187 fNoise[channel][i][j] = noise[channel][fLatticeSelector[i]][j];
188 }
189 }
190 }
191 }
192
193 // Half of the largest possible value for 16 bit unsigned int
John Stiles039f6812020-08-10 09:51:42 -0400194 static constexpr SkScalar kHalfMax16bits = 32767.5f;
Florin Malita83223bc2017-05-31 14:14:05 -0400195
196 // Compute gradients from permutated noise data
John Stiles039f6812020-08-10 09:51:42 -0400197 static constexpr SkScalar kInvBlockSizef = 1.0 / SkIntToScalar(kBlockSize);
Florin Malita83223bc2017-05-31 14:14:05 -0400198 for (int channel = 0; channel < 4; ++channel) {
199 for (int i = 0; i < kBlockSize; ++i) {
200 fGradient[channel][i] = SkPoint::Make(
John Stiles039f6812020-08-10 09:51:42 -0400201 (fNoise[channel][i][0] - kBlockSize) * kInvBlockSizef,
202 (fNoise[channel][i][1] - kBlockSize) * kInvBlockSizef);
Florin Malita83223bc2017-05-31 14:14:05 -0400203 fGradient[channel][i].normalize();
204 // Put the normalized gradient back into the noise data
John Stiles039f6812020-08-10 09:51:42 -0400205 fNoise[channel][i][0] =
206 SkScalarRoundToInt((fGradient[channel][i].fX + 1) * kHalfMax16bits);
207 fNoise[channel][i][1] =
208 SkScalarRoundToInt((fGradient[channel][i].fY + 1) * kHalfMax16bits);
Florin Malita83223bc2017-05-31 14:14:05 -0400209 }
210 }
211 }
212
213 // Only called once. Could be part of the constructor.
214 void stitch() {
215 SkScalar tileWidth = SkIntToScalar(fTileSize.width());
216 SkScalar tileHeight = SkIntToScalar(fTileSize.height());
217 SkASSERT(tileWidth > 0 && tileHeight > 0);
218 // When stitching tiled turbulence, the frequencies must be adjusted
219 // so that the tile borders will be continuous.
220 if (fBaseFrequency.fX) {
221 SkScalar lowFrequencx =
222 SkScalarFloorToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
223 SkScalar highFrequencx =
224 SkScalarCeilToScalar(tileWidth * fBaseFrequency.fX) / tileWidth;
225 // BaseFrequency should be non-negative according to the standard.
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400226 // lowFrequencx can be 0 if fBaseFrequency.fX is very small.
227 if (sk_ieee_float_divide(fBaseFrequency.fX, lowFrequencx) < highFrequencx / fBaseFrequency.fX) {
Florin Malita83223bc2017-05-31 14:14:05 -0400228 fBaseFrequency.fX = lowFrequencx;
229 } else {
230 fBaseFrequency.fX = highFrequencx;
231 }
232 }
233 if (fBaseFrequency.fY) {
234 SkScalar lowFrequency =
235 SkScalarFloorToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
236 SkScalar highFrequency =
237 SkScalarCeilToScalar(tileHeight * fBaseFrequency.fY) / tileHeight;
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400238 // lowFrequency can be 0 if fBaseFrequency.fY is very small.
239 if (sk_ieee_float_divide(fBaseFrequency.fY, lowFrequency) < highFrequency / fBaseFrequency.fY) {
Florin Malita83223bc2017-05-31 14:14:05 -0400240 fBaseFrequency.fY = lowFrequency;
241 } else {
242 fBaseFrequency.fY = highFrequency;
243 }
244 }
245 // Set up TurbulenceInitial stitch values.
Florin Malita102c8cf2018-06-05 17:37:12 -0400246 fStitchDataInit = StitchData(tileWidth * fBaseFrequency.fX,
247 tileHeight * fBaseFrequency.fY);
Florin Malita83223bc2017-05-31 14:14:05 -0400248 }
249
250 public:
251
252#if SK_SUPPORT_GPU
Greg Daniel6f5441a2020-01-28 17:02:49 -0500253 const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400254
Greg Daniel6f5441a2020-01-28 17:02:49 -0500255 const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
Florin Malita83223bc2017-05-31 14:14:05 -0400256#endif
257 };
Mike Reedf2ae2b22017-05-30 15:22:54 -0400258
259 /**
260 * About the noise types : the difference between the first 2 is just minor tweaks to the
261 * algorithm, they're not 2 entirely different noises. The output looks different, but once the
262 * noise is generated in the [1, -1] range, the output is brought back in the [0, 1] range by
263 * doing :
264 * kFractalNoise_Type : noise * 0.5 + 0.5
265 * kTurbulence_Type : abs(noise)
266 * Very little differences between the 2 types, although you can tell the difference visually.
Mike Reedf2ae2b22017-05-30 15:22:54 -0400267 */
268 enum Type {
269 kFractalNoise_Type,
270 kTurbulence_Type,
Brian Salomon4878b3e2021-01-08 18:11:33 -0500271 kLast_Type = kTurbulence_Type
Mike Reedf2ae2b22017-05-30 15:22:54 -0400272 };
273
Robert Phillipsbee27322018-01-23 09:58:18 -0500274 static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
275
Mike Reedf2ae2b22017-05-30 15:22:54 -0400276 SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type, SkScalar baseFrequencyX,
277 SkScalar baseFrequencyY, int numOctaves, SkScalar seed,
278 const SkISize* tileSize);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400279
280 class PerlinNoiseShaderContext : public Context {
281 public:
282 PerlinNoiseShaderContext(const SkPerlinNoiseShaderImpl& shader, const ContextRec&);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400283
284 void shadeSpan(int x, int y, SkPMColor[], int count) override;
285
286 private:
287 SkPMColor shade(const SkPoint& point, StitchData& stitchData) const;
288 SkScalar calculateTurbulenceValueForPoint(
289 int channel,
290 StitchData& stitchData, const SkPoint& point) const;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400291 SkScalar noise2D(int channel,
292 const StitchData& stitchData, const SkPoint& noiseVector) const;
293
Florin Malita83223bc2017-05-31 14:14:05 -0400294 SkMatrix fMatrix;
295 PaintingData fPaintingData;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400296
John Stiles7571f9e2020-09-02 22:42:33 -0400297 using INHERITED = Context;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400298 };
299
300#if SK_SUPPORT_GPU
Mike Reede3429e62018-01-19 11:43:34 -0500301 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400302#endif
303
Mike Kleine7541d92021-01-13 13:53:05 -0600304 skvm::Color onProgram(skvm::Builder*,
305 skvm::Coord, skvm::Coord, skvm::Color,
Mike Reed80468372021-03-19 14:05:19 -0400306 const SkMatrixProvider&, const SkMatrix*, const SkColorInfo&,
Mike Kleine7541d92021-01-13 13:53:05 -0600307 skvm::Uniforms*, SkArenaAlloc*) const override {
308 // TODO?
309 return {};
310 }
311
Mike Reedf2ae2b22017-05-30 15:22:54 -0400312protected:
313 void flatten(SkWriteBuffer&) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400314#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400315 Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
Mike Reede92aae62018-10-17 10:21:51 -0400316#endif
Mike Reedf2ae2b22017-05-30 15:22:54 -0400317
318private:
Mike Klein4fee3232018-10-18 17:27:16 -0400319 SK_FLATTENABLE_HOOKS(SkPerlinNoiseShaderImpl)
320
Mike Reedf2ae2b22017-05-30 15:22:54 -0400321 const SkPerlinNoiseShaderImpl::Type fType;
322 const SkScalar fBaseFrequencyX;
323 const SkScalar fBaseFrequencyY;
324 const int fNumOctaves;
325 const SkScalar fSeed;
326 const SkISize fTileSize;
327 const bool fStitchTiles;
328
329 friend class ::SkPerlinNoiseShader;
330
John Stiles7571f9e2020-09-02 22:42:33 -0400331 using INHERITED = SkShaderBase;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400332};
333
sugoi@google.come3b4c502013-04-05 13:47:09 +0000334namespace {
335
336// noiseValue is the color component's value (or color)
337// limitValue is the maximum perlin noise array index value allowed
338// newValue is the current noise dimension (either width or height)
339inline int checkNoise(int noiseValue, int limitValue, int newValue) {
340 // If the noise value would bring us out of bounds of the current noise array while we are
341 // stiching noise tiles together, wrap the noise around the current dimension of the noise to
342 // stay within the array bounds in a continuous fashion (so that tiling lines are not visible)
343 if (noiseValue >= limitValue) {
344 noiseValue -= newValue;
345 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000346 return noiseValue;
347}
348
349inline SkScalar smoothCurve(SkScalar t) {
Mike Reed8be952a2017-02-13 20:44:33 -0500350 return t * t * (3 - 2 * t);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000351}
352
353} // end namespace
354
Mike Reedf2ae2b22017-05-30 15:22:54 -0400355SkPerlinNoiseShaderImpl::SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::Type type,
Robert Phillipsbee27322018-01-23 09:58:18 -0500356 SkScalar baseFrequencyX,
357 SkScalar baseFrequencyY,
358 int numOctaves,
359 SkScalar seed,
360 const SkISize* tileSize)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000361 : fType(type)
362 , fBaseFrequencyX(baseFrequencyX)
363 , fBaseFrequencyY(baseFrequencyY)
Robert Phillipsbee27322018-01-23 09:58:18 -0500364 , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves : numOctaves/*[0,255] octaves allowed*/)
sugoi@google.come3b4c502013-04-05 13:47:09 +0000365 , fSeed(seed)
halcanary96fcdcc2015-08-27 07:41:13 -0700366 , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
commit-bot@chromium.orgfd5c9a62014-03-06 15:13:53 +0000367 , fStitchTiles(!fTileSize.isEmpty())
sugoi@google.come3b4c502013-04-05 13:47:09 +0000368{
Robert Phillipsbee27322018-01-23 09:58:18 -0500369 SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
Kevin Lubick6ee268d2018-05-15 13:59:54 -0400370 SkASSERT(fBaseFrequencyX >= 0);
371 SkASSERT(fBaseFrequencyY >= 0);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400372}
373
Florin Malita14d54c22017-05-18 11:52:59 -0400374sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
Mike Reedde5c5022018-01-26 14:59:12 -0500375 Type type = buffer.read32LE(kLast_Type);
Robert Phillipsbee27322018-01-23 09:58:18 -0500376
reed9fa60da2014-08-21 07:59:51 -0700377 SkScalar freqX = buffer.readScalar();
378 SkScalar freqY = buffer.readScalar();
Mike Reedde5c5022018-01-26 14:59:12 -0500379 int octaves = buffer.read32LE<int>(kMaxOctaves);
Robert Phillipsbee27322018-01-23 09:58:18 -0500380
reed9fa60da2014-08-21 07:59:51 -0700381 SkScalar seed = buffer.readScalar();
382 SkISize tileSize;
383 tileSize.fWidth = buffer.readInt();
384 tileSize.fHeight = buffer.readInt();
385
386 switch (type) {
387 case kFractalNoise_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400388 return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700389 case kTurbulence_Type:
Mike Reedf2ae2b22017-05-30 15:22:54 -0400390 return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
reed9fa60da2014-08-21 07:59:51 -0700391 default:
Mike Reedde5c5022018-01-26 14:59:12 -0500392 // Really shouldn't get here b.c. of earlier check on type
Robert Phillipsbee27322018-01-23 09:58:18 -0500393 buffer.validate(false);
halcanary96fcdcc2015-08-27 07:41:13 -0700394 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700395 }
396}
397
Florin Malita14d54c22017-05-18 11:52:59 -0400398void SkPerlinNoiseShaderImpl::flatten(SkWriteBuffer& buffer) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000399 buffer.writeInt((int) fType);
400 buffer.writeScalar(fBaseFrequencyX);
401 buffer.writeScalar(fBaseFrequencyY);
402 buffer.writeInt(fNumOctaves);
403 buffer.writeScalar(fSeed);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000404 buffer.writeInt(fTileSize.fWidth);
405 buffer.writeInt(fTileSize.fHeight);
406}
407
Florin Malita14d54c22017-05-18 11:52:59 -0400408SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::noise2D(
senorblancoca6a7c22014-06-27 13:35:52 -0700409 int channel, const StitchData& stitchData, const SkPoint& noiseVector) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000410 struct Noise {
411 int noisePositionIntegerValue;
senorblancoce6a3542014-06-12 11:24:19 -0700412 int nextNoisePositionIntegerValue;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000413 SkScalar noisePositionFractionValue;
414 Noise(SkScalar component)
415 {
416 SkScalar position = component + kPerlinNoise;
417 noisePositionIntegerValue = SkScalarFloorToInt(position);
418 noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue);
senorblancoce6a3542014-06-12 11:24:19 -0700419 nextNoisePositionIntegerValue = noisePositionIntegerValue + 1;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000420 }
421 };
422 Noise noiseX(noiseVector.x());
423 Noise noiseY(noiseVector.y());
424 SkScalar u, v;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400425 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000426 // If stitching, adjust lattice points accordingly.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000427 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000428 noiseX.noisePositionIntegerValue =
429 checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
430 noiseY.noisePositionIntegerValue =
431 checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
senorblancoce6a3542014-06-12 11:24:19 -0700432 noiseX.nextNoisePositionIntegerValue =
433 checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth);
434 noiseY.nextNoisePositionIntegerValue =
435 checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000436 }
437 noiseX.noisePositionIntegerValue &= kBlockMask;
438 noiseY.noisePositionIntegerValue &= kBlockMask;
senorblancoce6a3542014-06-12 11:24:19 -0700439 noiseX.nextNoisePositionIntegerValue &= kBlockMask;
440 noiseY.nextNoisePositionIntegerValue &= kBlockMask;
Florin Malita83223bc2017-05-31 14:14:05 -0400441 int i = fPaintingData.fLatticeSelector[noiseX.noisePositionIntegerValue];
442 int j = fPaintingData.fLatticeSelector[noiseX.nextNoisePositionIntegerValue];
senorblancoce6a3542014-06-12 11:24:19 -0700443 int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask;
444 int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask;
445 int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
446 int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000447 SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue);
448 SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400449
Hal Canaryfda46002017-05-08 17:17:47 -0400450 if (sx < 0 || sy < 0 || sx > 1 || sy > 1) {
451 return 0; // Check for pathological inputs.
452 }
Ben Wagner63fd7602017-10-09 15:45:33 -0400453
sugoi@google.come3b4c502013-04-05 13:47:09 +0000454 // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement
455 SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue,
456 noiseY.noisePositionFractionValue); // Offset (0,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400457 u = fPaintingData.fGradient[channel][b00].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000458 fractionValue.fX -= SK_Scalar1; // Offset (-1,0)
Florin Malita83223bc2017-05-31 14:14:05 -0400459 v = fPaintingData.fGradient[channel][b10].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000460 SkScalar a = SkScalarInterp(u, v, sx);
461 fractionValue.fY -= SK_Scalar1; // Offset (-1,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400462 v = fPaintingData.fGradient[channel][b11].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000463 fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1)
Florin Malita83223bc2017-05-31 14:14:05 -0400464 u = fPaintingData.fGradient[channel][b01].dot(fractionValue);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000465 SkScalar b = SkScalarInterp(u, v, sx);
466 return SkScalarInterp(a, b, sy);
467}
468
Florin Malita14d54c22017-05-18 11:52:59 -0400469SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceValueForPoint(
senorblancoca6a7c22014-06-27 13:35:52 -0700470 int channel, StitchData& stitchData, const SkPoint& point) const {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400471 const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000472 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000473 // Set up TurbulenceInitial stitch values.
Florin Malita83223bc2017-05-31 14:14:05 -0400474 stitchData = fPaintingData.fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000475 }
476 SkScalar turbulenceFunctionResult = 0;
Florin Malita83223bc2017-05-31 14:14:05 -0400477 SkPoint noiseVector(SkPoint::Make(point.x() * fPaintingData.fBaseFrequency.fX,
478 point.y() * fPaintingData.fBaseFrequency.fY));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000479 SkScalar ratio = SK_Scalar1;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000480 for (int octave = 0; octave < perlinNoiseShader.fNumOctaves; ++octave) {
senorblancoca6a7c22014-06-27 13:35:52 -0700481 SkScalar noise = noise2D(channel, stitchData, noiseVector);
reed80ea19c2015-05-12 10:37:34 -0700482 SkScalar numer = (perlinNoiseShader.fType == kFractalNoise_Type) ?
483 noise : SkScalarAbs(noise);
484 turbulenceFunctionResult += numer / ratio;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000485 noiseVector.fX *= 2;
486 noiseVector.fY *= 2;
487 ratio *= 2;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000488 if (perlinNoiseShader.fStitchTiles) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000489 // Update stitch values
John Stiles039f6812020-08-10 09:51:42 -0400490 stitchData = StitchData(SkIntToScalar(stitchData.fWidth) * 2,
Florin Malita102c8cf2018-06-05 17:37:12 -0400491 SkIntToScalar(stitchData.fHeight) * 2);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000492 }
493 }
494
495 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
496 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000497 if (perlinNoiseShader.fType == kFractalNoise_Type) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400498 turbulenceFunctionResult = SkScalarHalf(turbulenceFunctionResult + 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000499 }
500
501 if (channel == 3) { // Scale alpha by paint value
reed80ea19c2015-05-12 10:37:34 -0700502 turbulenceFunctionResult *= SkIntToScalar(getPaintAlpha()) / 255;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000503 }
504
505 // Clamp result
Brian Osmanaba642c2020-02-06 12:52:25 -0500506 return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000507}
508
Mike Reedf2ae2b22017-05-30 15:22:54 -0400509////////////////////////////////////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400510
Florin Malita14d54c22017-05-18 11:52:59 -0400511SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000512 const SkPoint& point, StitchData& stitchData) const {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000513 SkPoint newPoint;
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000514 fMatrix.mapPoints(&newPoint, &point, 1);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000515 newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
516 newPoint.fY = SkScalarRoundToScalar(newPoint.fY);
517
518 U8CPU rgba[4];
519 for (int channel = 3; channel >= 0; --channel) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400520 SkScalar value;
Brian Salomon4878b3e2021-01-08 18:11:33 -0500521 value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400522 rgba[channel] = SkScalarFloorToInt(255 * value);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000523 }
524 return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
525}
526
Mike Reede92aae62018-10-17 10:21:51 -0400527#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Mike Reedf2ae2b22017-05-30 15:22:54 -0400528SkShaderBase::Context* SkPerlinNoiseShaderImpl::onMakeContext(const ContextRec& rec,
Robert Phillipsf18c7562018-06-13 09:01:36 -0400529 SkArenaAlloc* alloc) const {
Mike Reed011d1662019-02-28 17:19:25 -0500530 // should we pay attention to rec's device-colorspace?
Herb Derby83e939b2017-02-07 14:25:11 -0500531 return alloc->make<PerlinNoiseShaderContext>(*this, rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000532}
Mike Reede92aae62018-10-17 10:21:51 -0400533#endif
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000534
Florin Malita83223bc2017-05-31 14:14:05 -0400535static inline SkMatrix total_matrix(const SkShaderBase::ContextRec& rec,
536 const SkShaderBase& shader) {
537 SkMatrix matrix = SkMatrix::Concat(*rec.fMatrix, shader.getLocalMatrix());
538 if (rec.fLocalMatrix) {
539 matrix.preConcat(*rec.fLocalMatrix);
540 }
541
542 return matrix;
543}
544
Florin Malita14d54c22017-05-18 11:52:59 -0400545SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::PerlinNoiseShaderContext(
546 const SkPerlinNoiseShaderImpl& shader, const ContextRec& rec)
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000547 : INHERITED(shader, rec)
Florin Malita83223bc2017-05-31 14:14:05 -0400548 , fMatrix(total_matrix(rec, shader)) // used for temp storage, adjusted below
549 , fPaintingData(shader.fTileSize, shader.fSeed, shader.fBaseFrequencyX,
550 shader.fBaseFrequencyY, fMatrix)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000551{
senorblanco@chromium.orga8d95f82014-04-04 14:46:10 +0000552 // This (1,1) translation is due to WebKit's 1 based coordinates for the noise
553 // (as opposed to 0 based, usually). The same adjustment is in the setData() function.
Florin Malita83223bc2017-05-31 14:14:05 -0400554 fMatrix.setTranslate(-fMatrix.getTranslateX() + SK_Scalar1,
555 -fMatrix.getTranslateY() + SK_Scalar1);
senorblancoca6a7c22014-06-27 13:35:52 -0700556}
557
Florin Malita14d54c22017-05-18 11:52:59 -0400558void SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shadeSpan(
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000559 int x, int y, SkPMColor result[], int count) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000560 SkPoint point = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
561 StitchData stitchData;
562 for (int i = 0; i < count; ++i) {
563 result[i] = shade(point, stitchData);
564 point.fX += SK_Scalar1;
565 }
566}
567
sugoi@google.come3b4c502013-04-05 13:47:09 +0000568/////////////////////////////////////////////////////////////////////
569
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000570#if SK_SUPPORT_GPU
sugoi@google.come3b4c502013-04-05 13:47:09 +0000571
Brian Salomon3176e862021-08-09 11:23:04 -0400572class GrGLPerlinNoise : public GrFragmentProcessor::ProgramImpl {
sugoi@google.com4775cba2013-04-17 13:46:56 +0000573public:
robertphillips9cdb9922016-02-03 12:25:40 -0800574 void emitCode(EmitArgs&) override;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000575
Mike Reedf2ae2b22017-05-30 15:22:54 -0400576 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
sugoi@google.com4775cba2013-04-17 13:46:56 +0000577
wangyixb1daa862015-08-18 11:29:31 -0700578protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400579 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700580
sugoi@google.com4775cba2013-04-17 13:46:56 +0000581private:
egdaniel018fb622015-10-28 07:26:40 -0700582 GrGLSLProgramDataManager::UniformHandle fStitchDataUni;
egdaniel018fb622015-10-28 07:26:40 -0700583 GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
senorblancof3b50272014-06-16 10:49:58 -0700584
Brian Salomon3176e862021-08-09 11:23:04 -0400585 using INHERITED = GrFragmentProcessor::ProgramImpl;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000586};
587
588/////////////////////////////////////////////////////////////////////
589
Mike Reedf2ae2b22017-05-30 15:22:54 -0400590class GrPerlinNoise2Effect : public GrFragmentProcessor {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000591public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400592 static std::unique_ptr<GrFragmentProcessor> Make(
Brian Salomon83c2d352020-06-17 11:46:21 -0400593 SkPerlinNoiseShaderImpl::Type type,
594 int numOctaves,
595 bool stitchTiles,
Brian Salomonaff329b2017-08-11 09:40:37 -0400596 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400597 GrSurfaceProxyView permutationsView,
598 GrSurfaceProxyView noiseView,
599 const SkMatrix& matrix,
600 const GrCaps& caps) {
601 static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
602 GrSamplerState::WrapMode::kClamp,
603 GrSamplerState::Filter::kNearest};
604 auto permutationsFP =
605 GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
606 SkMatrix::I(), kRepeatXSampler, caps);
607 auto noiseFP = GrTextureEffect::Make(std::move(noiseView), kPremul_SkAlphaType,
608 SkMatrix::I(), kRepeatXSampler, caps);
609
Michael Ludwigf2935c62020-06-26 11:07:23 -0400610 return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
Brian Salomon83c2d352020-06-17 11:46:21 -0400611 new GrPerlinNoise2Effect(type, numOctaves, stitchTiles, std::move(paintingData),
Michael Ludwigf2935c62020-06-26 11:07:23 -0400612 std::move(permutationsFP), std::move(noiseFP))));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000613 }
614
mtklein36352bf2015-03-25 18:17:31 -0700615 const char* name() const override { return "PerlinNoise"; }
joshualitteb2a6762014-12-04 11:35:33 -0800616
Brian Salomonaff329b2017-08-11 09:40:37 -0400617 std::unique_ptr<GrFragmentProcessor> clone() const override {
618 return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect(*this));
Brian Salomon4331e462017-07-26 14:58:11 -0400619 }
620
Mike Reedf2ae2b22017-05-30 15:22:54 -0400621 const SkPerlinNoiseShaderImpl::StitchData& stitchData() const { return fPaintingData->fStitchDataInit; }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000622
Florin Malita14d54c22017-05-18 11:52:59 -0400623 SkPerlinNoiseShaderImpl::Type type() const { return fType; }
senorblancof3b50272014-06-16 10:49:58 -0700624 bool stitchTiles() const { return fStitchTiles; }
senorblancoca6a7c22014-06-27 13:35:52 -0700625 const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
senorblancof3b50272014-06-16 10:49:58 -0700626 int numOctaves() const { return fNumOctaves; }
senorblancof3b50272014-06-16 10:49:58 -0700627
sugoi@google.come3b4c502013-04-05 13:47:09 +0000628private:
Brian Salomon3176e862021-08-09 11:23:04 -0400629 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomon18ab2032021-02-23 10:07:05 -0500630 return std::make_unique<GrGLPerlinNoise>();
wangyixb1daa862015-08-18 11:29:31 -0700631 }
632
Brian Salomon13b28732021-08-06 15:33:58 -0400633 void onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
wangyix4b3050b2015-08-04 07:59:37 -0700634 GrGLPerlinNoise::GenKey(*this, caps, b);
635 }
636
mtklein36352bf2015-03-25 18:17:31 -0700637 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400638 const GrPerlinNoise2Effect& s = sBase.cast<GrPerlinNoise2Effect>();
senorblancof3b50272014-06-16 10:49:58 -0700639 return fType == s.fType &&
senorblancoca6a7c22014-06-27 13:35:52 -0700640 fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency &&
senorblancof3b50272014-06-16 10:49:58 -0700641 fNumOctaves == s.fNumOctaves &&
642 fStitchTiles == s.fStitchTiles &&
senorblancoca6a7c22014-06-27 13:35:52 -0700643 fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000644 }
645
Brian Salomon83c2d352020-06-17 11:46:21 -0400646 GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type,
647 int numOctaves,
648 bool stitchTiles,
Florin Malitab365cf52017-05-30 17:18:01 -0400649 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
Brian Salomon83c2d352020-06-17 11:46:21 -0400650 std::unique_ptr<GrFragmentProcessor> permutationsFP,
Michael Ludwigf2935c62020-06-26 11:07:23 -0400651 std::unique_ptr<GrFragmentProcessor> noiseFP)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400652 : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags)
Brian Salomon587e08f2017-01-27 10:59:27 -0500653 , fType(type)
Brian Salomon587e08f2017-01-27 10:59:27 -0500654 , fNumOctaves(numOctaves)
655 , fStitchTiles(stitchTiles)
Florin Malitab365cf52017-05-30 17:18:01 -0400656 , fPaintingData(std::move(paintingData)) {
Brian Osman1298bc42020-06-30 13:39:35 -0400657 this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
658 this->registerChild(std::move(noiseFP), SkSL::SampleUsage::Explicit());
Michael Ludwigf2935c62020-06-26 11:07:23 -0400659 this->setUsesSampleCoordsDirectly();
sugoi@google.come3b4c502013-04-05 13:47:09 +0000660 }
661
Brian Salomon4331e462017-07-26 14:58:11 -0400662 GrPerlinNoise2Effect(const GrPerlinNoise2Effect& that)
John Stiles307f8f52021-08-09 15:36:59 -0400663 : INHERITED(that)
Brian Salomon4331e462017-07-26 14:58:11 -0400664 , fType(that.fType)
Brian Salomon4331e462017-07-26 14:58:11 -0400665 , fNumOctaves(that.fNumOctaves)
666 , fStitchTiles(that.fStitchTiles)
John Stiles307f8f52021-08-09 15:36:59 -0400667 , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) {}
Brian Salomonf7dcd762018-07-30 14:48:15 -0400668
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400669 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
sugoi@google.come3b4c502013-04-05 13:47:09 +0000670
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400671 SkPerlinNoiseShaderImpl::Type fType;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400672 int fNumOctaves;
673 bool fStitchTiles;
Brian Salomon83c2d352020-06-17 11:46:21 -0400674
Florin Malitab365cf52017-05-30 17:18:01 -0400675 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000676
John Stiles7571f9e2020-09-02 22:42:33 -0400677 using INHERITED = GrFragmentProcessor;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000678};
679
680/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400681GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000682
Hal Canary6f6961e2017-01-31 13:50:44 -0500683#if GR_TEST_UTILS
Brian Salomonaff329b2017-08-11 09:40:37 -0400684std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700685 int numOctaves = d->fRandom->nextRangeU(2, 10);
686 bool stitchTiles = d->fRandom->nextBool();
687 SkScalar seed = SkIntToScalar(d->fRandom->nextU());
John Stiles391a9f62021-04-29 23:17:41 -0400688 SkISize tileSize;
689 tileSize.fWidth = d->fRandom->nextRangeU(4, 4096);
690 tileSize.fHeight = d->fRandom->nextRangeU(4, 4096);
691 SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f, 0.99f);
692 SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f, 0.99f);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000693
reedfe630452016-03-25 09:08:00 -0700694 sk_sp<SkShader> shader(d->fRandom->nextBool() ?
695 SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400696 stitchTiles ? &tileSize : nullptr) :
reedfe630452016-03-25 09:08:00 -0700697 SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
Mike Reedf2ae2b22017-05-30 15:22:54 -0400698 stitchTiles ? &tileSize : nullptr));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000699
Brian Osman9f532a32016-10-19 11:12:09 -0400700 GrTest::TestAsFPArgs asFPArgs(d);
Florin Malita4aed1382017-05-25 10:38:07 -0400701 return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000702}
Hal Canary6f6961e2017-01-31 13:50:44 -0500703#endif
sugoi@google.com4775cba2013-04-17 13:46:56 +0000704
wangyix7c157a92015-07-22 15:08:53 -0700705void GrGLPerlinNoise::emitCode(EmitArgs& args) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400706 const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
robertphillipsbf536af2016-02-04 06:11:53 -0800707
Brian Salomonffd15ea2020-07-01 16:48:20 -0400708 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel7ea439b2015-12-03 09:20:44 -0800709 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000710
Ethan Nicholas16464c32020-04-06 13:53:05 -0400711 fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800712 "baseFrequency");
713 const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000714
halcanary96fcdcc2015-08-27 07:41:13 -0700715 const char* stitchDataUni = nullptr;
robertphillipsbf536af2016-02-04 06:11:53 -0800716 if (pne.stitchTiles()) {
Ethan Nicholas16464c32020-04-06 13:53:05 -0400717 fStitchDataUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
egdaniel7ea439b2015-12-03 09:20:44 -0800718 "stitchData");
719 stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000720 }
721
sugoi@google.comd537af52013-06-10 13:59:25 +0000722 // Add noise function
Brian Salomone338c292020-06-16 16:52:17 -0400723 const GrShaderVar gPerlinNoiseArgs[] = {{"chanCoord", kHalf_GrSLType },
724 {"noiseVec ", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000725
Brian Salomone338c292020-06-16 16:52:17 -0400726 const GrShaderVar gPerlinNoiseStitchArgs[] = {{"chanCoord" , kHalf_GrSLType },
727 {"noiseVec" , kHalf2_GrSLType},
728 {"stitchData", kHalf2_GrSLType}};
sugoi@google.come3b4c502013-04-05 13:47:09 +0000729
sugoi@google.comd537af52013-06-10 13:59:25 +0000730 SkString noiseCode;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000731
Brian Salomone338c292020-06-16 16:52:17 -0400732 noiseCode.append(
733 R"(half4 floorVal;
734 floorVal.xy = floor(noiseVec);
735 floorVal.zw = floorVal.xy + half2(1);
736 half2 fractVal = fract(noiseVec);
737 // smooth curve : t^2*(3 - 2*t)
738 half2 noiseSmooth = fractVal*fractVal*(half2(3) - 2*fractVal);)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000739
740 // Adjust frequencies if we're stitching tiles
robertphillipsbf536af2016-02-04 06:11:53 -0800741 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400742 noiseCode.append(
743 R"(if (floorVal.x >= stitchData.x) { floorVal.x -= stitchData.x; };
744 if (floorVal.y >= stitchData.y) { floorVal.y -= stitchData.y; };
745 if (floorVal.z >= stitchData.x) { floorVal.z -= stitchData.x; };
746 if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };)");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000747 }
748
Brian Osman6b5dbb42020-07-15 15:31:05 -0400749 // NOTE: We need to explicitly pass half4(1) as input color here, because the helper function
750 // can't see fInputColor (which is "_input" in the FP's outer function). skbug.com/10506
751 SkString sampleX = this->invokeChild(0, "half4(1)", args, "half2(floorVal.x, 0.5)");
752 SkString sampleY = this->invokeChild(0, "half4(1)", args, "half2(floorVal.z, 0.5)");
Brian Salomonb43d6992021-01-05 14:37:40 -0500753 noiseCode.appendf("half2 latticeIdx = half2(%s.a, %s.a);", sampleX.c_str(), sampleY.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000754
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000755#if defined(SK_BUILD_FOR_ANDROID)
756 // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
757 // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
758 // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
759 // (or 0.484368 here). The following rounding operation prevents these precision issues from
760 // affecting the result of the noise by making sure that we only have multiples of 1/255.
761 // (Note that 1/255 is about 0.003921569, which is the value used here).
Brian Salomone338c292020-06-16 16:52:17 -0400762 noiseCode.append(
763 "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);");
commit-bot@chromium.org344cf452013-06-17 14:19:01 +0000764#endif
765
sugoi@google.come3b4c502013-04-05 13:47:09 +0000766 // Get (x,y) coordinates with the permutated x
Brian Salomon83c2d352020-06-17 11:46:21 -0400767 noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000768
Brian Salomone338c292020-06-16 16:52:17 -0400769 noiseCode.append("half2 uv;");
770
771 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
772 // [-1,1] vector and perform a dot product between that vector and the provided vector.
773 // Save it as a string because we will repeat it 4x.
774 static constexpr const char* inc8bit = "0.00390625"; // 1.0 / 256.0
775 SkString dotLattice =
776 SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
777
Brian Osman6b5dbb42020-07-15 15:31:05 -0400778 SkString sampleA = this->invokeChild(1, "half4(1)", args, "half2(bcoords.x, chanCoord)");
779 SkString sampleB = this->invokeChild(1, "half4(1)", args, "half2(bcoords.y, chanCoord)");
780 SkString sampleC = this->invokeChild(1, "half4(1)", args, "half2(bcoords.w, chanCoord)");
781 SkString sampleD = this->invokeChild(1, "half4(1)", args, "half2(bcoords.z, chanCoord)");
Brian Salomon83c2d352020-06-17 11:46:21 -0400782
sugoi@google.come3b4c502013-04-05 13:47:09 +0000783 // Compute u, at offset (0,0)
Brian Salomon83c2d352020-06-17 11:46:21 -0400784 noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
785 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000786
sugoi@google.come3b4c502013-04-05 13:47:09 +0000787 // Compute v, at offset (-1,0)
Brian Salomone338c292020-06-16 16:52:17 -0400788 noiseCode.append("fractVal.x -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400789 noiseCode.appendf("lattice = %s;", sampleB.c_str());
790 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000791
792 // Compute 'a' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400793 noiseCode.append("half2 ab;");
794 noiseCode.append("ab.x = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000795
sugoi@google.come3b4c502013-04-05 13:47:09 +0000796 // Compute v, at offset (-1,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400797 noiseCode.append("fractVal.y -= 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400798 noiseCode.appendf("lattice = %s;", sampleC.c_str());
799 noiseCode.appendf("uv.y = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000800
sugoi@google.come3b4c502013-04-05 13:47:09 +0000801 // Compute u, at offset (0,-1)
Brian Salomone338c292020-06-16 16:52:17 -0400802 noiseCode.append("fractVal.x += 1.0;");
Brian Salomon83c2d352020-06-17 11:46:21 -0400803 noiseCode.appendf("lattice = %s;", sampleD.c_str());
804 noiseCode.appendf("uv.x = %s;", dotLattice.c_str());
sugoi@google.come3b4c502013-04-05 13:47:09 +0000805
806 // Compute 'b' as a linear interpolation of 'u' and 'v'
Brian Salomone338c292020-06-16 16:52:17 -0400807 noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000808 // Compute the noise as a linear interpolation of 'a' and 'b'
Brian Salomone338c292020-06-16 16:52:17 -0400809 noiseCode.append("return mix(ab.x, ab.y, noiseSmooth.y);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000810
John Stiles6b58a332020-10-26 17:53:06 -0400811 SkString noiseFuncName = fragBuilder->getMangledFunctionName("noiseFuncName");
robertphillipsbf536af2016-02-04 06:11:53 -0800812 if (pne.stitchTiles()) {
John Stiles6b58a332020-10-26 17:53:06 -0400813 fragBuilder->emitFunction(kHalf_GrSLType, noiseFuncName.c_str(),
John Stilesfdf61482020-10-27 09:45:40 -0400814 {gPerlinNoiseStitchArgs, SK_ARRAY_COUNT(gPerlinNoiseStitchArgs)},
John Stiles6b58a332020-10-26 17:53:06 -0400815 noiseCode.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000816 } else {
John Stiles6b58a332020-10-26 17:53:06 -0400817 fragBuilder->emitFunction(kHalf_GrSLType, noiseFuncName.c_str(),
John Stilesfdf61482020-10-27 09:45:40 -0400818 {gPerlinNoiseArgs, SK_ARRAY_COUNT(gPerlinNoiseArgs)},
John Stiles6b58a332020-10-26 17:53:06 -0400819 noiseCode.c_str());
sugoi@google.comd537af52013-06-10 13:59:25 +0000820 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000821
sugoi@google.comd537af52013-06-10 13:59:25 +0000822 // There are rounding errors if the floor operation is not performed here
Brian Salomone338c292020-06-16 16:52:17 -0400823 fragBuilder->codeAppendf("half2 noiseVec = half2(floor(%s.xy) * %s);",
Michael Ludwige88320b2020-06-24 09:04:56 -0400824 args.fSampleCoord, baseFrequencyUni);
sugoi@google.comd537af52013-06-10 13:59:25 +0000825
826 // Clear the color accumulator
John Stilesd1eab8b2020-12-15 09:47:26 -0500827 fragBuilder->codeAppendf("half4 color = half4(0);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000828
robertphillipsbf536af2016-02-04 06:11:53 -0800829 if (pne.stitchTiles()) {
sugoi@google.comd537af52013-06-10 13:59:25 +0000830 // Set up TurbulenceInitial stitch values.
Brian Salomone338c292020-06-16 16:52:17 -0400831 fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000832 }
sugoi@google.come3b4c502013-04-05 13:47:09 +0000833
Brian Salomone338c292020-06-16 16:52:17 -0400834 fragBuilder->codeAppendf("half ratio = 1.0;");
sugoi@google.comd537af52013-06-10 13:59:25 +0000835
836 // Loop over all octaves
robertphillipsbf536af2016-02-04 06:11:53 -0800837 fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
John Stilesd1eab8b2020-12-15 09:47:26 -0500838 fragBuilder->codeAppendf(" color += ");
Florin Malita14d54c22017-05-18 11:52:59 -0400839 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
egdaniel4ca2e602015-11-18 08:01:26 -0800840 fragBuilder->codeAppend("abs(");
sugoi@google.comd537af52013-06-10 13:59:25 +0000841 }
Brian Salomone338c292020-06-16 16:52:17 -0400842
Brian Salomon83c2d352020-06-17 11:46:21 -0400843 // There are 4 lines, put y coords at center of each.
844 static constexpr const char* chanCoordR = "0.5";
845 static constexpr const char* chanCoordG = "1.5";
846 static constexpr const char* chanCoordB = "2.5";
847 static constexpr const char* chanCoordA = "3.5";
robertphillipsbf536af2016-02-04 06:11:53 -0800848 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400849 fragBuilder->codeAppendf(R"(
John Stiles7cbb09c22021-01-07 16:07:00 -0500850 half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),
Brian Salomone338c292020-06-16 16:52:17 -0400851 %s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)))",
852 noiseFuncName.c_str(), chanCoordR,
853 noiseFuncName.c_str(), chanCoordG,
854 noiseFuncName.c_str(), chanCoordB,
855 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000856 } else {
Brian Salomone338c292020-06-16 16:52:17 -0400857 fragBuilder->codeAppendf(R"(
858 half4(%s(%s, noiseVec), %s(%s, noiseVec),
859 %s(%s, noiseVec), %s(%s, noiseVec)))",
860 noiseFuncName.c_str(), chanCoordR,
861 noiseFuncName.c_str(), chanCoordG,
862 noiseFuncName.c_str(), chanCoordB,
863 noiseFuncName.c_str(), chanCoordA);
sugoi@google.comd537af52013-06-10 13:59:25 +0000864 }
Florin Malita14d54c22017-05-18 11:52:59 -0400865 if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
Brian Salomone338c292020-06-16 16:52:17 -0400866 fragBuilder->codeAppend(")"); // end of "abs("
sugoi@google.comd537af52013-06-10 13:59:25 +0000867 }
Brian Salomone338c292020-06-16 16:52:17 -0400868 fragBuilder->codeAppend(" * ratio;");
sugoi@google.comd537af52013-06-10 13:59:25 +0000869
Brian Salomone338c292020-06-16 16:52:17 -0400870 fragBuilder->codeAppend(R"(noiseVec *= half2(2.0);
871 ratio *= 0.5;)");
sugoi@google.comd537af52013-06-10 13:59:25 +0000872
robertphillipsbf536af2016-02-04 06:11:53 -0800873 if (pne.stitchTiles()) {
Brian Salomone338c292020-06-16 16:52:17 -0400874 fragBuilder->codeAppend("stitchData *= half2(2.0);");
sugoi@google.comd537af52013-06-10 13:59:25 +0000875 }
Brian Salomone338c292020-06-16 16:52:17 -0400876 fragBuilder->codeAppend("}"); // end of the for loop on octaves
sugoi@google.come3b4c502013-04-05 13:47:09 +0000877
Florin Malita14d54c22017-05-18 11:52:59 -0400878 if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) {
sugoi@google.come3b4c502013-04-05 13:47:09 +0000879 // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
880 // by fractalNoise and (turbulenceFunctionResult) by turbulence.
John Stilesd1eab8b2020-12-15 09:47:26 -0500881 fragBuilder->codeAppendf("color = color * half4(0.5) + half4(0.5);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000882 }
883
sugoi@google.come3b4c502013-04-05 13:47:09 +0000884 // Clamp values
John Stilesd1eab8b2020-12-15 09:47:26 -0500885 fragBuilder->codeAppendf("color = saturate(color);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000886
887 // Pre-multiply the result
John Stilesd1eab8b2020-12-15 09:47:26 -0500888 fragBuilder->codeAppendf("return half4(color.rgb * color.aaa, color.a);");
sugoi@google.come3b4c502013-04-05 13:47:09 +0000889}
890
Brian Salomon94efbf52016-11-29 13:43:05 -0500891void GrGLPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700892 GrProcessorKeyBuilder* b) {
Mike Reedf2ae2b22017-05-30 15:22:54 -0400893 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +0000894
bsalomon63e99f72014-07-21 08:03:14 -0700895 uint32_t key = turbulence.numOctaves();
sugoi@google.come3b4c502013-04-05 13:47:09 +0000896
897 key = key << 3; // Make room for next 3 bits
898
899 switch (turbulence.type()) {
Florin Malita14d54c22017-05-18 11:52:59 -0400900 case SkPerlinNoiseShaderImpl::kFractalNoise_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +0000901 key |= 0x1;
902 break;
Florin Malita14d54c22017-05-18 11:52:59 -0400903 case SkPerlinNoiseShaderImpl::kTurbulence_Type:
sugoi@google.come3b4c502013-04-05 13:47:09 +0000904 key |= 0x2;
905 break;
906 default:
907 // leave key at 0
908 break;
909 }
910
911 if (turbulence.stitchTiles()) {
912 key |= 0x4; // Flip the 3rd bit if tile stitching is on
913 }
914
bsalomon63e99f72014-07-21 08:03:14 -0700915 b->add32(key);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000916}
917
egdaniel018fb622015-10-28 07:26:40 -0700918void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -0400919 const GrFragmentProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700920 INHERITED::onSetData(pdman, processor);
senorblancof3b50272014-06-16 10:49:58 -0700921
Mike Reedf2ae2b22017-05-30 15:22:54 -0400922 const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
sugoi@google.come3b4c502013-04-05 13:47:09 +0000923
924 const SkVector& baseFrequency = turbulence.baseFrequency();
kkinnunen7510b222014-07-30 00:04:16 -0700925 pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
sugoi@google.come3b4c502013-04-05 13:47:09 +0000926
sugoi@google.com4775cba2013-04-17 13:46:56 +0000927 if (turbulence.stitchTiles()) {
Florin Malita14d54c22017-05-18 11:52:59 -0400928 const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData();
kkinnunen7510b222014-07-30 00:04:16 -0700929 pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth),
Brian Salomon81454df2020-06-17 10:59:28 -0400930 SkIntToScalar(stitchData.fHeight));
sugoi@google.com4775cba2013-04-17 13:46:56 +0000931 }
932}
933
sugoi@google.come3b4c502013-04-05 13:47:09 +0000934/////////////////////////////////////////////////////////////////////
Mike Reedf2ae2b22017-05-30 15:22:54 -0400935
Brian Salomonaff329b2017-08-11 09:40:37 -0400936std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
Mike Reede3429e62018-01-19 11:43:34 -0500937 const GrFPArgs& args) const {
brianosman839345d2016-07-22 11:04:53 -0700938 SkASSERT(args.fContext);
mtklein3f3b3d02014-12-01 11:47:08 -0800939
Florin Malita52f02912020-03-09 16:33:17 -0400940 const auto localMatrix = this->totalLocalMatrix(args.fPreLocalMatrix);
Brian Osman449b1152020-04-15 16:43:00 -0400941 const auto paintMatrix = SkMatrix::Concat(args.fMatrixProvider.localToDevice(), *localMatrix);
senorblancoca6a7c22014-06-27 13:35:52 -0700942
Mike Reedf2ae2b22017-05-30 15:22:54 -0400943 // Either we don't stitch tiles, either we have a valid tile size
944 SkASSERT(!fStitchTiles || !fTileSize.isEmpty());
945
Florin Malitab365cf52017-05-30 17:18:01 -0400946 std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData =
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500947 std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(fTileSize,
Florin Malitab365cf52017-05-30 17:18:01 -0400948 fSeed,
949 fBaseFrequencyX,
950 fBaseFrequencyY,
Ethan Nicholas82940152019-01-10 13:58:14 -0500951 paintMatrix);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400952
Brian Osman449b1152020-04-15 16:43:00 -0400953 SkMatrix m = args.fMatrixProvider.localToDevice();
Florin Malitac6c5ead2018-04-11 15:33:40 -0400954 m.setTranslateX(-localMatrix->getTranslateX() + SK_Scalar1);
955 m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
Mike Reedf2ae2b22017-05-30 15:22:54 -0400956
Greg Daniel6f5441a2020-01-28 17:02:49 -0500957 auto context = args.fContext;
Mike Reedf2ae2b22017-05-30 15:22:54 -0400958
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +0000959 if (0 == fNumOctaves) {
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +0000960 if (kFractalNoise_Type == fType) {
bsalomonc21b09e2015-08-28 18:46:56 -0700961 // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
Brian Osman618d3042016-10-25 10:51:28 -0400962 // TODO: Either treat the output of this shader as sRGB or allow client to specify a
963 // color space of the noise. Either way, this case (and the GLSL) need to convert to
964 // the destination.
John Stiles85894302020-07-13 11:39:52 -0400965 auto inner = GrFragmentProcessor::ModulateRGBA(
966 /*child=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040));
Mike Reed28eaed22018-02-01 11:24:53 -0500967 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
reedcff10b22015-03-03 06:41:45 -0800968 }
bsalomonc21b09e2015-08-28 18:46:56 -0700969 // Emit zero.
Brian Salomon354147a2021-04-14 11:15:05 -0400970 return GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT);
commit-bot@chromium.orgc2a0ea62013-11-06 10:08:38 +0000971 }
972
Greg Daniel6f5441a2020-01-28 17:02:49 -0500973 const SkBitmap& permutationsBitmap = paintingData->getPermutationsBitmap();
Brian Salomon27c42022021-04-28 12:39:21 -0400974 const SkBitmap& noiseBitmap = paintingData->getNoiseBitmap();
Greg Daniel7e1912a2018-02-08 09:15:33 -0500975
Brian Salomon27c42022021-04-28 12:39:21 -0400976 auto permutationsView = std::get<0>(GrMakeCachedBitmapProxyView(context, permutationsBitmap));
977 auto noiseView = std::get<0>(GrMakeCachedBitmapProxyView(context, noiseBitmap));
sugoi@google.come3b4c502013-04-05 13:47:09 +0000978
Brian Salomon27c42022021-04-28 12:39:21 -0400979 if (permutationsView && noiseView) {
Brian Salomonaff329b2017-08-11 09:40:37 -0400980 auto inner = GrPerlinNoise2Effect::Make(fType,
981 fNumOctaves,
982 fStitchTiles,
983 std::move(paintingData),
Greg Danielc52db712020-01-28 17:03:46 -0500984 std::move(permutationsView),
985 std::move(noiseView),
Brian Salomon83c2d352020-06-17 11:46:21 -0400986 m,
987 *context->priv().caps());
Mike Reed28eaed22018-02-01 11:24:53 -0500988 return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
senorblancoca6a7c22014-06-27 13:35:52 -0700989 }
bsalomonc21b09e2015-08-28 18:46:56 -0700990 return nullptr;
sugoi@google.come3b4c502013-04-05 13:47:09 +0000991}
992
993#endif
994
Mike Reedf2ae2b22017-05-30 15:22:54 -0400995///////////////////////////////////////////////////////////////////////////////////////////////////
996
Mike Reed832aa112018-05-18 11:48:50 -0400997static bool valid_input(SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize,
998 SkScalar seed) {
999 if (!(baseX >= 0 && baseY >= 0)) {
1000 return false;
1001 }
1002 if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShaderImpl::kMaxOctaves)) {
1003 return false;
1004 }
1005 if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
1006 return false;
1007 }
1008 if (!SkScalarIsFinite(seed)) {
1009 return false;
1010 }
1011 return true;
1012}
1013
Mike Reedf2ae2b22017-05-30 15:22:54 -04001014sk_sp<SkShader> SkPerlinNoiseShader::MakeFractalNoise(SkScalar baseFrequencyX,
1015 SkScalar baseFrequencyY,
1016 int numOctaves, SkScalar seed,
1017 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001018 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1019 return nullptr;
1020 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001021 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kFractalNoise_Type,
1022 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1023 tileSize));
1024}
1025
1026sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
1027 SkScalar baseFrequencyY,
1028 int numOctaves, SkScalar seed,
1029 const SkISize* tileSize) {
Mike Reed832aa112018-05-18 11:48:50 -04001030 if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
1031 return nullptr;
1032 }
Mike Reedf2ae2b22017-05-30 15:22:54 -04001033 return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kTurbulence_Type,
1034 baseFrequencyX, baseFrequencyY, numOctaves, seed,
1035 tileSize));
1036}
1037
Mike Kleinfa5f6ce2018-10-20 08:21:31 -04001038void SkPerlinNoiseShader::RegisterFlattenables() {
Brian Salomon23356442018-11-30 15:33:19 -05001039 SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
Mike Klein12956722018-10-19 10:00:21 -04001040}