Commit 938f0029 by Corentin Wallez

Revert "Use the AST analyses to narrow the usage of [[loop]] and [[unroll]]"

Caused linking failures on mac because the unit test asks for TranslatorHLSL which is not compiled. This reverts commit 3342e01f. Change-Id: I02b2f54ca5b90611f11b7a549e75bf2e8310639d Reviewed-on: https://chromium-review.googlesource.com/264790Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Tested-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 3342e01f
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "common/utilities.h" #include "common/utilities.h"
#include "compiler/translator/BuiltInFunctionEmulator.h" #include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
#include "compiler/translator/DetectDiscontinuity.h"
#include "compiler/translator/FlagStd140Structs.h" #include "compiler/translator/FlagStd140Structs.h"
#include "compiler/translator/InfoSink.h" #include "compiler/translator/InfoSink.h"
#include "compiler/translator/NodeSearch.h" #include "compiler/translator/NodeSearch.h"
...@@ -108,8 +109,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion, ...@@ -108,8 +109,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
mSourcePath(sourcePath), mSourcePath(sourcePath),
mOutputType(outputType), mOutputType(outputType),
mNumRenderTargets(numRenderTargets), mNumRenderTargets(numRenderTargets),
mCompileOptions(compileOptions), mCompileOptions(compileOptions)
mCurrentFunctionMetadata(nullptr)
{ {
mUnfoldShortCircuit = new UnfoldShortCircuit(this); mUnfoldShortCircuit = new UnfoldShortCircuit(this);
mInsideFunction = false; mInsideFunction = false;
...@@ -130,6 +130,8 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion, ...@@ -130,6 +130,8 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
mUniqueIndex = 0; mUniqueIndex = 0;
mContainsLoopDiscontinuity = false;
mContainsAnyLoop = false;
mOutputLod0Function = false; mOutputLod0Function = false;
mInsideDiscontinuousLoop = false; mInsideDiscontinuousLoop = false;
mNestedLoopDepth = 0; mNestedLoopDepth = 0;
...@@ -168,6 +170,9 @@ OutputHLSL::~OutputHLSL() ...@@ -168,6 +170,9 @@ OutputHLSL::~OutputHLSL()
void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink) void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
{ {
mContainsLoopDiscontinuity = mShaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(treeRoot);
mContainsAnyLoop = containsAnyLoop(treeRoot);
const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(treeRoot); const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(treeRoot);
makeFlaggedStructMaps(flaggedStructs); makeFlaggedStructMaps(flaggedStructs);
...@@ -183,9 +188,12 @@ void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink) ...@@ -183,9 +188,12 @@ void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink)
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot); builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot);
// Now that we are done changing the AST, do the analyses need for HLSL generation // Now that we are done changing the AST, do the analyses need for HLSL generation
CallDAG::InitResult success = mCallDag.init(treeRoot, &objSink); {
ASSERT(success == CallDAG::INITDAG_SUCCESS); CallDAG dag;
mASTMetadataList = CreateASTMetadataHLSL(treeRoot, mCallDag); CallDAG::InitResult success = dag.init(treeRoot, &objSink);
ASSERT(success == CallDAG::INITDAG_SUCCESS);
mASTAnalyses = CreateASTMetadataHLSL(treeRoot, dag);
}
// Output the body and footer first to determine what has to go in the header // Output the body and footer first to determine what has to go in the header
mInfoSinkStack.push(&mBody); mInfoSinkStack.push(&mBody);
...@@ -1955,13 +1963,6 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1955,13 +1963,6 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpPrototype: case EOpPrototype:
if (visit == PreVisit) if (visit == PreVisit)
{ {
size_t index = mCallDag.findIndex(node);
// Skip the prototype if it is not implemented (and thus not used)
if (index == CallDAG::InvalidIndex)
{
return false;
}
out << TypeString(node->getType()) << " " << Decorate(TFunction::unmangleName(node->getName())) << (mOutputLod0Function ? "Lod0(" : "("); out << TypeString(node->getType()) << " " << Decorate(TFunction::unmangleName(node->getName())) << (mOutputLod0Function ? "Lod0(" : "(");
TIntermSequence *arguments = node->getSequence(); TIntermSequence *arguments = node->getSequence();
...@@ -1985,8 +1986,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1985,8 +1986,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
out << ");\n"; out << ");\n";
// Also prototype the Lod0 variant if needed // Also prototype the Lod0 variant if needed
bool needsLod0 = mASTMetadataList[index].mNeedsLod0; if (mContainsLoopDiscontinuity && !mOutputLod0Function)
if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
{ {
mOutputLod0Function = true; mOutputLod0Function = true;
node->traverse(this); node->traverse(this);
...@@ -1999,13 +1999,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1999,13 +1999,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpComma: outputTriplet(visit, "(", ", ", ")"); break; case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
case EOpFunction: case EOpFunction:
{ {
ASSERT(mCurrentFunctionMetadata == nullptr);
TString name = TFunction::unmangleName(node->getName()); TString name = TFunction::unmangleName(node->getName());
size_t index = mCallDag.findIndex(node);
ASSERT(index != CallDAG::InvalidIndex);
mCurrentFunctionMetadata = &mASTMetadataList[index];
out << TypeString(node->getType()) << " "; out << TypeString(node->getType()) << " ";
if (name == "main") if (name == "main")
...@@ -2055,15 +2050,14 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2055,15 +2050,14 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
out << "}\n"; out << "}\n";
mCurrentFunctionMetadata = nullptr; if (mContainsLoopDiscontinuity && !mOutputLod0Function)
bool needsLod0 = mASTMetadataList[index].mNeedsLod0;
if (needsLod0 && !mOutputLod0Function && mShaderType == GL_FRAGMENT_SHADER)
{ {
ASSERT(name != "main"); if (name != "main")
mOutputLod0Function = true; {
node->traverse(this); mOutputLod0Function = true;
mOutputLod0Function = false; node->traverse(this);
mOutputLod0Function = false;
}
} }
return false; return false;
...@@ -2072,15 +2066,11 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2072,15 +2066,11 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpFunctionCall: case EOpFunctionCall:
{ {
TString name = TFunction::unmangleName(node->getName()); TString name = TFunction::unmangleName(node->getName());
bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
TIntermSequence *arguments = node->getSequence(); TIntermSequence *arguments = node->getSequence();
bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
if (node->isUserDefined()) if (node->isUserDefined())
{ {
size_t index = mCallDag.findIndex(node);
ASSERT(index != CallDAG::InvalidIndex);
lod0 &= mASTMetadataList[index].mNeedsLod0;
out << Decorate(name) << (lod0 ? "Lod0(" : "("); out << Decorate(name) << (lod0 ? "Lod0(" : "(");
} }
else else
...@@ -2311,10 +2301,11 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) ...@@ -2311,10 +2301,11 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
{ {
mUnfoldShortCircuit->traverse(node->getCondition()); mUnfoldShortCircuit->traverse(node->getCondition());
// D3D errors when there is a gradient operation in a loop in an unflattened if. // D3D errors when there is a gradient operation in a loop in an unflattened if
if (mShaderType == GL_FRAGMENT_SHADER // however flattening all the ifs in branch heavy shaders made D3D error too.
&& mCurrentFunctionMetadata->hasDiscontinuousLoop(node) // As a temporary workaround we flatten the ifs only if there is at least a loop
&& mCurrentFunctionMetadata->hasGradientInCallGraph(node)) // present somewhere in the shader.
if (mShaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop)
{ {
out << "FLATTEN "; out << "FLATTEN ";
} }
...@@ -2409,8 +2400,11 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) ...@@ -2409,8 +2400,11 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
mNestedLoopDepth++; mNestedLoopDepth++;
bool wasDiscontinuous = mInsideDiscontinuousLoop; bool wasDiscontinuous = mInsideDiscontinuousLoop;
mInsideDiscontinuousLoop = mInsideDiscontinuousLoop ||
mCurrentFunctionMetadata->mDiscontinuousLoops.count(node) >= 0; if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
{
mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
}
if (mOutputType == SH_HLSL9_OUTPUT) if (mOutputType == SH_HLSL9_OUTPUT)
{ {
...@@ -2425,17 +2419,16 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) ...@@ -2425,17 +2419,16 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
TInfoSinkBase &out = getInfoSink(); TInfoSinkBase &out = getInfoSink();
const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
if (node->getType() == ELoopDoWhile) if (node->getType() == ELoopDoWhile)
{ {
out << "{" << unroll << " do\n"; out << "{LOOP do\n";
outputLineDirective(node->getLine().first_line); outputLineDirective(node->getLine().first_line);
out << "{\n"; out << "{\n";
} }
else else
{ {
out << "{" << unroll << " for("; out << "{LOOP for(";
if (node->getInit()) if (node->getInit())
{ {
...@@ -2741,9 +2734,8 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) ...@@ -2741,9 +2734,8 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
} }
// for(int index = initial; index < clampedLimit; index += increment) // for(int index = initial; index < clampedLimit; index += increment)
const char *unroll = mCurrentFunctionMetadata->hasGradientInCallGraph(node) ? "LOOP" : "";
out << unroll << " for("; out << "LOOP for(";
index->traverse(this); index->traverse(this);
out << " = "; out << " = ";
out << initial; out << initial;
......
...@@ -170,9 +170,9 @@ class OutputHLSL : public TIntermTraverser ...@@ -170,9 +170,9 @@ class OutputHLSL : public TIntermTraverser
int mUniqueIndex; // For creating unique names int mUniqueIndex; // For creating unique names
CallDAG mCallDag; std::vector<ASTMetadataHLSL> mASTAnalyses;
MetadataList mASTMetadataList; bool mContainsLoopDiscontinuity;
ASTMetadataHLSL *mCurrentFunctionMetadata; bool mContainsAnyLoop;
bool mOutputLod0Function; bool mOutputLod0Function;
bool mInsideDiscontinuousLoop; bool mInsideDiscontinuousLoop;
int mNestedLoopDepth; int mNestedLoopDepth;
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
'<(angle_path)/src/tests/compiler_tests/ShaderExtension_test.cpp', '<(angle_path)/src/tests/compiler_tests/ShaderExtension_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShaderVariable_test.cpp', '<(angle_path)/src/tests/compiler_tests/ShaderVariable_test.cpp',
'<(angle_path)/src/tests/compiler_tests/TypeTracking_test.cpp', '<(angle_path)/src/tests/compiler_tests/TypeTracking_test.cpp',
'<(angle_path)/src/tests/compiler_tests/UnrollFlatten_test.cpp',
'<(angle_path)/src/tests/preprocessor_tests/char_test.cpp', '<(angle_path)/src/tests/preprocessor_tests/char_test.cpp',
'<(angle_path)/src/tests/preprocessor_tests/comment_test.cpp', '<(angle_path)/src/tests/preprocessor_tests/comment_test.cpp',
'<(angle_path)/src/tests/preprocessor_tests/define_test.cpp', '<(angle_path)/src/tests/preprocessor_tests/define_test.cpp',
......
//
// Copyright (c) 2015 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.
//
// UnrollFlatten_test.cpp:
// Test for the outputting of [[unroll]] and [[flatten]] for the D3D compiler
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/TranslatorHLSL.h"
namespace
{
class UnrollFlattenTest : public testing::Test
{
public:
UnrollFlattenTest() {}
protected:
void SetUp() override
{
ShBuiltInResources resources;
ShInitBuiltInResources(&resources);
resources.FragmentPrecisionHigh = 1;
mTranslator = new TranslatorHLSL(GL_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL11_OUTPUT);
ASSERT_TRUE(mTranslator->Init(resources));
}
void TearDown() override
{
SafeDelete(mTranslator);
}
void compile(const std::string &shaderString)
{
const char *shaderStrings[] = { shaderString.c_str() };
bool compilationSuccess = mTranslator->compile(shaderStrings, 1, SH_VARIABLES | SH_OBJECT_CODE);
TInfoSink &infoSink = mTranslator->getInfoSink();
if (!compilationSuccess)
{
FAIL() << "Shader compilation failed " << infoSink.info.str();
}
mTranslatedSource = infoSink.obj.str();
// Ignore the beginning of the shader to avoid the definitions of LOOP and FLATTEN
mCurrentPosition = mTranslatedSource.find("GL_USES_FRAG_COLOR");
}
void expect(const char *patterns[], size_t count)
{
const char *badPatterns[] = { UNROLL, FLATTEN };
for (size_t i = 0; i < count; i++)
{
const char *pattern = patterns[i];
auto position = mTranslatedSource.find(pattern, mCurrentPosition);
if (position == std::string::npos)
{
FAIL() << "Couldn't find '" << pattern << "' after expectations '"
<< mExpectationList << "' in translated source:\n" << mTranslatedSource;
}
for (size_t j = 0; j < ArraySize(badPatterns); j++)
{
const char *badPattern = badPatterns[j];
if (pattern != badPattern &&
mTranslatedSource.find(badPattern, mCurrentPosition) < position)
{
FAIL() << "Found '" << badPattern << "' before '" << pattern << "' after expectations '"
<< mExpectationList << "' in translated source:\n" << mTranslatedSource;
}
}
mExpectationList += " - " + std::string(pattern);
mCurrentPosition = position + 1;
}
}
static const char *UNROLL;
static const char *FLATTEN;
private:
TranslatorHLSL *mTranslator;
std::string mTranslatedSource;
int mCurrentPosition;
std::string mExpectationList;
};
const char *UnrollFlattenTest::UNROLL = "LOOP";
const char *UnrollFlattenTest::FLATTEN = "FLATTEN";
// Check that the nothing is added if there is no gradient operation
// even when there is ifs and discontinuous loops
TEST_F(UnrollFlattenTest, NoGradient)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform float f;\n"
"float fun(float a){\n" // 1
" if (a > 1.0) {return f;}\n" // 2
" else {return a + 1.0;}\n"
"}\n"
"float fun2(float a){\n" // 3
" for (int i = 0; i < 10; i++) {\n" // 4
" if (a > 1.0) {break;}\n" // 5
" a = fun(a);\n" // 6
" }\n"
" return a;\n"
"}\n"
"void main() {\n"
" float accum = 0.0;\n"
" if (f < 5.0) {accum = fun2(accum);}\n" // 7
" gl_FragColor = vec4(accum);\n"
"}\n";
compile(shaderString);
// 1 - shouldn't get a Lod0 version generated
// 2 - no FLATTEN because does not contain discont loop
// 3 - shouldn't get a Lod0 version generated
// 4 - no LOOP because discont, and also no gradient
// 5 - no FLATTEN because does not contain discont loop
// 6 - call non-Lod0 version
// 7 - no FLATTEN
const char *expectations[] =
{
"fun(", "if",
"fun2(", "for", "if", "break", "fun(",
"main(", "if", "fun2("
};
expect(expectations, ArraySize(expectations));
}
// Check that when we have a gradient in a non-discontinuous loop
// we use the regular version of the functions. Also checks that
// LOOP is generated for the loop containing the gradient.
TEST_F(UnrollFlattenTest, GradientNotInDiscont)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform float f;\n"
"uniform sampler2D tex;"
"float fun(float a){\n" // 1
" return texture2D(tex, vec2(0.5, f)).x;\n" // 2
"}\n"
"float fun2(float a){\n" // 3
" for (int i = 0; i < 10; i++) {\n" // 4
" if (a > 1.0) {}\n" // 5
" a = fun(a);\n" // 6
" }\n"
" return a;\n"
"}\n"
"void main() {\n"
" float accum = 0.0;\n"
" if (f < 5.0) {accum = fun2(accum);}\n" // 7
" gl_FragColor = vec4(accum);\n"
"}\n";
// 1 - shouldn't get a Lod0 version generated
// 2 - no Lod0 version generated
// 3 - shouldn't get a Lod0 version generated (not in discont loop)
// 4 - should have LOOP because it contains a gradient operation (even if Lod0)
// 5 - no FLATTEN because doesn't contain discont loop
// 6 - call Lod0 version
// 7 - no FLATTEN
compile(shaderString);
const char *expectations[] =
{
"fun(", "texture2D(",
"fun2(", "LOOP", "for", "if", "fun(",
"main(", "if", "fun2("
};
expect(expectations, ArraySize(expectations));
}
// Check that when we have a gradient in a discontinuous loop
// we use the Lod0 version of the functions.
TEST_F(UnrollFlattenTest, GradientInDiscont)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform float f;\n"
"uniform sampler2D tex;"
"float fun(float a){\n" // 1
" return texture2D(tex, vec2(0.5, f)).x;\n" // 2
"}\n"
"float fun2(float a){\n" // 3
" for (int i = 0; i < 10; i++) {\n" // 4
" if (a > 1.0) {break;}\n" // 5
" a = fun(a);\n" // 6
" }\n"
" return a;\n"
"}\n"
"void main() {\n"
" float accum = 0.0;\n"
" if (f < 5.0) {accum = fun2(accum);}\n" // 7
" gl_FragColor = vec4(accum);\n"
"}\n";
// 1 - should get a Lod0 version generated (gradient + discont loop)
// 2 - will get the Lod0 if in funLod0
// 3 - shouldn't get a Lod0 version generated (not in discont loop)
// 4 - should have LOOP because it contains a gradient operation (even if Lod0)
// 5 - no FLATTEN because doesn't contain discont loop
// 6 - call Lod0 version
// 7 - should have a FLATTEN because has a discont loop and gradient
compile(shaderString);
const char *expectations[] =
{
"fun(", "texture2D(",
"funLod0(", "texture2DLod0(",
"fun2(", "LOOP", "for", "if", "break", "funLod0(",
"main(", "FLATTEN", "if", "fun2("
};
expect(expectations, ArraySize(expectations));
}
}
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