Commit ff526f14 by Olli Etuaho Committed by Commit Bot

Fix variable vs. function name conflict in HLSL output

GLSL ES spec accepts the case where an initializer of a variable calls a function with the same name as the variable. The HLSL compiler doesn't accept that. Work around this limitation in the HLSL compiler by disambiguating user-defined functions from variables with a different prefix. BUG=angleproject:2095 TEST=angle_end2end_test, angle_unittests Change-Id: I41b32a3fcc6fd4c548e8dc3aa680d1b07fcf8719 Reviewed-on: https://chromium-review.googlesource.com/557872Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 77891c0a
...@@ -783,8 +783,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -783,8 +783,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
ensureStructDefined(nodeType); ensureStructDefined(nodeType);
const TName &nameWithMetadata = node->getName(); out << DecorateVariableIfNeeded(node->getName());
out << DecorateUniform(nameWithMetadata, nodeType);
} }
else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
{ {
...@@ -873,7 +872,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -873,7 +872,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
} }
else else
{ {
out << DecorateIfNeeded(node->getName()); out << DecorateVariableIfNeeded(node->getName());
} }
} }
} }
...@@ -1593,7 +1592,7 @@ bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition ...@@ -1593,7 +1592,7 @@ bool OutputHLSL::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition
} }
else else
{ {
out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj())
<< DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "("); << DisambiguateFunctionName(parameters) << (mOutputLod0Function ? "Lod0(" : "(");
} }
...@@ -1725,7 +1724,7 @@ bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *n ...@@ -1725,7 +1724,7 @@ bool OutputHLSL::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *n
TIntermSequence *arguments = node->getSequence(); TIntermSequence *arguments = node->getSequence();
TString name = DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj()); TString name = DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments) out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
<< (mOutputLod0Function ? "Lod0(" : "("); << (mOutputLod0Function ? "Lod0(" : "(");
...@@ -1779,7 +1778,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1779,7 +1778,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
ASSERT(index != CallDAG::InvalidIndex); ASSERT(index != CallDAG::InvalidIndex);
lod0 &= mASTMetadataList[index].mNeedsLod0; lod0 &= mASTMetadataList[index].mNeedsLod0;
out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj()); out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
out << DisambiguateFunctionName(node->getSequence()); out << DisambiguateFunctionName(node->getSequence());
out << (lod0 ? "Lod0(" : "("); out << (lod0 ? "Lod0(" : "(");
} }
...@@ -1787,7 +1786,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1787,7 +1786,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
{ {
// This path is used for internal functions that don't have their definitions in the // This path is used for internal functions that don't have their definitions in the
// AST, such as precision emulation functions. // AST, such as precision emulation functions.
out << DecorateIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "("; out << DecorateFunctionIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
} }
else else
{ {
...@@ -2537,7 +2536,7 @@ TString OutputHLSL::argumentString(const TIntermSymbol *symbol) ...@@ -2537,7 +2536,7 @@ TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
} }
else else
{ {
nameStr = DecorateIfNeeded(name); nameStr = DecorateVariableIfNeeded(name);
} }
if (IsSampler(type.getBasicType())) if (IsSampler(type.getBasicType()))
......
...@@ -178,8 +178,8 @@ void UniformHLSL::outputHLSLSamplerUniformGroup( ...@@ -178,8 +178,8 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(
if (type.isArray()) if (type.isArray())
{ {
out << "static const uint " << DecorateIfNeeded(uniform->getName()) << ArrayString(type) out << "static const uint " << DecorateVariableIfNeeded(uniform->getName())
<< " = {"; << ArrayString(type) << " = {";
for (unsigned int i = 0u; i < type.getArraySize(); ++i) for (unsigned int i = 0u; i < type.getArraySize(); ++i)
{ {
if (i > 0u) if (i > 0u)
...@@ -190,7 +190,7 @@ void UniformHLSL::outputHLSLSamplerUniformGroup( ...@@ -190,7 +190,7 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(
} }
else else
{ {
out << "static const uint " << DecorateIfNeeded(uniform->getName()) << " = " out << "static const uint " << DecorateVariableIfNeeded(uniform->getName()) << " = "
<< samplerArrayIndex << ";\n"; << samplerArrayIndex << ";\n";
} }
} }
...@@ -218,11 +218,11 @@ void UniformHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out, ...@@ -218,11 +218,11 @@ void UniformHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
const unsigned int registerIndex) const unsigned int registerIndex)
{ {
out << "uniform " << SamplerString(type.getBasicType()) << " sampler_" out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
<< DecorateUniform(name, type) << ArrayString(type) << " : register(s" << str(registerIndex) << DecorateVariableIfNeeded(name) << ArrayString(type) << " : register(s"
<< ");\n"; << str(registerIndex) << ");\n";
out << "uniform " << TextureString(type.getBasicType()) << " texture_" out << "uniform " << TextureString(type.getBasicType()) << " texture_"
<< DecorateUniform(name, type) << ArrayString(type) << " : register(t" << str(registerIndex) << DecorateVariableIfNeeded(name) << ArrayString(type) << " : register(t"
<< ");\n"; << str(registerIndex) << ");\n";
} }
void UniformHLSL::outputUniform(TInfoSinkBase &out, void UniformHLSL::outputUniform(TInfoSinkBase &out,
...@@ -245,7 +245,7 @@ void UniformHLSL::outputUniform(TInfoSinkBase &out, ...@@ -245,7 +245,7 @@ void UniformHLSL::outputUniform(TInfoSinkBase &out,
out << "uniform " << typeName << " "; out << "uniform " << typeName << " ";
out << DecorateUniform(name, type); out << DecorateVariableIfNeeded(name);
out << ArrayString(type) << " : " << registerString << ";\n"; out << ArrayString(type) << " : " << registerString << ";\n";
} }
......
...@@ -199,11 +199,6 @@ TString TextureTypeSuffix(const TBasicType type) ...@@ -199,11 +199,6 @@ TString TextureTypeSuffix(const TBasicType type)
} }
} }
TString DecorateUniform(const TName &name, const TType &type)
{
return DecorateIfNeeded(name);
}
TString DecorateField(const TString &string, const TStructure &structure) TString DecorateField(const TString &string, const TStructure &structure)
{ {
if (structure.name().compare(0, 3, "gl_") != 0) if (structure.name().compare(0, 3, "gl_") != 0)
...@@ -229,10 +224,13 @@ TString Decorate(const TString &string) ...@@ -229,10 +224,13 @@ TString Decorate(const TString &string)
return string; return string;
} }
TString DecorateIfNeeded(const TName &name) TString DecorateVariableIfNeeded(const TName &name)
{ {
if (name.isInternal()) if (name.isInternal())
{ {
// The name should not have a prefix reserved for user-defined variables or functions.
ASSERT(name.getString().compare(0, 2, "f_") != 0);
ASSERT(name.getString().compare(0, 1, "_") != 0);
return name.getString(); return name.getString();
} }
else else
...@@ -241,6 +239,22 @@ TString DecorateIfNeeded(const TName &name) ...@@ -241,6 +239,22 @@ TString DecorateIfNeeded(const TName &name)
} }
} }
TString DecorateFunctionIfNeeded(const TName &name)
{
if (name.isInternal())
{
// The name should not have a prefix reserved for user-defined variables or functions.
ASSERT(name.getString().compare(0, 2, "f_") != 0);
ASSERT(name.getString().compare(0, 1, "_") != 0);
return name.getString();
}
ASSERT(name.getString().compare(0, 3, "gl_") != 0);
// Add an additional f prefix to functions so that they're always disambiguated from variables.
// This is necessary in the corner case where a variable declaration hides a function that it
// uses in its initializer.
return "f_" + name.getString();
}
TString TypeString(const TType &type) TString TypeString(const TType &type)
{ {
const TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
......
...@@ -62,10 +62,10 @@ TString TextureGroupSuffix(const TBasicType type); ...@@ -62,10 +62,10 @@ TString TextureGroupSuffix(const TBasicType type);
TString TextureTypeSuffix(const TBasicType type); TString TextureTypeSuffix(const TBasicType type);
TString SamplerString(const TBasicType type); TString SamplerString(const TBasicType type);
TString SamplerString(HLSLTextureSamplerGroup type); TString SamplerString(HLSLTextureSamplerGroup type);
// Prepends an underscore to avoid naming clashes // Adds a prefix to user-defined names to avoid naming clashes.
TString Decorate(const TString &string); TString Decorate(const TString &string);
TString DecorateIfNeeded(const TName &name); TString DecorateVariableIfNeeded(const TName &name);
TString DecorateUniform(const TName &name, const TType &type); TString DecorateFunctionIfNeeded(const TName &name);
TString DecorateField(const TString &string, const TStructure &structure); TString DecorateField(const TString &string, const TStructure &structure);
TString DecoratePrivate(const TString &privateText); TString DecoratePrivate(const TString &privateText);
TString TypeString(const TType &type); TString TypeString(const TType &type);
......
...@@ -892,7 +892,7 @@ TEST_F(DebugShaderPrecisionTest, FunctionCallParameterQualifiersFromDefinition) ...@@ -892,7 +892,7 @@ TEST_F(DebugShaderPrecisionTest, FunctionCallParameterQualifiersFromDefinition)
// otherwise. // otherwise.
// Test in parameters // Test in parameters
ASSERT_TRUE(foundInAllGLSLCode("v = add(angle_frm(u1), angle_frm(u2))")); ASSERT_TRUE(foundInAllGLSLCode("v = add(angle_frm(u1), angle_frm(u2))"));
ASSERT_TRUE(foundInHLSLCode("v = _add_float4_float4(angle_frm(_u1), angle_frm(_u2))")); ASSERT_TRUE(foundInHLSLCode("v = f_add_float4_float4(angle_frm(_u1), angle_frm(_u2))"));
// Test inout parameter // Test inout parameter
ASSERT_TRUE(foundInAllGLSLCode("compound_add(v, angle_frm(u3))")); ASSERT_TRUE(foundInAllGLSLCode("compound_add(v, angle_frm(u3))"));
ASSERT_TRUE(foundInHLSLCode("compound_add_float4_float4(_v, angle_frm(_u3))")); ASSERT_TRUE(foundInHLSLCode("compound_add_float4_float4(_v, angle_frm(_u3))"));
...@@ -933,7 +933,7 @@ TEST_F(DebugShaderPrecisionTest, FunctionCallParameterQualifiersFromPrototype) ...@@ -933,7 +933,7 @@ TEST_F(DebugShaderPrecisionTest, FunctionCallParameterQualifiersFromPrototype)
compile(shaderString); compile(shaderString);
// Test in parameters // Test in parameters
ASSERT_TRUE(foundInAllGLSLCode("v = add(angle_frm(u1), angle_frm(u2))")); ASSERT_TRUE(foundInAllGLSLCode("v = add(angle_frm(u1), angle_frm(u2))"));
ASSERT_TRUE(foundInHLSLCode("v = _add_float4_float4(angle_frm(_u1), angle_frm(_u2))")); ASSERT_TRUE(foundInHLSLCode("v = f_add_float4_float4(angle_frm(_u1), angle_frm(_u2))"));
// Test inout parameter // Test inout parameter
ASSERT_TRUE(foundInAllGLSLCode("compound_add(v, angle_frm(u3))")); ASSERT_TRUE(foundInAllGLSLCode("compound_add(v, angle_frm(u3))"));
ASSERT_TRUE(foundInHLSLCode("compound_add_float4_float4(_v, angle_frm(_u3))")); ASSERT_TRUE(foundInHLSLCode("compound_add_float4_float4(_v, angle_frm(_u3))"));
...@@ -966,9 +966,9 @@ TEST_F(DebugShaderPrecisionTest, NestedFunctionCalls) ...@@ -966,9 +966,9 @@ TEST_F(DebugShaderPrecisionTest, NestedFunctionCalls)
// Test nested calls // Test nested calls
ASSERT_TRUE(foundInAllGLSLCode( ASSERT_TRUE(foundInAllGLSLCode(
"v2 = add(compound_add(v, angle_frm(u2)), angle_frm(fract(angle_frm(u3))))")); "v2 = add(compound_add(v, angle_frm(u2)), angle_frm(fract(angle_frm(u3))))"));
ASSERT_TRUE( ASSERT_TRUE(foundInHLSLCode(
foundInHLSLCode("v2 = _add_float4_float4(_compound_add_float4_float4(_v, angle_frm(_u2)), " "v2 = f_add_float4_float4(f_compound_add_float4_float4(_v, angle_frm(_u2)), "
"angle_frm(frac(angle_frm(_u3))))")); "angle_frm(frac(angle_frm(_u3))))"));
} }
// Test that code inside an index of a function out parameter gets processed. // Test that code inside an index of a function out parameter gets processed.
......
...@@ -3110,6 +3110,29 @@ TEST_P(GLSLTest_ES3, ConditionInitializerDeclaresVariable) ...@@ -3110,6 +3110,29 @@ TEST_P(GLSLTest_ES3, ConditionInitializerDeclaresVariable)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Test that a variable hides a user-defined function with the same name after its initializer.
// GLSL ES 1.00.17 section 4.2.2: "A variable declaration is visible immediately following the
// initializer if present, otherwise immediately following the identifier"
TEST_P(GLSLTest, VariableHidesUserDefinedFunctionAfterInitializer)
{
const std::string &fragmentShader =
"precision mediump float;\n"
"uniform vec4 u;\n"
"vec4 foo()\n"
"{\n"
" return u;\n"
"}\n"
"void main()\n"
"{\n"
" vec4 foo = foo();\n"
" gl_FragColor = foo + vec4(0, 1, 0, 1);\n"
"}\n";
ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader);
drawQuad(program.get(), "inputAttribute", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest, ANGLE_INSTANTIATE_TEST(GLSLTest,
ES2_D3D9(), ES2_D3D9(),
......
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