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