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 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 194
#define ANGLE_SH_VERSION 195
enum ShShaderSpec
{
......@@ -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.
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.
enum ShArrayIndexClampingStrategy
{
......
......@@ -31,6 +31,8 @@
'compiler/translator/BreakVariableAliasingInInnerLoops.h',
'compiler/translator/CallDAG.cpp',
'compiler/translator/CallDAG.h',
'compiler/translator/ClampFragDepth.cpp',
'compiler/translator/ClampFragDepth.h',
'compiler/translator/ClampPointSize.cpp',
'compiler/translator/ClampPointSize.h',
'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 @@
#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 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
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());
......
......@@ -127,6 +127,11 @@ ShCompileOptions ShaderGL::prepareSourceAndReturnOptions(std::stringstream *sour
options |= SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES;
}
if (mWorkarounds.clampFragDepth)
{
options |= SH_CLAMP_FRAG_DEPTH;
}
if (mMultiviewImplementationType == MultiviewImplementationTypeGL::NV_VIEWPORT_ARRAY2)
{
options |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
......
......@@ -143,6 +143,10 @@ struct WorkaroundsGL
// On some Android devices for loops used to initialize variables hit native GLSL compiler bugs.
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;
......
......@@ -1157,6 +1157,10 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround
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)
// TODO(jmadill): Narrow workaround range for specific devices.
workarounds->reapplyUBOBindingsAfterUsingBinaryProgram = true;
......
......@@ -301,14 +301,12 @@ class BuiltinVariableFragDepthClampingFloatRBOTest : public ANGLETest
// Test that gl_FragDepth is clamped above 0
TEST_P(BuiltinVariableFragDepthClampingFloatRBOTest, Above0)
{
ANGLE_SKIP_TEST_IF(IsNVIDIA());
CheckDepthWritten(0.0f, -1.0f);
}
// Test that gl_FragDepth is clamped below 1
TEST_P(BuiltinVariableFragDepthClampingFloatRBOTest, Below1)
{
ANGLE_SKIP_TEST_IF(IsNVIDIA());
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