Commit be59c2fb by Olli Etuaho Committed by Commit Bot

Fix ambiguous function call issues in HLSL output

D3D compiler can't resolve between these overloaded functions: float4 vec4(float2x2 x0); float4 vec4(float4 x0); Include the parameter types in the function name to disambiguate between overloaded user-defined functions and constructors, like this: float4 vec4_float2x2(float2x2 x0); float4 vec4_float4(float4 x0); This is only done for float2x2 and float4 parameters, other parameter types like float2x3 vs. float3x2 don't need this. BUG=angleproject:1099 BUG=angleproject:1030 TEST=angle_end2end_tests, dEQP-GLES3.functional.attribute_location.* (10 more tests pass), dEQP-GLES2.functional.attribute_location.* Change-Id: Ief047d41b0adbc238393c3c13cb29771cbb83d58 Reviewed-on: https://chromium-review.googlesource.com/329882Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 2b3cc815
...@@ -2221,12 +2221,12 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2221,12 +2221,12 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
return false; return false;
} }
TIntermSequence *arguments = node->getSequence();
TString name = DecorateFunctionIfNeeded(node->getNameObj()); TString name = DecorateFunctionIfNeeded(node->getNameObj());
out << TypeString(node->getType()) << " " << name out << TypeString(node->getType()) << " " << name << DisambiguateFunctionName(arguments)
<< (mOutputLod0Function ? "Lod0(" : "("); << (mOutputLod0Function ? "Lod0(" : "(");
TIntermSequence *arguments = node->getSequence();
for (unsigned int i = 0; i < arguments->size(); i++) for (unsigned int i = 0; i < arguments->size(); i++)
{ {
TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode(); TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
...@@ -2271,6 +2271,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2271,6 +2271,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
out << TypeString(node->getType()) << " "; out << TypeString(node->getType()) << " ";
TIntermSequence *sequence = node->getSequence();
TIntermSequence *arguments = (*sequence)[0]->getAsAggregate()->getSequence();
if (name == "main") if (name == "main")
{ {
out << "gl_main("; out << "gl_main(";
...@@ -2278,12 +2281,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2278,12 +2281,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
else else
{ {
out << DecorateFunctionIfNeeded(node->getNameObj()) out << DecorateFunctionIfNeeded(node->getNameObj())
<< (mOutputLod0Function ? "Lod0(" : "("); << DisambiguateFunctionName(arguments) << (mOutputLod0Function ? "Lod0(" : "(");
} }
TIntermSequence *sequence = node->getSequence();
TIntermSequence *arguments = (*sequence)[0]->getAsAggregate()->getSequence();
for (unsigned int i = 0; i < arguments->size(); i++) for (unsigned int i = 0; i < arguments->size(); i++)
{ {
TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode(); TIntermSymbol *symbol = (*arguments)[i]->getAsSymbolNode();
...@@ -2347,7 +2347,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2347,7 +2347,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
ASSERT(index != CallDAG::InvalidIndex); ASSERT(index != CallDAG::InvalidIndex);
lod0 &= mASTMetadataList[index].mNeedsLod0; lod0 &= mASTMetadataList[index].mNeedsLod0;
out << DecorateFunctionIfNeeded(node->getNameObj()) << (lod0 ? "Lod0(" : "("); out << DecorateFunctionIfNeeded(node->getNameObj());
out << DisambiguateFunctionName(node->getSequence());
out << (lod0 ? "Lod0(" : "(");
} }
else else
{ {
...@@ -3285,9 +3287,9 @@ void OutputHLSL::outputConstructor(TInfoSinkBase &out, ...@@ -3285,9 +3287,9 @@ void OutputHLSL::outputConstructor(TInfoSinkBase &out,
if (visit == PreVisit) if (visit == PreVisit)
{ {
mStructureHLSL->addConstructor(type, name, parameters); TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
out << name << "("; out << constructorName << "(";
} }
else if (visit == InVisit) else if (visit == InVisit)
{ {
......
...@@ -211,16 +211,18 @@ TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorP ...@@ -211,16 +211,18 @@ TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorP
return string; return string;
} }
void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters) TString StructureHLSL::addConstructor(const TType &type,
const TString &name,
const TIntermSequence *parameters)
{ {
if (name == "") if (name == "")
{ {
return; // Nameless structures don't have constructors return TString(); // Nameless structures don't have constructors
} }
if (type.getStruct() && mStructNames.find(name) != mStructNames.end()) if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
{ {
return; // Already added return TString(name); // Already added
} }
TType ctorType = type; TType ctorType = type;
...@@ -231,6 +233,8 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const ...@@ -231,6 +233,8 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const
typedef std::vector<TType> ParameterArray; typedef std::vector<TType> ParameterArray;
ParameterArray ctorParameters; ParameterArray ctorParameters;
TString constructorFunctionName;
const TStructure* structure = type.getStruct(); const TStructure* structure = type.getStruct();
if (structure) if (structure)
{ {
...@@ -265,13 +269,16 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const ...@@ -265,13 +269,16 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const
{ {
ctorParameters.push_back(*fields[i]->type()); ctorParameters.push_back(*fields[i]->type());
} }
constructorFunctionName = TString(name);
} }
else if (parameters) else if (parameters)
{ {
for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++) for (auto parameter : *parameters)
{ {
ctorParameters.push_back((*parameter)->getAsTyped()->getType()); const TType &paramType = parameter->getAsTyped()->getType();
ctorParameters.push_back(paramType);
} }
constructorFunctionName = TString(name) + DisambiguateFunctionName(parameters);
} }
else UNREACHABLE(); else UNREACHABLE();
...@@ -283,7 +290,7 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const ...@@ -283,7 +290,7 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const
} }
else // Built-in type else // Built-in type
{ {
constructor += TypeString(ctorType) + " " + name + "("; constructor += TypeString(ctorType) + " " + constructorFunctionName + "(";
} }
for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
...@@ -465,6 +472,8 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const ...@@ -465,6 +472,8 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const
} }
mConstructors.insert(constructor); mConstructors.insert(constructor);
return constructorFunctionName;
} }
std::string StructureHLSL::structsHeader() const std::string StructureHLSL::structsHeader() const
......
...@@ -49,7 +49,11 @@ class StructureHLSL : angle::NonCopyable ...@@ -49,7 +49,11 @@ class StructureHLSL : angle::NonCopyable
public: public:
StructureHLSL(); StructureHLSL();
void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters); // Returns the name of the constructor function. "name" parameter is the name of the type being
// constructed.
TString addConstructor(const TType &type,
const TString &name,
const TIntermSequence *parameters);
std::string structsHeader() const; std::string structsHeader() const;
TString defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing); TString defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing);
......
...@@ -435,4 +435,23 @@ int HLSLTextureCoordsCount(const TBasicType samplerType) ...@@ -435,4 +435,23 @@ int HLSLTextureCoordsCount(const TBasicType samplerType)
} }
return 0; return 0;
} }
TString DisambiguateFunctionName(const TIntermSequence *parameters)
{
TString disambiguatingString;
for (auto parameter : *parameters)
{
const TType &paramType = parameter->getAsTyped()->getType();
// Disambiguation is needed for float2x2 and float4 parameters. These are the only parameter
// types that HLSL thinks are identical. float2x3 and float3x2 are different types, for
// example. Other parameter types are not added to function names to avoid making function
// names longer.
if (paramType.getObjectSize() == 4 && paramType.getBasicType() == EbtFloat)
{
disambiguatingString += "_" + TypeString(paramType);
}
}
return disambiguatingString;
} }
} // namespace sh
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define COMPILER_TRANSLATOR_UTILSHLSL_H_ #define COMPILER_TRANSLATOR_UTILSHLSL_H_
#include <vector> #include <vector>
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/Types.h" #include "compiler/translator/Types.h"
#include "angle_gl.h" #include "angle_gl.h"
...@@ -73,6 +74,9 @@ TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMa ...@@ -73,6 +74,9 @@ TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMa
TString InterpolationString(TQualifier qualifier); TString InterpolationString(TQualifier qualifier);
TString QualifierString(TQualifier qualifier); TString QualifierString(TQualifier qualifier);
int HLSLTextureCoordsCount(const TBasicType samplerType); int HLSLTextureCoordsCount(const TBasicType samplerType);
// Parameters may need to be included in function names to disambiguate between overloaded
// functions.
TString DisambiguateFunctionName(const TIntermSequence *parameters);
} }
#endif // COMPILER_TRANSLATOR_UTILSHLSL_H_ #endif // COMPILER_TRANSLATOR_UTILSHLSL_H_
...@@ -49,8 +49,6 @@ ...@@ -49,8 +49,6 @@
// TODO(jmadill): triage these into temporary and permanent suppressions // TODO(jmadill): triage these into temporary and permanent suppressions
1030 WIN : dEQP-GLES2.functional.attribute_location.bind_hole.mat2 = FAIL
1030 WIN : dEQP-GLES2.functional.attribute_location.bind_relink_hole.mat2 = FAIL
1027 WIN : dEQP-GLES2.functional.fbo.render.color_clear.rbo_rgb5_a1 = FAIL 1027 WIN : dEQP-GLES2.functional.fbo.render.color_clear.rbo_rgb5_a1 = FAIL
1027 WIN : dEQP-GLES2.functional.fbo.render.color_clear.rbo_rgb5_a1_stencil_index8 = FAIL 1027 WIN : dEQP-GLES2.functional.fbo.render.color_clear.rbo_rgb5_a1_stencil_index8 = FAIL
1027 WIN : dEQP-GLES2.functional.fbo.render.color_clear.rbo_rgb5_a1_depth_component16 = FAIL 1027 WIN : dEQP-GLES2.functional.fbo.render.color_clear.rbo_rgb5_a1_depth_component16 = FAIL
......
...@@ -568,12 +568,6 @@ ...@@ -568,12 +568,6 @@
1098 WIN : dEQP-GLES3.functional.uniform_api.random.81 = FAIL 1098 WIN : dEQP-GLES3.functional.uniform_api.random.81 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.83 = FAIL 1098 WIN : dEQP-GLES3.functional.uniform_api.random.83 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.87 = FAIL 1098 WIN : dEQP-GLES3.functional.uniform_api.random.87 = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.bind_hole.mat2 = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.bind_hole.mat2x2 = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.layout_hole.mat2 = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.layout_hole.mat2x2 = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.mixed_hole.mat2 = FAIL
1099 WIN : dEQP-GLES3.functional.attribute_location.mixed_hole.mat2x2 = FAIL
1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed16_render_with_units = FAIL 1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed16_render_with_units = FAIL
1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed24_render_with_units = FAIL 1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed24_render_with_units = FAIL
1101 WIN : dEQP-GLES3.functional.lifetime.attach.deleted_input.buffer_vertex_array = FAIL 1101 WIN : dEQP-GLES3.functional.lifetime.attach.deleted_input.buffer_vertex_array = FAIL
......
...@@ -1428,6 +1428,142 @@ TEST_P(GLSLTest, VerifyMaxFragmentUniformVectorsExceeded) ...@@ -1428,6 +1428,142 @@ TEST_P(GLSLTest, VerifyMaxFragmentUniformVectorsExceeded)
CompileGLSLWithUniformsAndSamplers(0, maxUniforms + 1, 0, 0, false); CompileGLSLWithUniformsAndSamplers(0, maxUniforms + 1, 0, 0, false);
} }
// Test that two constructors which have vec4 and mat2 parameters get disambiguated (issue in
// HLSL).
TEST_P(GLSLTest_ES3, AmbiguousConstructorCall2x2)
{
const std::string fragmentShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}";
const std::string vertexShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"in vec4 a_vec;\n"
"in mat2 a_mat;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(a_vec) + vec4(a_mat);\n"
"}";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_NE(0u, program);
}
// Test that two constructors which have mat2x3 and mat3x2 parameters get disambiguated.
// This was suspected to be an issue in HLSL, but HLSL seems to be able to natively choose between
// the function signatures in this case.
TEST_P(GLSLTest_ES3, AmbiguousConstructorCall2x3)
{
const std::string fragmentShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}";
const std::string vertexShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"in mat3x2 a_matA;\n"
"in mat2x3 a_matB;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(a_matA) + vec4(a_matB);\n"
"}";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_NE(0u, program);
}
// Test that two functions which have vec4 and mat2 parameters get disambiguated (issue in HLSL).
TEST_P(GLSLTest_ES3, AmbiguousFunctionCall2x2)
{
const std::string fragmentShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}";
const std::string vertexShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"in vec4 a_vec;\n"
"in mat2 a_mat;\n"
"vec4 foo(vec4 a)\n"
"{\n"
" return a;\n"
"}\n"
"vec4 foo(mat2 a)\n"
"{\n"
" return vec4(a[0][0]);\n"
"}\n"
"void main()\n"
"{\n"
" gl_Position = foo(a_vec) + foo(a_mat);\n"
"}";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_NE(0u, program);
}
// Test that an user-defined function with a large number of float4 parameters doesn't fail due to
// the function name being too long.
TEST_P(GLSLTest_ES3, LargeNumberOfFloat4Parameters)
{
const std::string fragmentShaderSource =
"#version 300 es\n"
"precision highp float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}";
std::stringstream vertexShaderStream;
const unsigned int paramCount = 1024u;
vertexShaderStream << "#version 300 es\n"
"precision highp float;\n"
"in vec4 a_vec;\n"
"vec4 lotsOfVec4Parameters(";
for (unsigned int i = 0; i < paramCount; ++i)
{
vertexShaderStream << "vec4 a" << i << ", ";
}
vertexShaderStream << "vec4 aLast)\n"
"{\n"
" return ";
for (unsigned int i = 0; i < paramCount; ++i)
{
vertexShaderStream << "a" << i << " + ";
}
vertexShaderStream << "aLast;\n"
"}\n"
"void main()\n"
"{\n"
" gl_Position = lotsOfVec4Parameters(";
for (unsigned int i = 0; i < paramCount; ++i)
{
vertexShaderStream << "a_vec, ";
}
vertexShaderStream << "a_vec);\n"
"}";
GLuint program = CompileProgram(vertexShaderStream.str(), fragmentShaderSource);
EXPECT_NE(0u, program);
}
// 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