Commit 509e4560 by Corentin Wallez Committed by Commit Bot

compiler: Work around a HLSL compiler aliasing opt bug.

BUG=angleproject:1448 Change-Id: I7d5bcbd100069152cea0cb03bc4fa6af1044460b Reviewed-on: https://chromium-review.googlesource.com/376020 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 9e3d7aa0
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
'compiler/translator/BaseTypes.h', 'compiler/translator/BaseTypes.h',
'compiler/translator/BuiltInFunctionEmulator.cpp', 'compiler/translator/BuiltInFunctionEmulator.cpp',
'compiler/translator/BuiltInFunctionEmulator.h', 'compiler/translator/BuiltInFunctionEmulator.h',
'compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
'compiler/translator/BreakVariableAliasingInInnerLoops.h',
'compiler/translator/Cache.cpp', 'compiler/translator/Cache.cpp',
'compiler/translator/Cache.h', 'compiler/translator/Cache.h',
'compiler/translator/CallDAG.cpp', 'compiler/translator/CallDAG.cpp',
......
...@@ -54,48 +54,13 @@ class AddDefaultReturnStatementsTraverser : private TIntermTraverser ...@@ -54,48 +54,13 @@ class AddDefaultReturnStatementsTraverser : private TIntermTraverser
return true; return true;
} }
static TIntermTyped *GenerateTypeConstructor(const TType &returnType)
{
// Base case, constructing a single element
if (!returnType.isArray())
{
size_t objectSize = returnType.getObjectSize();
TConstantUnion *constantUnion = new TConstantUnion[objectSize];
for (size_t constantIdx = 0; constantIdx < objectSize; constantIdx++)
{
constantUnion[constantIdx].setFConst(0.0f);
}
TIntermConstantUnion *intermConstantUnion =
new TIntermConstantUnion(constantUnion, returnType);
return intermConstantUnion;
}
// Recursive case, construct an array of single elements
TIntermAggregate *constructorAggrigate =
new TIntermAggregate(TypeToConstructorOperator(returnType));
constructorAggrigate->setType(returnType);
size_t arraySize = returnType.getArraySize();
for (size_t arrayIdx = 0; arrayIdx < arraySize; arrayIdx++)
{
TType arrayElementType(returnType);
arrayElementType.clearArrayness();
constructorAggrigate->getSequence()->push_back(
GenerateTypeConstructor(arrayElementType));
}
return constructorAggrigate;
}
bool visitAggregate(Visit, TIntermAggregate *node) override bool visitAggregate(Visit, TIntermAggregate *node) override
{ {
TType returnType; TType returnType;
if (IsFunctionWithoutReturnStatement(node, &returnType)) if (IsFunctionWithoutReturnStatement(node, &returnType))
{ {
TIntermBranch *branch = TIntermBranch *branch =
new TIntermBranch(EOpReturn, GenerateTypeConstructor(returnType)); new TIntermBranch(EOpReturn, TIntermTyped::CreateZero(returnType));
TIntermAggregate *lastNode = node->getSequence()->back()->getAsAggregate(); TIntermAggregate *lastNode = node->getSequence()->back()->getAsAggregate();
lastNode->getSequence()->push_back(branch); lastNode->getSequence()->push_back(branch);
......
//
// 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.
//
// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
// may record a variable as aliasing another. Sometimes the alias information gets garbled
// so we work around this issue by breaking the aliasing chain in inner loops.
#include "BreakVariableAliasingInInnerLoops.h"
#include "compiler/translator/IntermNode.h"
// A HLSL compiler developer gave us more details on the root cause and the workaround needed:
// The root problem is that if the HLSL compiler is applying aliasing information even on
// incomplete simulations (in this case, a single pass). The bug is triggered by an assignment
// that comes from a series of assignments, possibly with swizzled or ternary operators with
// known conditionals, where the source is before the loop.
// So, a workaround is to add a +0 term to variables the first time they are assigned to in
// an inner loop (if they are declared in an outside scope, otherwise there is no need).
// This will break the aliasing chain.
// For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because
// the bug only shows up with swizzles, and ternary assignment, whole array or whole structure
// assignment don't need a workaround.
namespace
{
class AliasingBreaker : public TIntermTraverser
{
public:
AliasingBreaker() : TIntermTraverser(true, false, true) {}
protected:
bool visitBinary(Visit visit, TIntermBinary *binary)
{
if (visit != PreVisit)
{
return false;
}
if (mLoopLevel < 2 || !binary->isAssignment())
{
return true;
}
TIntermTyped *B = binary->getRight();
TType type = B->getType();
if (!type.isScalar() && !type.isVector() && !type.isMatrix())
{
return true;
}
if (type.isArray() || IsSampler(type.getBasicType()))
{
return true;
}
// We have a scalar / vector / matrix assignment with loop depth 2.
// Transform it from
// A = B
// to
// A = (B + typeof<B>(0));
TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, TIntermTyped::CreateZero(type));
bPlusZero->setLine(B->getLine());
binary->setRight(bPlusZero);
return true;
}
bool visitLoop(Visit visit, TIntermLoop *loop)
{
if (visit == PreVisit)
{
mLoopLevel++;
}
else
{
ASSERT(mLoopLevel > 0);
mLoopLevel--;
}
return true;
}
private:
int mLoopLevel = 0;
};
} // anonymous namespace
namespace sh
{
void BreakVariableAliasingInInnerLoops(TIntermNode *root)
{
AliasingBreaker breaker;
root->traverse(&breaker);
}
} // namespace sh
//
// 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.
//
// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
// may record a variable as aliasing another. Sometimes the alias information gets garbled
// so we work around this issue by breaking the aliasing chain in inner loops.
#ifndef COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
#define COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
class TIntermNode;
namespace sh
{
void BreakVariableAliasingInInnerLoops(TIntermNode *root);
} // namespace sh
#endif // COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
...@@ -17,44 +17,18 @@ ...@@ -17,44 +17,18 @@
namespace namespace
{ {
TIntermConstantUnion *constructIndexNode(int index)
{
TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
return node;
}
TIntermBinary *constructGLFragDataNode(int index)
{
TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
TIntermSymbol *symbol = new TIntermSymbol(0, "gl_FragData", TType(EbtFloat, 4));
indexDirect->setLeft(symbol);
TIntermConstantUnion *indexNode = constructIndexNode(index);
indexDirect->setRight(indexNode);
return indexDirect;
}
TIntermBinary *constructGLFragDataAssignNode(int index)
{
TIntermBinary *assign = new TIntermBinary(EOpAssign);
assign->setLeft(constructGLFragDataNode(index));
assign->setRight(constructGLFragDataNode(0));
assign->setType(TType(EbtFloat, 4));
return assign;
}
class GLFragColorBroadcastTraverser : public TIntermTraverser class GLFragColorBroadcastTraverser : public TIntermTraverser
{ {
public: public:
GLFragColorBroadcastTraverser() GLFragColorBroadcastTraverser(int maxDrawBuffers)
: TIntermTraverser(true, false, false), mMainSequence(nullptr), mGLFragColorUsed(false) : TIntermTraverser(true, false, false),
mMainSequence(nullptr),
mGLFragColorUsed(false),
mMaxDrawBuffers(maxDrawBuffers)
{ {
} }
void broadcastGLFragColor(int maxDrawBuffers); void broadcastGLFragColor();
bool isGLFragColorUsed() const { return mGLFragColorUsed; } bool isGLFragColorUsed() const { return mGLFragColorUsed; }
...@@ -62,11 +36,39 @@ class GLFragColorBroadcastTraverser : public TIntermTraverser ...@@ -62,11 +36,39 @@ class GLFragColorBroadcastTraverser : public TIntermTraverser
void visitSymbol(TIntermSymbol *node) override; void visitSymbol(TIntermSymbol *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override; bool visitAggregate(Visit visit, TIntermAggregate *node) override;
TIntermBinary *constructGLFragDataNode(int index) const;
TIntermBinary *constructGLFragDataAssignNode(int index) const;
private: private:
TIntermSequence *mMainSequence; TIntermSequence *mMainSequence;
bool mGLFragColorUsed; bool mGLFragColorUsed;
int mMaxDrawBuffers;
}; };
TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const
{
TType gl_FragDataElementType = TType(EbtFloat, 4);
TType gl_FragDataType = gl_FragDataElementType;
gl_FragDataType.setArraySize(mMaxDrawBuffers);
TIntermSymbol *symbol = new TIntermSymbol(0, "gl_FragData", gl_FragDataType);
TIntermTyped *indexNode = TIntermTyped::CreateIndexNode(index);
TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
binary->setLeft(symbol);
binary->setRight(indexNode);
binary->setType(gl_FragDataElementType);
return binary;
}
TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataAssignNode(int index) const
{
TIntermTyped *fragDataIndex = constructGLFragDataNode(index);
TIntermTyped *fragDataZero = constructGLFragDataNode(0);
return new TIntermBinary(EOpAssign, fragDataIndex, fragDataZero);
}
void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node) void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node)
{ {
if (node->getSymbol() == "gl_FragColor") if (node->getSymbol() == "gl_FragColor")
...@@ -101,9 +103,9 @@ bool GLFragColorBroadcastTraverser::visitAggregate(Visit visit, TIntermAggregate ...@@ -101,9 +103,9 @@ bool GLFragColorBroadcastTraverser::visitAggregate(Visit visit, TIntermAggregate
return true; return true;
} }
void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers) void GLFragColorBroadcastTraverser::broadcastGLFragColor()
{ {
ASSERT(maxDrawBuffers > 1); ASSERT(mMaxDrawBuffers > 1);
if (!mGLFragColorUsed) if (!mGLFragColorUsed)
{ {
return; return;
...@@ -113,7 +115,7 @@ void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers) ...@@ -113,7 +115,7 @@ void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers)
// gl_FragData[1] = gl_FragData[0]; // gl_FragData[1] = gl_FragData[0];
// ... // ...
// gl_FragData[maxDrawBuffers - 1] = gl_FragData[0]; // gl_FragData[maxDrawBuffers - 1] = gl_FragData[0];
for (int colorIndex = 1; colorIndex < maxDrawBuffers; ++colorIndex) for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex)
{ {
mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex)); mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex));
} }
...@@ -126,12 +128,12 @@ void EmulateGLFragColorBroadcast(TIntermNode *root, ...@@ -126,12 +128,12 @@ void EmulateGLFragColorBroadcast(TIntermNode *root,
std::vector<sh::OutputVariable> *outputVariables) std::vector<sh::OutputVariable> *outputVariables)
{ {
ASSERT(maxDrawBuffers > 1); ASSERT(maxDrawBuffers > 1);
GLFragColorBroadcastTraverser traverser; GLFragColorBroadcastTraverser traverser(maxDrawBuffers);
root->traverse(&traverser); root->traverse(&traverser);
if (traverser.isGLFragColorUsed()) if (traverser.isGLFragColorUsed())
{ {
traverser.updateTree(); traverser.updateTree();
traverser.broadcastGLFragColor(maxDrawBuffers); traverser.broadcastGLFragColor();
for (auto &var : *outputVariables) for (auto &var : *outputVariables)
{ {
if (var.name == "gl_FragColor") if (var.name == "gl_FragColor")
......
...@@ -14,46 +14,6 @@ ...@@ -14,46 +14,6 @@
namespace namespace
{ {
TIntermConstantUnion *constructConstUnionNode(const TType &type)
{
TType myType = type;
myType.clearArrayness();
myType.setQualifier(EvqConst);
size_t size = myType.getObjectSize();
TConstantUnion *u = new TConstantUnion[size];
for (size_t ii = 0; ii < size; ++ii)
{
switch (type.getBasicType())
{
case EbtFloat:
u[ii].setFConst(0.0f);
break;
case EbtInt:
u[ii].setIConst(0);
break;
case EbtUInt:
u[ii].setUConst(0u);
break;
default:
UNREACHABLE();
return nullptr;
}
}
TIntermConstantUnion *node = new TIntermConstantUnion(u, myType);
return node;
}
TIntermConstantUnion *constructIndexNode(int index)
{
TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
return node;
}
class VariableInitializer : public TIntermTraverser class VariableInitializer : public TIntermTraverser
{ {
public: public:
...@@ -120,73 +80,44 @@ bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -120,73 +80,44 @@ bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node)
void VariableInitializer::insertInitCode(TIntermSequence *sequence) void VariableInitializer::insertInitCode(TIntermSequence *sequence)
{ {
for (size_t ii = 0; ii < mVariables.size(); ++ii) for (const auto &var : mVariables)
{ {
const sh::ShaderVariable &var = mVariables[ii];
TString name = TString(var.name.c_str()); TString name = TString(var.name.c_str());
TType type = sh::GetShaderVariableType(var);
// Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
// doesn't have array assignment.
if (var.isArray()) if (var.isArray())
{ {
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
size_t pos = name.find_last_of('['); size_t pos = name.find_last_of('[');
if (pos != TString::npos) if (pos != TString::npos)
name = name.substr(0, pos);
for (int index = static_cast<int>(var.arraySize) - 1; index >= 0; --index)
{ {
TIntermBinary *assign = new TIntermBinary(EOpAssign); name = name.substr(0, pos);
sequence->insert(sequence->begin(), assign); }
TType elementType = type;
elementType.clearArrayness();
TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect); for (unsigned int i = 0; i < var.arraySize; ++i)
TIntermSymbol *symbol = new TIntermSymbol(0, name, type); {
indexDirect->setLeft(symbol); TIntermBinary *element = new TIntermBinary(EOpIndexDirect);
TIntermConstantUnion *indexNode = constructIndexNode(index); element->setLeft(new TIntermSymbol(0, name, type));
indexDirect->setRight(indexNode); element->setRight(TIntermTyped::CreateIndexNode(i));
element->setType(elementType);
assign->setLeft(indexDirect); TIntermTyped *zero = TIntermTyped::CreateZero(elementType);
TIntermBinary *assignment = new TIntermBinary(EOpAssign, element, zero);
TIntermConstantUnion *zeroConst = constructConstUnionNode(type); sequence->insert(sequence->begin(), assignment);
assign->setRight(zeroConst);
}
}
else if (var.isStruct())
{
TFieldList *fields = new TFieldList;
TSourceLoc loc;
for (auto field : var.fields)
{
fields->push_back(new TField(nullptr, new TString(field.name.c_str()), loc));
}
TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields);
TType type;
type.setStruct(structure);
for (int fieldIndex = 0; fieldIndex < static_cast<int>(var.fields.size()); ++fieldIndex)
{
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TIntermBinary *indexDirectStruct = new TIntermBinary(EOpIndexDirectStruct);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
indexDirectStruct->setLeft(symbol);
TIntermConstantUnion *indexNode = constructIndexNode(fieldIndex);
indexDirectStruct->setRight(indexNode);
assign->setLeft(indexDirectStruct);
const sh::ShaderVariable &field = var.fields[fieldIndex];
TType fieldType = sh::ConvertShaderVariableTypeToTType(field.type);
TIntermConstantUnion *zeroConst = constructConstUnionNode(fieldType);
assign->setRight(zeroConst);
} }
} }
else else
{ {
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type); TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
assign->setLeft(symbol); TIntermTyped *zero = TIntermTyped::CreateZero(type);
TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
assign->setRight(zeroConst);
}
TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
sequence->insert(sequence->begin(), assign);
}
} }
} }
......
...@@ -13,6 +13,7 @@ class TIntermNode; ...@@ -13,6 +13,7 @@ class TIntermNode;
typedef std::vector<sh::ShaderVariable> InitVariableList; typedef std::vector<sh::ShaderVariable> InitVariableList;
// This function cannot currently initialize structures containing arrays for an ESSL 1.00 backend.
void InitializeVariables(TIntermNode *root, const InitVariableList &vars); void InitializeVariables(TIntermNode *root, const InitVariableList &vars);
#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ #endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "compiler/translator/HashNames.h" #include "compiler/translator/HashNames.h"
#include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h" #include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
namespace namespace
{ {
...@@ -336,6 +337,83 @@ bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters() ...@@ -336,6 +337,83 @@ bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
return true; return true;
} }
// static
TIntermTyped *TIntermTyped::CreateIndexNode(int index)
{
TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
return node;
}
// static
TIntermTyped *TIntermTyped::CreateZero(const TType &type)
{
TType constType(type);
constType.setQualifier(EvqConst);
if (!type.isArray() && type.getBasicType() != EbtStruct)
{
ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
size_t size = constType.getObjectSize();
TConstantUnion *u = new TConstantUnion[size];
for (size_t i = 0; i < size; ++i)
{
switch (type.getBasicType())
{
case EbtFloat:
u[i].setFConst(0.0f);
break;
case EbtInt:
u[i].setIConst(0);
break;
case EbtUInt:
u[i].setUConst(0u);
break;
case EbtBool:
u[i].setBConst(false);
break;
default:
UNREACHABLE();
return nullptr;
}
}
TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
return node;
}
TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
constructor->setType(constType);
if (type.isArray())
{
TType elementType(type);
elementType.clearArrayness();
size_t arraySize = type.getArraySize();
for (size_t i = 0; i < arraySize; ++i)
{
constructor->getSequence()->push_back(CreateZero(elementType));
}
}
else
{
ASSERT(type.getBasicType() == EbtStruct);
TStructure *structure = type.getStruct();
for (const auto &field : structure->fields())
{
constructor->getSequence()->push_back(CreateZero(*field->type()));
}
}
return constructor;
}
TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node) TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
{ {
mUnionArrayPointer = node.mUnionArrayPointer; mUnionArrayPointer = node.mUnionArrayPointer;
......
...@@ -159,6 +159,9 @@ class TIntermTyped : public TIntermNode ...@@ -159,6 +159,9 @@ class TIntermTyped : public TIntermNode
bool isConstructorWithOnlyConstantUnionParameters(); bool isConstructorWithOnlyConstantUnionParameters();
static TIntermTyped *CreateIndexNode(int index);
static TIntermTyped *CreateZero(const TType &type);
protected: protected:
TType mType; TType mType;
......
...@@ -37,21 +37,11 @@ bool ContainsVectorNode(const TIntermSequence &sequence) ...@@ -37,21 +37,11 @@ bool ContainsVectorNode(const TIntermSequence &sequence)
return false; return false;
} }
TIntermConstantUnion *ConstructIndexNode(int index)
{
TConstantUnion *u = new TConstantUnion[1];
u[0].setIConst(index);
TType type(EbtInt, EbpUndefined, EvqConst, 1);
TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
return node;
}
TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index) TIntermBinary *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index)
{ {
TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
binary->setLeft(symbolNode); binary->setLeft(symbolNode);
TIntermConstantUnion *indexNode = ConstructIndexNode(index); TIntermTyped *indexNode = TIntermTyped::CreateIndexNode(index);
binary->setRight(indexNode); binary->setRight(indexNode);
return binary; return binary;
} }
...@@ -64,7 +54,7 @@ TIntermBinary *ConstructMatrixIndexBinaryNode( ...@@ -64,7 +54,7 @@ TIntermBinary *ConstructMatrixIndexBinaryNode(
TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); TIntermBinary *binary = new TIntermBinary(EOpIndexDirect);
binary->setLeft(colVectorNode); binary->setLeft(colVectorNode);
TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex); TIntermTyped *rowIndexNode = TIntermTyped::CreateIndexNode(rowIndex);
binary->setRight(rowIndexNode); binary->setRight(rowIndexNode);
return binary; return binary;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "compiler/translator/AddDefaultReturnStatements.h" #include "compiler/translator/AddDefaultReturnStatements.h"
#include "compiler/translator/ArrayReturnValueToOutParameter.h" #include "compiler/translator/ArrayReturnValueToOutParameter.h"
#include "compiler/translator/BreakVariableAliasingInInnerLoops.h"
#include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/ExpandIntegerPowExpressions.h" #include "compiler/translator/ExpandIntegerPowExpressions.h"
#include "compiler/translator/IntermNodePatternMatcher.h" #include "compiler/translator/IntermNodePatternMatcher.h"
...@@ -75,6 +76,12 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) ...@@ -75,6 +76,12 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions)
sh::RewriteElseBlocks(root, getTemporaryIndex()); sh::RewriteElseBlocks(root, getTemporaryIndex());
} }
// Work around an HLSL compiler frontend aliasing optimization bug.
// TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed
// in the next release of d3dcompiler.dll, it would be nice to detect the DLL
// version and only apply the workaround if it is too old.
sh::BreakVariableAliasingInInnerLoops(root);
bool precisionEmulation = bool precisionEmulation =
getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision;
......
...@@ -278,9 +278,9 @@ InterpolationType GetInterpolationType(TQualifier qualifier) ...@@ -278,9 +278,9 @@ InterpolationType GetInterpolationType(TQualifier qualifier)
} }
} }
TType ConvertShaderVariableTypeToTType(sh::GLenum type) TType GetShaderVariableBasicType(const sh::ShaderVariable &var)
{ {
switch (type) switch (var.type)
{ {
case GL_FLOAT: case GL_FLOAT:
return TType(EbtFloat); return TType(EbtFloat);
...@@ -330,6 +330,35 @@ TType ConvertShaderVariableTypeToTType(sh::GLenum type) ...@@ -330,6 +330,35 @@ TType ConvertShaderVariableTypeToTType(sh::GLenum type)
} }
} }
TType GetShaderVariableType(const sh::ShaderVariable &var)
{
TType type;
if (var.isStruct())
{
TFieldList *fields = new TFieldList;
TSourceLoc loc;
for (const auto &field : var.fields)
{
TType *fieldType = new TType(GetShaderVariableType(field));
fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc));
}
TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields);
type.setBasicType(EbtStruct);
type.setStruct(structure);
}
else
{
type = GetShaderVariableBasicType(var);
}
if (var.isArray())
{
type.setArraySize(var.elementCount());
}
return type;
}
TOperator TypeToConstructorOperator(const TType &type) TOperator TypeToConstructorOperator(const TType &type)
{ {
switch (type.getBasicType()) switch (type.getBasicType())
......
...@@ -37,8 +37,9 @@ bool IsVaryingOut(TQualifier qualifier); ...@@ -37,8 +37,9 @@ bool IsVaryingOut(TQualifier qualifier);
bool IsVarying(TQualifier qualifier); bool IsVarying(TQualifier qualifier);
InterpolationType GetInterpolationType(TQualifier qualifier); InterpolationType GetInterpolationType(TQualifier qualifier);
TString ArrayString(const TType &type); TString ArrayString(const TType &type);
// Handles only basic output variable types.
TType ConvertShaderVariableTypeToTType(sh::GLenum type); TType GetShaderVariableBasicType(const sh::ShaderVariable &var);
TType GetShaderVariableType(const sh::ShaderVariable &var);
TOperator TypeToConstructorOperator(const TType &type); TOperator TypeToConstructorOperator(const TType &type);
......
...@@ -56,22 +56,6 @@ ...@@ -56,22 +56,6 @@
// TODO(jmadill): Find why this fails when run in a certain sequence, but not singly. // TODO(jmadill): Find why this fails when run in a certain sequence, but not singly.
1098 WIN : dEQP-GLES3.functional.uniform_api.random.50 = FAIL 1098 WIN : dEQP-GLES3.functional.uniform_api.random.50 = FAIL
// Caused by a D3D compiler bug
1448 WIN : dEQP-GLES3.functional.shaders.loops.for_constant_iterations.nested_sequence_vertex = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.for_constant_iterations.nested_sequence_fragment = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.for_constant_iterations.nested_tricky_dataflow_1_vertex = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.for_constant_iterations.nested_tricky_dataflow_1_fragment = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.for_constant_iterations.nested_tricky_dataflow_2_vertex = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.for_constant_iterations.nested_tricky_dataflow_2_fragment = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.while_constant_iterations.nested_tricky_dataflow_1_vertex = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.while_constant_iterations.nested_tricky_dataflow_1_fragment = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.while_constant_iterations.nested_tricky_dataflow_2_vertex = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.while_constant_iterations.nested_tricky_dataflow_2_fragment = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_1_vertex = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_1_fragment = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_2_vertex = FAIL
1448 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_2_fragment = FAIL
// Missing the SampleCmp instruction in vertex shaders. // Missing the SampleCmp instruction in vertex shaders.
1435 WIN : dEQP-GLES3.functional.shaders.texture_functions.texturelod.sampler2dshadow_vertex = FAIL 1435 WIN : dEQP-GLES3.functional.shaders.texture_functions.texturelod.sampler2dshadow_vertex = FAIL
1435 WIN : dEQP-GLES3.functional.shaders.texture_functions.texturelodoffset.sampler2dshadow_vertex = FAIL 1435 WIN : dEQP-GLES3.functional.shaders.texture_functions.texturelodoffset.sampler2dshadow_vertex = FAIL
......
...@@ -1063,6 +1063,37 @@ TEST_P(GLSLTest_ES3, MissingReturnArrayOfStructs) ...@@ -1063,6 +1063,37 @@ TEST_P(GLSLTest_ES3, MissingReturnArrayOfStructs)
EXPECT_NE(0u, program); EXPECT_NE(0u, program);
} }
// Verify that functions without return statements still compile
TEST_P(GLSLTest_ES3, MissingReturnStructOfArrays)
{
// TODO(cwallez) remove the suppression once NVIDIA removes the restriction for
// GLSL >= 300. It was defined only in GLSL 2.0, section 6.1.
if (IsNVIDIA() && IsOpenGLES())
{
std::cout << "Test skipped on NVIDIA OpenGL ES because it disallows returning "
"structure of arrays"
<< std::endl;
return;
}
const std::string vertexShaderSource =
"#version 300 es\n"
"in float v_varying;\n"
"struct s { float a[2]; int b[2]; vec2 c[2]; };\n"
"s f() { if (v_varying > 0.0) { return s(float[2](1.0, 1.0), int[2](1, 1),"
"vec2[2](vec2(1.0, 1.0), vec2(1.0, 1.0))); } }\n"
"void main() { gl_Position = vec4(f().a[0], 0, 0, 1); }\n";
const std::string fragmentShaderSource =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() { my_FragColor = vec4(0, 0, 0, 1); }\n";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_NE(0u, program);
}
// Verify that using invariant(all) in both shaders fails in ESSL 3.00. // Verify that using invariant(all) in both shaders fails in ESSL 3.00.
TEST_P(GLSLTest_ES3, InvariantAllBoth) TEST_P(GLSLTest_ES3, InvariantAllBoth)
{ {
......
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