Commit bd3cd506 by Olli Etuaho Committed by Commit Bot

Clean up HLSL constructor output

Split generating HLSL struct constructors from generating built-in type constructors, as these didn't have much in common. Struct constructors are now only generated when they are needed, as opposed to before, when they were generated on any use of a struct. This changes built-in constructor naming to include "_ctor" and gets rid of having special built-in type names just for constructors. This will make it easier to do changes to constructor output, for example to add constructors for structs in std140 layout. This might be needed to implement SSBOs efficiently. This includes one bug fix for writing out struct declarations for varyings. Also improves const-correctness of accessing structs through TType in general. BUG=angleproject:2218 TEST=angle_unittests, angle_end2end_tests Change-Id: If865fb56f86486b9c4a2c31e016ea16427f4a5fa Reviewed-on: https://chromium-review.googlesource.com/753883Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 5b09d90d
...@@ -38,7 +38,7 @@ void AddStructZeroInitSequence(const TIntermTyped *initializedNode, ...@@ -38,7 +38,7 @@ void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
TIntermSequence *initSequenceOut) TIntermSequence *initSequenceOut)
{ {
ASSERT(initializedNode->getBasicType() == EbtStruct); ASSERT(initializedNode->getBasicType() == EbtStruct);
TStructure *structType = initializedNode->getType().getStruct(); const TStructure *structType = initializedNode->getType().getStruct();
for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i) for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
{ {
TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct, TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct,
......
...@@ -140,7 +140,7 @@ TIntermTyped *CreateZeroNode(const TType &type) ...@@ -140,7 +140,7 @@ TIntermTyped *CreateZeroNode(const TType &type)
{ {
ASSERT(type.getBasicType() == EbtStruct); ASSERT(type.getBasicType() == EbtStruct);
TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
for (const auto &field : structure->fields()) for (const auto &field : structure->fields())
{ {
arguments->push_back(CreateZeroNode(*field->type())); arguments->push_back(CreateZeroNode(*field->type()));
......
...@@ -306,7 +306,7 @@ void TOutputGLSLBase::writeVariableType(const TType &type) ...@@ -306,7 +306,7 @@ void TOutputGLSLBase::writeVariableType(const TType &type)
// Declare the struct if we have not done so already. // Declare the struct if we have not done so already.
if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
{ {
TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
declareStruct(structure); declareStruct(structure);
......
...@@ -878,11 +878,13 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -878,11 +878,13 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
} }
else else
{ {
const TType &nodeType = node->getType();
TQualifier qualifier = node->getQualifier(); TQualifier qualifier = node->getQualifier();
ensureStructDefined(nodeType);
if (qualifier == EvqUniform) if (qualifier == EvqUniform)
{ {
const TType &nodeType = node->getType();
const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock(); const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
if (interfaceBlock) if (interfaceBlock)
...@@ -894,8 +896,6 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -894,8 +896,6 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
mReferencedUniforms[name] = node; mReferencedUniforms[name] = node;
} }
ensureStructDefined(nodeType);
out << DecorateVariableIfNeeded(node->getName()); out << DecorateVariableIfNeeded(node->getName());
} }
else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
...@@ -1654,7 +1654,7 @@ TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node) ...@@ -1654,7 +1654,7 @@ TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
} }
case EOpIndexDirectStruct: case EOpIndexDirectStruct:
{ {
TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct(); const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0); int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
const TField *field = s->fields()[index]; const TField *field = s->fields()[index];
...@@ -1821,7 +1821,8 @@ bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node) ...@@ -1821,7 +1821,8 @@ bool OutputHLSL::visitDeclaration(Visit visit, TIntermDeclaration *node)
else if (variable->getAsSymbolNode() && else if (variable->getAsSymbolNode() &&
variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
{ {
// Already added to constructor map ASSERT(variable->getBasicType() == EbtStruct);
// ensureStructDefined has already been called.
} }
else else
UNREACHABLE(); UNREACHABLE();
...@@ -1992,45 +1993,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -1992,45 +1993,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
return false; return false;
} }
case EOpConstruct: case EOpConstruct:
if (node->getBasicType() == EbtStruct) outputConstructor(out, visit, node);
{
if (node->getType().isArray())
{
UNIMPLEMENTED();
}
const TString &structName = StructNameString(*node->getType().getStruct());
mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
}
else
{
const char *name = "";
if (node->getType().getNominalSize() == 1)
{
switch (node->getBasicType())
{
case EbtFloat:
name = "vec1";
break;
case EbtInt:
name = "ivec1";
break;
case EbtUInt:
name = "uvec1";
break;
case EbtBool:
name = "bvec1";
break;
default:
UNREACHABLE();
}
}
else
{
name = node->getType().getBuiltInTypeNameString();
}
outputConstructor(out, visit, node->getType(), name, node->getSequence());
}
break; break;
case EOpEqualComponentWise: case EOpEqualComponentWise:
outputTriplet(out, visit, "(", " == ", ")"); outputTriplet(out, visit, "(", " == ", ")");
...@@ -2742,21 +2705,23 @@ TString OutputHLSL::initializer(const TType &type) ...@@ -2742,21 +2705,23 @@ TString OutputHLSL::initializer(const TType &type)
return "{" + string + "}"; return "{" + string + "}";
} }
void OutputHLSL::outputConstructor(TInfoSinkBase &out, void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
Visit visit,
const TType &type,
const char *name,
const TIntermSequence *parameters)
{ {
if (type.isArray()) // Array constructors should have been already pruned from the code.
{ ASSERT(!node->getType().isArray());
UNIMPLEMENTED();
}
if (visit == PreVisit) if (visit == PreVisit)
{ {
TString constructorName = mStructureHLSL->addConstructor(type, name, parameters); TString constructorName;
if (node->getBasicType() == EbtStruct)
{
constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
}
else
{
constructorName =
mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
}
out << constructorName << "("; out << constructorName << "(";
} }
else if (visit == InVisit) else if (visit == InVisit)
...@@ -2778,7 +2743,7 @@ const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out, ...@@ -2778,7 +2743,7 @@ const TConstantUnion *OutputHLSL::writeConstantUnion(TInfoSinkBase &out,
const TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
if (structure) if (structure)
{ {
out << StructNameString(*structure) + "_ctor("; out << mStructureHLSL->addStructConstructor(*structure) << "(";
const TFieldList &fields = structure->fields(); const TFieldList &fields = structure->fields();
...@@ -3105,11 +3070,11 @@ TString OutputHLSL::addArrayConstructIntoFunction(const TType &type) ...@@ -3105,11 +3070,11 @@ TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
void OutputHLSL::ensureStructDefined(const TType &type) void OutputHLSL::ensureStructDefined(const TType &type)
{ {
TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
if (structure) if (structure)
{ {
mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr); ASSERT(type.getBasicType() == EbtStruct);
mStructureHLSL->ensureStructDefined(*structure);
} }
} }
......
...@@ -104,12 +104,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -104,12 +104,7 @@ class OutputHLSL : public TIntermTraverser
void outputLineDirective(TInfoSinkBase &out, int line); void outputLineDirective(TInfoSinkBase &out, int line);
TString argumentString(const TIntermSymbol *symbol); TString argumentString(const TIntermSymbol *symbol);
// Emit constructor. Called with literal names so using const char* instead of TString. void outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node);
void outputConstructor(TInfoSinkBase &out,
Visit visit,
const TType &type,
const char *name,
const TIntermSequence *parameters);
const TConstantUnion *writeConstantUnion(TInfoSinkBase &out, const TConstantUnion *writeConstantUnion(TInfoSinkBase &out,
const TType &type, const TType &type,
const TConstantUnion *constUnion); const TConstantUnion *constUnion);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
// StructureHLSL.cpp: // StructureHLSL.cpp:
// Definitions of methods for HLSL translation of GLSL structures. // HLSL translation of GLSL constructors and structures.
// //
#include "compiler/translator/StructureHLSL.h" #include "compiler/translator/StructureHLSL.h"
...@@ -17,6 +17,77 @@ ...@@ -17,6 +17,77 @@
namespace sh namespace sh
{ {
namespace
{
TString Define(const TStructure &structure,
bool useHLSLRowMajorPacking,
bool useStd140Packing,
Std140PaddingHelper *padHelper)
{
const TFieldList &fields = structure.fields();
const bool isNameless = (structure.name() == "");
const TString &structName =
QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing);
const TString declareString = (isNameless ? "struct" : "struct " + structName);
TString string;
string += declareString +
"\n"
"{\n";
for (const TField *field : fields)
{
const TType &fieldType = *field->type();
if (!IsSampler(fieldType.getBasicType()))
{
const TStructure *fieldStruct = fieldType.getStruct();
const TString &fieldTypeString =
fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
useStd140Packing)
: TypeString(fieldType);
if (padHelper)
{
string += padHelper->prePaddingString(fieldType);
}
string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) +
ArrayString(fieldType) + ";\n";
if (padHelper)
{
string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
}
}
}
// Nameless structs do not finish with a semicolon and newline, to leave room for an instance
// variable
string += (isNameless ? "} " : "};\n");
return string;
}
TString WriteParameterList(const std::vector<TType> &parameters)
{
TString parameterList;
for (size_t parameter = 0u; parameter < parameters.size(); parameter++)
{
const TType &paramType = parameters[parameter];
parameterList += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType);
if (parameter < parameters.size() - 1u)
{
parameterList += ", ";
}
}
return parameterList;
}
} // anonymous namespace
Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes, Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
unsigned *uniqueCounter) unsigned *uniqueCounter)
: mPaddingCounter(uniqueCounter), mElementIndex(0), mStructElementIndexes(&structElementIndexes) : mPaddingCounter(uniqueCounter), mElementIndex(0), mStructElementIndexes(&structElementIndexes)
...@@ -103,7 +174,7 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo ...@@ -103,7 +174,7 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo
} }
int numComponents = 0; int numComponents = 0;
TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
if (type.isMatrix()) if (type.isMatrix())
{ {
...@@ -159,196 +230,162 @@ TString StructureHLSL::defineQualified(const TStructure &structure, ...@@ -159,196 +230,162 @@ TString StructureHLSL::defineQualified(const TStructure &structure,
if (useStd140Packing) if (useStd140Packing)
{ {
Std140PaddingHelper padHelper = getPaddingHelper(); Std140PaddingHelper padHelper = getPaddingHelper();
return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper); return Define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
} }
else else
{ {
return define(structure, useHLSLRowMajorPacking, useStd140Packing, nullptr); return Define(structure, useHLSLRowMajorPacking, useStd140Packing, nullptr);
} }
} }
TString StructureHLSL::defineNameless(const TStructure &structure) TString StructureHLSL::defineNameless(const TStructure &structure)
{ {
return define(structure, false, false, nullptr); return Define(structure, false, false, nullptr);
} }
TString StructureHLSL::define(const TStructure &structure, StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStructure &structure,
bool useHLSLRowMajorPacking, const TString &name)
bool useStd140Packing,
Std140PaddingHelper *padHelper)
{ {
const TFieldList &fields = structure.fields(); ASSERT(mDefinedStructs.find(name) == mDefinedStructs.end());
const bool isNameless = (structure.name() == "");
const TString &structName =
QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing);
const TString declareString = (isNameless ? "struct" : "struct " + structName);
TString string; for (const TField *field : structure.fields())
string += declareString +
"\n"
"{\n";
for (const TField *field : fields)
{ {
const TType &fieldType = *field->type(); const TType *fieldType = field->type();
if (!IsSampler(fieldType.getBasicType())) if (fieldType->getBasicType() == EbtStruct)
{ {
const TStructure *fieldStruct = fieldType.getStruct(); ensureStructDefined(*fieldType->getStruct());
const TString &fieldTypeString =
fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
useStd140Packing)
: TypeString(fieldType);
if (padHelper)
{
string += padHelper->prePaddingString(fieldType);
}
string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) +
ArrayString(fieldType) + ";\n";
if (padHelper)
{
string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
}
} }
} }
// Nameless structs do not finish with a semicolon and newline, to leave room for an instance DefinedStructs::iterator addedStruct =
// variable mDefinedStructs.insert(std::make_pair(name, new TStructProperties())).first;
string += (isNameless ? "} " : "};\n"); // Add element index
storeStd140ElementIndex(structure, false);
storeStd140ElementIndex(structure, true);
const TString &structString = defineQualified(structure, false, false);
ASSERT(std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) ==
mStructDeclarations.end());
// Add row-major packed struct for interface blocks
TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
defineQualified(structure, true, false) +
"#pragma pack_matrix(column_major)\n";
TString std140String = defineQualified(structure, false, true);
TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
defineQualified(structure, true, true) +
"#pragma pack_matrix(column_major)\n";
mStructDeclarations.push_back(structString);
mStructDeclarations.push_back(rowMajorString);
mStructDeclarations.push_back(std140String);
mStructDeclarations.push_back(std140RowMajorString);
return addedStruct;
}
return string; void StructureHLSL::ensureStructDefined(const TStructure &structure)
{
const TString name = StructNameString(structure);
if (name == "")
{
return; // Nameless structures are not defined
}
if (mDefinedStructs.find(name) == mDefinedStructs.end())
{
defineVariants(structure, name);
}
} }
TString StructureHLSL::addConstructor(const TType &type, TString StructureHLSL::addStructConstructor(const TStructure &structure)
const TString &name,
const TIntermSequence *parameters)
{ {
const TString name = StructNameString(structure);
if (name == "") if (name == "")
{ {
return TString(); // Nameless structures don't have constructors return TString(); // Nameless structures don't have constructors
} }
if (type.getStruct() && mStructNames.find(name) != mStructNames.end()) auto definedStruct = mDefinedStructs.find(name);
if (definedStruct == mDefinedStructs.end())
{ {
return TString(name); // Already added definedStruct = defineVariants(structure, name);
} }
const TString constructorFunctionName = TString(name) + "_ctor";
TType ctorType = type; TString *constructor = &definedStruct->second->constructor;
while (ctorType.isArray()) if (!constructor->empty())
{ {
ctorType.toArrayElementType(); return constructorFunctionName; // Already added
} }
ctorType.setPrecision(EbpHigh); *constructor += name + " " + constructorFunctionName + "(";
ctorType.setQualifier(EvqTemporary);
typedef std::vector<TType> ParameterArray; std::vector<TType> ctorParameters;
ParameterArray ctorParameters; const TFieldList &fields = structure.fields();
for (const TField *field : fields)
TString constructorFunctionName;
const TStructure *structure = type.getStruct();
if (structure)
{ {
const TFieldList &fields = structure->fields(); const TType *fieldType = field->type();
for (const TField *field : fields) if (!IsSampler(fieldType->getBasicType()))
{ {
const TType *fieldType = field->type(); ctorParameters.push_back(*fieldType);
if (!IsSampler(fieldType->getBasicType()))
{
ctorParameters.push_back(*fieldType);
}
if (fieldType->getBasicType() == EbtStruct)
{
addConstructor(*fieldType, StructNameString(*fieldType->getStruct()), nullptr);
}
} }
}
// Structs that have sampler members should not have constructor calls, and otherwise structs
// are guaranteed to be non-empty by the grammar. Structs can't contain empty declarations
// either.
ASSERT(!ctorParameters.empty());
mStructNames.insert(name); *constructor += WriteParameterList(ctorParameters);
// Add element index
storeStd140ElementIndex(*structure, false);
storeStd140ElementIndex(*structure, true);
const TString &structString = defineQualified(*structure, false, false);
if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == *constructor +=
mStructDeclarations.end()) ")\n"
{ "{\n"
// Add row-major packed struct for interface blocks " " +
TString rowMajorString = "#pragma pack_matrix(row_major)\n" + name + " structure = { ";
defineQualified(*structure, true, false) +
"#pragma pack_matrix(column_major)\n";
TString std140String = defineQualified(*structure, false, true);
TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
defineQualified(*structure, true, true) +
"#pragma pack_matrix(column_major)\n";
mStructDeclarations.push_back(structString);
mStructDeclarations.push_back(rowMajorString);
mStructDeclarations.push_back(std140String);
mStructDeclarations.push_back(std140RowMajorString);
}
constructorFunctionName = TString(name); for (size_t parameterIndex = 0u; parameterIndex < ctorParameters.size(); ++parameterIndex)
}
else if (parameters)
{ {
for (auto parameter : *parameters) *constructor += "x" + str(parameterIndex);
if (parameterIndex < ctorParameters.size() - 1u)
{ {
const TType &paramType = parameter->getAsTyped()->getType(); *constructor += ", ";
ctorParameters.push_back(paramType);
} }
constructorFunctionName = TString(name) + DisambiguateFunctionName(parameters);
} }
else *constructor +=
UNREACHABLE(); "};\n"
" return structure;\n"
"}\n";
TString constructor; return constructorFunctionName;
}
if (ctorType.getStruct()) TString StructureHLSL::addBuiltInConstructor(const TType &type, const TIntermSequence *parameters)
{ {
constructor += name + " " + name + "_ctor("; ASSERT(!type.isArray());
} ASSERT(type.getStruct() == nullptr);
else // Built-in type ASSERT(parameters);
{
constructor += TypeString(ctorType) + " " + constructorFunctionName + "(";
}
for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) TType ctorType = type;
{ ctorType.setPrecision(EbpHigh);
const TType &paramType = ctorParameters[parameter]; ctorType.setQualifier(EvqTemporary);
constructor += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType); const TString constructorFunctionName =
TString(type.getBuiltInTypeNameString()) + "_ctor" + DisambiguateFunctionName(parameters);
TString constructor = TypeString(ctorType) + " " + constructorFunctionName + "(";
if (parameter < ctorParameters.size() - 1) std::vector<TType> ctorParameters;
{ for (auto parameter : *parameters)
constructor += ", "; {
} const TType &paramType = parameter->getAsTyped()->getType();
ASSERT(!paramType.isArray());
ctorParameters.push_back(paramType);
} }
constructor += WriteParameterList(ctorParameters);
constructor += constructor +=
")\n" ")\n"
"{\n"; "{\n"
" return " +
if (ctorType.getStruct()) TypeString(ctorType) + "(";
{
constructor += " " + name + " structure";
if (ctorParameters.empty())
{
constructor += ";\n";
}
else
{
constructor += " = { ";
}
}
else
{
constructor += " return " + TypeString(ctorType) + "(";
}
if (ctorType.isMatrix() && ctorParameters.size() == 1) if (ctorType.isMatrix() && ctorParameters.size() == 1)
{ {
...@@ -403,15 +440,7 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -403,15 +440,7 @@ TString StructureHLSL::addConstructor(const TType &type,
} }
else else
{ {
size_t remainingComponents = 0; size_t remainingComponents = ctorType.getObjectSize();
if (ctorType.getStruct())
{
remainingComponents = ctorParameters.size();
}
else
{
remainingComponents = ctorType.getObjectSize();
}
size_t parameterIndex = 0; size_t parameterIndex = 0;
while (remainingComponents > 0) while (remainingComponents > 0)
...@@ -422,13 +451,7 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -422,13 +451,7 @@ TString StructureHLSL::addConstructor(const TType &type,
constructor += "x" + str(parameterIndex); constructor += "x" + str(parameterIndex);
if (ctorType.getStruct()) if (parameter.isScalar())
{
ASSERT(remainingComponents == 1 || moreParameters);
--remainingComponents;
}
else if (parameter.isScalar())
{ {
remainingComponents -= parameter.getObjectSize(); remainingComponents -= parameter.getObjectSize();
} }
...@@ -504,7 +527,9 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -504,7 +527,9 @@ TString StructureHLSL::addConstructor(const TType &type,
} }
} }
else else
{
UNREACHABLE(); UNREACHABLE();
}
if (moreParameters) if (moreParameters)
{ {
...@@ -518,24 +543,11 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -518,24 +543,11 @@ TString StructureHLSL::addConstructor(const TType &type,
} }
} }
if (ctorType.getStruct()) constructor +=
{ ");\n"
if (!ctorParameters.empty()) "}\n";
{
constructor += "};\n";
}
constructor +=
" return structure;\n"
"}\n";
}
else
{
constructor +=
");\n"
"}\n";
}
mConstructors.insert(constructor); mBuiltInConstructors.insert(constructor);
return constructorFunctionName; return constructorFunctionName;
} }
...@@ -544,15 +556,19 @@ std::string StructureHLSL::structsHeader() const ...@@ -544,15 +556,19 @@ std::string StructureHLSL::structsHeader() const
{ {
TInfoSinkBase out; TInfoSinkBase out;
for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++) for (auto &declaration : mStructDeclarations)
{
out << declaration;
}
for (auto &structure : mDefinedStructs)
{ {
out << mStructDeclarations[structIndex]; out << structure.second->constructor;
} }
for (Constructors::const_iterator constructor = mConstructors.begin(); for (auto &constructor : mBuiltInConstructors)
constructor != mConstructors.end(); constructor++)
{ {
out << *constructor; out << constructor;
} }
return out.str(); return out.str();
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
// StructureHLSL.h: // StructureHLSL.h:
// Interfaces of methods for HLSL translation of GLSL structures. // HLSL translation of GLSL constructors and structures.
// //
#ifndef COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ #ifndef COMPILER_TRANSLATOR_STRUCTUREHLSL_H_
...@@ -49,17 +49,14 @@ class StructureHLSL : angle::NonCopyable ...@@ -49,17 +49,14 @@ class StructureHLSL : angle::NonCopyable
public: public:
StructureHLSL(); StructureHLSL();
// Returns the name of the constructor function. "name" parameter is the name of the type being // Returns the name of the constructor function.
// constructed. TString addStructConstructor(const TStructure &structure);
TString addConstructor(const TType &type, TString addBuiltInConstructor(const TType &type, const TIntermSequence *parameters);
const TString &name,
const TIntermSequence *parameters);
std::string structsHeader() const;
TString defineQualified(const TStructure &structure,
bool useHLSLRowMajorPacking,
bool useStd140Packing);
static TString defineNameless(const TStructure &structure); static TString defineNameless(const TStructure &structure);
void ensureStructDefined(const TStructure &structure);
std::string structsHeader() const;
Std140PaddingHelper getPaddingHelper(); Std140PaddingHelper getPaddingHelper();
...@@ -68,20 +65,33 @@ class StructureHLSL : angle::NonCopyable ...@@ -68,20 +65,33 @@ class StructureHLSL : angle::NonCopyable
std::map<TString, int> mStd140StructElementIndexes; std::map<TString, int> mStd140StructElementIndexes;
typedef std::set<TString> StructNames; struct TStructProperties : public angle::NonCopyable
StructNames mStructNames; {
POOL_ALLOCATOR_NEW_DELETE();
typedef std::set<TString> Constructors; TStructProperties() {}
Constructors mConstructors;
// Constructor is an empty string in case the struct doesn't have a constructor yet.
TString constructor;
};
// Map from struct name to struct properties.
typedef std::map<TString, TStructProperties *> DefinedStructs;
DefinedStructs mDefinedStructs;
// Struct declarations need to be kept in a vector instead of having them inside mDefinedStructs
// since maintaining the original order is necessary for nested structs.
typedef std::vector<TString> StructDeclarations; typedef std::vector<TString> StructDeclarations;
StructDeclarations mStructDeclarations; StructDeclarations mStructDeclarations;
typedef std::set<TString> BuiltInConstructors;
BuiltInConstructors mBuiltInConstructors;
void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking); void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking);
static TString define(const TStructure &structure, TString defineQualified(const TStructure &structure,
bool useHLSLRowMajorPacking, bool useHLSLRowMajorPacking,
bool useStd140Packing, bool useStd140Packing);
Std140PaddingHelper *padHelper); DefinedStructs::iterator defineVariants(const TStructure &structure, const TString &name);
}; };
} }
......
...@@ -383,7 +383,8 @@ class TType ...@@ -383,7 +383,8 @@ class TType
bool canBeConstructed() const; bool canBeConstructed() const;
TStructure *getStruct() const { return structure; } TStructure *getStruct() { return structure; }
const TStructure *getStruct() const { return structure; }
void setStruct(TStructure *s) void setStruct(TStructure *s)
{ {
if (structure != s) if (structure != s)
......
...@@ -38,7 +38,7 @@ static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockSt ...@@ -38,7 +38,7 @@ static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockSt
const TType &fieldType = *field.type(); const TType &fieldType = *field.type();
const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking; const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
ASSERT(matrixPacking != EmpUnspecified); ASSERT(matrixPacking != EmpUnspecified);
TStructure *structure = fieldType.getStruct(); const TStructure *structure = fieldType.getStruct();
if (fieldType.isMatrix()) if (fieldType.isMatrix())
{ {
......
...@@ -817,8 +817,8 @@ TEST_F(DebugShaderPrecisionTest, ConstructorRounding) ...@@ -817,8 +817,8 @@ TEST_F(DebugShaderPrecisionTest, ConstructorRounding)
ASSERT_TRUE(foundInAllGLSLCode("v1 = angle_frm(vec4(_uu1, _uu2, angle_frl(_uu3), _uu4))")); ASSERT_TRUE(foundInAllGLSLCode("v1 = angle_frm(vec4(_uu1, _uu2, angle_frl(_uu3), _uu4))"));
ASSERT_TRUE(foundInAllGLSLCode("v2 = angle_frm(vec4(_uuiv))")); ASSERT_TRUE(foundInAllGLSLCode("v2 = angle_frm(vec4(_uuiv))"));
ASSERT_TRUE(foundInHLSLCode("v1 = angle_frm(vec4(_u1, _u2, angle_frl(_u3), _u4))")); ASSERT_TRUE(foundInHLSLCode("v1 = angle_frm(vec4_ctor(_u1, _u2, angle_frl(_u3), _u4))"));
ASSERT_TRUE(foundInHLSLCode("v2 = angle_frm(vec4(_uiv))")); ASSERT_TRUE(foundInHLSLCode("v2 = angle_frm(vec4_ctor(_uiv))"));
} }
TEST_F(DebugShaderPrecisionTest, StructConstructorNoRounding) TEST_F(DebugShaderPrecisionTest, StructConstructorNoRounding)
......
...@@ -162,7 +162,7 @@ class FindStructByName final : public TIntermTraverser ...@@ -162,7 +162,7 @@ class FindStructByName final : public TIntermTraverser
return; return;
} }
TStructure *structure = symbol->getType().getStruct(); TStructure *structure = symbol->getTypePointer()->getStruct();
if (structure != nullptr && structure->name() == mStructName) if (structure != nullptr && structure->name() == mStructName)
{ {
......
...@@ -555,8 +555,8 @@ TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, ViewIDAndInstanceIDHaveCorrectV ...@@ -555,8 +555,8 @@ TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, ViewIDAndInstanceIDHaveCorrectV
EXPECT_TRUE(foundInAllGLSLCode("ViewID_OVR = (uint(gl_InstanceID) % 3u)")); EXPECT_TRUE(foundInAllGLSLCode("ViewID_OVR = (uint(gl_InstanceID) % 3u)"));
EXPECT_TRUE(foundInAllGLSLCode("InstanceID = int((uint(gl_InstanceID) / 3u))")); EXPECT_TRUE(foundInAllGLSLCode("InstanceID = int((uint(gl_InstanceID) / 3u))"));
EXPECT_TRUE(foundInHLSLCode("ViewID_OVR = (uvec1(gl_InstanceID) % 3)")); EXPECT_TRUE(foundInHLSLCode("ViewID_OVR = (uint_ctor(gl_InstanceID) % 3)"));
EXPECT_TRUE(foundInHLSLCode("InstanceID = ivec1((uvec1(gl_InstanceID) / 3))")); EXPECT_TRUE(foundInHLSLCode("InstanceID = int_ctor((uint_ctor(gl_InstanceID) / 3))"));
} }
// The test checks that the directive enabling GL_OVR_multiview is not outputted if the extension is // The test checks that the directive enabling GL_OVR_multiview is not outputted if the extension is
......
...@@ -3715,6 +3715,87 @@ TEST_P(GLSLTest_ES3, EmptySwitch) ...@@ -3715,6 +3715,87 @@ TEST_P(GLSLTest_ES3, EmptySwitch)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Test that a constant struct inside an expression is handled correctly.
TEST_P(GLSLTest_ES3, ConstStructInsideExpression)
{
// Incorrect output color was seen on Android. http://anglebug.com/2226
ANGLE_SKIP_TEST_IF(IsAndroid() && !IsNVIDIA() && IsOpenGLES());
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
uniform float u_zero;
struct S
{
float field;
};
void main()
{
const S constS = S(1.0);
S nonConstS = constS;
nonConstS.field = u_zero;
bool fail = (constS == nonConstS);
my_FragColor = vec4(0, 1, 0, 1);
if (fail)
{
my_FragColor = vec4(1, 0, 0, 1);
}
})";
ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader);
drawQuad(program.get(), "inputAttribute", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that a varying struct that's defined as a part of the declaration is handled correctly.
TEST_P(GLSLTest_ES3, VaryingStructWithInlineDefinition)
{
const std::string &vertexShader =
R"(#version 300 es
in vec4 inputAttribute;
flat out struct S
{
int field;
} v_s;
void main()
{
v_s.field = 1;
gl_Position = inputAttribute;
})";
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
flat in struct S
{
int field;
} v_s;
void main()
{
bool success = (v_s.field == 1);
my_FragColor = vec4(1, 0, 0, 1);
if (success)
{
my_FragColor = vec4(0, 1, 0, 1);
}
})";
ANGLE_GL_PROGRAM(program, vertexShader, 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