зеркало из https://github.com/AvaloniaUI/angle.git
Add a workaround for Intel drivers on glsl function texelfetchoffset
GLSL function texelfetchoffset will be translated into texture.Load in ANGLE. In D3D there is a note that When one or more of the coordinates in Location exceeds the u, v, or w mipmap level dimensions of the texture, Load returns zero in all components, but in glsl there is no such restriction, which will cause the WebGL 2 dEQP test deqp/functional/gles3/shadertexturefunction/texelfetchoffset.html fail on Windows with Intel GPU. Adapted from ExpandIntegerPowExpressions.cpp, this patch adds a translation from texelFetchOffset into texelFetch to work around this issue. BUG=angleproject:1469 Change-Id: Iecfb9570472036acf5960789bdb1a63f191316be Reviewed-on: https://chromium-review.googlesource.com/367883 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Родитель
1fe74c7e2e
Коммит
11e43ecee2
|
@ -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 154
|
||||
#define ANGLE_SH_VERSION 155
|
||||
|
||||
typedef enum {
|
||||
SH_GLES2_SPEC,
|
||||
|
@ -227,6 +227,10 @@ typedef enum {
|
|||
// HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level
|
||||
// offsetting.
|
||||
SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL = 0x2000000,
|
||||
|
||||
// This flag works around an issue in translating GLSL function texelFetchOffset on
|
||||
// INTEL drivers. It works by translating texelFetchOffset into texelFetch.
|
||||
SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = 0x4000000,
|
||||
} ShCompileOptions;
|
||||
|
||||
// Defines alternate strategies for implementing array index clamping.
|
||||
|
|
|
@ -89,6 +89,8 @@
|
|||
'compiler/translator/RemovePow.h',
|
||||
'compiler/translator/RewriteDoWhile.cpp',
|
||||
'compiler/translator/RewriteDoWhile.h',
|
||||
'compiler/translator/RewriteTexelFetchOffset.cpp',
|
||||
'compiler/translator/RewriteTexelFetchOffset.h',
|
||||
'compiler/translator/RenameFunction.h',
|
||||
'compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp',
|
||||
'compiler/translator/ScalarizeVecAndMatConstructorArgs.h',
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
// Implementation of texelFetchOffset translation issue workaround.
|
||||
// See header for more info.
|
||||
|
||||
#include "compiler/translator/RewriteTexelFetchOffset.h"
|
||||
|
||||
#include "common/angleutils.h"
|
||||
#include "compiler/translator/IntermNode.h"
|
||||
#include "compiler/translator/SymbolTable.h"
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class Traverser : public TIntermTraverser
|
||||
{
|
||||
public:
|
||||
static void Apply(TIntermNode *root,
|
||||
unsigned int *tempIndex,
|
||||
const TSymbolTable &symbolTable,
|
||||
int shaderVersion);
|
||||
|
||||
private:
|
||||
Traverser(const TSymbolTable &symbolTable, int shaderVersion);
|
||||
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
|
||||
void nextIteration();
|
||||
|
||||
const TSymbolTable *symbolTable;
|
||||
const int shaderVersion;
|
||||
bool mFound = false;
|
||||
};
|
||||
|
||||
Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion)
|
||||
: TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion)
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
void Traverser::Apply(TIntermNode *root,
|
||||
unsigned int *tempIndex,
|
||||
const TSymbolTable &symbolTable,
|
||||
int shaderVersion)
|
||||
{
|
||||
Traverser traverser(symbolTable, shaderVersion);
|
||||
traverser.useTemporaryIndex(tempIndex);
|
||||
do
|
||||
{
|
||||
traverser.nextIteration();
|
||||
root->traverse(&traverser);
|
||||
if (traverser.mFound)
|
||||
{
|
||||
traverser.updateTree();
|
||||
}
|
||||
} while (traverser.mFound);
|
||||
}
|
||||
|
||||
void Traverser::nextIteration()
|
||||
{
|
||||
mFound = false;
|
||||
nextTemporaryIndex();
|
||||
}
|
||||
|
||||
bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
|
||||
{
|
||||
if (mFound)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decide if the node represents the call of texelFetchOffset.
|
||||
if (node->getOp() != EOpFunctionCall || node->isUserDefined())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node->getName().compare(0, 16, "texelFetchOffset") != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Potential problem case detected, apply workaround.
|
||||
const TIntermSequence *sequence = node->getSequence();
|
||||
ASSERT(sequence->size() == 4u);
|
||||
nextTemporaryIndex();
|
||||
|
||||
// Decide if there is a 2DArray sampler.
|
||||
bool is2DArray = node->getName().find("s2a1") != TString::npos;
|
||||
|
||||
// Create new argument list from node->getName().
|
||||
// e.g. Get "(is2a1;vi3;i1;" from "texelFetchOffset(is2a1;vi3;i1;vi2;"
|
||||
TString newArgs = node->getName().substr(16, node->getName().length() - 20);
|
||||
TString newName = "texelFetch" + newArgs;
|
||||
TSymbol *texelFetchSymbol = symbolTable->findBuiltIn(newName, shaderVersion);
|
||||
ASSERT(texelFetchSymbol);
|
||||
int uniqueId = texelFetchSymbol->getUniqueId();
|
||||
|
||||
// Create new node that represents the call of function texelFetch.
|
||||
TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpFunctionCall);
|
||||
texelFetchNode->setName(newName);
|
||||
texelFetchNode->setFunctionId(uniqueId);
|
||||
texelFetchNode->setType(node->getType());
|
||||
texelFetchNode->setLine(node->getLine());
|
||||
|
||||
// Create argument List of texelFetch(sampler, Position+offset, lod).
|
||||
TIntermSequence newsequence;
|
||||
|
||||
// sampler
|
||||
newsequence.push_back(sequence->at(0));
|
||||
|
||||
// Position+offset
|
||||
TIntermBinary *add = new TIntermBinary(EOpAdd);
|
||||
add->setType(node->getType());
|
||||
// Position
|
||||
TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
|
||||
ASSERT(texCoordNode);
|
||||
add->setLine(texCoordNode->getLine());
|
||||
add->setType(texCoordNode->getType());
|
||||
add->setLeft(texCoordNode);
|
||||
// offset
|
||||
ASSERT(sequence->at(3)->getAsTyped());
|
||||
if (is2DArray)
|
||||
{
|
||||
// For 2DArray samplers, Position is ivec3 and offset is ivec2;
|
||||
// So offset must be converted into an ivec3 before being added to Position.
|
||||
TIntermAggregate *constructIVec3Node = new TIntermAggregate(EOpConstructIVec3);
|
||||
constructIVec3Node->setLine(texCoordNode->getLine());
|
||||
constructIVec3Node->setType(texCoordNode->getType());
|
||||
|
||||
TIntermSequence ivec3Sequence;
|
||||
ivec3Sequence.push_back(sequence->at(3)->getAsTyped());
|
||||
|
||||
TConstantUnion *zero = new TConstantUnion();
|
||||
zero->setIConst(0);
|
||||
TType *intType = new TType(EbtInt);
|
||||
|
||||
TIntermConstantUnion *zeroNode = new TIntermConstantUnion(zero, *intType);
|
||||
ivec3Sequence.push_back(zeroNode);
|
||||
constructIVec3Node->insertChildNodes(0, ivec3Sequence);
|
||||
|
||||
add->setRight(constructIVec3Node);
|
||||
}
|
||||
else
|
||||
{
|
||||
add->setRight(sequence->at(3)->getAsTyped());
|
||||
}
|
||||
newsequence.push_back(add);
|
||||
|
||||
// lod
|
||||
newsequence.push_back(sequence->at(2));
|
||||
texelFetchNode->insertChildNodes(0, newsequence);
|
||||
|
||||
// Replace the old node by this new node.
|
||||
queueReplacement(node, texelFetchNode, OriginalNode::IS_DROPPED);
|
||||
mFound = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void RewriteTexelFetchOffset(TIntermNode *root,
|
||||
unsigned int *tempIndex,
|
||||
const TSymbolTable &symbolTable,
|
||||
int shaderVersion)
|
||||
{
|
||||
// texelFetchOffset is only valid in GLSL 3.0 and later.
|
||||
if (shaderVersion < 300)
|
||||
return;
|
||||
|
||||
Traverser::Apply(root, tempIndex, symbolTable, shaderVersion);
|
||||
}
|
||||
|
||||
} // namespace sh
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
// This mutating tree traversal works around an issue on the translation
|
||||
// from texelFetchOffset into HLSL function Load on INTEL drivers. It
|
||||
// works by translating texelFetchOffset into texelFetch:
|
||||
//
|
||||
// - From: texelFetchOffset(sampler, Position, lod, offset)
|
||||
// - To: texelFetch(sampler, Position+offset, lod)
|
||||
//
|
||||
// See http://anglebug.com/1469
|
||||
|
||||
#ifndef COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_
|
||||
#define COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_
|
||||
|
||||
class TIntermNode;
|
||||
class TSymbolTable;
|
||||
|
||||
namespace sh
|
||||
{
|
||||
|
||||
void RewriteTexelFetchOffset(TIntermNode *root,
|
||||
unsigned int *tempIndex,
|
||||
const TSymbolTable &symbolTable,
|
||||
int shaderVersion);
|
||||
|
||||
} // namespace sh
|
||||
|
||||
#endif // COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_
|
|
@ -14,6 +14,7 @@
|
|||
#include "compiler/translator/OutputHLSL.h"
|
||||
#include "compiler/translator/RemoveDynamicIndexing.h"
|
||||
#include "compiler/translator/RewriteElseBlocks.h"
|
||||
#include "compiler/translator/RewriteTexelFetchOffset.h"
|
||||
#include "compiler/translator/SeparateArrayInitialization.h"
|
||||
#include "compiler/translator/SeparateDeclarations.h"
|
||||
#include "compiler/translator/SeparateExpressionsReturningArrays.h"
|
||||
|
@ -91,6 +92,12 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
|
|||
sh::ExpandIntegerPowExpressions(root, getTemporaryIndex());
|
||||
}
|
||||
|
||||
if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0)
|
||||
{
|
||||
sh::RewriteTexelFetchOffset(root, getTemporaryIndex(), getSymbolTable(),
|
||||
getShaderVersion());
|
||||
}
|
||||
|
||||
sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
|
||||
getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions);
|
||||
|
||||
|
|
|
@ -49,10 +49,16 @@ ShaderD3D::ShaderD3D(const gl::ShaderState &data, const WorkaroundsD3D &workarou
|
|||
{
|
||||
mAdditionalOptions |= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS;
|
||||
}
|
||||
|
||||
if (workarounds.getDimensionsIgnoresBaseLevel)
|
||||
{
|
||||
mAdditionalOptions |= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL;
|
||||
}
|
||||
|
||||
if (workarounds.preAddTexelFetchOffsets)
|
||||
{
|
||||
mAdditionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderD3D::~ShaderD3D()
|
||||
|
|
|
@ -67,6 +67,14 @@ struct WorkaroundsD3D
|
|||
// Some drivers (NVIDIA) do not take into account the base level of the texture in the results
|
||||
// of the HLSL GetDimensions builtin.
|
||||
bool getDimensionsIgnoresBaseLevel = false;
|
||||
|
||||
// On some Intel drivers, HLSL's function texture.Load returns 0 when the parameter Location
|
||||
// is negative, even if the sum of Offset and Location is in range. This may cause errors when
|
||||
// translating GLSL's function texelFetchOffset into texture.Load, as it is valid for
|
||||
// texelFetchOffset to use negative texture coordinates as its parameter P when the sum of P
|
||||
// and Offset is in range. To work around this, we translatie texelFetchOffset into texelFetch
|
||||
// by adding Offset directly to Location before reading the texture.
|
||||
bool preAddTexelFetchOffsets = false;
|
||||
};
|
||||
|
||||
} // namespace rx
|
||||
|
|
|
@ -1540,6 +1540,8 @@ WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps,
|
|||
workarounds.flushAfterEndingTransformFeedback = (adapterDesc.VendorId == VENDOR_ID_NVIDIA);
|
||||
workarounds.getDimensionsIgnoresBaseLevel = (adapterDesc.VendorId == VENDOR_ID_NVIDIA);
|
||||
|
||||
workarounds.preAddTexelFetchOffsets = (adapterDesc.VendorId == VENDOR_ID_INTEL);
|
||||
|
||||
return workarounds;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче