Chromium Code Reviews| Index: src/effects/SkPerlinNoiseShader.cpp |
| =================================================================== |
| --- src/effects/SkPerlinNoiseShader.cpp (revision 9474) |
| +++ src/effects/SkPerlinNoiseShader.cpp (working copy) |
| @@ -494,7 +494,7 @@ |
| ///////////////////////////////////////////////////////////////////// |
| -#if SK_SUPPORT_GPU && !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_WIN) |
| +#if SK_SUPPORT_GPU && !defined(SK_BUILD_FOR_ANDROID) |
| // CPU noise is faster on Android, so the GPU implementation is only for desktop |
| #include "GrTBackendEffectFactory.h" |
| @@ -986,13 +986,16 @@ |
| stitchDataUni = builder->getUniformCStr(fStitchDataUni); |
| } |
| - const char* chanCoords = "chanCoords"; |
| + // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8 |
| + const char* chanCoordR = "0.125"; |
| + const char* chanCoordG = "0.375"; |
| + const char* chanCoordB = "0.625"; |
| + const char* chanCoordA = "0.875"; |
| + const char* chanCoord = "chanCoord"; |
| const char* stitchData = "stitchData"; |
| const char* ratio = "ratio"; |
| - const char* noise = "noise"; |
| const char* noiseXY = "noiseXY"; |
| const char* noiseVec = "noiseVec"; |
| - const char* noiseVecIni = "noiseVecIni"; |
| const char* noiseSmooth = "noiseSmooth"; |
| const char* fractVal = "fractVal"; |
| const char* uv = "uv"; |
| @@ -1005,61 +1008,52 @@ |
| // [-1,1] vector and perform a dot product between that vector and the provided vector. |
| const char* dotLattice = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);"; |
| - // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8 |
| - builder->fsCodeAppendf("\t\tconst vec4 %s = vec4(0.125, 0.375, 0.625, 0.875);", chanCoords); |
| + // Add noise function |
| + static const GrGLShaderVar perlinnoise_Args[] = { |
|
bsalomon
2013/06/10 13:39:25
We already have two conventions for static const g
|
| + GrGLShaderVar(chanCoord, kFloat_GrSLType), |
| + GrGLShaderVar(noiseVec, kVec2f_GrSLType) |
| + }; |
| - // There are rounding errors if the floor operation is not performed here |
| - builder->fsCodeAppendf("\t\tvec2 %s = floor((%s*vec3(%s, 1.0)).xy) * %s;", |
| - noiseVecIni, invMatrixUni, vCoords, baseFrequencyUni); |
| + static const GrGLShaderVar perlinnoise_stitch_Args[] = { |
| + GrGLShaderVar(chanCoord, kFloat_GrSLType), |
| + GrGLShaderVar(noiseVec, kVec2f_GrSLType), |
| + GrGLShaderVar(stitchData, kVec4f_GrSLType) |
| + }; |
| - // Loop over the 4 channels |
| - builder->fsCodeAppend("\t\tfor (int channel = 3; channel >= 0; --channel) {"); |
| + SkString noise_code; |
|
bsalomon
2013/06/10 13:39:25
localVarsAreLikeThis.
|
| - if (fStitchTiles) { |
| - // Set up TurbulenceInitial stitch values. |
| - builder->fsCodeAppendf("\t\tvec4 %s = %s;", stitchData, stitchDataUni); |
| - } |
| + noise_code.appendf( |
| + "\tvec4 %s = vec4(floor(%s) + vec2(%s), fract(%s));", |
| + noiseXY, noiseVec, perlinNoise, noiseVec); |
| - builder->fsCodeAppendf("\t\t%s[channel] = 0.0;", outputColor); |
| - |
| - builder->fsCodeAppendf("\t\tfloat %s = 1.0;", ratio); |
| - builder->fsCodeAppendf("\t\tvec2 %s = %s;", noiseVec, noiseVecIni); |
| - |
| - // Loop over all octaves |
| - builder->fsCodeAppendf("\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves); |
| - |
| - builder->fsCodeAppendf("\t\tvec4 %s = vec4(floor(%s) + vec2(%s), fract(%s));", |
| - noiseXY, noiseVec, perlinNoise, noiseVec); |
| - |
| // smooth curve : t * t * (3 - 2 * t) |
| - builder->fsCodeAppendf("\t\tvec2 %s = %s.zw * %s.zw * (vec2(3.0) - vec2(2.0) * %s.zw);", |
| - noiseSmooth, noiseXY, noiseXY, noiseXY); |
| + noise_code.appendf("\n\tvec2 %s = %s.zw * %s.zw * (vec2(3.0) - vec2(2.0) * %s.zw);", |
| + noiseSmooth, noiseXY, noiseXY, noiseXY); |
| // Adjust frequencies if we're stitching tiles |
| if (fStitchTiles) { |
| - builder->fsCodeAppendf("\t\tif(%s.x >= %s.y) { %s.x -= %s.x; }", |
| - noiseXY, stitchData, noiseXY, stitchData); |
| - builder->fsCodeAppendf("\t\tif(%s.x >= (%s.y - 1.0)) { %s.x -= (%s.x - 1.0); }", |
| - noiseXY, stitchData, noiseXY, stitchData); |
| - builder->fsCodeAppendf("\t\tif(%s.y >= %s.w) { %s.y -= %s.z; }", |
| - noiseXY, stitchData, noiseXY, stitchData); |
| - builder->fsCodeAppendf("\t\tif(%s.y >= (%s.w - 1.0)) { %s.y -= (%s.z - 1.0); }", |
| - noiseXY, stitchData, noiseXY, stitchData); |
| + noise_code.appendf("\n\tif(%s.x >= %s.y) { %s.x -= %s.x; }", |
| + noiseXY, stitchData, noiseXY, stitchData); |
| + noise_code.appendf("\n\tif(%s.x >= (%s.y - 1.0)) { %s.x -= (%s.x - 1.0); }", |
| + noiseXY, stitchData, noiseXY, stitchData); |
| + noise_code.appendf("\n\tif(%s.y >= %s.w) { %s.y -= %s.z; }", |
| + noiseXY, stitchData, noiseXY, stitchData); |
| + noise_code.appendf("\n\tif(%s.y >= (%s.w - 1.0)) { %s.y -= (%s.z - 1.0); }", |
| + noiseXY, stitchData, noiseXY, stitchData); |
| } |
| // Get texture coordinates and normalize |
| - builder->fsCodeAppendf("\t\t%s.xy = fract(floor(mod(%s.xy, 256.0)) / vec2(256.0));", |
| - noiseXY, noiseXY); |
| + noise_code.appendf("\n\t%s.xy = fract(floor(mod(%s.xy, 256.0)) / vec2(256.0));\n", |
| + noiseXY, noiseXY); |
| // Get permutation for x |
| { |
| SkString xCoords(""); |
| xCoords.appendf("vec2(%s.x, 0.5)", noiseXY); |
| - builder->fsCodeAppendf("\t\tvec2 %s;\t\t%s.x = ", latticeIdx, latticeIdx); |
| - builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, |
| - samplers[0], xCoords.c_str(), kVec2f_GrSLType); |
| - builder->fsCodeAppend(".r;\n"); |
| + noise_code.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx); |
| + builder->appendTextureLookup(&noise_code, samplers[0], xCoords.c_str(), kVec2f_GrSLType); |
| + noise_code.append(".r;"); |
| } |
| // Get permutation for x + 1 |
| @@ -1067,104 +1061,145 @@ |
| SkString xCoords(""); |
| xCoords.appendf("vec2(fract(%s.x + %s), 0.5)", noiseXY, inc8bit); |
| - builder->fsCodeAppendf("\t\t%s.y = ", latticeIdx); |
| - builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, |
| - samplers[0], xCoords.c_str(), kVec2f_GrSLType); |
| - builder->fsCodeAppend(".r;\n"); |
| + noise_code.appendf("\n\t%s.y = ", latticeIdx); |
| + builder->appendTextureLookup(&noise_code, samplers[0], xCoords.c_str(), kVec2f_GrSLType); |
| + noise_code.append(".r;"); |
| } |
| // Get (x,y) coordinates with the permutated x |
| - builder->fsCodeAppendf("\t\t%s = fract(%s + %s.yy);", latticeIdx, latticeIdx, noiseXY); |
| + noise_code.appendf("\n\t%s = fract(%s + %s.yy);", latticeIdx, latticeIdx, noiseXY); |
| - builder->fsCodeAppendf("\t\tvec2 %s = %s.zw;", fractVal, noiseXY); |
| + noise_code.appendf("\n\tvec2 %s = %s.zw;", fractVal, noiseXY); |
| - builder->fsCodeAppendf("\t\tvec2 %s;", uv); |
| + noise_code.appendf("\n\n\tvec2 %s;", uv); |
| // Compute u, at offset (0,0) |
| { |
| SkString latticeCoords(""); |
| - latticeCoords.appendf("vec2(%s.x, %s[channel])", latticeIdx, chanCoords); |
| - builder->fsCodeAppendf("vec4 %s = ", lattice); |
| - builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, |
| - samplers[1], latticeCoords.c_str(), kVec2f_GrSLType); |
| - builder->fsCodeAppendf(".bgra;\n\t\t%s.x = ", uv); |
| - builder->fsCodeAppendf(dotLattice, lattice, lattice, inc8bit, fractVal); |
| + latticeCoords.appendf("vec2(%s.x, %s)", latticeIdx, chanCoord); |
| + noise_code.appendf("\n\tvec4 %s = ", lattice); |
| + builder->appendTextureLookup(&noise_code, samplers[1], latticeCoords.c_str(), |
| + kVec2f_GrSLType); |
| + noise_code.appendf(".bgra;\n\t%s.x = ", uv); |
| + noise_code.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); |
| } |
| - builder->fsCodeAppendf("\t\t%s.x -= 1.0;", fractVal); |
| + noise_code.appendf("\n\t%s.x -= 1.0;", fractVal); |
| // Compute v, at offset (-1,0) |
| { |
| SkString latticeCoords(""); |
| - latticeCoords.appendf("vec2(%s.y, %s[channel])", latticeIdx, chanCoords); |
| - builder->fsCodeAppend("lattice = "); |
| - builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, |
| - samplers[1], latticeCoords.c_str(), kVec2f_GrSLType); |
| - builder->fsCodeAppendf(".bgra;\n\t\t%s.y = ", uv); |
| - builder->fsCodeAppendf(dotLattice, lattice, lattice, inc8bit, fractVal); |
| + latticeCoords.appendf("vec2(%s.y, %s)", latticeIdx, chanCoord); |
| + noise_code.append("lattice = "); |
| + builder->appendTextureLookup(&noise_code, samplers[1], latticeCoords.c_str(), |
| + kVec2f_GrSLType); |
| + noise_code.appendf(".bgra;\n\t%s.y = ", uv); |
| + noise_code.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); |
| } |
| // Compute 'a' as a linear interpolation of 'u' and 'v' |
| - builder->fsCodeAppendf("\t\tvec2 %s;", ab); |
| - builder->fsCodeAppendf("\t\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); |
| + noise_code.appendf("\n\tvec2 %s;", ab); |
| + noise_code.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); |
| - builder->fsCodeAppendf("\t\t%s.y -= 1.0;", fractVal); |
| + noise_code.appendf("\n\t%s.y -= 1.0;", fractVal); |
| // Compute v, at offset (-1,-1) |
| { |
| SkString latticeCoords(""); |
| - latticeCoords.appendf("vec2(fract(%s.y + %s), %s[channel])", |
| - latticeIdx, inc8bit, chanCoords); |
| - builder->fsCodeAppend("lattice = "); |
| - builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, |
| - samplers[1], latticeCoords.c_str(), kVec2f_GrSLType); |
| - builder->fsCodeAppendf(".bgra;\n\t\t%s.y = ", uv); |
| - builder->fsCodeAppendf(dotLattice, lattice, lattice, inc8bit, fractVal); |
| + latticeCoords.appendf("vec2(fract(%s.y + %s), %s)", latticeIdx, inc8bit, chanCoord); |
| + noise_code.append("lattice = "); |
| + builder->appendTextureLookup(&noise_code, samplers[1], latticeCoords.c_str(), |
| + kVec2f_GrSLType); |
| + noise_code.appendf(".bgra;\n\t%s.y = ", uv); |
| + noise_code.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); |
| } |
| - builder->fsCodeAppendf("\t\t%s.x += 1.0;", fractVal); |
| + noise_code.appendf("\n\t%s.x += 1.0;", fractVal); |
| // Compute u, at offset (0,-1) |
| { |
| SkString latticeCoords(""); |
| - latticeCoords.appendf("vec2(fract(%s.x + %s), %s[channel])", |
| - latticeIdx, inc8bit, chanCoords); |
| - builder->fsCodeAppend("lattice = "); |
| - builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, |
| - samplers[1], latticeCoords.c_str(), kVec2f_GrSLType); |
| - builder->fsCodeAppendf(".bgra;\n\t\t%s.x = ", uv); |
| - builder->fsCodeAppendf(dotLattice, lattice, lattice, inc8bit, fractVal); |
| + latticeCoords.appendf("vec2(fract(%s.x + %s), %s)", latticeIdx, inc8bit, chanCoord); |
| + noise_code.append("lattice = "); |
| + builder->appendTextureLookup(&noise_code, samplers[1], latticeCoords.c_str(), |
| + kVec2f_GrSLType); |
| + noise_code.appendf(".bgra;\n\t%s.x = ", uv); |
| + noise_code.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); |
| } |
| // Compute 'b' as a linear interpolation of 'u' and 'v' |
| - builder->fsCodeAppendf("\t\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); |
| + noise_code.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); |
| // Compute the noise as a linear interpolation of 'a' and 'b' |
| - builder->fsCodeAppendf("\t\tfloat %s = mix(%s.x, %s.y, %s.y);", noise, ab, ab, noiseSmooth); |
| + noise_code.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth); |
| - builder->fsCodeAppendf("\t\t%s[channel] += ", outputColor); |
| - builder->fsCodeAppendf((fType == SkPerlinNoiseShader::kFractalNoise_Type) ? |
| - "%s / %s;" : "abs(%s) / %s;", noise, ratio); |
| + SkString noise_funcName; |
| + builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "perlinnoise", |
|
bsalomon
2013/06/10 13:39:25
Would this be easier to read if the there was just
|
| + fStitchTiles ? SK_ARRAY_COUNT(perlinnoise_stitch_Args) : |
| + SK_ARRAY_COUNT(perlinnoise_Args), |
| + fStitchTiles ? perlinnoise_stitch_Args : perlinnoise_Args, |
| + noise_code.c_str(), &noise_funcName); |
| - builder->fsCodeAppendf("\t\t%s *= vec2(2.0);", noiseVec); |
| - builder->fsCodeAppendf("\t\t%s *= 2.0;", ratio); |
| + // There are rounding errors if the floor operation is not performed here |
| + builder->fsCodeAppendf("\n\t\tvec2 %s = floor((%s * vec3(%s, 1.0)).xy) * %s;", |
| + noiseVec, invMatrixUni, vCoords, baseFrequencyUni); |
| + // Clear the color accumulator |
| + builder->fsCodeAppendf("\n\t\t%s = vec4(0.0);", outputColor); |
| + |
| if (fStitchTiles) { |
| - builder->fsCodeAppendf("\t\t%s.xz *= vec2(2.0);", stitchData); |
| - builder->fsCodeAppendf("\t\t%s.yw = %s.xz + vec2(%s);", stitchData, stitchData, perlinNoise); |
| + // Set up TurbulenceInitial stitch values. |
| + builder->fsCodeAppendf("\n\t\tvec4 %s = %s;", stitchData, stitchDataUni); |
| } |
| - builder->fsCodeAppend("\t\t}"); // end of the for loop on octaves |
| - builder->fsCodeAppend("\t\t}"); // end of the for loop on channels |
| + builder->fsCodeAppendf("\n\t\tfloat %s = 1.0;", ratio); |
| + // Loop over all octaves |
| + builder->fsCodeAppendf("\n\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves); |
| + |
| + builder->fsCodeAppendf("\n\t\t\t%s += ", outputColor); |
| + if (fType != SkPerlinNoiseShader::kFractalNoise_Type) { |
| + builder->fsCodeAppend("abs("); |
| + } |
| + if (fStitchTiles) { |
| + builder->fsCodeAppendf( |
| + "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s)," |
| + "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))", |
| + noise_funcName.c_str(), chanCoordR, noiseVec, stitchData, |
| + noise_funcName.c_str(), chanCoordG, noiseVec, stitchData, |
| + noise_funcName.c_str(), chanCoordB, noiseVec, stitchData, |
| + noise_funcName.c_str(), chanCoordA, noiseVec, stitchData); |
| + } else { |
| + builder->fsCodeAppendf( |
| + "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s)," |
| + "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))", |
| + noise_funcName.c_str(), chanCoordR, noiseVec, |
| + noise_funcName.c_str(), chanCoordG, noiseVec, |
| + noise_funcName.c_str(), chanCoordB, noiseVec, |
| + noise_funcName.c_str(), chanCoordA, noiseVec); |
| + } |
| + if (fType != SkPerlinNoiseShader::kFractalNoise_Type) { |
| + builder->fsCodeAppendf(")"); // end of "abs(" |
| + } |
| + builder->fsCodeAppendf(" * %s;", ratio); |
| + |
| + builder->fsCodeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec); |
| + builder->fsCodeAppendf("\n\t\t\t%s *= 0.5;", ratio); |
| + |
| + if (fStitchTiles) { |
| + builder->fsCodeAppendf("\n\t\t\t%s.xz *= vec2(2.0);", stitchData); |
| + builder->fsCodeAppendf("\n\t\t\t%s.yw = %s.xz + vec2(%s);", stitchData, stitchData, perlinNoise); |
| + } |
| + builder->fsCodeAppend("\n\t\t}"); // end of the for loop on octaves |
| + |
| if (fType == SkPerlinNoiseShader::kFractalNoise_Type) { |
| // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 |
| // by fractalNoise and (turbulenceFunctionResult) by turbulence. |
| - builder->fsCodeAppendf("\t\t%s = %s * vec4(0.5) + vec4(0.5);", outputColor, outputColor); |
| + builder->fsCodeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);", outputColor, outputColor); |
| } |
| - builder->fsCodeAppendf("\t\t%s.a *= %s;", outputColor, alphaUni); |
| + builder->fsCodeAppendf("\n\t\t%s.a *= %s;", outputColor, alphaUni); |
| // Clamp values |
| - builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);", outputColor, outputColor); |
| + builder->fsCodeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", outputColor, outputColor); |
| // Pre-multiply the result |
| - builder->fsCodeAppendf("\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n", |
| + builder->fsCodeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n", |
| outputColor, outputColor, outputColor, outputColor); |
| } |
| @@ -1295,7 +1330,7 @@ |
| #else |
| GrEffectRef* SkPerlinNoiseShader::asNewEffect(GrContext*, const SkPaint&) const { |
| -#if !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_WIN) |
| +#if !defined(SK_BUILD_FOR_ANDROID) |
| SkDEBUGFAIL("Should not call in GPU-less build"); |
| #endif |
| return NULL; |