Commit 3c9eeb97 by Jamie Madill

Disable optimizations for shaders with conditional discard in D3D9, and

only use expanded short-circuiting conditionals for expressions with potential side-effects. Conservatively assume aggreate and selection operators have side effects for now. BUG= ANGLEBUG=486 R=geofflang@chromium.org, kbr@chromium.org, nicolas@transgaming.com, shannonwoods@chromium.org Review URL: https://codereview.appspot.com/14441075 Conflicts: src/common/version.h src/compiler/translator.vcxproj src/compiler/translator.vcxproj.filters src/compiler/translator/OutputHLSL.cpp src/libGLESv2/ProgramBinary.cpp src/libGLESv2/Shader.cpp src/libGLESv2/Shader.h Change-Id: Iaf9f10b5de7b33c927ef032f3c4fe9d5095f64dd
parent 5a60b739
...@@ -150,6 +150,7 @@ ...@@ -150,6 +150,7 @@
<ClInclude Include="..\..\src\compiler\translator\VersionGLSL.h"/> <ClInclude Include="..\..\src\compiler\translator\VersionGLSL.h"/>
<ClInclude Include="..\..\src\compiler\translator\HashNames.h"/> <ClInclude Include="..\..\src\compiler\translator\HashNames.h"/>
<ClInclude Include="..\..\src\compiler\translator\DirectiveHandler.h"/> <ClInclude Include="..\..\src\compiler\translator\DirectiveHandler.h"/>
<ClInclude Include="..\..\src\compiler\translator\NodeSearch.h"/>
<ClInclude Include="..\..\src\compiler\translator\TranslatorESSL.h"/> <ClInclude Include="..\..\src\compiler\translator\TranslatorESSL.h"/>
<ClInclude Include="..\..\src\compiler\translator\InitializeDll.h"/> <ClInclude Include="..\..\src\compiler\translator\InitializeDll.h"/>
<ClInclude Include="..\..\src\compiler\translator\localintermediate.h"/> <ClInclude Include="..\..\src\compiler\translator\localintermediate.h"/>
......
...@@ -222,6 +222,9 @@ ...@@ -222,6 +222,9 @@
<ClCompile Include="..\..\src\compiler\translator\ValidateOutputs.cpp"> <ClCompile Include="..\..\src\compiler\translator\ValidateOutputs.cpp">
<Filter>..\..\src\compiler\translator</Filter> <Filter>..\..\src\compiler\translator</Filter>
</ClCompile> </ClCompile>
<ClInclude Include="..\..\src\compiler\translator\NodeSearch.h">
<Filter>..\..\src\compiler\translator</Filter>
</ClInclude>
<ClInclude Include="..\..\src\compiler\translator\TranslatorESSL.h"> <ClInclude Include="..\..\src\compiler\translator\TranslatorESSL.h">
<Filter>..\..\src\compiler\translator</Filter> <Filter>..\..\src\compiler\translator</Filter>
</ClInclude> </ClInclude>
......
...@@ -150,6 +150,7 @@ ...@@ -150,6 +150,7 @@
<ClInclude Include="..\..\src\compiler\translator\VersionGLSL.h"/> <ClInclude Include="..\..\src\compiler\translator\VersionGLSL.h"/>
<ClInclude Include="..\..\src\compiler\translator\HashNames.h"/> <ClInclude Include="..\..\src\compiler\translator\HashNames.h"/>
<ClInclude Include="..\..\src\compiler\translator\DirectiveHandler.h"/> <ClInclude Include="..\..\src\compiler\translator\DirectiveHandler.h"/>
<ClInclude Include="..\..\src\compiler\translator\NodeSearch.h"/>
<ClInclude Include="..\..\src\compiler\translator\TranslatorESSL.h"/> <ClInclude Include="..\..\src\compiler\translator\TranslatorESSL.h"/>
<ClInclude Include="..\..\src\compiler\translator\InitializeDll.h"/> <ClInclude Include="..\..\src\compiler\translator\InitializeDll.h"/>
<ClInclude Include="..\..\src\compiler\translator\localintermediate.h"/> <ClInclude Include="..\..\src\compiler\translator\localintermediate.h"/>
......
...@@ -222,6 +222,9 @@ ...@@ -222,6 +222,9 @@
<ClCompile Include="..\..\src\compiler\translator\ValidateOutputs.cpp"> <ClCompile Include="..\..\src\compiler\translator\ValidateOutputs.cpp">
<Filter>..\..\src\compiler\translator</Filter> <Filter>..\..\src\compiler\translator</Filter>
</ClCompile> </ClCompile>
<ClInclude Include="..\..\src\compiler\translator\NodeSearch.h">
<Filter>..\..\src\compiler\translator</Filter>
</ClInclude>
<ClInclude Include="..\..\src\compiler\translator\TranslatorESSL.h"> <ClInclude Include="..\..\src\compiler\translator\TranslatorESSL.h">
<Filter>..\..\src\compiler\translator</Filter> <Filter>..\..\src\compiler\translator</Filter>
</ClInclude> </ClInclude>
......
#define MAJOR_VERSION 2 #define MAJOR_VERSION 2
#define MINOR_VERSION 0 #define MINOR_VERSION 0
#define BUILD_VERSION 0 #define BUILD_VERSION 0
#define BUILD_REVISION 2016 #define BUILD_REVISION 2017
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x) #define MACRO_STRINGIFY(x) STRINGIFY(x)
......
...@@ -774,7 +774,7 @@ void TIntermediate::remove(TIntermNode* root) ...@@ -774,7 +774,7 @@ void TIntermediate::remove(TIntermNode* root)
// //
// Returns true if state is modified. // Returns true if state is modified.
// //
bool TIntermOperator::modifiesState() const bool TIntermOperator::hasSideEffects() const
{ {
switch (op) { switch (op) {
case EOpPostIncrement: case EOpPostIncrement:
......
//
// Copyright (c) 2002-2013 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.
//
// NodeSearch.h: Utilities for searching translator node graphs
//
#ifndef TRANSLATOR_NODESEARCH_H_
#define TRANSLATOR_NODESEARCH_H_
namespace sh
{
template <class Parent>
class NodeSearchTraverser : public TIntermTraverser
{
public:
NodeSearchTraverser()
: mFound(false)
{}
bool found() const { return mFound; }
static bool search(TIntermNode *node)
{
Parent searchTraverser;
node->traverse(&searchTraverser);
return searchTraverser.found();
}
protected:
bool mFound;
};
class FindDiscard : public NodeSearchTraverser<FindDiscard>
{
public:
virtual bool visitBranch(Visit visit, TIntermBranch *node)
{
switch (node->getFlowOp())
{
case EOpKill:
mFound = true;
break;
default: break;
}
return !mFound;
}
};
class FindSideEffectRewriting : public NodeSearchTraverser<FindSideEffectRewriting>
{
public:
virtual bool visitBinary(Visit visit, TIntermBinary *node)
{
switch (node->getOp())
{
case EOpLogicalOr:
case EOpLogicalAnd:
if (node->getRight()->hasSideEffects())
{
mFound = true;
}
break;
default: break;
}
return !mFound;
}
};
}
#endif // TRANSLATOR_NODESEARCH_H_
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "compiler/translator/UnfoldShortCircuit.h" #include "compiler/translator/UnfoldShortCircuit.h"
#include "compiler/translator/HLSLLayoutEncoder.h" #include "compiler/translator/HLSLLayoutEncoder.h"
#include "compiler/translator/FlagStd140Structs.h" #include "compiler/translator/FlagStd140Structs.h"
#include "compiler/translator/NodeSearch.h"
#include <algorithm> #include <algorithm>
#include <cfloat> #include <cfloat>
...@@ -121,6 +122,7 @@ OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resourc ...@@ -121,6 +122,7 @@ OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resourc
mUsesAtan2_2 = false; mUsesAtan2_2 = false;
mUsesAtan2_3 = false; mUsesAtan2_3 = false;
mUsesAtan2_4 = false; mUsesAtan2_4 = false;
mUsesDiscardRewriting = false;
mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
...@@ -663,6 +665,11 @@ void OutputHLSL::header() ...@@ -663,6 +665,11 @@ void OutputHLSL::header()
out << *constructor; out << *constructor;
} }
if (mUsesDiscardRewriting)
{
out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n";
}
if (mContext.shaderType == SH_FRAGMENT_SHADER) if (mContext.shaderType == SH_FRAGMENT_SHADER)
{ {
TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers"); TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
...@@ -1883,15 +1890,31 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1883,15 +1890,31 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break; case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break; case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
case EOpLogicalOr: case EOpLogicalOr:
out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); if (node->getRight()->hasSideEffects())
return false; {
out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
return false;
}
else
{
outputTriplet(visit, "(", " || ", ")");
return true;
}
case EOpLogicalXor: case EOpLogicalXor:
mUsesXor = true; mUsesXor = true;
outputTriplet(visit, "xor(", ", ", ")"); outputTriplet(visit, "xor(", ", ", ")");
break; break;
case EOpLogicalAnd: case EOpLogicalAnd:
out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); if (node->getRight()->hasSideEffects())
return false; {
out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
return false;
}
else
{
outputTriplet(visit, "(", " && ", ")");
return true;
}
default: UNREACHABLE(); default: UNREACHABLE();
} }
...@@ -2483,7 +2506,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) ...@@ -2483,7 +2506,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
{ {
mUnfoldShortCircuit->traverse(node->getCondition()); mUnfoldShortCircuit->traverse(node->getCondition());
out << "if("; out << "if (";
node->getCondition()->traverse(this); node->getCondition()->traverse(this);
...@@ -2492,9 +2515,14 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) ...@@ -2492,9 +2515,14 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
outputLineDirective(node->getLine().first_line); outputLineDirective(node->getLine().first_line);
out << "{\n"; out << "{\n";
bool discard = false;
if (node->getTrueBlock()) if (node->getTrueBlock())
{ {
traverseStatements(node->getTrueBlock()); traverseStatements(node->getTrueBlock());
// Detect true discard
discard = (discard || FindDiscard::search(node->getTrueBlock()));
} }
outputLineDirective(node->getLine().first_line); outputLineDirective(node->getLine().first_line);
...@@ -2512,6 +2540,15 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) ...@@ -2512,6 +2540,15 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
outputLineDirective(node->getFalseBlock()->getLine().first_line); outputLineDirective(node->getFalseBlock()->getLine().first_line);
out << ";\n}\n"; out << ";\n}\n";
// Detect false discard
discard = (discard || FindDiscard::search(node->getFalseBlock()));
}
// ANGLE issue 486: Detect problematic conditional discard
if (discard && FindSideEffectRewriting::search(node))
{
mUsesDiscardRewriting = true;
} }
} }
...@@ -2609,7 +2646,9 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) ...@@ -2609,7 +2646,9 @@ bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
switch (node->getFlowOp()) switch (node->getFlowOp())
{ {
case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break; case EOpKill:
outputTriplet(visit, "discard;\n", "", "");
break;
case EOpBreak: case EOpBreak:
if (visit == PreVisit) if (visit == PreVisit)
{ {
...@@ -2832,7 +2871,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) ...@@ -2832,7 +2871,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
if (!firstLoopFragment) if (!firstLoopFragment)
{ {
out << "if(!Break"; out << "if (!Break";
index->traverse(this); index->traverse(this);
out << ") {\n"; out << ") {\n";
} }
......
...@@ -145,6 +145,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -145,6 +145,7 @@ class OutputHLSL : public TIntermTraverser
bool mUsesAtan2_2; bool mUsesAtan2_2;
bool mUsesAtan2_3; bool mUsesAtan2_3;
bool mUsesAtan2_4; bool mUsesAtan2_4;
bool mUsesDiscardRewriting;
int mNumRenderTargets; int mNumRenderTargets;
......
...@@ -31,6 +31,14 @@ bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) ...@@ -31,6 +31,14 @@ bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
{ {
TInfoSinkBase &out = mOutputHLSL->getBodyStream(); TInfoSinkBase &out = mOutputHLSL->getBodyStream();
// If our right node doesn't have side effects, we know we don't need to unfold this
// expression: there will be no short-circuiting side effects to avoid
// (note: unfolding doesn't depend on the left node -- it will always be evaluated)
if (!node->getRight()->hasSideEffects())
{
return true;
}
switch (node->getOp()) switch (node->getOp())
{ {
case EOpLogicalOr: case EOpLogicalOr:
...@@ -49,7 +57,7 @@ bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) ...@@ -49,7 +57,7 @@ bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
mTemporaryIndex = i + 1; mTemporaryIndex = i + 1;
node->getLeft()->traverse(mOutputHLSL); node->getLeft()->traverse(mOutputHLSL);
out << ";\n"; out << ";\n";
out << "if(!s" << i << ")\n" out << "if (!s" << i << ")\n"
"{\n"; "{\n";
mTemporaryIndex = i + 1; mTemporaryIndex = i + 1;
node->getRight()->traverse(this); node->getRight()->traverse(this);
...@@ -80,7 +88,7 @@ bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) ...@@ -80,7 +88,7 @@ bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
mTemporaryIndex = i + 1; mTemporaryIndex = i + 1;
node->getLeft()->traverse(mOutputHLSL); node->getLeft()->traverse(mOutputHLSL);
out << ";\n"; out << ";\n";
out << "if(s" << i << ")\n" out << "if (s" << i << ")\n"
"{\n"; "{\n";
mTemporaryIndex = i + 1; mTemporaryIndex = i + 1;
node->getRight()->traverse(this); node->getRight()->traverse(this);
...@@ -115,7 +123,7 @@ bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) ...@@ -115,7 +123,7 @@ bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node)
mTemporaryIndex = i + 1; mTemporaryIndex = i + 1;
node->getCondition()->traverse(this); node->getCondition()->traverse(this);
out << "if("; out << "if (";
mTemporaryIndex = i + 1; mTemporaryIndex = i + 1;
node->getCondition()->traverse(mOutputHLSL); node->getCondition()->traverse(mOutputHLSL);
out << ")\n" out << ")\n"
......
...@@ -461,7 +461,7 @@ bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node) ...@@ -461,7 +461,7 @@ bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node)
bool ValidateLimitations::validateOperation(TIntermOperator* node, bool ValidateLimitations::validateOperation(TIntermOperator* node,
TIntermNode* operand) { TIntermNode* operand) {
// Check if loop index is modified in the loop body. // Check if loop index is modified in the loop body.
if (!withinLoopBody() || !node->modifiesState()) if (!withinLoopBody() || !node->hasSideEffects())
return true; return true;
const TIntermSymbol* symbol = operand->getAsSymbolNode(); const TIntermSymbol* symbol = operand->getAsSymbolNode();
......
...@@ -94,7 +94,7 @@ void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol) ...@@ -94,7 +94,7 @@ void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol)
bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary) bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary)
{ {
TOperator op = intermBinary->getOp(); TOperator op = intermBinary->getOp();
if (op == EOpInitialize || intermBinary->modifiesState()) if (op == EOpInitialize || intermBinary->hasSideEffects())
visitAssignment(intermBinary); visitAssignment(intermBinary);
else if (op == EOpLogicalAnd || op == EOpLogicalOr) else if (op == EOpLogicalAnd || op == EOpLogicalOr)
visitLogicalOp(intermBinary); visitLogicalOp(intermBinary);
......
...@@ -258,6 +258,8 @@ public: ...@@ -258,6 +258,8 @@ public:
TIntermTyped(const TType& t) : type(t) { } TIntermTyped(const TType& t) : type(t) { }
virtual TIntermTyped* getAsTyped() { return this; } virtual TIntermTyped* getAsTyped() { return this; }
virtual bool hasSideEffects() const = 0;
void setType(const TType& t) { type = t; } void setType(const TType& t) { type = t; }
const TType& getType() const { return type; } const TType& getType() const { return type; }
TType* getTypePointer() { return &type; } TType* getTypePointer() { return &type; }
...@@ -359,6 +361,8 @@ public: ...@@ -359,6 +361,8 @@ public:
TIntermSymbol(int i, const TString& sym, const TType& t) : TIntermSymbol(int i, const TString& sym, const TType& t) :
TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; } TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; }
virtual bool hasSideEffects() const { return false; }
int getId() const { return id; } int getId() const { return id; }
const TString& getSymbol() const { return symbol; } const TString& getSymbol() const { return symbol; }
...@@ -380,6 +384,8 @@ class TIntermConstantUnion : public TIntermTyped { ...@@ -380,6 +384,8 @@ class TIntermConstantUnion : public TIntermTyped {
public: public:
TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
virtual bool hasSideEffects() const { return false; }
ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
int getIConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; } int getIConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
...@@ -404,7 +410,7 @@ public: ...@@ -404,7 +410,7 @@ public:
TOperator getOp() const { return op; } TOperator getOp() const { return op; }
void setOp(TOperator o) { op = o; } void setOp(TOperator o) { op = o; }
bool modifiesState() const; virtual bool hasSideEffects() const;
bool isConstructor() const; bool isConstructor() const;
protected: protected:
...@@ -423,6 +429,8 @@ public: ...@@ -423,6 +429,8 @@ public:
virtual TIntermBinary* getAsBinaryNode() { return this; } virtual TIntermBinary* getAsBinaryNode() { return this; }
virtual void traverse(TIntermTraverser*); virtual void traverse(TIntermTraverser*);
virtual bool hasSideEffects() const { return (TIntermOperator::hasSideEffects() || left->hasSideEffects() || right->hasSideEffects()); }
void setLeft(TIntermTyped* n) { left = n; } void setLeft(TIntermTyped* n) { left = n; }
void setRight(TIntermTyped* n) { right = n; } void setRight(TIntermTyped* n) { right = n; }
TIntermTyped* getLeft() const { return left; } TIntermTyped* getLeft() const { return left; }
...@@ -451,6 +459,8 @@ public: ...@@ -451,6 +459,8 @@ public:
virtual void traverse(TIntermTraverser*); virtual void traverse(TIntermTraverser*);
virtual TIntermUnary* getAsUnaryNode() { return this; } virtual TIntermUnary* getAsUnaryNode() { return this; }
virtual bool hasSideEffects() const { return (TIntermOperator::hasSideEffects() || operand->hasSideEffects()); }
void setOperand(TIntermTyped* o) { operand = o; } void setOperand(TIntermTyped* o) { operand = o; }
TIntermTyped* getOperand() { return operand; } TIntermTyped* getOperand() { return operand; }
bool promote(TInfoSink&); bool promote(TInfoSink&);
...@@ -481,6 +491,9 @@ public: ...@@ -481,6 +491,9 @@ public:
virtual TIntermAggregate* getAsAggregate() { return this; } virtual TIntermAggregate* getAsAggregate() { return this; }
virtual void traverse(TIntermTraverser*); virtual void traverse(TIntermTraverser*);
// Conservatively assume function calls and other aggregate operators have side-effects
virtual bool hasSideEffects() const { return true; }
TIntermSequence& getSequence() { return sequence; } TIntermSequence& getSequence() { return sequence; }
void setName(const TString& n) { name = n; } void setName(const TString& n) { name = n; }
...@@ -524,6 +537,9 @@ public: ...@@ -524,6 +537,9 @@ public:
virtual void traverse(TIntermTraverser*); virtual void traverse(TIntermTraverser*);
// Conservatively assume selections have side-effects
virtual bool hasSideEffects() const { return true; }
bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
TIntermNode* getCondition() const { return condition; } TIntermNode* getCondition() const { return condition; }
TIntermNode* getTrueBlock() const { return trueBlock; } TIntermNode* getTrueBlock() const { return trueBlock; }
......
...@@ -99,6 +99,11 @@ unsigned int parseAndStripArrayIndex(std::string* name) ...@@ -99,6 +99,11 @@ unsigned int parseAndStripArrayIndex(std::string* name)
return subscript; return subscript;
} }
static rx::D3DWorkaroundType DiscardWorkaround(bool usesDiscard)
{
return (usesDiscard ? rx::ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER : rx::ANGLE_D3D_WORKAROUND_NONE);
}
} }
VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
...@@ -2060,13 +2065,13 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin ...@@ -2060,13 +2065,13 @@ bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBin
if (success) if (success)
{ {
mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX); mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, DiscardWorkaround(vertexShader->mUsesDiscardRewriting));
mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL); mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, DiscardWorkaround(fragmentShader->mUsesDiscardRewriting));
if (usesGeometryShader()) if (usesGeometryShader())
{ {
std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader); std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY); mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, rx::ANGLE_D3D_WORKAROUND_NONE);
} }
if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable)) if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
......
...@@ -232,6 +232,7 @@ void Shader::parseVaryings(void *compiler) ...@@ -232,6 +232,7 @@ void Shader::parseVaryings(void *compiler)
mUsesPointCoord = mHlsl.find("GL_USES_POINT_COORD") != std::string::npos; mUsesPointCoord = mHlsl.find("GL_USES_POINT_COORD") != std::string::npos;
mUsesDepthRange = mHlsl.find("GL_USES_DEPTH_RANGE") != std::string::npos; mUsesDepthRange = mHlsl.find("GL_USES_DEPTH_RANGE") != std::string::npos;
mUsesFragDepth = mHlsl.find("GL_USES_FRAG_DEPTH") != std::string::npos; mUsesFragDepth = mHlsl.find("GL_USES_FRAG_DEPTH") != std::string::npos;
mUsesDiscardRewriting = mHlsl.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
} }
} }
...@@ -263,6 +264,7 @@ void Shader::uncompile() ...@@ -263,6 +264,7 @@ void Shader::uncompile()
mUsesDepthRange = false; mUsesDepthRange = false;
mUsesFragDepth = false; mUsesFragDepth = false;
mShaderVersion = 100; mShaderVersion = 100;
mUsesDiscardRewriting = false;
mActiveUniforms.clear(); mActiveUniforms.clear();
mActiveInterfaceBlocks.clear(); mActiveInterfaceBlocks.clear();
......
...@@ -92,6 +92,7 @@ class Shader ...@@ -92,6 +92,7 @@ class Shader
bool mUsesDepthRange; bool mUsesDepthRange;
bool mUsesFragDepth; bool mUsesFragDepth;
int mShaderVersion; int mShaderVersion;
bool mUsesDiscardRewriting;
static void *mFragmentCompiler; static void *mFragmentCompiler;
static void *mVertexCompiler; static void *mVertexCompiler;
......
...@@ -96,6 +96,12 @@ enum ShaderType ...@@ -96,6 +96,12 @@ enum ShaderType
SHADER_GEOMETRY SHADER_GEOMETRY
}; };
enum D3DWorkaroundType
{
ANGLE_D3D_WORKAROUND_NONE,
ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER
};
class Renderer class Renderer
{ {
public: public:
...@@ -236,7 +242,7 @@ class Renderer ...@@ -236,7 +242,7 @@ class Renderer
// Shader operations // Shader operations
virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type) = 0; virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type) = 0;
virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type) = 0; virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround) = 0;
// Image operations // Image operations
virtual Image *createImage() = 0; virtual Image *createImage() = 0;
......
...@@ -2758,7 +2758,7 @@ ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length ...@@ -2758,7 +2758,7 @@ ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length
return executable; return executable;
} }
ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type) ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround)
{ {
const char *profile = NULL; const char *profile = NULL;
......
...@@ -181,7 +181,7 @@ class Renderer11 : public Renderer ...@@ -181,7 +181,7 @@ class Renderer11 : public Renderer
// Shader operations // Shader operations
virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type); virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type);
virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type); virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround);
// Image operations // Image operations
virtual Image *createImage(); virtual Image *createImage();
......
...@@ -3226,7 +3226,7 @@ ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, ...@@ -3226,7 +3226,7 @@ ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length,
return executable; return executable;
} }
ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type) ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround)
{ {
const char *profile = NULL; const char *profile = NULL;
...@@ -3243,7 +3243,11 @@ ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const cha ...@@ -3243,7 +3243,11 @@ ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const cha
return NULL; return NULL;
} }
ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, ANGLE_COMPILE_OPTIMIZATION_LEVEL, true); // ANGLE issue 486:
// Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization
UINT optimizationFlags = (workaround == ANGLE_D3D_WORKAROUND_SM3_OPTIMIZER ? D3DCOMPILE_SKIP_OPTIMIZATION : ANGLE_COMPILE_OPTIMIZATION_LEVEL);
ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, optimizationFlags, true);
if (!binary) if (!binary)
{ {
return NULL; return NULL;
......
...@@ -197,7 +197,7 @@ class Renderer9 : public Renderer ...@@ -197,7 +197,7 @@ class Renderer9 : public Renderer
// Shader operations // Shader operations
virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type); virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type);
virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type); virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, D3DWorkaroundType workaround);
// Image operations // Image operations
virtual Image *createImage(); virtual Image *createImage();
......
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