Commit 0690e1aa by Olli Etuaho Committed by Commit Bot

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: 's avatarCorentin Wallez <cwallez@chromium.org>
parent b38dfde0
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 194 #define ANGLE_SH_VERSION 195
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -258,6 +258,9 @@ const ShCompileOptions SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES = UINT64_C(1) < ...@@ -258,6 +258,9 @@ const ShCompileOptions SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES = UINT64_C(1) <
// not handle constant register zero correctly. Only has an effect on HLSL translation. // not handle constant register zero correctly. Only has an effect on HLSL translation.
const ShCompileOptions SH_SKIP_D3D_CONSTANT_REGISTER_ZERO = UINT64_C(1) << 37; const ShCompileOptions SH_SKIP_D3D_CONSTANT_REGISTER_ZERO = UINT64_C(1) << 37;
// Clamp gl_FragDepth to the range [0.0, 1.0] in case it is statically used.
const ShCompileOptions SH_CLAMP_FRAG_DEPTH = UINT64_C(1) << 38;
// Defines alternate strategies for implementing array index clamping. // Defines alternate strategies for implementing array index clamping.
enum ShArrayIndexClampingStrategy enum ShArrayIndexClampingStrategy
{ {
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
'compiler/translator/BreakVariableAliasingInInnerLoops.h', 'compiler/translator/BreakVariableAliasingInInnerLoops.h',
'compiler/translator/CallDAG.cpp', 'compiler/translator/CallDAG.cpp',
'compiler/translator/CallDAG.h', 'compiler/translator/CallDAG.h',
'compiler/translator/ClampFragDepth.cpp',
'compiler/translator/ClampFragDepth.h',
'compiler/translator/ClampPointSize.cpp', 'compiler/translator/ClampPointSize.cpp',
'compiler/translator/ClampPointSize.h', 'compiler/translator/ClampPointSize.h',
'compiler/translator/CodeGen.cpp', 'compiler/translator/CodeGen.cpp',
......
//
// 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
//
// 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_
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "common/utilities.h" #include "common/utilities.h"
#include "compiler/translator/AddAndTrueToLoopCondition.h" #include "compiler/translator/AddAndTrueToLoopCondition.h"
#include "compiler/translator/CallDAG.h" #include "compiler/translator/CallDAG.h"
#include "compiler/translator/ClampFragDepth.h"
#include "compiler/translator/ClampPointSize.h" #include "compiler/translator/ClampPointSize.h"
#include "compiler/translator/CollectVariables.h" #include "compiler/translator/CollectVariables.h"
#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h" #include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h"
...@@ -641,6 +642,11 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root, ...@@ -641,6 +642,11 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
ClampPointSize(root, compileResources.MaxPointSize, &getSymbolTable()); 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) if (compileOptions & SH_REWRITE_VECTOR_SCALAR_ARITHMETIC)
{ {
VectorizeVectorScalarArithmetic(root, &getSymbolTable()); VectorizeVectorScalarArithmetic(root, &getSymbolTable());
......
...@@ -127,6 +127,11 @@ ShCompileOptions ShaderGL::prepareSourceAndReturnOptions(std::stringstream *sour ...@@ -127,6 +127,11 @@ ShCompileOptions ShaderGL::prepareSourceAndReturnOptions(std::stringstream *sour
options |= SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES; options |= SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES;
} }
if (mWorkarounds.clampFragDepth)
{
options |= SH_CLAMP_FRAG_DEPTH;
}
if (mMultiviewImplementationType == MultiviewImplementationTypeGL::NV_VIEWPORT_ARRAY2) if (mMultiviewImplementationType == MultiviewImplementationTypeGL::NV_VIEWPORT_ARRAY2)
{ {
options |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW; options |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
......
...@@ -143,6 +143,10 @@ struct WorkaroundsGL ...@@ -143,6 +143,10 @@ struct WorkaroundsGL
// On some Android devices for loops used to initialize variables hit native GLSL compiler bugs. // On some Android devices for loops used to initialize variables hit native GLSL compiler bugs.
bool dontUseLoopsToInitializeVariables = false; bool dontUseLoopsToInitializeVariables = false;
// On some NVIDIA drivers gl_FragDepth is not clamped correctly when rendering to a floating
// point depth buffer. Clamp it in the translated shader to fix this.
bool clampFragDepth = false;
}; };
inline WorkaroundsGL::WorkaroundsGL() = default; inline WorkaroundsGL::WorkaroundsGL() = default;
......
...@@ -1157,6 +1157,10 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround ...@@ -1157,6 +1157,10 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround
workarounds->rewriteVectorScalarArithmetic = IsNvidia(vendor); workarounds->rewriteVectorScalarArithmetic = IsNvidia(vendor);
// TODO(oetuaho): Make this specific to the affected driver versions. Versions at least up to
// 390 are known to be affected. Versions after that are expected not to be affected.
workarounds->clampFragDepth = IsNvidia(vendor);
#if defined(ANGLE_PLATFORM_ANDROID) #if defined(ANGLE_PLATFORM_ANDROID)
// TODO(jmadill): Narrow workaround range for specific devices. // TODO(jmadill): Narrow workaround range for specific devices.
workarounds->reapplyUBOBindingsAfterUsingBinaryProgram = true; workarounds->reapplyUBOBindingsAfterUsingBinaryProgram = true;
......
...@@ -301,14 +301,12 @@ class BuiltinVariableFragDepthClampingFloatRBOTest : public ANGLETest ...@@ -301,14 +301,12 @@ class BuiltinVariableFragDepthClampingFloatRBOTest : public ANGLETest
// Test that gl_FragDepth is clamped above 0 // Test that gl_FragDepth is clamped above 0
TEST_P(BuiltinVariableFragDepthClampingFloatRBOTest, Above0) TEST_P(BuiltinVariableFragDepthClampingFloatRBOTest, Above0)
{ {
ANGLE_SKIP_TEST_IF(IsNVIDIA());
CheckDepthWritten(0.0f, -1.0f); CheckDepthWritten(0.0f, -1.0f);
} }
// Test that gl_FragDepth is clamped below 1 // Test that gl_FragDepth is clamped below 1
TEST_P(BuiltinVariableFragDepthClampingFloatRBOTest, Below1) TEST_P(BuiltinVariableFragDepthClampingFloatRBOTest, Below1)
{ {
ANGLE_SKIP_TEST_IF(IsNVIDIA());
CheckDepthWritten(1.0f, 42.0f); CheckDepthWritten(1.0f, 42.0f);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment