*** Perlin noise GM needs to be rebaselined ***
Enabling Perlin Noise on Android I enabled the Perlin Noise shader on Android after doing some minor modifications to the shader, specifically for Android (and #ifdefed for Android, to make sure none of this affects other platforms). For Tegra devices (Nexus 7, Xoom), a precision issue related to the color values read from textures caused the noise to read the wrong indices and produce bad noise. I fixed this by adding a founding of the values read by simply doing the equivalent of "colorValue = floor(colorValue * 255.0) / 255.0" to make sure we retrieve the colors that were written in the texture originally. For non-Tegra devices (Nexus 10), dealing with values in the order of 4096.0 was problematic without using the "highp" precision setting. To solve this, a few variables were given the high precision setting. Since both fixes don't seem to do considerable harm to the platforms that are not being targetted, I left both fixes on all android devices for now. I also reduced the Perlin noise gm so that it takes less time to test it on the Xoom (Original time was about 20 seconds, this shold take less than 10, hopefully) BUG= R=senorblanco@google.com, bsalomon@google.com, sugoi@google.com, senorblanco@chromium.org Author: sugoi@chromium.org Review URL: https://chromiumcodereview.appspot.com/16818013 git-svn-id: http://skia.googlecode.com/svn/trunk@9637 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
d892bd8ba6
commit
344cf45a40
@ -23,7 +23,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual SkISize onISize() {
|
virtual SkISize onISize() {
|
||||||
return make_isize(500, 400);
|
return make_isize(200, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawClippedRect(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
|
void drawClippedRect(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
|
||||||
@ -56,48 +56,24 @@ protected:
|
|||||||
test(canvas, 0, 0, SkPerlinNoiseShader::kFractalNoise_Type,
|
test(canvas, 0, 0, SkPerlinNoiseShader::kFractalNoise_Type,
|
||||||
0.1f, 0.1f, 2, 0, false);
|
0.1f, 0.1f, 2, 0, false);
|
||||||
test(canvas, 100, 0, SkPerlinNoiseShader::kFractalNoise_Type,
|
test(canvas, 100, 0, SkPerlinNoiseShader::kFractalNoise_Type,
|
||||||
0.4f, 0.2f, 3, 0, true);
|
|
||||||
test(canvas, 200, 0, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.3f, 0.6f, 4, 0, false);
|
|
||||||
test(canvas, 300, 0, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.2f, 0.4f, 5, 0, true);
|
0.2f, 0.4f, 5, 0, true);
|
||||||
test(canvas, 400, 0, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.5f, 0.8f, 6, 0, false);
|
|
||||||
|
|
||||||
test(canvas, 0, 100, SkPerlinNoiseShader::kTurbulence_Type,
|
test(canvas, 0, 100, SkPerlinNoiseShader::kTurbulence_Type,
|
||||||
0.1f, 0.1f, 2, 0, true);
|
0.1f, 0.1f, 2, 0, true);
|
||||||
test(canvas, 100, 100, SkPerlinNoiseShader::kTurbulence_Type,
|
test(canvas, 100, 100, SkPerlinNoiseShader::kTurbulence_Type,
|
||||||
0.4f, 0.2f, 3, 0, false);
|
|
||||||
test(canvas, 200, 100, SkPerlinNoiseShader::kTurbulence_Type,
|
|
||||||
0.3f, 0.6f, 4, 0, true);
|
|
||||||
test(canvas, 300, 100, SkPerlinNoiseShader::kTurbulence_Type,
|
|
||||||
0.2f, 0.4f, 5, 0, false);
|
0.2f, 0.4f, 5, 0, false);
|
||||||
test(canvas, 400, 100, SkPerlinNoiseShader::kTurbulence_Type,
|
|
||||||
0.5f, 0.8f, 6, 0, true);
|
|
||||||
|
|
||||||
test(canvas, 0, 200, SkPerlinNoiseShader::kFractalNoise_Type,
|
test(canvas, 0, 200, SkPerlinNoiseShader::kFractalNoise_Type,
|
||||||
0.1f, 0.1f, 3, 1, false);
|
0.1f, 0.1f, 3, 1, false);
|
||||||
test(canvas, 100, 200, SkPerlinNoiseShader::kFractalNoise_Type,
|
test(canvas, 100, 200, SkPerlinNoiseShader::kFractalNoise_Type,
|
||||||
0.1f, 0.1f, 3, 2, false);
|
|
||||||
test(canvas, 200, 200, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.1f, 0.1f, 3, 3, false);
|
|
||||||
test(canvas, 300, 200, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.1f, 0.1f, 3, 4, false);
|
0.1f, 0.1f, 3, 4, false);
|
||||||
test(canvas, 400, 200, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.1f, 0.1f, 3, 5, false);
|
|
||||||
|
|
||||||
canvas->scale(SkFloatToScalar(0.75f), SkFloatToScalar(1.0f));
|
canvas->scale(SkFloatToScalar(0.75f), SkFloatToScalar(1.0f));
|
||||||
|
|
||||||
test(canvas, 0, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
test(canvas, 0, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
||||||
0.1f, 0.1f, 2, 0, false);
|
0.1f, 0.1f, 2, 0, false);
|
||||||
test(canvas, 100, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
test(canvas, 100, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
||||||
0.4f, 0.2f, 3, 0, true);
|
|
||||||
test(canvas, 200, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.3f, 0.6f, 4, 0, false);
|
|
||||||
test(canvas, 300, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.2f, 0.4f, 5, 0, true);
|
0.2f, 0.4f, 5, 0, true);
|
||||||
test(canvas, 400, 300, SkPerlinNoiseShader::kFractalNoise_Type,
|
|
||||||
0.5f, 0.8f, 6, 0, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -494,8 +494,7 @@ void SkPerlinNoiseShader::shadeSpan16(int x, int y, uint16_t result[], int count
|
|||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#if SK_SUPPORT_GPU && !defined(SK_BUILD_FOR_ANDROID)
|
#if SK_SUPPORT_GPU
|
||||||
// CPU noise is faster on Android, so the GPU implementation is only for desktop
|
|
||||||
|
|
||||||
#include "GrTBackendEffectFactory.h"
|
#include "GrTBackendEffectFactory.h"
|
||||||
|
|
||||||
@ -1008,23 +1007,29 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
|
|||||||
// [-1,1] vector and perform a dot product between that vector and the provided vector.
|
// [-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);";
|
const char* dotLattice = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);";
|
||||||
|
|
||||||
|
// Android precision fix for NON Tegra devices, like, for example: Nexus 10 (ARM's Mali-T604)
|
||||||
|
// The value of perlinNoise is 4096.0, so we need a high precision float to store this
|
||||||
|
const GrGLShaderVar::Precision precision = GrGLShaderVar::kHigh_Precision;
|
||||||
|
const char* precisionString =
|
||||||
|
GrGLShaderVar::PrecisionString(precision, builder->ctxInfo().binding());
|
||||||
|
|
||||||
// Add noise function
|
// Add noise function
|
||||||
static const GrGLShaderVar gPerlinNoiseArgs[] = {
|
static const GrGLShaderVar gPerlinNoiseArgs[] = {
|
||||||
GrGLShaderVar(chanCoord, kFloat_GrSLType),
|
GrGLShaderVar(chanCoord, kFloat_GrSLType),
|
||||||
GrGLShaderVar(noiseVec, kVec2f_GrSLType)
|
GrGLShaderVar(noiseVec, kVec2f_GrSLType, GrGLShaderVar::kNonArray, precision)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const GrGLShaderVar gPerlinNoiseStitchArgs[] = {
|
static const GrGLShaderVar gPerlinNoiseStitchArgs[] = {
|
||||||
GrGLShaderVar(chanCoord, kFloat_GrSLType),
|
GrGLShaderVar(chanCoord, kFloat_GrSLType),
|
||||||
GrGLShaderVar(noiseVec, kVec2f_GrSLType),
|
GrGLShaderVar(noiseVec, kVec2f_GrSLType, GrGLShaderVar::kNonArray, precision),
|
||||||
GrGLShaderVar(stitchData, kVec4f_GrSLType)
|
GrGLShaderVar(stitchData, kVec4f_GrSLType, GrGLShaderVar::kNonArray, precision)
|
||||||
};
|
};
|
||||||
|
|
||||||
SkString noiseCode;
|
SkString noiseCode;
|
||||||
|
|
||||||
noiseCode.appendf(
|
noiseCode.appendf(
|
||||||
"\tvec4 %s = vec4(floor(%s) + vec2(%s), fract(%s));",
|
"\t%svec4 %s = vec4(floor(%s) + vec2(%s), fract(%s));",
|
||||||
noiseXY, noiseVec, perlinNoise, noiseVec);
|
precisionString, noiseXY, noiseVec, perlinNoise, noiseVec);
|
||||||
|
|
||||||
// smooth curve : t * t * (3 - 2 * t)
|
// smooth curve : t * t * (3 - 2 * t)
|
||||||
noiseCode.appendf("\n\tvec2 %s = %s.zw * %s.zw * (vec2(3.0) - vec2(2.0) * %s.zw);",
|
noiseCode.appendf("\n\tvec2 %s = %s.zw * %s.zw * (vec2(3.0) - vec2(2.0) * %s.zw);",
|
||||||
@ -1066,6 +1071,17 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
|
|||||||
noiseCode.append(".r;");
|
noiseCode.append(".r;");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(SK_BUILD_FOR_ANDROID)
|
||||||
|
// Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3).
|
||||||
|
// The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit
|
||||||
|
// value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725
|
||||||
|
// (or 0.484368 here). The following rounding operation prevents these precision issues from
|
||||||
|
// affecting the result of the noise by making sure that we only have multiples of 1/255.
|
||||||
|
// (Note that 1/255 is about 0.003921569, which is the value used here).
|
||||||
|
noiseCode.appendf("\n\t%s = floor(%s * vec2(255.0) + vec2(0.5)) * vec2(0.003921569);",
|
||||||
|
latticeIdx, latticeIdx);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Get (x,y) coordinates with the permutated x
|
// Get (x,y) coordinates with the permutated x
|
||||||
noiseCode.appendf("\n\t%s = fract(%s + %s.yy);", latticeIdx, latticeIdx, noiseXY);
|
noiseCode.appendf("\n\t%s = fract(%s + %s.yy);", latticeIdx, latticeIdx, noiseXY);
|
||||||
|
|
||||||
@ -1088,7 +1104,7 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
|
|||||||
{
|
{
|
||||||
SkString latticeCoords("");
|
SkString latticeCoords("");
|
||||||
latticeCoords.appendf("vec2(%s.y, %s)", latticeIdx, chanCoord);
|
latticeCoords.appendf("vec2(%s.y, %s)", latticeIdx, chanCoord);
|
||||||
noiseCode.append("lattice = ");
|
noiseCode.append("\n\tlattice = ");
|
||||||
builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
|
builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
|
||||||
kVec2f_GrSLType);
|
kVec2f_GrSLType);
|
||||||
noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
|
noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
|
||||||
@ -1104,7 +1120,7 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
|
|||||||
{
|
{
|
||||||
SkString latticeCoords("");
|
SkString latticeCoords("");
|
||||||
latticeCoords.appendf("vec2(fract(%s.y + %s), %s)", latticeIdx, inc8bit, chanCoord);
|
latticeCoords.appendf("vec2(fract(%s.y + %s), %s)", latticeIdx, inc8bit, chanCoord);
|
||||||
noiseCode.append("lattice = ");
|
noiseCode.append("\n\tlattice = ");
|
||||||
builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
|
builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
|
||||||
kVec2f_GrSLType);
|
kVec2f_GrSLType);
|
||||||
noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
|
noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
|
||||||
@ -1116,7 +1132,7 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
|
|||||||
{
|
{
|
||||||
SkString latticeCoords("");
|
SkString latticeCoords("");
|
||||||
latticeCoords.appendf("vec2(fract(%s.x + %s), %s)", latticeIdx, inc8bit, chanCoord);
|
latticeCoords.appendf("vec2(fract(%s.x + %s), %s)", latticeIdx, inc8bit, chanCoord);
|
||||||
noiseCode.append("lattice = ");
|
noiseCode.append("\n\tlattice = ");
|
||||||
builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
|
builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
|
||||||
kVec2f_GrSLType);
|
kVec2f_GrSLType);
|
||||||
noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
|
noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
|
||||||
@ -1130,13 +1146,13 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
|
|||||||
|
|
||||||
SkString noiseFuncName;
|
SkString noiseFuncName;
|
||||||
if (fStitchTiles) {
|
if (fStitchTiles) {
|
||||||
builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "perlinnoise",
|
builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType,
|
||||||
SK_ARRAY_COUNT(gPerlinNoiseStitchArgs), gPerlinNoiseStitchArgs,
|
"perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
|
||||||
noiseCode.c_str(), &noiseFuncName);
|
gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
|
||||||
} else {
|
} else {
|
||||||
builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType, "perlinnoise",
|
builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, kFloat_GrSLType,
|
||||||
SK_ARRAY_COUNT(gPerlinNoiseArgs), gPerlinNoiseArgs,
|
"perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
|
||||||
noiseCode.c_str(), &noiseFuncName);
|
gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are rounding errors if the floor operation is not performed here
|
// There are rounding errors if the floor operation is not performed here
|
||||||
@ -1148,7 +1164,7 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
|
|||||||
|
|
||||||
if (fStitchTiles) {
|
if (fStitchTiles) {
|
||||||
// Set up TurbulenceInitial stitch values.
|
// Set up TurbulenceInitial stitch values.
|
||||||
builder->fsCodeAppendf("\n\t\tvec4 %s = %s;", stitchData, stitchDataUni);
|
builder->fsCodeAppendf("\n\t\t%s vec4 %s = %s;", precisionString, stitchData, stitchDataUni);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder->fsCodeAppendf("\n\t\tfloat %s = 1.0;", ratio);
|
builder->fsCodeAppendf("\n\t\tfloat %s = 1.0;", ratio);
|
||||||
@ -1187,7 +1203,8 @@ void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
|
|||||||
|
|
||||||
if (fStitchTiles) {
|
if (fStitchTiles) {
|
||||||
builder->fsCodeAppendf("\n\t\t\t%s.xz *= vec2(2.0);", stitchData);
|
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->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
|
builder->fsCodeAppend("\n\t\t}"); // end of the for loop on octaves
|
||||||
|
|
||||||
@ -1334,9 +1351,7 @@ GrEffectRef* SkPerlinNoiseShader::asNewEffect(GrContext* context, const SkPaint&
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
GrEffectRef* SkPerlinNoiseShader::asNewEffect(GrContext*, const SkPaint&) const {
|
GrEffectRef* SkPerlinNoiseShader::asNewEffect(GrContext*, const SkPaint&) const {
|
||||||
#if !defined(SK_BUILD_FOR_ANDROID)
|
|
||||||
SkDEBUGFAIL("Should not call in GPU-less build");
|
SkDEBUGFAIL("Should not call in GPU-less build");
|
||||||
#endif
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,12 +67,13 @@ public:
|
|||||||
fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
|
fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrGLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray) {
|
GrGLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray,
|
||||||
|
Precision precision = kDefault_Precision) {
|
||||||
GrAssert(kVoid_GrSLType != type);
|
GrAssert(kVoid_GrSLType != type);
|
||||||
fType = type;
|
fType = type;
|
||||||
fTypeModifier = kNone_TypeModifier;
|
fTypeModifier = kNone_TypeModifier;
|
||||||
fCount = arrayCount;
|
fCount = arrayCount;
|
||||||
fPrecision = kDefault_Precision;
|
fPrecision = precision;
|
||||||
fOrigin = kDefault_Origin;
|
fOrigin = kDefault_Origin;
|
||||||
fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
|
fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
|
||||||
fName = name;
|
fName = name;
|
||||||
@ -301,6 +302,25 @@ public:
|
|||||||
fUseUniformFloatArrays ? "" : ".x");
|
fUseUniformFloatArrays ? "" : ".x");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* PrecisionString(Precision p, GrGLBinding binding) {
|
||||||
|
// Desktop GLSL has added precision qualifiers but they don't do anything.
|
||||||
|
if (kES2_GrGLBinding == binding) {
|
||||||
|
switch (p) {
|
||||||
|
case kLow_Precision:
|
||||||
|
return "lowp ";
|
||||||
|
case kMedium_Precision:
|
||||||
|
return "mediump ";
|
||||||
|
case kHigh_Precision:
|
||||||
|
return "highp ";
|
||||||
|
case kDefault_Precision:
|
||||||
|
return "";
|
||||||
|
default:
|
||||||
|
GrCrash("Unexpected precision type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const char* TypeModifierString(TypeModifier t, GrGLSLGeneration gen) {
|
static const char* TypeModifierString(TypeModifier t, GrGLSLGeneration gen) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
@ -326,25 +346,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* PrecisionString(Precision p, GrGLBinding binding) {
|
|
||||||
// Desktop GLSL has added precision qualifiers but they don't do anything.
|
|
||||||
if (kES2_GrGLBinding == binding) {
|
|
||||||
switch (p) {
|
|
||||||
case kLow_Precision:
|
|
||||||
return "lowp ";
|
|
||||||
case kMedium_Precision:
|
|
||||||
return "mediump ";
|
|
||||||
case kHigh_Precision:
|
|
||||||
return "highp ";
|
|
||||||
case kDefault_Precision:
|
|
||||||
return "";
|
|
||||||
default:
|
|
||||||
GrCrash("Unexpected precision type.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
GrSLType fType;
|
GrSLType fType;
|
||||||
TypeModifier fTypeModifier;
|
TypeModifier fTypeModifier;
|
||||||
SkString fName;
|
SkString fName;
|
||||||
|
Loading…
Reference in New Issue
Block a user