aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2018-01-22 08:43:38 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-01-22 14:14:18 +0000
commitdba65f95e40fb1a4ea936b453b9bcb3fdbe178e1 (patch)
tree307b8b391870d8891e523fc3879c6787da5e8146
parent5081eede67601e5c5c0fc343b787490603e058cc (diff)
Add a workaround for inaccurate interpolants on Adreno 3xx.
Also ensure that sk_FragCoord x and y values are at pixel centers when workaround is used. Change-Id: Ib748af9e496a406a50622e00e96e1346cbb5eb26 Reviewed-on: https://skia-review.googlesource.com/97064 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
-rw-r--r--include/gpu/GrShaderCaps.h4
-rw-r--r--src/gpu/GrShaderCaps.cpp2
-rw-r--r--src/gpu/gl/GrGLCaps.cpp4
-rw-r--r--src/gpu/ops/GrTextureOp.cpp57
-rw-r--r--src/sksl/SkSLGLSLCodeGenerator.cpp15
-rw-r--r--src/sksl/SkSLGLSLCodeGenerator.h1
-rw-r--r--tests/SkSLGLSLTest.cpp7
7 files changed, 71 insertions, 19 deletions
diff --git a/include/gpu/GrShaderCaps.h b/include/gpu/GrShaderCaps.h
index 66e7d42306..887dc2e928 100644
--- a/include/gpu/GrShaderCaps.h
+++ b/include/gpu/GrShaderCaps.h
@@ -124,6 +124,9 @@ public:
// If false, SkSL uses a workaround so that sk_FragCoord doesn't actually query gl_FragCoord
bool canUseFragCoord() const { return fCanUseFragCoord; }
+ // If true interpolated vertex shader outputs are inaccurate.
+ bool interpolantsAreInaccurate() const { return fInterpolantsAreInaccurate; }
+
bool requiresLocalOutputColorForFBFetch() const { return fRequiresLocalOutputColorForFBFetch; }
bool mustObfuscateUniformColor() const { return fMustObfuscateUniformColor; }
@@ -279,6 +282,7 @@ private:
bool fMustObfuscateUniformColor : 1;
bool fMustGuardDivisionEvenAfterExplicitZeroCheck : 1;
bool fCanUseFragCoord : 1;
+ bool fInterpolantsAreInaccurate : 1;
const char* fVersionDeclString;
diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp
index 2ab19478af..6c6e00024f 100644
--- a/src/gpu/GrShaderCaps.cpp
+++ b/src/gpu/GrShaderCaps.cpp
@@ -39,6 +39,7 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
fMustObfuscateUniformColor = false;
fMustGuardDivisionEvenAfterExplicitZeroCheck = false;
fCanUseFragCoord = true;
+ fInterpolantsAreInaccurate = false;
fFlatInterpolationSupport = false;
fPreferFlatInterpolation = false;
fNoPerspectiveInterpolationSupport = false;
@@ -115,6 +116,7 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
writer->appendBool("Must guard division even after explicit zero check",
fMustGuardDivisionEvenAfterExplicitZeroCheck);
writer->appendBool("Can use gl_FragCoord", fCanUseFragCoord);
+ writer->appendBool("Interpolants are inaccurate", fInterpolantsAreInaccurate);
writer->appendBool("Flat interpolation support", fFlatInterpolationSupport);
writer->appendBool("Prefer flat interpolation", fPreferFlatInterpolation);
writer->appendBool("No perspective interpolation support", fNoPerspectiveInterpolationSupport);
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 14be2153a5..cec02a1faa 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1045,9 +1045,11 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli
#endif
// We've seen Adreno 3xx devices produce incorrect (flipped) values for gl_FragCoord, in some
- // (rare) situations. It's sporadic, and mostly on older drviers.
+ // (rare) situations. It's sporadic, and mostly on older drivers. It also seems to be the case
+ // that the interpolation of vertex shader outputs is quite inaccurate.
if (kAdreno3xx_GrGLRenderer == ctxInfo.renderer()) {
shaderCaps->fCanUseFragCoord = false;
+ shaderCaps->fInterpolantsAreInaccurate = true;
}
}
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 7c4842f73a..46d2630270 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -168,22 +168,51 @@ public:
}
args.fFragBuilder->codeAppend(";");
if (textureGP.usesCoverageEdgeAA()) {
- GrGLSLVarying aaDistVarying(kFloat4_GrSLType,
- GrGLSLVarying::Scope::kVertToFrag);
- args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
- args.fVertBuilder->codeAppendf(
- R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z,
- dot(aaEdge1.xy, %s.xy) + aaEdge1.z,
- dot(aaEdge2.xy, %s.xy) + aaEdge2.z,
- dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)",
- aaDistVarying.vsOut(), textureGP.fPositions.fName,
- textureGP.fPositions.fName, textureGP.fPositions.fName,
- textureGP.fPositions.fName);
-
+ const char* aaDistName = nullptr;
+ // When interpolation is innacurate we perform the evaluation of the edge
+ // equations in the fragment shader rather than interpolating values computed
+ // in the vertex shader.
+ if (!args.fShaderCaps->interpolantsAreInaccurate()) {
+ GrGLSLVarying aaDistVarying(kFloat4_GrSLType,
+ GrGLSLVarying::Scope::kVertToFrag);
+ args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
+ args.fVertBuilder->codeAppendf(
+ R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z,
+ dot(aaEdge1.xy, %s.xy) + aaEdge1.z,
+ dot(aaEdge2.xy, %s.xy) + aaEdge2.z,
+ dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)",
+ aaDistVarying.vsOut(), textureGP.fPositions.fName,
+ textureGP.fPositions.fName, textureGP.fPositions.fName,
+ textureGP.fPositions.fName);
+ aaDistName = aaDistVarying.fsIn();
+ } else {
+ GrGLSLVarying aaEdgeVarying[4]{
+ {kFloat3_GrSLType, GrGLSLVarying::Scope::kVertToFrag},
+ {kFloat3_GrSLType, GrGLSLVarying::Scope::kVertToFrag},
+ {kFloat3_GrSLType, GrGLSLVarying::Scope::kVertToFrag},
+ {kFloat3_GrSLType, GrGLSLVarying::Scope::kVertToFrag}
+ };
+ for (int i = 0; i < 4; ++i) {
+ SkString name;
+ name.printf("aaEdge%d", i);
+ args.fVaryingHandler->addVarying(name.c_str(), &aaEdgeVarying[i]);
+ args.fVertBuilder->codeAppendf(
+ "%s = aaEdge%d;", aaEdgeVarying[i].vsOut(), i);
+ }
+ args.fFragBuilder->codeAppendf(
+ R"(float4 aaDists = float4(dot(%s.xy, sk_FragCoord.xy) + %s.z,
+ dot(%s.xy, sk_FragCoord.xy) + %s.z,
+ dot(%s.xy, sk_FragCoord.xy) + %s.z,
+ dot(%s.xy, sk_FragCoord.xy) + %s.z);)",
+ aaEdgeVarying[0].fsIn(), aaEdgeVarying[0].fsIn(),
+ aaEdgeVarying[1].fsIn(), aaEdgeVarying[1].fsIn(),
+ aaEdgeVarying[2].fsIn(), aaEdgeVarying[2].fsIn(),
+ aaEdgeVarying[3].fsIn(), aaEdgeVarying[3].fsIn());
+ aaDistName = "aaDists";
+ }
args.fFragBuilder->codeAppendf(
"float mindist = min(min(%s.x, %s.y), min(%s.z, %s.w));",
- aaDistVarying.fsIn(), aaDistVarying.fsIn(), aaDistVarying.fsIn(),
- aaDistVarying.fsIn());
+ aaDistName, aaDistName, aaDistName, aaDistName);
args.fFragBuilder->codeAppendf("%s = float4(clamp(mindist, 0, 1));",
args.fOutputCoverage);
} else {
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index f3400c7f5a..d02948f388 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -598,8 +598,19 @@ void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parent
void GLSLCodeGenerator::writeFragCoord() {
if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
- this->write("vec4(sk_FragCoord_Workaround.xyz / sk_FragCoord_Workaround.w, "
- "1.0 / sk_FragCoord_Workaround.w)");
+ if (!fSetupFragCoordWorkaround) {
+ const char* precision = usesPrecisionModifiers() ? "highp " : "";
+ fFunctionHeader += precision;
+ fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
+ fFunctionHeader += precision;
+ fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
+ "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
+ // Ensure that we get exact .5 values for x and y.
+ fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
+ "vec2(.5);\n";
+ fSetupFragCoordWorkaround = true;
+ }
+ this->write("sk_FragCoord_Resolved");
return;
}
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
index 70ce920900..2b308e3702 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.h
+++ b/src/sksl/SkSLGLSLCodeGenerator.h
@@ -212,6 +212,7 @@ protected:
bool fFoundGSInvocations = false;
bool fSetupFragPositionGlobal = false;
bool fSetupFragPositionLocal = false;
+ bool fSetupFragCoordWorkaround = false;
typedef CodeGenerator INHERITED;
};
diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp
index 10b94b81f4..62c5cd6955 100644
--- a/tests/SkSLGLSLTest.cpp
+++ b/tests/SkSLGLSLTest.cpp
@@ -1093,8 +1093,11 @@ DEF_TEST(SkSLFragCoord, r) {
"in vec4 sk_FragCoord_Workaround;\n"
"out vec4 sk_FragColor;\n"
"void main() {\n"
- " sk_FragColor.xy = vec4(sk_FragCoord_Workaround.xyz / sk_FragCoord_Workaround.w, "
- "1.0 / sk_FragCoord_Workaround.w).xy;\n"
+ " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n"
+ " vec4 sk_FragCoord_Resolved = vec4(sk_FragCoord_Workaround.xyz * "
+ "sk_FragCoord_InvW, sk_FragCoord_InvW);\n"
+ " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + vec2(.5);\n"
+ " sk_FragColor.xy = sk_FragCoord_Resolved.xy;\n"
"}\n");
}