diff options
author | Brian Salomon <bsalomon@google.com> | 2018-01-22 08:43:38 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-22 14:14:18 +0000 |
commit | dba65f95e40fb1a4ea936b453b9bcb3fdbe178e1 (patch) | |
tree | 307b8b391870d8891e523fc3879c6787da5e8146 | |
parent | 5081eede67601e5c5c0fc343b787490603e058cc (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.h | 4 | ||||
-rw-r--r-- | src/gpu/GrShaderCaps.cpp | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 4 | ||||
-rw-r--r-- | src/gpu/ops/GrTextureOp.cpp | 57 | ||||
-rw-r--r-- | src/sksl/SkSLGLSLCodeGenerator.cpp | 15 | ||||
-rw-r--r-- | src/sksl/SkSLGLSLCodeGenerator.h | 1 | ||||
-rw-r--r-- | tests/SkSLGLSLTest.cpp | 7 |
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"); } |