Guard against D3D NaN/Infinity literals bug
Bug: angle:2098 skia:6857
Change-Id: I502f05cdeb56514db4e144fdbb6d6f5a6f476b2e
Reviewed-on: https://skia-review.googlesource.com/29520
Reviewed-by: Yuqian Li <liyuqian@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp
index 6f5dc7f..7d34df9 100644
--- a/src/gpu/GrShaderCaps.cpp
+++ b/src/gpu/GrShaderCaps.cpp
@@ -61,6 +61,7 @@
fRequiresLocalOutputColorForFBFetch = false;
fMustImplementGSInvocationsWithLoop = false;
fMustObfuscateUniformColor = false;
+ fMustGuardDivisionEvenAfterExplicitZeroCheck = false;
fFlatInterpolationSupport = false;
fNoPerspectiveInterpolationSupport = false;
fMultisampleInterpolationSupport = false;
@@ -149,6 +150,8 @@
r.appendf("Must implement geo shader invocations with loop : %s\n",
(fMustImplementGSInvocationsWithLoop ? "YES" : "NO"));
r.appendf("Must obfuscate uniform color: %s\n", (fMustObfuscateUniformColor ? "YES" : "NO"));
+ r.appendf("Must guard division even after explicit zero check: %s\n",
+ (fMustGuardDivisionEvenAfterExplicitZeroCheck ? "YES" : "NO"));
r.appendf("Flat interpolation support: %s\n", (fFlatInterpolationSupport ? "YES" : "NO"));
r.appendf("No perspective interpolation support: %s\n", (fNoPerspectiveInterpolationSupport ?
"YES" : "NO"));
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 6becba8..6ca9d63 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -927,6 +927,24 @@
if (kMaliT_GrGLRenderer == ctxInfo.renderer()) {
shaderCaps->fMustObfuscateUniformColor = true;
}
+
+#ifdef SK_BUILD_FOR_WIN
+ // Check for ANGLE on Windows, so we can workaround a bug in D3D itself (anglebug.com/2098).
+ //
+ // Basically, if a shader has a construct like:
+ //
+ // float x = someCondition ? someValue : 0;
+ // float2 result = (0 == x) ? float2(x, x)
+ // : float2(2 * x / x, 0);
+ //
+ // ... the compiler will produce an error 'NaN and infinity literals not allowed', even though
+ // we've explicitly guarded the division with a check against zero. This manifests in much
+ // more complex ways in some of our shaders, so we use this caps bit to add an epsilon value
+ // to the denominator of divisions, even when we've added checks that the denominator isn't 0.
+ if (kANGLE_GrGLDriver == ctxInfo.driver() || kChromium_GrGLDriver == ctxInfo.driver()) {
+ shaderCaps->fMustGuardDivisionEvenAfterExplicitZeroCheck = true;
+ }
+#endif
}
bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
diff --git a/src/gpu/glsl/GrGLSLBlend.cpp b/src/gpu/glsl/GrGLSLBlend.cpp
index b37169b..9d7a064 100644
--- a/src/gpu/glsl/GrGLSLBlend.cpp
+++ b/src/gpu/glsl/GrGLSLBlend.cpp
@@ -7,6 +7,7 @@
#include "GrGLSLBlend.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
#include "SkBlendModePriv.h"
//////////////////////////////////////////////////////////////////////////////
@@ -39,6 +40,12 @@
const char* src,
const char* dst,
const char component) {
+ const char* divisorGuard = "";
+ const GrShaderCaps* shaderCaps = fsBuilder->getProgramBuilder()->shaderCaps();
+ if (shaderCaps->mustGuardDivisionEvenAfterExplicitZeroCheck()) {
+ divisorGuard = "+ 0.00000001";
+ }
+
fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component);
fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
final, component, src, component, dst);
@@ -49,8 +56,8 @@
final, component, src, dst, src, component, dst, dst, component,
src);
fsBuilder->codeAppend("} else {");
- fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);",
- dst, dst, component, src);
+ fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / (d %s));",
+ dst, dst, component, src, divisorGuard);
fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, src, component, dst, dst, component, src);
fsBuilder->codeAppend("}");
@@ -84,14 +91,20 @@
const char* src,
const char* dst,
const char component) {
+ const char* divisorGuard = "";
+ const GrShaderCaps* shaderCaps = fsBuilder->getProgramBuilder()->shaderCaps();
+ if (shaderCaps->mustGuardDivisionEvenAfterExplicitZeroCheck()) {
+ divisorGuard = "+ 0.00000001";
+ }
+
// if (2S < Sa)
fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
// (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
- fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +"
+ fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / (%s.a %s) +"
"(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
final, component, dst, component, dst, component, src, src,
- component, dst, dst, src, component, dst, component, src, src,
- component);
+ component, dst, divisorGuard, dst, src, component, dst, component, src,
+ src, component);
// else if (4D < Da)
fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
dst, component, dst);
@@ -104,10 +117,10 @@
fsBuilder->codeAppendf("%s.%c ="
"(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
" 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -"
- " DaCub*%s.%c) / DaSqd;",
+ " DaCub*%s.%c) / (DaSqd %s);",
final, component, src, component, dst, component,
src, src, component, dst, src, src, component, src, src,
- component, src, component);
+ component, src, component, divisorGuard);
fsBuilder->codeAppendf("} else {");
// -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -"