Add a workaround to clamp gl_FragDepth
NVIDIA OpenGL drivers at least up to version 388.59 don't clamp
gl_FragDepth when it is written to a floating point depth buffer.
This bug is now worked around by clamping gl_FragDepth in the shader
if it is statically used.
BUG=angleproject:2299
TEST=angle_end2end_tests on NVIDIA
Change-Id: I61589b2b0dd2813c4901a157c8d37e470063773c
Reviewed-on: https://chromium-review.googlesource.com/840842
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/ClampFragDepth.cpp b/src/compiler/translator/ClampFragDepth.cpp
new file mode 100644
index 0000000..70852aa
--- /dev/null
+++ b/src/compiler/translator/ClampFragDepth.cpp
@@ -0,0 +1,52 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ClampFragDepth.cpp: Limit the value that is written to gl_FragDepth to the range [0.0, 1.0].
+// The clamping is run at the very end of shader execution, and is only performed if the shader
+// statically accesses gl_FragDepth.
+//
+
+#include "compiler/translator/ClampFragDepth.h"
+
+#include "compiler/translator/FindSymbolNode.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/RunAtTheEndOfShader.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+void ClampFragDepth(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+ // Only clamp gl_FragDepth if it's used in the shader.
+ if (!FindSymbolNode(root, TString("gl_FragDepth")))
+ {
+ return;
+ }
+
+ TIntermSymbol *fragDepthNode = ReferenceBuiltInVariable("gl_FragDepth", *symbolTable, 300);
+
+ TIntermTyped *minFragDepthNode = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
+
+ TConstantUnion *maxFragDepthConstant = new TConstantUnion();
+ maxFragDepthConstant->setFConst(1.0);
+ TIntermConstantUnion *maxFragDepthNode =
+ new TIntermConstantUnion(maxFragDepthConstant, TType(EbtFloat, EbpHigh, EvqConst));
+
+ // clamp(gl_FragDepth, 0.0, 1.0)
+ TIntermSequence *clampArguments = new TIntermSequence();
+ clampArguments->push_back(fragDepthNode->deepCopy());
+ clampArguments->push_back(minFragDepthNode);
+ clampArguments->push_back(maxFragDepthNode);
+ TIntermTyped *clampedFragDepth =
+ CreateBuiltInFunctionCallNode("clamp", clampArguments, *symbolTable, 100);
+
+ // gl_FragDepth = clamp(gl_FragDepth, 0.0, 1.0)
+ TIntermBinary *assignFragDepth = new TIntermBinary(EOpAssign, fragDepthNode, clampedFragDepth);
+
+ RunAtTheEndOfShader(root, assignFragDepth, symbolTable);
+}
+
+} // namespace sh
diff --git a/src/compiler/translator/ClampFragDepth.h b/src/compiler/translator/ClampFragDepth.h
new file mode 100644
index 0000000..aa0ed1a
--- /dev/null
+++ b/src/compiler/translator/ClampFragDepth.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ClampFragDepth.h: Limit the value that is written to gl_FragDepth to the range [0.0, 1.0].
+// The clamping is run at the very end of shader execution, and is only performed if the shader
+// statically accesses gl_FragDepth.
+//
+
+#ifndef COMPILER_TRANSLATOR_CLAMPFRAGDEPTH_H_
+#define COMPILER_TRANSLATOR_CLAMPFRAGDEPTH_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void ClampFragDepth(TIntermBlock *root, TSymbolTable *symbolTable);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_CLAMPFRAGDEPTH_H_
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 2d58a28..669365b 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -12,6 +12,7 @@
#include "common/utilities.h"
#include "compiler/translator/AddAndTrueToLoopCondition.h"
#include "compiler/translator/CallDAG.h"
+#include "compiler/translator/ClampFragDepth.h"
#include "compiler/translator/ClampPointSize.h"
#include "compiler/translator/CollectVariables.h"
#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h"
@@ -641,6 +642,11 @@
ClampPointSize(root, compileResources.MaxPointSize, &getSymbolTable());
}
+ if (getShaderType() == GL_FRAGMENT_SHADER && (compileOptions & SH_CLAMP_FRAG_DEPTH))
+ {
+ ClampFragDepth(root, &getSymbolTable());
+ }
+
if (compileOptions & SH_REWRITE_VECTOR_SCALAR_ARITHMETIC)
{
VectorizeVectorScalarArithmetic(root, &getSymbolTable());