Commit 37997145 by Jamie Madill

Defer dependent HLSL global var inits.

Some global initializers depend on other globals, for instance a varying or attribute value. Since we use a static proxy variable for these varyings, we need to initialize the global static after we initialize the proxy in the shader preamble. This fixes a long- standing compiler bug. We should also add a WebGL test for this. BUG=angle:878 Change-Id: I71db103a6b8c24fb862e0d8b32293da9bc2e8103 Reviewed-on: https://chromium-review.googlesource.com/243581Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 448d3db5
...@@ -173,11 +173,18 @@ void OutputHLSL::output() ...@@ -173,11 +173,18 @@ void OutputHLSL::output()
BuiltInFunctionEmulatorHLSL builtInFunctionEmulator; BuiltInFunctionEmulatorHLSL builtInFunctionEmulator;
builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(mContext.treeRoot); builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(mContext.treeRoot);
// Output the body 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);
mContext.treeRoot->traverse(this); mContext.treeRoot->traverse(this);
mInfoSinkStack.pop(); mInfoSinkStack.pop();
mInfoSinkStack.push(&mFooter);
if (!mDeferredGlobalInitializers.empty())
{
writeDeferredGlobalInitializers(mFooter);
}
mInfoSinkStack.pop();
mInfoSinkStack.push(&mHeader); mInfoSinkStack.push(&mHeader);
header(&builtInFunctionEmulator); header(&builtInFunctionEmulator);
mInfoSinkStack.pop(); mInfoSinkStack.pop();
...@@ -185,6 +192,7 @@ void OutputHLSL::output() ...@@ -185,6 +192,7 @@ void OutputHLSL::output()
TInfoSinkBase& sink = mContext.infoSink().obj; TInfoSinkBase& sink = mContext.infoSink().obj;
sink << mHeader.c_str(); sink << mHeader.c_str();
sink << mBody.c_str(); sink << mBody.c_str();
sink << mFooter.c_str();
builtInFunctionEmulator.Cleanup(); builtInFunctionEmulator.Cleanup();
} }
...@@ -1341,22 +1349,21 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1341,22 +1349,21 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
// this to "float t = x, x = t;". // this to "float t = x, x = t;".
TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
ASSERT(symbolNode);
TIntermTyped *expression = node->getRight(); TIntermTyped *expression = node->getRight();
sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); // TODO (jmadill): do a 'deep' scan to know if an expression is statically const
expression->traverse(&searchSymbol); if (symbolNode->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst)
bool sameSymbol = searchSymbol.foundMatch();
if (sameSymbol)
{ {
// Type already printed // For variables which are not constant, defer their real initialization until
out << "t" + str(mUniqueIndex) + " = "; // after we initialize other globals: uniforms, attributes and varyings.
expression->traverse(this); mDeferredGlobalInitializers.push_back(std::make_pair(symbolNode, expression));
out << ", "; const TString &initString = initializer(node->getType());
symbolNode->traverse(this); node->setRight(new TIntermRaw(node->getType(), initString));
out << " = t" + str(mUniqueIndex); }
else if (writeSameSymbolInitializer(out, symbolNode, expression))
mUniqueIndex++; {
// Skip initializing the rest of the expression
return false; return false;
} }
} }
...@@ -1773,11 +1780,11 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1773,11 +1780,11 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
{ {
for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) for (const auto &seqElement : *sequence)
{ {
if (isSingleStatement(*sit)) if (isSingleStatement(seqElement))
{ {
mUnfoldShortCircuit->traverse(*sit); mUnfoldShortCircuit->traverse(seqElement);
} }
if (!mInsideFunction) if (!mInsideFunction)
...@@ -1787,7 +1794,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1787,7 +1794,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
out << TypeString(variable->getType()) + " "; out << TypeString(variable->getType()) + " ";
TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); TIntermSymbol *symbol = seqElement->getAsSymbolNode();
if (symbol) if (symbol)
{ {
...@@ -1797,10 +1804,10 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1797,10 +1804,10 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
} }
else else
{ {
(*sit)->traverse(this); seqElement->traverse(this);
} }
if (*sit != sequence->back()) if (seqElement != sequence->back())
{ {
out << ";\n"; out << ";\n";
} }
...@@ -2793,4 +2800,54 @@ void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr) ...@@ -2793,4 +2800,54 @@ void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr)
outputTriplet(visit, preString.c_str(), ", ", ")"); outputTriplet(visit, preString.c_str(), ", ", ")");
} }
bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression)
{
sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
expression->traverse(&searchSymbol);
if (searchSymbol.foundMatch())
{
// Type already printed
out << "t" + str(mUniqueIndex) + " = ";
expression->traverse(this);
out << ", ";
symbolNode->traverse(this);
out << " = t" + str(mUniqueIndex);
mUniqueIndex++;
return true;
}
return false;
}
void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out)
{
out << "#define ANGLE_USES_DEFERRED_INIT\n"
<< "\n"
<< "void initializeDeferredGlobals()\n"
<< "{\n";
for (const auto &deferredGlobal : mDeferredGlobalInitializers)
{
TIntermSymbol *symbol = deferredGlobal.first;
TIntermTyped *expression = deferredGlobal.second;
ASSERT(symbol);
ASSERT(symbol->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst);
out << " " << Decorate(symbol->getSymbol()) << " = ";
if (!writeSameSymbolInitializer(out, symbol, expression))
{
ASSERT(mInfoSinkStack.top() == &out);
expression->traverse(this);
}
out << ";\n";
}
out << "}\n"
<< "\n";
}
} }
...@@ -67,6 +67,11 @@ class OutputHLSL : public TIntermTraverser ...@@ -67,6 +67,11 @@ class OutputHLSL : public TIntermTraverser
const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion); const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
void writeEmulatedFunctionTriplet(Visit visit, const char *preStr); void writeEmulatedFunctionTriplet(Visit visit, const char *preStr);
void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
// Returns true if it found a 'same symbol' initializer (initializer that references the variable it's initting)
bool writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression);
void writeDeferredGlobalInitializers(TInfoSinkBase &out);
TParseContext &mContext; TParseContext &mContext;
const ShShaderOutput mOutputType; const ShShaderOutput mOutputType;
...@@ -149,7 +154,11 @@ class OutputHLSL : public TIntermTraverser ...@@ -149,7 +154,11 @@ class OutputHLSL : public TIntermTraverser
std::map<TIntermTyped*, TString> mFlaggedStructMappedNames; std::map<TIntermTyped*, TString> mFlaggedStructMappedNames;
std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames; std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames;
void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs); // Some initializers use varyings, uniforms or attributes, thus we can't evaluate some variables
// at global static scope in HLSL. These variables depend on values which we retrieve from the
// shader input structure, which we set in the D3D main function. Instead, we can initialize
// these static globals after we initialize our other globals.
std::vector<std::pair<TIntermSymbol*, TIntermTyped*>> mDeferredGlobalInitializers;
}; };
} }
......
...@@ -765,27 +765,29 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog, ...@@ -765,27 +765,29 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog,
"{\n" "{\n"
" initAttributes(input);\n"; " initAttributes(input);\n";
if (vertexShader->usesDeferredInit())
{
vertexHLSL += "\n"
" initializeDeferredGlobals();\n";
}
vertexHLSL += "\n"
" gl_main();\n"
"\n"
" VS_OUTPUT output;\n"
" output.gl_Position = gl_Position;\n";
// On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust. // On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust.
if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
{ {
vertexHLSL += "\n" vertexHLSL += " output.dx_Position.x = gl_Position.x;\n"
" gl_main();\n"
"\n"
" VS_OUTPUT output;\n"
" output.gl_Position = gl_Position;\n"
" output.dx_Position.x = gl_Position.x;\n"
" output.dx_Position.y = -gl_Position.y;\n" " output.dx_Position.y = -gl_Position.y;\n"
" output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
" output.dx_Position.w = gl_Position.w;\n"; " output.dx_Position.w = gl_Position.w;\n";
} }
else else
{ {
vertexHLSL += "\n" vertexHLSL += " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
" gl_main();\n"
"\n"
" VS_OUTPUT output;\n"
" output.gl_Position = gl_Position;\n"
" output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
" output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n" " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
" output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
" output.dx_Position.w = gl_Position.w;\n"; " output.dx_Position.w = gl_Position.w;\n";
...@@ -1016,6 +1018,12 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog, ...@@ -1016,6 +1018,12 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog,
} }
} }
if (fragmentShader->usesDeferredInit())
{
pixelHLSL += "\n"
" initializeDeferredGlobals();\n";
}
pixelHLSL += "\n" pixelHLSL += "\n"
" gl_main();\n" " gl_main();\n"
"\n" "\n"
...@@ -1083,31 +1091,31 @@ std::string DynamicHLSL::generatePointSpriteHLSL(int registers, ShaderD3D *fragm ...@@ -1083,31 +1091,31 @@ std::string DynamicHLSL::generatePointSpriteHLSL(int registers, ShaderD3D *fragm
"struct GS_INPUT\n" + inLinkHLSL + "\n" + "struct GS_INPUT\n" + inLinkHLSL + "\n" +
"struct GS_OUTPUT\n" + outLinkHLSL + "\n" + "struct GS_OUTPUT\n" + outLinkHLSL + "\n" +
"\n" "\n"
"static float2 pointSpriteCorners[] = \n" "static float2 pointSpriteCorners[] = \n"
"{\n" "{\n"
" float2( 0.5f, -0.5f),\n" " float2( 0.5f, -0.5f),\n"
" float2( 0.5f, 0.5f),\n" " float2( 0.5f, 0.5f),\n"
" float2(-0.5f, -0.5f),\n" " float2(-0.5f, -0.5f),\n"
" float2(-0.5f, 0.5f)\n" " float2(-0.5f, 0.5f)\n"
"};\n" "};\n"
"\n" "\n"
"static float2 pointSpriteTexcoords[] = \n" "static float2 pointSpriteTexcoords[] = \n"
"{\n" "{\n"
" float2(1.0f, 1.0f),\n" " float2(1.0f, 1.0f),\n"
" float2(1.0f, 0.0f),\n" " float2(1.0f, 0.0f),\n"
" float2(0.0f, 1.0f),\n" " float2(0.0f, 1.0f),\n"
" float2(0.0f, 0.0f)\n" " float2(0.0f, 0.0f)\n"
"};\n" "};\n"
"\n" "\n"
"static float minPointSize = " + Str(mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n" "static float minPointSize = " + Str(mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n"
"static float maxPointSize = " + Str(mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n" "static float maxPointSize = " + Str(mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n"
"\n" "\n"
"[maxvertexcount(4)]\n" "[maxvertexcount(4)]\n"
"void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n" "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
"{\n" "{\n"
" GS_OUTPUT output = (GS_OUTPUT)0;\n" " GS_OUTPUT output = (GS_OUTPUT)0;\n"
" output.gl_Position = input[0].gl_Position;\n" " output.gl_Position = input[0].gl_Position;\n"
" output.gl_PointSize = input[0].gl_PointSize;\n"; " output.gl_PointSize = input[0].gl_PointSize;\n";
for (int r = 0; r < registers; r++) for (int r = 0; r < registers; r++)
{ {
......
...@@ -106,17 +106,18 @@ void ShaderD3D::parseVaryings(ShHandle compiler) ...@@ -106,17 +106,18 @@ void ShaderD3D::parseVaryings(ShHandle compiler)
mVaryings.push_back(gl::PackedVarying((*varyings)[varyingIndex])); mVaryings.push_back(gl::PackedVarying((*varyings)[varyingIndex]));
} }
mUsesMultipleRenderTargets = mHlsl.find("GL_USES_MRT") != std::string::npos; mUsesMultipleRenderTargets = mHlsl.find("GL_USES_MRT") != std::string::npos;
mUsesFragColor = mHlsl.find("GL_USES_FRAG_COLOR") != std::string::npos; mUsesFragColor = mHlsl.find("GL_USES_FRAG_COLOR") != std::string::npos;
mUsesFragData = mHlsl.find("GL_USES_FRAG_DATA") != std::string::npos; mUsesFragData = mHlsl.find("GL_USES_FRAG_DATA") != std::string::npos;
mUsesFragCoord = mHlsl.find("GL_USES_FRAG_COORD") != std::string::npos; mUsesFragCoord = mHlsl.find("GL_USES_FRAG_COORD") != std::string::npos;
mUsesFrontFacing = mHlsl.find("GL_USES_FRONT_FACING") != std::string::npos; mUsesFrontFacing = mHlsl.find("GL_USES_FRONT_FACING") != std::string::npos;
mUsesPointSize = mHlsl.find("GL_USES_POINT_SIZE") != std::string::npos; mUsesPointSize = mHlsl.find("GL_USES_POINT_SIZE") != std::string::npos;
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; mUsesDiscardRewriting = mHlsl.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
mUsesNestedBreak = mHlsl.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; mUsesNestedBreak = mHlsl.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
mUsesDeferredInit = mHlsl.find("ANGLE_USES_DEFERRED_INIT") != std::string::npos;
} }
} }
...@@ -148,6 +149,7 @@ void ShaderD3D::uncompile() ...@@ -148,6 +149,7 @@ void ShaderD3D::uncompile()
mShaderVersion = 100; mShaderVersion = 100;
mUsesDiscardRewriting = false; mUsesDiscardRewriting = false;
mUsesNestedBreak = false; mUsesNestedBreak = false;
mUsesDeferredInit = false;
mVaryings.clear(); mVaryings.clear();
mUniforms.clear(); mUniforms.clear();
......
...@@ -47,6 +47,7 @@ class ShaderD3D : public ShaderImpl ...@@ -47,6 +47,7 @@ class ShaderD3D : public ShaderImpl
int getShaderVersion() const { return mShaderVersion; } int getShaderVersion() const { return mShaderVersion; }
bool usesDepthRange() const { return mUsesDepthRange; } bool usesDepthRange() const { return mUsesDepthRange; }
bool usesPointSize() const { return mUsesPointSize; } bool usesPointSize() const { return mUsesPointSize; }
bool usesDeferredInit() const { return mUsesDeferredInit; }
GLenum getShaderType() const; GLenum getShaderType() const;
ShShaderOutput getCompilerOutputType() const; ShShaderOutput getCompilerOutputType() const;
...@@ -78,6 +79,7 @@ class ShaderD3D : public ShaderImpl ...@@ -78,6 +79,7 @@ class ShaderD3D : public ShaderImpl
bool mUsesFragDepth; bool mUsesFragDepth;
bool mUsesDiscardRewriting; bool mUsesDiscardRewriting;
bool mUsesNestedBreak; bool mUsesNestedBreak;
bool mUsesDeferredInit;
ShShaderOutput mCompilerOutputType; ShShaderOutput mCompilerOutputType;
std::string mHlsl; std::string mHlsl;
......
...@@ -873,4 +873,35 @@ TYPED_TEST(GLSLTest, BadIndexBug) ...@@ -873,4 +873,35 @@ TYPED_TEST(GLSLTest, BadIndexBug)
{ {
glDeleteShader(shader); glDeleteShader(shader);
} }
} }
\ No newline at end of file
// Tests that using a global static initialized from a varying works as expected.
// See: https://code.google.com/p/angleproject/issues/detail?id=878
TYPED_TEST(GLSLTest, GlobalStaticAndVarying)
{
const std::string &vertexShaderSource =
"attribute vec4 a_position;\n"
"varying float v;\n"
"void main() {\n"
" gl_Position = a_position;\n"
" v = 1.0;\n"
"}\n";
const std::string &fragmentShaderSource =
"precision highp float;\n"
"varying float v;\n"
"float x = v;"
"float global_v = x;"
"void main() {\n"
" gl_FragColor = vec4(global_v, 0.0, 0.0, 1.0);\n"
"}\n";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
ASSERT_NE(0u, program);
drawQuad(program, "a_position", 0.5f);
swapBuffers();
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
}
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