Commit 3f2c0b38 by Jamie Madill

Add work-around for D3D9 shader compiler bug.

With certain selection statements with a vertex input in the condition and side-effects in the else-block, we'd run in to a D3D9 compiler bug which would cause incorrect results. We can work around this bug in D3D9 by selectively rewriting these statements to not use an else clause. BUG=322794 Change-Id: I93c96fb201ff4959c00d9a36321faac7e0343278 Reviewed-on: https://chromium-review.googlesource.com/184021Reviewed-by: 's avatarNicolas Capens <nicolascapens@chromium.org> Commit-Queue: Nicolas Capens <nicolascapens@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent a0931907
......@@ -82,6 +82,7 @@ enum TQualifier
{
EvqTemporary, // For temporaries (within a function), read/write
EvqGlobal, // For globals read/write
EvqInternal, // For internal use, not visible to the user
EvqConst, // User defined constants and non-output parameters in functions
EvqAttribute, // Readonly
EvqVaryingIn, // readonly, fragment shaders only
......
......@@ -13,6 +13,8 @@
#include <vector>
#include "compiler/translator/PoolAlloc.h"
#include "compiler/translator/compilerdebug.h"
#include "common/angleutils.h"
struct TSourceLoc {
int first_file;
......@@ -74,4 +76,15 @@ public:
TMap(const tAllocator& a) : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a) {}
};
// Integer to TString conversion
template <typename T>
inline TString str(T i)
{
ASSERT(std::numeric_limits<T>::is_integer);
char buffer[(CHAR_BIT * sizeof(T) / 3) + 3];
const char *formatStr = std::numeric_limits<T>::is_signed ? "%d" : "%u";
snprintf(buffer, sizeof(buffer), formatStr, i);
return buffer;
}
#endif // _COMMON_INCLUDED_
......@@ -9,6 +9,8 @@
#ifndef TRANSLATOR_NODESEARCH_H_
#define TRANSLATOR_NODESEARCH_H_
#include "compiler/translator/intermediate.h"
namespace sh
{
......
......@@ -13,6 +13,7 @@
#include "compiler/translator/SearchSymbol.h"
#include "compiler/translator/UnfoldShortCircuit.h"
#include "compiler/translator/NodeSearch.h"
#include "compiler/translator/RewriteElseBlocks.h"
#include <algorithm>
#include <cfloat>
......@@ -20,13 +21,6 @@
namespace sh
{
// Integer to TString conversion
TString str(int i)
{
char buffer[20];
snprintf(buffer, sizeof(buffer), "%d", i);
return buffer;
}
OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType)
: TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType)
......@@ -115,6 +109,13 @@ void OutputHLSL::output()
{
mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
// Work around D3D9 bug that would manifest in vertex shaders with selection blocks which
// use a vertex attribute as a condition, and some related computation in the else block.
if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == SH_VERTEX_SHADER)
{
RewriteElseBlocks(mContext.treeRoot);
}
mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
header();
......@@ -1099,6 +1100,10 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
mReferencedVaryings[name] = node;
out << decorate(name);
}
else if (qualifier == EvqInternal)
{
out << name;
}
else
{
out << decorate(name);
......
//
// Copyright (c) 2014 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.
//
// RewriteElseBlocks.cpp: Implementation for tree transform to change
// all if-else blocks to if-if blocks.
//
#include "compiler/translator/RewriteElseBlocks.h"
#include "compiler/translator/NodeSearch.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type)
{
TType variableType(type, EbpHigh, EvqInternal);
return new TIntermSymbol(-1, name, variableType);
}
TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType)
{
TIntermBinary *binary = new TIntermBinary(op);
binary->setLeft(left);
binary->setRight(right);
binary->setType(resultType);
return binary;
}
TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand)
{
TIntermUnary *unary = new TIntermUnary(op, operand->getType());
unary->setOperand(operand);
return unary;
}
bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
{
switch (node->getOp())
{
case EOpSequence:
{
for (size_t statementIndex = 0; statementIndex != node->getSequence().size(); statementIndex++)
{
TIntermNode *statement = node->getSequence()[statementIndex];
TIntermSelection *selection = statement->getAsSelectionNode();
if (selection && selection->getFalseBlock() != NULL)
{
node->getSequence()[statementIndex] = rewriteSelection(selection);
delete selection;
}
}
}
break;
default: break;
}
return true;
}
TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection)
{
ASSERT(selection->getFalseBlock() != NULL);
TString temporaryName = "cond_" + str(mTemporaryIndex++);
TIntermTyped *typedCondition = selection->getCondition()->getAsTyped();
TType resultType(EbtBool, EbpUndefined);
TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool);
TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool);
TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool);
TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA,
typedCondition, resultType);
TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB);
TIntermSelection *falseBlock = new TIntermSelection(negatedCondition,
selection->getFalseBlock(), NULL);
TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC,
selection->getTrueBlock(), falseBlock);
TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration);
declaration->getSequence().push_back(storeCondition);
TIntermAggregate *block = new TIntermAggregate(EOpSequence);
block->getSequence().push_back(declaration);
block->getSequence().push_back(newIfElse);
return block;
}
void RewriteElseBlocks(TIntermNode *node)
{
ElseBlockRewriter rewriter;
node->traverse(&rewriter);
}
}
//
// Copyright (c) 2014 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.
//
// RewriteElseBlocks.h: Prototype for tree transform to change
// all if-else blocks to if-if blocks.
//
#ifndef COMPILER_REWRITE_ELSE_BLOCKS_H_
#define COMPILER_REWRITE_ELSE_BLOCKS_H_
#include "compiler/translator/intermediate.h"
namespace sh
{
class ElseBlockRewriter : public TIntermTraverser
{
public:
ElseBlockRewriter()
: TIntermTraverser(false, false, true, false)
, mTemporaryIndex(0)
{}
protected:
bool visitAggregate(Visit visit, TIntermAggregate *aggregate);
private:
int mTemporaryIndex;
TIntermNode *rewriteSelection(TIntermSelection *selection);
};
void RewriteElseBlocks(TIntermNode *node);
}
#endif // COMPILER_REWRITE_ELSE_BLOCKS_H_
......@@ -413,7 +413,7 @@ public:
protected:
TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
TIntermOperator(TOperator o, const TType& t) : TIntermTyped(t), op(o) {}
TOperator op;
};
......@@ -453,7 +453,7 @@ protected:
//
class TIntermUnary : public TIntermOperator {
public:
TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
TIntermUnary(TOperator o, const TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {}
virtual void traverse(TIntermTraverser*);
......
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