зеркало из https://github.com/AvaloniaUI/angle.git
Reland "Remove invariant qualifier for input in fragment shader"
This relands https://chromium-review.googlesource.com/#/c/400005/. ESSL and GLSL are not consistent on invariant matching in vertex shader and fragment shader. See the following rules: ESSL 1.00 - input and output must match ESSL 3.00 - only output, inputs cannot be declared as invariant. GLSL 1.10.59 - does not exist GLSL 1.20.8 - input and output must match GLSL 1.30.10 - input and output must match GLSL 1.40.8 - input and output must match GLSL 1.50.11 - input and output must match GLSL 3.30.6 - input and output must match GLSL 4.00.9 - input and output must match GLSL 4.10.6 - input and output must match GLSL 4.20.11 - input can omit invariant GLSL 4.30.8 - input can omit invariant GLSL 4.40.9 - input can omit invariant GLSL 4.50.5 - input can omit invariant Since GLSL 4.20, invariant qualifier description were changed to: " Only variables output from a shader (including those that are then input to a subsequent shader) can be candidates for invariance. This includes user-defined output variables and the built-in output variables. As only outputs need be declared with invariant, an output from one shader stage will still match an input of a subsequent stage without the input being declared as invariant. " It's not very clear if input in fragment can be declared as invariant. Mesa driver disallows use of input declared as invariant in fragment shader, while other drivers may allow it. This CL removes invariant declaration for input in fragment shader except AMD driver in Linux. AMD's driver obviously contradicts the spec by forcing invariance to match between vertex and fragment shaders. BUG=chromium:639760, chromium:659326 TEST=conformance/glsl/misc/shaders-with-invariance.html and conformance/glsl/bugs/invariant-does-not-leak-across-shaders.html Change-Id: I0aa9be14f0cee7a11a249c91fba27c570c52ca1b Reviewed-on: https://chromium-review.googlesource.com/404228 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Yuly Novikov <ynovikov@chromium.org>
This commit is contained in:
Родитель
5677e4d136
Коммит
705a919443
|
@ -49,7 +49,7 @@ typedef unsigned int GLenum;
|
|||
|
||||
// Version number for shader translation API.
|
||||
// It is incremented every time the API changes.
|
||||
#define ANGLE_SH_VERSION 163
|
||||
#define ANGLE_SH_VERSION 164
|
||||
|
||||
typedef enum {
|
||||
SH_GLES2_SPEC,
|
||||
|
@ -216,6 +216,15 @@ const ShCompileOptions SH_EMULATE_ISNAN_FLOAT_FUNCTION = UINT64_C(1) << 27;
|
|||
// layout qualifier to be considered active. The uniform block itself is also considered active.
|
||||
const ShCompileOptions SH_USE_UNUSED_STANDARD_SHARED_BLOCKS = UINT64_C(1) << 28;
|
||||
|
||||
// This flag will keep invariant declaration for input in fragment shader for GLSL >=4.20 on AMD.
|
||||
// From GLSL >= 4.20, it's optional to add invariant for fragment input, but GPU vendors have
|
||||
// different implementations about this. Some drivers forbid invariant in fragment for GLSL>= 4.20,
|
||||
// e.g. Linux Mesa, some drivers treat that as optional, e.g. NVIDIA, some drivers require invariant
|
||||
// must match between vertex and fragment shader, e.g. AMD. The behavior on AMD is obviously wrong.
|
||||
// Remove invariant for input in fragment shader to workaround the restriction on Intel Mesa.
|
||||
// But don't remove on AMD Linux to avoid triggering the bug on AMD.
|
||||
const ShCompileOptions SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT = UINT64_C(1) << 29;
|
||||
|
||||
// Defines alternate strategies for implementing array index clamping.
|
||||
typedef enum {
|
||||
// Use the clamp intrinsic for array index clamping.
|
||||
|
|
|
@ -92,6 +92,8 @@
|
|||
'compiler/translator/RecordConstantPrecision.h',
|
||||
'compiler/translator/RegenerateStructNames.cpp',
|
||||
'compiler/translator/RegenerateStructNames.h',
|
||||
'compiler/translator/RemoveInvariantDeclaration.cpp',
|
||||
'compiler/translator/RemoveInvariantDeclaration.h',
|
||||
'compiler/translator/RemovePow.cpp',
|
||||
'compiler/translator/RemovePow.h',
|
||||
'compiler/translator/RewriteDoWhile.cpp',
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "compiler/translator/ParseContext.h"
|
||||
#include "compiler/translator/PruneEmptyDeclarations.h"
|
||||
#include "compiler/translator/RegenerateStructNames.h"
|
||||
#include "compiler/translator/RemoveInvariantDeclaration.h"
|
||||
#include "compiler/translator/RemovePow.h"
|
||||
#include "compiler/translator/RewriteDoWhile.h"
|
||||
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
|
||||
|
@ -91,6 +92,14 @@ bool IsGLSL130OrNewer(ShShaderOutput output)
|
|||
output == SH_GLSL_450_CORE_OUTPUT);
|
||||
}
|
||||
|
||||
bool IsGLSL420OrNewer(ShShaderOutput output)
|
||||
{
|
||||
return (output == SH_GLSL_420_CORE_OUTPUT ||
|
||||
output == SH_GLSL_430_CORE_OUTPUT ||
|
||||
output == SH_GLSL_440_CORE_OUTPUT ||
|
||||
output == SH_GLSL_450_CORE_OUTPUT);
|
||||
}
|
||||
|
||||
size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
|
||||
{
|
||||
// WebGL defines a max token legnth of 256, while ES2 leaves max token
|
||||
|
@ -382,6 +391,10 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
|
|||
(outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
|
||||
initializeGLPosition(root);
|
||||
|
||||
if (success && !(compileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT) &&
|
||||
shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType))
|
||||
sh::RemoveInvariantDeclaration(root);
|
||||
|
||||
// This pass might emit short circuits so keep it before the short circuit unfolding
|
||||
if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
|
||||
RewriteDoWhile(root, getTemporaryIndex());
|
||||
|
|
|
@ -38,6 +38,7 @@ bool IsWebGLBasedSpec(ShShaderSpec spec);
|
|||
// Helper function to check if the shader type is GLSL.
|
||||
//
|
||||
bool IsGLSL130OrNewer(ShShaderOutput output);
|
||||
bool IsGLSL420OrNewer(ShShaderOutput output);
|
||||
|
||||
//
|
||||
// The base class used to back handles returned to the driver.
|
||||
|
|
|
@ -12,14 +12,16 @@ TOutputESSL::TOutputESSL(TInfoSinkBase &objSink,
|
|||
NameMap &nameMap,
|
||||
TSymbolTable &symbolTable,
|
||||
int shaderVersion,
|
||||
bool forceHighp)
|
||||
bool forceHighp,
|
||||
ShCompileOptions compileOptions)
|
||||
: TOutputGLSLBase(objSink,
|
||||
clampingStrategy,
|
||||
hashFunction,
|
||||
nameMap,
|
||||
symbolTable,
|
||||
shaderVersion,
|
||||
SH_ESSL_OUTPUT),
|
||||
SH_ESSL_OUTPUT,
|
||||
compileOptions),
|
||||
mForceHighp(forceHighp)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ public:
|
|||
NameMap& nameMap,
|
||||
TSymbolTable& symbolTable,
|
||||
int shaderVersion,
|
||||
bool forceHighp);
|
||||
bool forceHighp,
|
||||
ShCompileOptions compileOptions);
|
||||
|
||||
protected:
|
||||
bool writeVariablePrecision(TPrecision precision) override;
|
||||
|
|
|
@ -12,14 +12,16 @@ TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink,
|
|||
NameMap& nameMap,
|
||||
TSymbolTable& symbolTable,
|
||||
int shaderVersion,
|
||||
ShShaderOutput output)
|
||||
ShShaderOutput output,
|
||||
ShCompileOptions compileOptions)
|
||||
: TOutputGLSLBase(objSink,
|
||||
clampingStrategy,
|
||||
hashFunction,
|
||||
nameMap,
|
||||
symbolTable,
|
||||
shaderVersion,
|
||||
output)
|
||||
output,
|
||||
compileOptions)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ class TOutputGLSL : public TOutputGLSLBase
|
|||
NameMap& nameMap,
|
||||
TSymbolTable& symbolTable,
|
||||
int shaderVersion,
|
||||
ShShaderOutput output);
|
||||
ShShaderOutput output,
|
||||
ShCompileOptions compileOptions);
|
||||
|
||||
protected:
|
||||
bool writeVariablePrecision(TPrecision) override;
|
||||
|
|
|
@ -83,7 +83,8 @@ TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
|
|||
NameMap &nameMap,
|
||||
TSymbolTable &symbolTable,
|
||||
int shaderVersion,
|
||||
ShShaderOutput output)
|
||||
ShShaderOutput output,
|
||||
ShCompileOptions compileOptions)
|
||||
: TIntermTraverser(true, true, true),
|
||||
mObjSink(objSink),
|
||||
mDeclaringVariables(false),
|
||||
|
@ -92,7 +93,8 @@ TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
|
|||
mNameMap(nameMap),
|
||||
mSymbolTable(symbolTable),
|
||||
mShaderVersion(shaderVersion),
|
||||
mOutput(output)
|
||||
mOutput(output),
|
||||
mCompileOptions(compileOptions)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -146,8 +148,11 @@ void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
|
|||
|
||||
void TOutputGLSLBase::writeVariableType(const TType &type)
|
||||
{
|
||||
TQualifier qualifier = type.getQualifier();
|
||||
TInfoSinkBase &out = objSink();
|
||||
if (type.isInvariant())
|
||||
bool removeInvariant = (qualifier == EvqVaryingIn && IsGLSL420OrNewer(mOutput) &&
|
||||
!(mCompileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT));
|
||||
if (type.isInvariant() && !removeInvariant)
|
||||
{
|
||||
out << "invariant ";
|
||||
}
|
||||
|
@ -156,7 +161,6 @@ void TOutputGLSLBase::writeVariableType(const TType &type)
|
|||
TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
|
||||
declareInterfaceBlockLayout(interfaceBlock);
|
||||
}
|
||||
TQualifier qualifier = type.getQualifier();
|
||||
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
|
||||
{
|
||||
if (IsGLSL130OrNewer(mOutput))
|
||||
|
|
|
@ -22,7 +22,8 @@ class TOutputGLSLBase : public TIntermTraverser
|
|||
NameMap &nameMap,
|
||||
TSymbolTable& symbolTable,
|
||||
int shaderVersion,
|
||||
ShShaderOutput output);
|
||||
ShShaderOutput output,
|
||||
ShCompileOptions compileOptions);
|
||||
|
||||
ShShaderOutput getShaderOutput() const
|
||||
{
|
||||
|
@ -98,6 +99,8 @@ class TOutputGLSLBase : public TIntermTraverser
|
|||
const int mShaderVersion;
|
||||
|
||||
ShShaderOutput mOutput;
|
||||
|
||||
ShCompileOptions mCompileOptions;
|
||||
};
|
||||
|
||||
#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Copyright (c) 2016 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.
|
||||
//
|
||||
|
||||
#include "compiler/translator/RemoveInvariantDeclaration.h"
|
||||
|
||||
#include "compiler/translator/IntermNode.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// An AST traverser that removes invariant declaration for input in fragment shader
|
||||
// when GLSL >= 4.20.
|
||||
class RemoveInvariantDeclarationTraverser : public TIntermTraverser
|
||||
{
|
||||
public:
|
||||
RemoveInvariantDeclarationTraverser() : TIntermTraverser(true, false, false) {}
|
||||
|
||||
private:
|
||||
bool visitAggregate(Visit visit, TIntermAggregate *node) override
|
||||
{
|
||||
if (node->getOp() == EOpInvariantDeclaration)
|
||||
{
|
||||
for (TIntermNode *&child : *node->getSequence())
|
||||
{
|
||||
TIntermTyped *typed = child->getAsTyped();
|
||||
if (typed && typed->getQualifier() == EvqVaryingIn)
|
||||
{
|
||||
TIntermSequence emptyReplacement;
|
||||
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(
|
||||
getParentNode()->getAsBlock(), node, emptyReplacement));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void RemoveInvariantDeclaration(TIntermNode *root)
|
||||
{
|
||||
RemoveInvariantDeclarationTraverser traverser;
|
||||
root->traverse(&traverser);
|
||||
traverser.updateTree();
|
||||
}
|
||||
|
||||
} // namespace sh
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Copyright (c) 2016 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.
|
||||
//
|
||||
|
||||
#ifndef COMPILER_TRANSLATOR_REMOVEINVARIANTDECLARATION_H_
|
||||
#define COMPILER_TRANSLATOR_REMOVEINVARIANTDECLARATION_H_
|
||||
|
||||
class TIntermNode;
|
||||
namespace sh
|
||||
{
|
||||
|
||||
void RemoveInvariantDeclaration(TIntermNode *root);
|
||||
|
||||
} // namespace sh
|
||||
|
||||
#endif // COMPILER_TRANSLATOR_REMOVEINVARIANTDECLARATION_H_
|
|
@ -78,7 +78,7 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption
|
|||
|
||||
// Write translated shader.
|
||||
TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
|
||||
getSymbolTable(), shaderVer, precisionEmulation);
|
||||
getSymbolTable(), shaderVer, precisionEmulation, compileOptions);
|
||||
root->traverse(&outputESSL);
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,8 @@ void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOption
|
|||
getNameMap(),
|
||||
getSymbolTable(),
|
||||
getShaderVersion(),
|
||||
getOutputType());
|
||||
getOutputType(),
|
||||
compileOptions);
|
||||
root->traverse(&outputGLSL);
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,11 @@ ShCompileOptions ShaderGL::prepareSourceAndReturnOptions(std::stringstream *sour
|
|||
options |= SH_USE_UNUSED_STANDARD_SHARED_BLOCKS;
|
||||
}
|
||||
|
||||
if (mWorkarounds.dontRemoveInvariantForFragmentInput)
|
||||
{
|
||||
options |= SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ struct WorkaroundsGL
|
|||
emulateAbsIntFunction(false),
|
||||
addAndTrueToLoopCondition(false),
|
||||
emulateIsnanFloat(false),
|
||||
useUnusedBlocksWithStandardOrSharedLayout(false)
|
||||
useUnusedBlocksWithStandardOrSharedLayout(false),
|
||||
dontRemoveInvariantForFragmentInput(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -111,6 +112,10 @@ struct WorkaroundsGL
|
|||
// treated as inactive which is not consistent with WebGL2.0 spec. Reference all members in a
|
||||
// unused std140 or shared uniform block at the beginning of main to work around it.
|
||||
bool useUnusedBlocksWithStandardOrSharedLayout;
|
||||
|
||||
// This flag will keep invariant declaration for input in fragment shader for GLSL >=4.20
|
||||
// on AMD.
|
||||
bool dontRemoveInvariantForFragmentInput;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -902,6 +902,9 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround
|
|||
{
|
||||
VendorID vendor = GetVendorID(functions);
|
||||
|
||||
workarounds->dontRemoveInvariantForFragmentInput =
|
||||
functions->standard == STANDARD_GL_DESKTOP && IsAMD(vendor);
|
||||
|
||||
// Don't use 1-bit alpha formats on desktop GL with AMD or Intel drivers.
|
||||
workarounds->avoid1BitAlphaTextureFormats =
|
||||
functions->standard == STANDARD_GL_DESKTOP && (IsAMD(vendor) || IsIntel(vendor));
|
||||
|
|
Загрузка…
Ссылка в новой задаче