xref: /aosp_15_r20/external/skia/src/gpu/ganesh/effects/GrPerlinNoise2Effect.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2023 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrPerlinNoise2Effect.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkPerlinNoiseShader.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSLTypeShared.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/KeyBuilder.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessor.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessors.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorUnitTest.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderCaps.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderVar.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTestUtils.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkPerlinNoiseShaderType.h"
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
30*c8dee2aaSAndroid Build Coastguard Worker #include <iterator>
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker class SkShader;
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect)35*c8dee2aaSAndroid Build Coastguard Worker GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrPerlinNoise2Effect)
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
38*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor> GrPerlinNoise2Effect::TestCreate(GrProcessorTestData* d) {
39*c8dee2aaSAndroid Build Coastguard Worker     int numOctaves = d->fRandom->nextRangeU(2, 10);
40*c8dee2aaSAndroid Build Coastguard Worker     bool stitchTiles = d->fRandom->nextBool();
41*c8dee2aaSAndroid Build Coastguard Worker     SkScalar seed = SkIntToScalar(d->fRandom->nextU());
42*c8dee2aaSAndroid Build Coastguard Worker     SkISize tileSize;
43*c8dee2aaSAndroid Build Coastguard Worker     tileSize.fWidth = d->fRandom->nextRangeU(4, 4096);
44*c8dee2aaSAndroid Build Coastguard Worker     tileSize.fHeight = d->fRandom->nextRangeU(4, 4096);
45*c8dee2aaSAndroid Build Coastguard Worker     SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f, 0.99f);
46*c8dee2aaSAndroid Build Coastguard Worker     SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f, 0.99f);
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> shader(d->fRandom->nextBool()
49*c8dee2aaSAndroid Build Coastguard Worker                                    ? SkShaders::MakeFractalNoise(baseFrequencyX,
50*c8dee2aaSAndroid Build Coastguard Worker                                                                  baseFrequencyY,
51*c8dee2aaSAndroid Build Coastguard Worker                                                                  numOctaves,
52*c8dee2aaSAndroid Build Coastguard Worker                                                                  seed,
53*c8dee2aaSAndroid Build Coastguard Worker                                                                  stitchTiles ? &tileSize : nullptr)
54*c8dee2aaSAndroid Build Coastguard Worker                                    : SkShaders::MakeTurbulence(baseFrequencyX,
55*c8dee2aaSAndroid Build Coastguard Worker                                                                baseFrequencyY,
56*c8dee2aaSAndroid Build Coastguard Worker                                                                numOctaves,
57*c8dee2aaSAndroid Build Coastguard Worker                                                                seed,
58*c8dee2aaSAndroid Build Coastguard Worker                                                                stitchTiles ? &tileSize : nullptr));
59*c8dee2aaSAndroid Build Coastguard Worker 
60*c8dee2aaSAndroid Build Coastguard Worker     GrTest::TestAsFPArgs asFPArgs(d);
61*c8dee2aaSAndroid Build Coastguard Worker     return GrFragmentProcessors::Make(
62*c8dee2aaSAndroid Build Coastguard Worker             shader.get(), asFPArgs.args(), GrTest::TestMatrix(d->fRandom));
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker #endif
65*c8dee2aaSAndroid Build Coastguard Worker 
emitHelper(EmitArgs & args)66*c8dee2aaSAndroid Build Coastguard Worker SkString GrPerlinNoise2Effect::Impl::emitHelper(EmitArgs& args) {
67*c8dee2aaSAndroid Build Coastguard Worker     const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker     // Add noise function
72*c8dee2aaSAndroid Build Coastguard Worker     const GrShaderVar gPerlinNoiseArgs[] = {{"chanCoord", SkSLType::kHalf},
73*c8dee2aaSAndroid Build Coastguard Worker                                             {"noiseVec ", SkSLType::kHalf2}};
74*c8dee2aaSAndroid Build Coastguard Worker 
75*c8dee2aaSAndroid Build Coastguard Worker     const GrShaderVar gPerlinNoiseStitchArgs[] = {{"chanCoord", SkSLType::kHalf},
76*c8dee2aaSAndroid Build Coastguard Worker                                                   {"noiseVec", SkSLType::kHalf2},
77*c8dee2aaSAndroid Build Coastguard Worker                                                   {"stitchData", SkSLType::kHalf2}};
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker     SkString noiseCode;
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.append(
82*c8dee2aaSAndroid Build Coastguard Worker             "half4 floorVal;"
83*c8dee2aaSAndroid Build Coastguard Worker             "floorVal.xy = floor(noiseVec);"
84*c8dee2aaSAndroid Build Coastguard Worker             "floorVal.zw = floorVal.xy + half2(1);"
85*c8dee2aaSAndroid Build Coastguard Worker             "half2 fractVal = fract(noiseVec);"
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker             // Hermite interpolation : t^2*(3 - 2*t)
88*c8dee2aaSAndroid Build Coastguard Worker             "half2 noiseSmooth = smoothstep(0, 1, fractVal);"
89*c8dee2aaSAndroid Build Coastguard Worker     );
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker     // Adjust frequencies if we're stitching tiles
92*c8dee2aaSAndroid Build Coastguard Worker     if (pne.stitchTiles()) {
93*c8dee2aaSAndroid Build Coastguard Worker         noiseCode.append("floorVal -= step(stitchData.xyxy, floorVal) * stitchData.xyxy;");
94*c8dee2aaSAndroid Build Coastguard Worker     }
95*c8dee2aaSAndroid Build Coastguard Worker 
96*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: We need to explicitly pass half4(1) as input color here, because the helper function
97*c8dee2aaSAndroid Build Coastguard Worker     // can't see fInputColor (which is "_input" in the FP's outer function). skbug.com/10506
98*c8dee2aaSAndroid Build Coastguard Worker     SkString sampleX = this->invokeChild(0, "half4(1)", args, "half2(floorVal.x + 0.5, 0.5)");
99*c8dee2aaSAndroid Build Coastguard Worker     SkString sampleY = this->invokeChild(0, "half4(1)", args, "half2(floorVal.z + 0.5, 0.5)");
100*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("half2 latticeIdx = half2(%s.a, %s.a);", sampleX.c_str(), sampleY.c_str());
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     if (args.fShaderCaps->fPerlinNoiseRoundingFix) {
103*c8dee2aaSAndroid Build Coastguard Worker         // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
104*c8dee2aaSAndroid Build Coastguard Worker         // The issue is that colors aren't accurate enough on Tegra devices. For example, if an
105*c8dee2aaSAndroid Build Coastguard Worker         // 8 bit value of 124 (or 0.486275 here) is entered, we can get a texture value of
106*c8dee2aaSAndroid Build Coastguard Worker         // 123.513725 (or 0.484368 here). The following rounding operation prevents these precision
107*c8dee2aaSAndroid Build Coastguard Worker         // issues from affecting the result of the noise by making sure that we only have multiples
108*c8dee2aaSAndroid Build Coastguard Worker         // of 1/255. (Note that 1/255 is about 0.003921569, which is the value used here).
109*c8dee2aaSAndroid Build Coastguard Worker         noiseCode.append(
110*c8dee2aaSAndroid Build Coastguard Worker                 "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);");
111*c8dee2aaSAndroid Build Coastguard Worker     }
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker     // Get (x,y) coordinates with the permuted x
114*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;");
115*c8dee2aaSAndroid Build Coastguard Worker 
116*c8dee2aaSAndroid Build Coastguard Worker     // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a
117*c8dee2aaSAndroid Build Coastguard Worker     // [-1,1] vector and perform a dot product between that vector and the provided vector.
118*c8dee2aaSAndroid Build Coastguard Worker     // Save it as a string because we will repeat it 4x.
119*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* inc8bit = "0.00390625";  // 1.0 / 256.0
120*c8dee2aaSAndroid Build Coastguard Worker     SkString dotLattice =
121*c8dee2aaSAndroid Build Coastguard Worker             SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit);
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker     SkString sampleA = this->invokeChild(1, "half4(1)", args, "half2(bcoords.x, chanCoord)");
124*c8dee2aaSAndroid Build Coastguard Worker     SkString sampleB = this->invokeChild(1, "half4(1)", args, "half2(bcoords.y, chanCoord)");
125*c8dee2aaSAndroid Build Coastguard Worker     SkString sampleC = this->invokeChild(1, "half4(1)", args, "half2(bcoords.w, chanCoord)");
126*c8dee2aaSAndroid Build Coastguard Worker     SkString sampleD = this->invokeChild(1, "half4(1)", args, "half2(bcoords.z, chanCoord)");
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker     // Compute u, at offset (0,0)
129*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("half4 lattice = %s;", sampleA.c_str());
130*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("half u = %s;", dotLattice.c_str());
131*c8dee2aaSAndroid Build Coastguard Worker 
132*c8dee2aaSAndroid Build Coastguard Worker     // Compute v, at offset (-1,0)
133*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.append("fractVal.x -= 1.0;");
134*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("lattice = %s;", sampleB.c_str());
135*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("half v = %s;", dotLattice.c_str());
136*c8dee2aaSAndroid Build Coastguard Worker 
137*c8dee2aaSAndroid Build Coastguard Worker     // Compute 'a' as a linear interpolation of 'u' and 'v'
138*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.append("half a = mix(u, v, noiseSmooth.x);");
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker     // Compute v, at offset (-1,-1)
141*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.append("fractVal.y -= 1.0;");
142*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("lattice = %s;", sampleC.c_str());
143*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("v = %s;", dotLattice.c_str());
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker     // Compute u, at offset (0,-1)
146*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.append("fractVal.x += 1.0;");
147*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("lattice = %s;", sampleD.c_str());
148*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.appendf("u = %s;", dotLattice.c_str());
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker     // Compute 'b' as a linear interpolation of 'u' and 'v'
151*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.append("half b = mix(u, v, noiseSmooth.x);");
152*c8dee2aaSAndroid Build Coastguard Worker 
153*c8dee2aaSAndroid Build Coastguard Worker     // Compute the noise as a linear interpolation of 'a' and 'b'
154*c8dee2aaSAndroid Build Coastguard Worker     noiseCode.append("return mix(a, b, noiseSmooth.y);");
155*c8dee2aaSAndroid Build Coastguard Worker 
156*c8dee2aaSAndroid Build Coastguard Worker     SkString noiseFuncName = fragBuilder->getMangledFunctionName("noiseFuncName");
157*c8dee2aaSAndroid Build Coastguard Worker     if (pne.stitchTiles()) {
158*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->emitFunction(SkSLType::kHalf,
159*c8dee2aaSAndroid Build Coastguard Worker                                   noiseFuncName.c_str(),
160*c8dee2aaSAndroid Build Coastguard Worker                                   {gPerlinNoiseStitchArgs, std::size(gPerlinNoiseStitchArgs)},
161*c8dee2aaSAndroid Build Coastguard Worker                                   noiseCode.c_str());
162*c8dee2aaSAndroid Build Coastguard Worker     } else {
163*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->emitFunction(SkSLType::kHalf,
164*c8dee2aaSAndroid Build Coastguard Worker                                   noiseFuncName.c_str(),
165*c8dee2aaSAndroid Build Coastguard Worker                                   {gPerlinNoiseArgs, std::size(gPerlinNoiseArgs)},
166*c8dee2aaSAndroid Build Coastguard Worker                                   noiseCode.c_str());
167*c8dee2aaSAndroid Build Coastguard Worker     }
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker     return noiseFuncName;
170*c8dee2aaSAndroid Build Coastguard Worker }
171*c8dee2aaSAndroid Build Coastguard Worker 
emitCode(EmitArgs & args)172*c8dee2aaSAndroid Build Coastguard Worker void GrPerlinNoise2Effect::Impl::emitCode(EmitArgs& args) {
173*c8dee2aaSAndroid Build Coastguard Worker     SkString noiseFuncName = this->emitHelper(args);
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker     const GrPerlinNoise2Effect& pne = args.fFp.cast<GrPerlinNoise2Effect>();
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
178*c8dee2aaSAndroid Build Coastguard Worker     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker     fBaseFrequencyUni = uniformHandler->addUniform(
181*c8dee2aaSAndroid Build Coastguard Worker             &pne, kFragment_GrShaderFlag, SkSLType::kHalf2, "baseFrequency");
182*c8dee2aaSAndroid Build Coastguard Worker     const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker     const char* stitchDataUni = nullptr;
185*c8dee2aaSAndroid Build Coastguard Worker     if (pne.stitchTiles()) {
186*c8dee2aaSAndroid Build Coastguard Worker         fStitchDataUni = uniformHandler->addUniform(
187*c8dee2aaSAndroid Build Coastguard Worker                 &pne, kFragment_GrShaderFlag, SkSLType::kHalf2, "stitchData");
188*c8dee2aaSAndroid Build Coastguard Worker         stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni);
189*c8dee2aaSAndroid Build Coastguard Worker     }
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     // In the past, Perlin noise handled coordinates a bit differently than most shaders.
192*c8dee2aaSAndroid Build Coastguard Worker     // It operated in device space, floored; it also had a one-pixel transform matrix applied to
193*c8dee2aaSAndroid Build Coastguard Worker     // both the X and Y coordinates. This is roughly equivalent to adding 0.5 to the coordinates.
194*c8dee2aaSAndroid Build Coastguard Worker     // This was originally done in order to better match preexisting golden images from WebKit.
195*c8dee2aaSAndroid Build Coastguard Worker     // Perlin noise now operates in local space, which allows rotation to work correctly. To better
196*c8dee2aaSAndroid Build Coastguard Worker     // approximate past behavior, we add 0.5 to the coordinates here. This is _not_ the same because
197*c8dee2aaSAndroid Build Coastguard Worker     // this adjustment is occurring in local space, not device space, but it means that the "same"
198*c8dee2aaSAndroid Build Coastguard Worker     // noise will be calculated regardless of CTM.
199*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppendf(
200*c8dee2aaSAndroid Build Coastguard Worker             "half2 noiseVec = half2((%s + 0.5) * %s);", args.fSampleCoord, baseFrequencyUni);
201*c8dee2aaSAndroid Build Coastguard Worker 
202*c8dee2aaSAndroid Build Coastguard Worker     // Clear the color accumulator
203*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppendf("half4 color = half4(0);");
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker     if (pne.stitchTiles()) {
206*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni);
207*c8dee2aaSAndroid Build Coastguard Worker     }
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppendf("half ratio = 1.0;");
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker     // Loop over all octaves
212*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves());
213*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppendf("color += ");
214*c8dee2aaSAndroid Build Coastguard Worker     if (pne.type() != SkPerlinNoiseShaderType::kFractalNoise) {
215*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->codeAppend("abs(");
216*c8dee2aaSAndroid Build Coastguard Worker     }
217*c8dee2aaSAndroid Build Coastguard Worker 
218*c8dee2aaSAndroid Build Coastguard Worker     // There are 4 lines, put y coords at center of each.
219*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* chanCoordR = "0.5";
220*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* chanCoordG = "1.5";
221*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* chanCoordB = "2.5";
222*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* chanCoordA = "3.5";
223*c8dee2aaSAndroid Build Coastguard Worker     if (pne.stitchTiles()) {
224*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->codeAppendf(
225*c8dee2aaSAndroid Build Coastguard Worker                 "half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData),"
226*c8dee2aaSAndroid Build Coastguard Worker                       "%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData))",
227*c8dee2aaSAndroid Build Coastguard Worker                 noiseFuncName.c_str(),
228*c8dee2aaSAndroid Build Coastguard Worker                 chanCoordR,
229*c8dee2aaSAndroid Build Coastguard Worker                 noiseFuncName.c_str(),
230*c8dee2aaSAndroid Build Coastguard Worker                 chanCoordG,
231*c8dee2aaSAndroid Build Coastguard Worker                 noiseFuncName.c_str(),
232*c8dee2aaSAndroid Build Coastguard Worker                 chanCoordB,
233*c8dee2aaSAndroid Build Coastguard Worker                 noiseFuncName.c_str(),
234*c8dee2aaSAndroid Build Coastguard Worker                 chanCoordA);
235*c8dee2aaSAndroid Build Coastguard Worker     } else {
236*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->codeAppendf(
237*c8dee2aaSAndroid Build Coastguard Worker                 "half4(%s(%s, noiseVec), %s(%s, noiseVec),"
238*c8dee2aaSAndroid Build Coastguard Worker                       "%s(%s, noiseVec), %s(%s, noiseVec))",
239*c8dee2aaSAndroid Build Coastguard Worker                 noiseFuncName.c_str(),
240*c8dee2aaSAndroid Build Coastguard Worker                 chanCoordR,
241*c8dee2aaSAndroid Build Coastguard Worker                 noiseFuncName.c_str(),
242*c8dee2aaSAndroid Build Coastguard Worker                 chanCoordG,
243*c8dee2aaSAndroid Build Coastguard Worker                 noiseFuncName.c_str(),
244*c8dee2aaSAndroid Build Coastguard Worker                 chanCoordB,
245*c8dee2aaSAndroid Build Coastguard Worker                 noiseFuncName.c_str(),
246*c8dee2aaSAndroid Build Coastguard Worker                 chanCoordA);
247*c8dee2aaSAndroid Build Coastguard Worker     }
248*c8dee2aaSAndroid Build Coastguard Worker     if (pne.type() != SkPerlinNoiseShaderType::kFractalNoise) {
249*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->codeAppend(")");  // end of "abs("
250*c8dee2aaSAndroid Build Coastguard Worker     }
251*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppend(" * ratio;");
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppend(
254*c8dee2aaSAndroid Build Coastguard Worker             "noiseVec *= half2(2.0);"
255*c8dee2aaSAndroid Build Coastguard Worker             "ratio *= 0.5;");
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker     if (pne.stitchTiles()) {
258*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->codeAppend("stitchData *= half2(2.0);");
259*c8dee2aaSAndroid Build Coastguard Worker     }
260*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppend("}");  // end of the for loop on octaves
261*c8dee2aaSAndroid Build Coastguard Worker 
262*c8dee2aaSAndroid Build Coastguard Worker     if (pne.type() == SkPerlinNoiseShaderType::kFractalNoise) {
263*c8dee2aaSAndroid Build Coastguard Worker         // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
264*c8dee2aaSAndroid Build Coastguard Worker         // by fractalNoise and (turbulenceFunctionResult) by turbulence.
265*c8dee2aaSAndroid Build Coastguard Worker         fragBuilder->codeAppendf("color = color * half4(0.5) + half4(0.5);");
266*c8dee2aaSAndroid Build Coastguard Worker     }
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker     // Clamp values
269*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppendf("color = saturate(color);");
270*c8dee2aaSAndroid Build Coastguard Worker 
271*c8dee2aaSAndroid Build Coastguard Worker     // Pre-multiply the result
272*c8dee2aaSAndroid Build Coastguard Worker     fragBuilder->codeAppendf("return half4(color.rgb * color.aaa, color.a);");
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & processor)275*c8dee2aaSAndroid Build Coastguard Worker void GrPerlinNoise2Effect::Impl::onSetData(const GrGLSLProgramDataManager& pdman,
276*c8dee2aaSAndroid Build Coastguard Worker                                            const GrFragmentProcessor& processor) {
277*c8dee2aaSAndroid Build Coastguard Worker     const GrPerlinNoise2Effect& turbulence = processor.cast<GrPerlinNoise2Effect>();
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker     const SkVector& baseFrequency = turbulence.baseFrequency();
280*c8dee2aaSAndroid Build Coastguard Worker     pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
281*c8dee2aaSAndroid Build Coastguard Worker 
282*c8dee2aaSAndroid Build Coastguard Worker     if (turbulence.stitchTiles()) {
283*c8dee2aaSAndroid Build Coastguard Worker         const SkPerlinNoiseShader::StitchData& stitchData = turbulence.stitchData();
284*c8dee2aaSAndroid Build Coastguard Worker         pdman.set2f(fStitchDataUni,
285*c8dee2aaSAndroid Build Coastguard Worker                     SkIntToScalar(stitchData.fWidth),
286*c8dee2aaSAndroid Build Coastguard Worker                     SkIntToScalar(stitchData.fHeight));
287*c8dee2aaSAndroid Build Coastguard Worker     }
288*c8dee2aaSAndroid Build Coastguard Worker }
289*c8dee2aaSAndroid Build Coastguard Worker 
onAddToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const290*c8dee2aaSAndroid Build Coastguard Worker void GrPerlinNoise2Effect::onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
291*c8dee2aaSAndroid Build Coastguard Worker     uint32_t key = fNumOctaves;
292*c8dee2aaSAndroid Build Coastguard Worker     key = key << 3;  // Make room for next 3 bits
293*c8dee2aaSAndroid Build Coastguard Worker     switch (fType) {
294*c8dee2aaSAndroid Build Coastguard Worker         case SkPerlinNoiseShaderType::kFractalNoise:
295*c8dee2aaSAndroid Build Coastguard Worker             key |= 0x1;
296*c8dee2aaSAndroid Build Coastguard Worker             break;
297*c8dee2aaSAndroid Build Coastguard Worker         case SkPerlinNoiseShaderType::kTurbulence:
298*c8dee2aaSAndroid Build Coastguard Worker             key |= 0x2;
299*c8dee2aaSAndroid Build Coastguard Worker             break;
300*c8dee2aaSAndroid Build Coastguard Worker         default:
301*c8dee2aaSAndroid Build Coastguard Worker             // leave key at 0
302*c8dee2aaSAndroid Build Coastguard Worker             break;
303*c8dee2aaSAndroid Build Coastguard Worker     }
304*c8dee2aaSAndroid Build Coastguard Worker     if (fStitchTiles) {
305*c8dee2aaSAndroid Build Coastguard Worker         key |= 0x4;  // Flip the 3rd bit if tile stitching is on
306*c8dee2aaSAndroid Build Coastguard Worker     }
307*c8dee2aaSAndroid Build Coastguard Worker     b->add32(key);
308*c8dee2aaSAndroid Build Coastguard Worker }
309