Commit 96f6adfa by Olli Etuaho Committed by Commit Bot

Add support for arrays of arrays in AST processing

Data concerning arrays of arrays is added in TType. Parsing arrays of arrays and support for arrays of arrays in TPublicType are still left to be implemented later. ShaderVariable interface for arrays of arrays is also left to be implemented later. We rely on existing test coverage to make sure that arrays of arrays are not accidentally exposed. BUG=angleproject:2125 TEST=angle_unittests, angle_end2end_tests, angle_deqp_gles31_tests Change-Id: Ie17d5ac9b8d33958e9126dc0fb40bf1c81ddeec9 Reviewed-on: https://chromium-review.googlesource.com/616146Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 5e424fae
...@@ -219,8 +219,9 @@ void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name, ...@@ -219,8 +219,9 @@ void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
info->name = name; info->name = name;
info->mappedName = name; info->mappedName = name;
info->type = GLVariableType(type); info->type = GLVariableType(type);
info->arraySize = type.isArray() ? type.getArraySize() : 0; ASSERT(!type.isArrayOfArrays());
info->precision = GLVariablePrecision(type); info->arraySize = type.isArray() ? type.getOutermostArraySize() : 0;
info->precision = GLVariablePrecision(type);
} }
void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name, void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name,
...@@ -511,7 +512,11 @@ void CollectVariablesTraverser::setCommonVariableProperties(const TType &type, ...@@ -511,7 +512,11 @@ void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
} }
variableOut->name = name.c_str(); variableOut->name = name.c_str();
variableOut->mappedName = HashName(name, mHashFunction).c_str(); variableOut->mappedName = HashName(name, mHashFunction).c_str();
variableOut->arraySize = type.getArraySize();
// TODO(oetuaho@nvidia.com): Uniforms can be arrays of arrays, so this assert will need to be
// removed.
ASSERT(!type.isArrayOfArrays());
variableOut->arraySize = type.isArray() ? type.getOutermostArraySize() : 0;
} }
Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
...@@ -581,7 +586,8 @@ void CollectVariablesTraverser::recordInterfaceBlock(const TType &interfaceBlock ...@@ -581,7 +586,8 @@ void CollectVariablesTraverser::recordInterfaceBlock(const TType &interfaceBlock
interfaceBlock->mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str(); interfaceBlock->mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
interfaceBlock->instanceName = interfaceBlock->instanceName =
(blockType->hasInstanceName() ? blockType->instanceName().c_str() : ""); (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
interfaceBlock->arraySize = interfaceBlockType.getArraySize(); ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9
interfaceBlock->arraySize = interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier()); interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM || if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
......
...@@ -816,11 +816,11 @@ void IdentifyBuiltIns(sh::GLenum type, ...@@ -816,11 +816,11 @@ void IdentifyBuiltIns(sh::GLenum type,
TType fragData(EbtFloat, EbpMedium, EvqFragData, 4); TType fragData(EbtFloat, EbpMedium, EvqFragData, 4);
if (spec != SH_WEBGL2_SPEC && spec != SH_WEBGL3_SPEC) if (spec != SH_WEBGL2_SPEC && spec != SH_WEBGL3_SPEC)
{ {
fragData.setArraySize(resources.MaxDrawBuffers); fragData.makeArray(resources.MaxDrawBuffers);
} }
else else
{ {
fragData.setArraySize(1u); fragData.makeArray(1u);
} }
symbolTable.insertVariable(ESSL1_BUILTINS, "gl_FragData", fragData); symbolTable.insertVariable(ESSL1_BUILTINS, "gl_FragData", fragData);
...@@ -829,8 +829,8 @@ void IdentifyBuiltIns(sh::GLenum type, ...@@ -829,8 +829,8 @@ void IdentifyBuiltIns(sh::GLenum type,
symbolTable.insertVariableExt( symbolTable.insertVariableExt(
ESSL1_BUILTINS, "GL_EXT_blend_func_extended", "gl_SecondaryFragColorEXT", ESSL1_BUILTINS, "GL_EXT_blend_func_extended", "gl_SecondaryFragColorEXT",
TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)); TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4));
TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true); TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1);
secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers); secondaryFragData.makeArray(resources.MaxDualSourceDrawBuffers);
symbolTable.insertVariableExt(ESSL1_BUILTINS, "GL_EXT_blend_func_extended", symbolTable.insertVariableExt(ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
"gl_SecondaryFragDataEXT", secondaryFragData); "gl_SecondaryFragDataEXT", secondaryFragData);
} }
...@@ -848,8 +848,8 @@ void IdentifyBuiltIns(sh::GLenum type, ...@@ -848,8 +848,8 @@ void IdentifyBuiltIns(sh::GLenum type,
if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch) if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
{ {
TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true); TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1);
lastFragData.setArraySize(resources.MaxDrawBuffers); lastFragData.makeArray(resources.MaxDrawBuffers);
if (resources.EXT_shader_framebuffer_fetch) if (resources.EXT_shader_framebuffer_fetch)
{ {
...@@ -928,8 +928,8 @@ void IdentifyBuiltIns(sh::GLenum type, ...@@ -928,8 +928,8 @@ void IdentifyBuiltIns(sh::GLenum type,
// The array size of gl_in is undefined until we get a valid input primitive // The array size of gl_in is undefined until we get a valid input primitive
// declaration. // declaration.
TType glInType(glInBlock, EvqPerVertexIn, TLayoutQualifier::create(), 0); TType glInType(glInBlock, EvqPerVertexIn, TLayoutQualifier::create());
glInType.setArrayUnsized(); glInType.makeArray(0u);
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_in", glInType); symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_in", glInType);
break; break;
......
...@@ -68,11 +68,15 @@ void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequen ...@@ -68,11 +68,15 @@ void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequen
// doesn't have array assignment. // doesn't have array assignment.
// Note that it is important to have the array init in the right order to workaround // Note that it is important to have the array init in the right order to workaround
// http://crbug.com/709317 // http://crbug.com/709317
for (unsigned int i = 0; i < initializedNode->getArraySize(); ++i) for (unsigned int i = 0; i < initializedNode->getOutermostArraySize(); ++i)
{ {
TIntermBinary *element = TIntermBinary *element =
new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i)); new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i));
if (element->getType().isStructureContainingArrays()) if (element->isArray())
{
AddArrayZeroInitSequence(element, initSequenceOut);
}
else if (element->getType().isStructureContainingArrays())
{ {
AddStructZeroInitSequence(element, initSequenceOut); AddStructZeroInitSequence(element, initSequenceOut);
} }
......
...@@ -502,7 +502,7 @@ void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator) ...@@ -502,7 +502,7 @@ void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
(declarator->getAsBinaryNode() != nullptr && (declarator->getAsBinaryNode() != nullptr &&
declarator->getAsBinaryNode()->getOp() == EOpInitialize)); declarator->getAsBinaryNode()->getOp() == EOpInitialize));
ASSERT(mDeclarators.empty() || ASSERT(mDeclarators.empty() ||
declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType())); declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
mDeclarators.push_back(declarator); mDeclarators.push_back(declarator);
} }
...@@ -1063,7 +1063,7 @@ void TIntermBinary::promote() ...@@ -1063,7 +1063,7 @@ void TIntermBinary::promote()
case EOpIndexIndirect: case EOpIndexIndirect:
if (mLeft->isArray()) if (mLeft->isArray())
{ {
mType.clearArrayness(); mType.toArrayElementType();
} }
else if (mLeft->isMatrix()) else if (mLeft->isMatrix())
{ {
...@@ -1242,9 +1242,9 @@ const TConstantUnion *TIntermConstantUnion::foldIndexing(int index) ...@@ -1242,9 +1242,9 @@ const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
{ {
if (isArray()) if (isArray())
{ {
ASSERT(index < static_cast<int>(getType().getArraySize())); ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
TType arrayElementType = getType(); TType arrayElementType = getType();
arrayElementType.clearArrayness(); arrayElementType.toArrayElementType();
size_t arrayElementSize = arrayElementType.getObjectSize(); size_t arrayElementSize = arrayElementType.getObjectSize();
return &mUnionArrayPointer[arrayElementSize * index]; return &mUnionArrayPointer[arrayElementSize * index];
} }
......
...@@ -176,7 +176,7 @@ class TIntermTyped : public TIntermNode ...@@ -176,7 +176,7 @@ class TIntermTyped : public TIntermNode
const char *getBasicString() const { return mType.getBasicString(); } const char *getBasicString() const { return mType.getBasicString(); }
TString getCompleteString() const { return mType.getCompleteString(); } TString getCompleteString() const { return mType.getCompleteString(); }
unsigned int getArraySize() const { return mType.getArraySize(); } unsigned int getOutermostArraySize() const { return mType.getOutermostArraySize(); }
bool isConstructorWithOnlyConstantUnionParameters(); bool isConstructorWithOnlyConstantUnionParameters();
......
...@@ -116,7 +116,10 @@ TIntermTyped *CreateZeroNode(const TType &type) ...@@ -116,7 +116,10 @@ TIntermTyped *CreateZeroNode(const TType &type)
// Void array. This happens only on error condition, similarly to the case above. We don't // Void array. This happens only on error condition, similarly to the case above. We don't
// have a constructor operator for void, so this needs special handling. We'll end up with a // have a constructor operator for void, so this needs special handling. We'll end up with a
// value without the array type, but that should not be a problem. // value without the array type, but that should not be a problem.
constType.clearArrayness(); while (constType.isArray())
{
constType.toArrayElementType();
}
return CreateZeroNode(constType); return CreateZeroNode(constType);
} }
...@@ -125,9 +128,9 @@ TIntermTyped *CreateZeroNode(const TType &type) ...@@ -125,9 +128,9 @@ TIntermTyped *CreateZeroNode(const TType &type)
if (type.isArray()) if (type.isArray())
{ {
TType elementType(type); TType elementType(type);
elementType.clearArrayness(); elementType.toArrayElementType();
size_t arraySize = type.getArraySize(); size_t arraySize = type.getOutermostArraySize();
for (size_t i = 0; i < arraySize; ++i) for (size_t i = 0; i < arraySize; ++i)
{ {
arguments->push_back(CreateZeroNode(elementType)); arguments->push_back(CreateZeroNode(elementType));
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/mathutil.h" #include "common/mathutil.h"
#include "compiler/translator/Compiler.h" #include "compiler/translator/Compiler.h"
#include "compiler/translator/util.h"
#include <cfloat> #include <cfloat>
...@@ -18,13 +19,6 @@ namespace sh ...@@ -18,13 +19,6 @@ namespace sh
namespace namespace
{ {
TString arrayBrackets(const TType &type)
{
ASSERT(type.isArray());
TInfoSinkBase out;
out << "[" << type.getArraySize() << "]";
return TString(out.c_str());
}
bool isSingleStatement(TIntermNode *node) bool isSingleStatement(TIntermNode *node)
{ {
...@@ -382,7 +376,7 @@ void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args) ...@@ -382,7 +376,7 @@ void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
if (!arg->getName().getString().empty()) if (!arg->getName().getString().empty())
out << " " << hashName(arg->getName()); out << " " << hashName(arg->getName());
if (type.isArray()) if (type.isArray())
out << arrayBrackets(type); out << ArrayString(type);
// Put a comma if this is not the last argument. // Put a comma if this is not the last argument.
if (iter != args.end() - 1) if (iter != args.end() - 1)
...@@ -456,7 +450,7 @@ void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type) ...@@ -456,7 +450,7 @@ void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
if (type.isArray()) if (type.isArray())
{ {
out << getTypeName(type); out << getTypeName(type);
out << arrayBrackets(type); out << ArrayString(type);
out << "("; out << "(";
} }
else else
...@@ -476,7 +470,7 @@ void TOutputGLSLBase::visitSymbol(TIntermSymbol *node) ...@@ -476,7 +470,7 @@ void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
out << hashVariableName(node->getName()); out << hashVariableName(node->getName());
if (mDeclaringVariables && node->getType().isArray()) if (mDeclaringVariables && node->getType().isArray())
out << arrayBrackets(node->getType()); out << ArrayString(node->getType());
} }
void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node) void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
...@@ -573,7 +567,7 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) ...@@ -573,7 +567,7 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
if (left->isArray()) if (left->isArray())
{ {
// The shader will fail validation if the array length is not > 0. // The shader will fail validation if the array length is not > 0.
maxSize = static_cast<int>(leftType.getArraySize()) - 1; maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
} }
else else
{ {
...@@ -931,7 +925,7 @@ bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototy ...@@ -931,7 +925,7 @@ bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototy
const TType &type = node->getType(); const TType &type = node->getType();
writeVariableType(type); writeVariableType(type);
if (type.isArray()) if (type.isArray())
out << arrayBrackets(type); out << ArrayString(type);
out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo()); out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
...@@ -1226,7 +1220,7 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure) ...@@ -1226,7 +1220,7 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure)
out << " "; out << " ";
out << getTypeName(*field->type()) << " " << hashName(TName(field->name())); out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
if (field->type()->isArray()) if (field->type()->isArray())
out << arrayBrackets(*field->type()); out << ArrayString(*field->type());
out << ";\n"; out << ";\n";
} }
out << "}"; out << "}";
...@@ -1294,7 +1288,7 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc ...@@ -1294,7 +1288,7 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc
out << " "; out << " ";
out << getTypeName(*field->type()) << " " << hashName(TName(field->name())); out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
if (field->type()->isArray()) if (field->type()->isArray())
out << arrayBrackets(*field->type()); out << ArrayString(*field->type());
out << ";\n"; out << ";\n";
} }
out << "}"; out << "}";
......
...@@ -31,6 +31,23 @@ ...@@ -31,6 +31,23 @@
namespace sh namespace sh
{ {
namespace
{
TString ArrayHelperFunctionName(const char *prefix, const TType &type)
{
TStringStream fnName;
fnName << prefix << "_";
for (unsigned int arraySize : type.getArraySizes())
{
fnName << arraySize << "_";
}
fnName << TypeString(type);
return fnName.str();
}
} // anonymous namespace
void OutputHLSL::writeFloat(TInfoSinkBase &out, float f) void OutputHLSL::writeFloat(TInfoSinkBase &out, float f)
{ {
// This is known not to work for NaN on all drivers but make the best effort to output NaNs // This is known not to work for NaN on all drivers but make the best effort to output NaNs
...@@ -257,14 +274,14 @@ TString OutputHLSL::structInitializerString(int indent, const TType &type, const ...@@ -257,14 +274,14 @@ TString OutputHLSL::structInitializerString(int indent, const TType &type, const
if (type.isArray()) if (type.isArray())
{ {
init += indentString + "{\n"; init += indentString + "{\n";
for (unsigned int arrayIndex = 0u; arrayIndex < type.getArraySize(); ++arrayIndex) for (unsigned int arrayIndex = 0u; arrayIndex < type.getOutermostArraySize(); ++arrayIndex)
{ {
TStringStream indexedString; TStringStream indexedString;
indexedString << name << "[" << arrayIndex << "]"; indexedString << name << "[" << arrayIndex << "]";
TType elementType = type; TType elementType = type;
elementType.clearArrayness(); elementType.toArrayElementType();
init += structInitializerString(indent + 1, elementType, indexedString.str()); init += structInitializerString(indent + 1, elementType, indexedString.str());
if (arrayIndex < type.getArraySize() - 1) if (arrayIndex < type.getOutermostArraySize() - 1)
{ {
init += ","; init += ",";
} }
...@@ -948,6 +965,19 @@ void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfo ...@@ -948,6 +965,19 @@ void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfo
} }
} }
void OutputHLSL::outputAssign(Visit visit, const TType &type, TInfoSinkBase &out)
{
if (type.isArray())
{
const TString &functionName = addArrayAssignmentFunction(type);
outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
}
else
{
outputTriplet(out, visit, "(", " = ", ")");
}
}
bool OutputHLSL::ancestorEvaluatesToSamplerInStruct() bool OutputHLSL::ancestorEvaluatesToSamplerInStruct()
{ {
for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n) for (unsigned int n = 0u; getAncestorNode(n) != nullptr; ++n)
...@@ -1010,7 +1040,7 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1010,7 +1040,7 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
outputTriplet(out, visit, "(", ", ", ")"); outputTriplet(out, visit, "(", ", ", ")");
break; break;
case EOpAssign: case EOpAssign:
if (node->getLeft()->isArray()) if (node->isArray())
{ {
TIntermAggregate *rightAgg = node->getRight()->getAsAggregate(); TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
if (rightAgg != nullptr && rightAgg->isConstructor()) if (rightAgg != nullptr && rightAgg->isConstructor())
...@@ -1030,14 +1060,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1030,14 +1060,8 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
// ArrayReturnValueToOutParameter should have eliminated expressions where a // ArrayReturnValueToOutParameter should have eliminated expressions where a
// function call is assigned. // function call is assigned.
ASSERT(rightAgg == nullptr); ASSERT(rightAgg == nullptr);
const TString &functionName = addArrayAssignmentFunction(node->getType());
outputTriplet(out, visit, (functionName + "(").c_str(), ", ", ")");
}
else
{
outputTriplet(out, visit, "(", " = ", ")");
} }
outputAssign(visit, node->getType(), out);
break; break;
case EOpInitialize: case EOpInitialize:
if (visit == PreVisit) if (visit == PreVisit)
...@@ -2744,31 +2768,33 @@ bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression) ...@@ -2744,31 +2768,33 @@ bool OutputHLSL::canWriteAsHLSLLiteral(TIntermTyped *expression)
{ {
// We support writing constant unions and constructors that only take constant unions as // We support writing constant unions and constructors that only take constant unions as
// parameters as HLSL literals. // parameters as HLSL literals.
return expression->getAsConstantUnion() || return !expression->getType().isArrayOfArrays() &&
expression->isConstructorWithOnlyConstantUnionParameters(); (expression->getAsConstantUnion() ||
expression->isConstructorWithOnlyConstantUnionParameters());
} }
bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out, bool OutputHLSL::writeConstantInitialization(TInfoSinkBase &out,
TIntermSymbol *symbolNode, TIntermSymbol *symbolNode,
TIntermTyped *expression) TIntermTyped *initializer)
{ {
if (canWriteAsHLSLLiteral(expression)) if (canWriteAsHLSLLiteral(initializer))
{ {
symbolNode->traverse(this); symbolNode->traverse(this);
if (expression->getType().isArray()) ASSERT(!symbolNode->getType().isArrayOfArrays());
if (symbolNode->getType().isArray())
{ {
out << "[" << expression->getType().getArraySize() << "]"; out << "[" << symbolNode->getType().getOutermostArraySize() << "]";
} }
out << " = {"; out << " = {";
if (expression->getAsConstantUnion()) if (initializer->getAsConstantUnion())
{ {
TIntermConstantUnion *nodeConst = expression->getAsConstantUnion(); TIntermConstantUnion *nodeConst = initializer->getAsConstantUnion();
const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer(); const TConstantUnion *constUnion = nodeConst->getUnionArrayPointer();
writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize()); writeConstantUnionArray(out, constUnion, nodeConst->getType().getObjectSize());
} }
else else
{ {
TIntermAggregate *constructor = expression->getAsAggregate(); TIntermAggregate *constructor = initializer->getAsAggregate();
ASSERT(constructor != nullptr); ASSERT(constructor != nullptr);
for (TIntermNode *&node : *constructor->getSequence()) for (TIntermNode *&node : *constructor->getSequence())
{ {
...@@ -2856,33 +2882,31 @@ TString OutputHLSL::addArrayEqualityFunction(const TType &type) ...@@ -2856,33 +2882,31 @@ TString OutputHLSL::addArrayEqualityFunction(const TType &type)
} }
} }
const TString &typeName = TypeString(type); TType elementType(type);
elementType.toArrayElementType();
ArrayHelperFunction *function = new ArrayHelperFunction(); ArrayHelperFunction *function = new ArrayHelperFunction();
function->type = type; function->type = type;
TInfoSinkBase fnNameOut; function->functionName = ArrayHelperFunctionName("angle_eq", type);
fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName;
function->functionName = fnNameOut.c_str();
TType nonArrayType = type;
nonArrayType.clearArrayness();
TInfoSinkBase fnOut; TInfoSinkBase fnOut;
fnOut << "bool " << function->functionName << "(" << typeName << " a[" << type.getArraySize() const TString &typeName = TypeString(type);
<< "], " << typeName << " b[" << type.getArraySize() << "])\n" fnOut << "bool " << function->functionName << "(" << typeName << " a" << ArrayString(type)
<< ", " << typeName << " b" << ArrayString(type) << ")\n"
<< "{\n" << "{\n"
" for (int i = 0; i < " " for (int i = 0; i < "
<< type.getArraySize() << "; ++i)\n" << type.getOutermostArraySize()
" {\n" << "; ++i)\n"
" if ("; " {\n"
" if (";
outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut); outputEqual(PreVisit, elementType, EOpNotEqual, fnOut);
fnOut << "a[i]"; fnOut << "a[i]";
outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut); outputEqual(InVisit, elementType, EOpNotEqual, fnOut);
fnOut << "b[i]"; fnOut << "b[i]";
outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut); outputEqual(PostVisit, elementType, EOpNotEqual, fnOut);
fnOut << ") { return false; }\n" fnOut << ") { return false; }\n"
" }\n" " }\n"
...@@ -2907,26 +2931,35 @@ TString OutputHLSL::addArrayAssignmentFunction(const TType &type) ...@@ -2907,26 +2931,35 @@ TString OutputHLSL::addArrayAssignmentFunction(const TType &type)
} }
} }
const TString &typeName = TypeString(type); TType elementType(type);
elementType.toArrayElementType();
ArrayHelperFunction function; ArrayHelperFunction function;
function.type = type; function.type = type;
TInfoSinkBase fnNameOut; function.functionName = ArrayHelperFunctionName("angle_assign", type);
fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName;
function.functionName = fnNameOut.c_str();
TInfoSinkBase fnOut; TInfoSinkBase fnOut;
fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize() const TString &typeName = TypeString(type);
<< "], " << typeName << " b[" << type.getArraySize() << "])\n" fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type)
<< ", " << typeName << " b" << ArrayString(type) << ")\n"
<< "{\n" << "{\n"
" for (int i = 0; i < " " for (int i = 0; i < "
<< type.getArraySize() << "; ++i)\n" << type.getOutermostArraySize()
" {\n" << "; ++i)\n"
" a[i] = b[i];\n" " {\n"
" }\n" " ";
"}\n";
outputAssign(PreVisit, elementType, fnOut);
fnOut << "a[i]";
outputAssign(InVisit, elementType, fnOut);
fnOut << "b[i]";
outputAssign(PostVisit, elementType, fnOut);
fnOut << ";\n"
" }\n"
"}\n";
function.functionDefinition = fnOut.c_str(); function.functionDefinition = fnOut.c_str();
...@@ -2945,29 +2978,34 @@ TString OutputHLSL::addArrayConstructIntoFunction(const TType &type) ...@@ -2945,29 +2978,34 @@ TString OutputHLSL::addArrayConstructIntoFunction(const TType &type)
} }
} }
const TString &typeName = TypeString(type); TType elementType(type);
elementType.toArrayElementType();
ArrayHelperFunction function; ArrayHelperFunction function;
function.type = type; function.type = type;
TInfoSinkBase fnNameOut; function.functionName = ArrayHelperFunctionName("angle_construct_into", type);
fnNameOut << "angle_construct_into_" << type.getArraySize() << "_" << typeName;
function.functionName = fnNameOut.c_str();
TInfoSinkBase fnOut; TInfoSinkBase fnOut;
fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize() const TString &typeName = TypeString(type);
<< "]"; fnOut << "void " << function.functionName << "(out " << typeName << " a" << ArrayString(type);
for (unsigned int i = 0u; i < type.getArraySize(); ++i) for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
{ {
fnOut << ", " << typeName << " b" << i; fnOut << ", " << typeName << " b" << i << ArrayString(elementType);
} }
fnOut << ")\n" fnOut << ")\n"
"{\n"; "{\n";
for (unsigned int i = 0u; i < type.getArraySize(); ++i) for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
{ {
fnOut << " a[" << i << "] = b" << i << ";\n"; fnOut << " ";
outputAssign(PreVisit, elementType, fnOut);
fnOut << "a[" << i << "]";
outputAssign(InVisit, elementType, fnOut);
fnOut << "b" << i;
outputAssign(PostVisit, elementType, fnOut);
fnOut << ";\n";
} }
fnOut << "}\n"; fnOut << "}\n";
......
...@@ -108,6 +108,7 @@ class OutputHLSL : public TIntermTraverser ...@@ -108,6 +108,7 @@ class OutputHLSL : public TIntermTraverser
const TConstantUnion *constUnion); const TConstantUnion *constUnion);
void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out); void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out);
void outputAssign(Visit visit, const TType &type, TInfoSinkBase &out);
void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op); void writeEmulatedFunctionTriplet(TInfoSinkBase &out, Visit visit, TOperator op);
void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs); void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
......
...@@ -680,7 +680,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line, ...@@ -680,7 +680,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
{ {
// The size of an unsized constructor should already have been determined. // The size of an unsized constructor should already have been determined.
ASSERT(!type.isUnsizedArray()); ASSERT(!type.isUnsizedArray());
if (static_cast<size_t>(type.getArraySize()) != arguments->size()) if (static_cast<size_t>(type.getOutermostArraySize()) != arguments->size())
{ {
error(line, "array constructor needs one argument per array element", "constructor"); error(line, "array constructor needs one argument per array element", "constructor");
return false; return false;
...@@ -695,7 +695,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line, ...@@ -695,7 +695,7 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
error(line, "constructing from a non-dereferenced array", "constructor"); error(line, "constructing from a non-dereferenced array", "constructor");
return false; return false;
} }
if (!argType.sameElementType(type)) if (!argType.isElementTypeOf(type))
{ {
error(line, "Array constructor argument has an incorrect type", "constructor"); error(line, "Array constructor argument has an incorrect type", "constructor");
return false; return false;
...@@ -1057,7 +1057,14 @@ bool TParseContext::declareVariable(const TSourceLoc &line, ...@@ -1057,7 +1057,14 @@ bool TParseContext::declareVariable(const TSourceLoc &line,
{ {
const TVariable *maxDrawBuffers = static_cast<const TVariable *>( const TVariable *maxDrawBuffers = static_cast<const TVariable *>(
symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion)); symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion));
if (static_cast<int>(type.getArraySize()) == maxDrawBuffers->getConstPointer()->getIConst()) if (type.isArrayOfArrays())
{
error(line, "redeclaration of gl_LastFragData as an array of arrays",
identifier.c_str());
return false;
}
else if (static_cast<int>(type.getOutermostArraySize()) ==
maxDrawBuffers->getConstPointer()->getIConst())
{ {
if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion)) if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion))
{ {
...@@ -1389,14 +1396,21 @@ void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType, ...@@ -1389,14 +1396,21 @@ void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type) void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type)
{ {
TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); TLayoutQualifier layoutQualifier = type.getLayoutQualifier();
int arraySize = type.isArray() ? type.getArraySize() : 1; // Note that the ESSL 3.10 section 4.4.5 is not particularly clear on how the binding qualifier
// on arrays of arrays should be handled. We interpret the spec so that the binding value is
// incremented for each element of the innermost nested arrays. This is in line with how arrays
// of arrays of blocks are specified to behave in GLSL 4.50 and a conservative interpretation
// when it comes to which shaders are accepted by the compiler.
int arrayTotalElementCount = type.getArraySizeProduct();
if (IsImage(type.getBasicType())) if (IsImage(type.getBasicType()))
{ {
checkImageBindingIsValid(identifierLocation, layoutQualifier.binding, arraySize); checkImageBindingIsValid(identifierLocation, layoutQualifier.binding,
arrayTotalElementCount);
} }
else if (IsSampler(type.getBasicType())) else if (IsSampler(type.getBasicType()))
{ {
checkSamplerBindingIsValid(identifierLocation, layoutQualifier.binding, arraySize); checkSamplerBindingIsValid(identifierLocation, layoutQualifier.binding,
arrayTotalElementCount);
} }
else if (IsAtomicCounter(type.getBasicType())) else if (IsAtomicCounter(type.getBasicType()))
{ {
...@@ -1468,10 +1482,12 @@ void TParseContext::checkOffsetIsNotSpecified(const TSourceLoc &location, int of ...@@ -1468,10 +1482,12 @@ void TParseContext::checkOffsetIsNotSpecified(const TSourceLoc &location, int of
} }
} }
void TParseContext::checkImageBindingIsValid(const TSourceLoc &location, int binding, int arraySize) void TParseContext::checkImageBindingIsValid(const TSourceLoc &location,
int binding,
int arrayTotalElementCount)
{ {
// Expects arraySize to be 1 when setting binding for only a single variable. // Expects arraySize to be 1 when setting binding for only a single variable.
if (binding >= 0 && binding + arraySize > mMaxImageUnits) if (binding >= 0 && binding + arrayTotalElementCount > mMaxImageUnits)
{ {
error(location, "image binding greater than gl_MaxImageUnits", "binding"); error(location, "image binding greater than gl_MaxImageUnits", "binding");
} }
...@@ -1479,10 +1495,10 @@ void TParseContext::checkImageBindingIsValid(const TSourceLoc &location, int bin ...@@ -1479,10 +1495,10 @@ void TParseContext::checkImageBindingIsValid(const TSourceLoc &location, int bin
void TParseContext::checkSamplerBindingIsValid(const TSourceLoc &location, void TParseContext::checkSamplerBindingIsValid(const TSourceLoc &location,
int binding, int binding,
int arraySize) int arrayTotalElementCount)
{ {
// Expects arraySize to be 1 when setting binding for only a single variable. // Expects arraySize to be 1 when setting binding for only a single variable.
if (binding >= 0 && binding + arraySize > mMaxCombinedTextureImageUnits) if (binding >= 0 && binding + arrayTotalElementCount > mMaxCombinedTextureImageUnits)
{ {
error(location, "sampler binding greater than maximum texture units", "binding"); error(location, "sampler binding greater than maximum texture units", "binding");
} }
...@@ -1777,7 +1793,7 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location, ...@@ -1777,7 +1793,7 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
else if (variable->getType().getQualifier() == EvqPerVertexIn) else if (variable->getType().getQualifier() == EvqPerVertexIn)
{ {
TType type(variable->getType()); TType type(variable->getType());
type.setArraySize(mGeometryShaderInputArraySize); type.setArraySize(0, mGeometryShaderInputArraySize);
node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), type); node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), type);
} }
else else
...@@ -1806,17 +1822,11 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, ...@@ -1806,17 +1822,11 @@ bool TParseContext::executeInitializer(const TSourceLoc &line,
TVariable *variable = nullptr; TVariable *variable = nullptr;
if (type.isUnsizedArray()) if (type.isUnsizedArray())
{ {
// We have not checked yet whether the initializer actually is an array or not. // In case initializer is not an array or type has more dimensions than initializer, this
if (initializer->isArray()) // will default to setting array sizes to 1. We have not checked yet whether the initializer
{ // actually is an array or not. Having a non-array initializer for an unsized array will
type.setArraySize(initializer->getArraySize()); // result in an error later, so we don't generate an error message here.
} type.sizeUnsizedArrays(initializer->getType().getArraySizes());
else
{
// Having a non-array initializer for an unsized array will result in an error later,
// so we don't generate an error message here.
type.setArraySize(1u);
}
} }
if (!declareVariable(line, identifier, type, &variable)) if (!declareVariable(line, identifier, type, &variable))
{ {
...@@ -2353,7 +2363,7 @@ TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publ ...@@ -2353,7 +2363,7 @@ TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publ
unsigned int size = checkIsValidArraySize(identifierLocation, indexExpression); unsigned int size = checkIsValidArraySize(identifierLocation, indexExpression);
// Make the type an array even if size check failed. // Make the type an array even if size check failed.
// This ensures useless error messages regarding the variable's non-arrayness won't follow. // This ensures useless error messages regarding the variable's non-arrayness won't follow.
arrayType.setArraySize(size); arrayType.makeArray(size);
if (IsAtomicCounter(publicType.getBasicType())) if (IsAtomicCounter(publicType.getBasicType()))
{ {
...@@ -2564,7 +2574,7 @@ void TParseContext::parseArrayDeclarator(TPublicType &publicType, ...@@ -2564,7 +2574,7 @@ void TParseContext::parseArrayDeclarator(TPublicType &publicType,
{ {
TType arrayType = TType(publicType); TType arrayType = TType(publicType);
unsigned int size = checkIsValidArraySize(arrayLocation, indexExpression); unsigned int size = checkIsValidArraySize(arrayLocation, indexExpression);
arrayType.setArraySize(size); arrayType.makeArray(size);
if (IsAtomicCounter(publicType.getBasicType())) if (IsAtomicCounter(publicType.getBasicType()))
{ {
...@@ -3341,6 +3351,45 @@ TParameter TParseContext::parseParameterArrayDeclarator(const TString *identifie ...@@ -3341,6 +3351,45 @@ TParameter TParseContext::parseParameterArrayDeclarator(const TString *identifie
return parseParameterDeclarator(*type, identifier, identifierLoc); return parseParameterDeclarator(*type, identifier, identifierLoc);
} }
bool TParseContext::checkUnsizedArrayConstructorArgumentDimensionality(TIntermSequence *arguments,
TType type,
const TSourceLoc &line)
{
if (arguments->empty())
{
error(line, "implicitly sized array constructor must have at least one argument", "[]");
return false;
}
for (TIntermNode *arg : *arguments)
{
TIntermTyped *element = arg->getAsTyped();
ASSERT(element);
size_t dimensionalityFromElement = element->getType().getArraySizes().size() + 1u;
if (dimensionalityFromElement > type.getArraySizes().size())
{
error(line, "constructing from a non-dereferenced array", "constructor");
return false;
}
else if (dimensionalityFromElement < type.getArraySizes().size())
{
if (dimensionalityFromElement == 1u)
{
error(line, "implicitly sized array of arrays constructor argument is not an array",
"constructor");
}
else
{
error(line,
"implicitly sized array of arrays constructor argument dimensionality is too "
"low",
"constructor");
}
return false;
}
}
return true;
}
// This function is used to test for the correctness of the parameters passed to various constructor // This function is used to test for the correctness of the parameters passed to various constructor
// functions and also convert them to the right datatype if it is allowed and required. // functions and also convert them to the right datatype if it is allowed and required.
// //
...@@ -3352,13 +3401,23 @@ TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments, ...@@ -3352,13 +3401,23 @@ TIntermTyped *TParseContext::addConstructor(TIntermSequence *arguments,
{ {
if (type.isUnsizedArray()) if (type.isUnsizedArray())
{ {
if (arguments->empty()) if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line))
{ {
error(line, "implicitly sized array constructor must have at least one argument", "[]"); type.sizeUnsizedArrays(TVector<unsigned int>());
type.setArraySize(1u);
return CreateZeroNode(type); return CreateZeroNode(type);
} }
type.setArraySize(static_cast<unsigned int>(arguments->size())); TIntermTyped *firstElement = arguments->at(0)->getAsTyped();
ASSERT(firstElement);
type.setArraySize(type.getArraySizes().size() - 1u,
static_cast<unsigned int>(arguments->size()));
for (size_t i = 0; i < firstElement->getType().getArraySizes().size(); ++i)
{
if (type.getArraySizes()[i] == 0u)
{
type.setArraySize(i, firstElement->getType().getArraySizes().at(i));
}
}
ASSERT(!type.isUnsizedArray());
} }
if (!checkConstructorArguments(line, arguments, type)) if (!checkConstructorArguments(line, arguments, type))
...@@ -3561,8 +3620,11 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( ...@@ -3561,8 +3620,11 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
TInterfaceBlock *interfaceBlock = TInterfaceBlock *interfaceBlock =
new TInterfaceBlock(&blockName, fieldList, instanceName, blockLayoutQualifier); new TInterfaceBlock(&blockName, fieldList, instanceName, blockLayoutQualifier);
TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier);
arraySize); if (arrayIndex != nullptr)
{
interfaceBlockType.makeArray(arraySize);
}
TString symbolName = ""; TString symbolName = "";
int symbolId = 0; int symbolId = 0;
...@@ -3768,7 +3830,7 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, ...@@ -3768,7 +3830,7 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
if (safeIndex < 0) if (safeIndex < 0)
{ {
safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index, safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
baseExpression->getArraySize(), baseExpression->getOutermostArraySize(),
"array index out of range"); "array index out of range");
} }
} }
...@@ -4408,7 +4470,7 @@ TField *TParseContext::parseStructArrayDeclarator(TString *identifier, ...@@ -4408,7 +4470,7 @@ TField *TParseContext::parseStructArrayDeclarator(TString *identifier,
TType *type = new TType(EbtVoid, EbpUndefined); TType *type = new TType(EbtVoid, EbpUndefined);
unsigned int size = checkIsValidArraySize(arraySizeLoc, arraySize); unsigned int size = checkIsValidArraySize(arraySizeLoc, arraySize);
type->setArraySize(size); type->makeArray(size);
return new TField(type, identifier, loc); return new TField(type, identifier, loc);
} }
...@@ -4450,46 +4512,36 @@ TFieldList *TParseContext::addStructDeclaratorListWithQualifiers( ...@@ -4450,46 +4512,36 @@ TFieldList *TParseContext::addStructDeclaratorListWithQualifiers(
} }
TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
TFieldList *fieldList) TFieldList *declaratorList)
{ {
checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision, checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision,
typeSpecifier.getBasicType()); typeSpecifier.getBasicType());
checkIsNonVoid(typeSpecifier.getLine(), (*fieldList)[0]->name(), typeSpecifier.getBasicType()); checkIsNonVoid(typeSpecifier.getLine(), (*declaratorList)[0]->name(),
typeSpecifier.getBasicType());
checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier); checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier);
for (unsigned int i = 0; i < fieldList->size(); ++i) for (unsigned int i = 0; i < declaratorList->size(); ++i)
{ {
// auto declaratorArraySizes = (*declaratorList)[i]->type()->getArraySizes();
// Careful not to replace already known aspects of type, like array-ness
//
TType *type = (*fieldList)[i]->type();
type->setBasicType(typeSpecifier.getBasicType());
type->setPrimarySize(typeSpecifier.getPrimarySize());
type->setSecondarySize(typeSpecifier.getSecondarySize());
type->setPrecision(typeSpecifier.precision);
type->setQualifier(typeSpecifier.qualifier);
type->setLayoutQualifier(typeSpecifier.layoutQualifier);
type->setMemoryQualifier(typeSpecifier.memoryQualifier);
type->setInvariant(typeSpecifier.invariant);
// don't allow arrays of arrays // don't allow arrays of arrays
if (type->isArray()) if (!declaratorArraySizes.empty())
{ {
checkIsValidTypeForArray(typeSpecifier.getLine(), typeSpecifier); checkIsValidTypeForArray(typeSpecifier.getLine(), typeSpecifier);
} }
if (typeSpecifier.array)
type->setArraySize(static_cast<unsigned int>(typeSpecifier.arraySize)); TType *type = (*declaratorList)[i]->type();
if (typeSpecifier.getUserDef()) *type = TType(typeSpecifier);
for (unsigned int arraySize : declaratorArraySizes)
{ {
type->setStruct(typeSpecifier.getUserDef()); type->makeArray(arraySize);
} }
checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*fieldList)[i]); checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*declaratorList)[i]);
} }
return fieldList; return declaratorList;
} }
TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine, TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
...@@ -4800,7 +4852,7 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, ...@@ -4800,7 +4852,7 @@ bool TParseContext::binaryOpCommonCheck(TOperator op,
return false; return false;
} }
// At this point, size of implicitly sized arrays should be resolved. // At this point, size of implicitly sized arrays should be resolved.
if (left->getArraySize() != right->getArraySize()) if (left->getType().getArraySizes() != right->getType().getArraySizes())
{ {
error(loc, "array size mismatch", GetOperatorString(op)); error(loc, "array size mismatch", GetOperatorString(op));
return false; return false;
...@@ -5398,7 +5450,7 @@ TIntermTyped *TParseContext::addMethod(TFunction *fnCall, ...@@ -5398,7 +5450,7 @@ TIntermTyped *TParseContext::addMethod(TFunction *fnCall,
} }
else else
{ {
arraySize = typedThis->getArraySize(); arraySize = typedThis->getOutermostArraySize();
if (typedThis->getAsSymbolNode() == nullptr) if (typedThis->getAsSymbolNode() == nullptr)
{ {
// This code path can be hit with expressions like these: // This code path can be hit with expressions like these:
......
...@@ -484,8 +484,12 @@ class TParseContext : angle::NonCopyable ...@@ -484,8 +484,12 @@ class TParseContext : angle::NonCopyable
void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type); void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type);
void checkBindingIsNotSpecified(const TSourceLoc &location, int binding); void checkBindingIsNotSpecified(const TSourceLoc &location, int binding);
void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset); void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset);
void checkImageBindingIsValid(const TSourceLoc &location, int binding, int arraySize); void checkImageBindingIsValid(const TSourceLoc &location,
void checkSamplerBindingIsValid(const TSourceLoc &location, int binding, int arraySize); int binding,
int arrayTotalElementCount);
void checkSamplerBindingIsValid(const TSourceLoc &location,
int binding,
int arrayTotalElementCount);
void checkBlockBindingIsValid(const TSourceLoc &location, void checkBlockBindingIsValid(const TSourceLoc &location,
const TQualifier &qualifier, const TQualifier &qualifier,
int binding, int binding,
...@@ -498,6 +502,10 @@ class TParseContext : angle::NonCopyable ...@@ -498,6 +502,10 @@ class TParseContext : angle::NonCopyable
void checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv); void checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv);
bool checkUnsizedArrayConstructorArgumentDimensionality(TIntermSequence *arguments,
TType type,
const TSourceLoc &line);
TIntermTyped *addBinaryMathInternal(TOperator op, TIntermTyped *addBinaryMathInternal(TOperator op,
TIntermTyped *left, TIntermTyped *left,
TIntermTyped *right, TIntermTyped *right,
......
...@@ -236,7 +236,10 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -236,7 +236,10 @@ TString StructureHLSL::addConstructor(const TType &type,
} }
TType ctorType = type; TType ctorType = type;
ctorType.clearArrayness(); while (ctorType.isArray())
{
ctorType.toArrayElementType();
}
ctorType.setPrecision(EbpHigh); ctorType.setPrecision(EbpHigh);
ctorType.setQualifier(EvqTemporary); ctorType.setQualifier(EvqTemporary);
......
...@@ -122,13 +122,15 @@ TType::TType(const TPublicType &p) ...@@ -122,13 +122,15 @@ TType::TType(const TPublicType &p)
layoutQualifier(p.layoutQualifier), layoutQualifier(p.layoutQualifier),
primarySize(p.getPrimarySize()), primarySize(p.getPrimarySize()),
secondarySize(p.getSecondarySize()), secondarySize(p.getSecondarySize()),
array(p.array),
arraySize(p.arraySize),
interfaceBlock(0), interfaceBlock(0),
structure(0) structure(0)
{ {
ASSERT(primarySize <= 4); ASSERT(primarySize <= 4);
ASSERT(secondarySize <= 4); ASSERT(secondarySize <= 4);
if (p.array)
{
makeArray(p.arraySize);
}
if (p.getUserDef()) if (p.getUserDef())
structure = p.getUserDef(); structure = p.getUserDef();
} }
...@@ -279,8 +281,11 @@ TString TType::getCompleteString() const ...@@ -279,8 +281,11 @@ TString TType::getCompleteString() const
stream << getQualifierString() << " "; stream << getQualifierString() << " ";
if (precision != EbpUndefined) if (precision != EbpUndefined)
stream << getPrecisionString() << " "; stream << getPrecisionString() << " ";
if (array) for (auto arraySizeIter = mArraySizes.rbegin(); arraySizeIter != mArraySizes.rend();
stream << "array[" << getArraySize() << "] of "; ++arraySizeIter)
{
stream << "array[" << (*arraySizeIter) << "] of ";
}
if (isMatrix()) if (isMatrix())
stream << getCols() << "X" << getRows() << " matrix of "; stream << getCols() << "X" << getRows() << " matrix of ";
else if (isVector()) else if (isVector())
...@@ -442,7 +447,7 @@ TString TType::buildMangledName() const ...@@ -442,7 +447,7 @@ TString TType::buildMangledName() const
mangledName += static_cast<char>('0' + getNominalSize()); mangledName += static_cast<char>('0' + getNominalSize());
} }
if (isArray()) for (unsigned int arraySize : mArraySizes)
{ {
char buf[20]; char buf[20];
snprintf(buf, sizeof(buf), "%d", arraySize); snprintf(buf, sizeof(buf), "%d", arraySize);
...@@ -462,16 +467,15 @@ size_t TType::getObjectSize() const ...@@ -462,16 +467,15 @@ size_t TType::getObjectSize() const
else else
totalSize = primarySize * secondarySize; totalSize = primarySize * secondarySize;
if (isArray()) if (totalSize == 0)
{ return 0;
if (totalSize == 0)
return 0;
size_t currentArraySize = getArraySize(); for (size_t arraySize : mArraySizes)
if (currentArraySize > INT_MAX / totalSize) {
if (arraySize > INT_MAX / totalSize)
totalSize = INT_MAX; totalSize = INT_MAX;
else else
totalSize *= currentArraySize; totalSize *= arraySize;
} }
return totalSize; return totalSize;
...@@ -486,27 +490,93 @@ int TType::getLocationCount() const ...@@ -486,27 +490,93 @@ int TType::getLocationCount() const
count = structure->getLocationCount(); count = structure->getLocationCount();
} }
if (isArray()) if (count == 0)
{ {
if (count == 0) return 0;
{ }
return 0;
}
unsigned int currentArraySize = getArraySize(); for (unsigned int arraySize : mArraySizes)
if (currentArraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count)) {
if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count))
{ {
count = std::numeric_limits<int>::max(); count = std::numeric_limits<int>::max();
} }
else else
{ {
count *= static_cast<int>(currentArraySize); count *= static_cast<int>(arraySize);
} }
} }
return count; return count;
} }
unsigned int TType::getArraySizeProduct() const
{
unsigned int product = 1u;
for (unsigned int arraySize : mArraySizes)
{
product *= arraySize;
}
return product;
}
bool TType::isUnsizedArray() const
{
for (unsigned int arraySize : mArraySizes)
{
if (arraySize == 0u)
{
return true;
}
}
return false;
}
bool TType::sameNonArrayType(const TType &right) const
{
return (type == right.type && primarySize == right.primarySize &&
secondarySize == right.secondarySize && structure == right.structure);
}
bool TType::isElementTypeOf(const TType &arrayType) const
{
if (!sameNonArrayType(arrayType))
{
return false;
}
if (arrayType.mArraySizes.size() != mArraySizes.size() + 1u)
{
return false;
}
for (size_t i = 0; i < mArraySizes.size(); ++i)
{
if (mArraySizes[i] != arrayType.mArraySizes[i])
{
return false;
}
}
return true;
}
void TType::sizeUnsizedArrays(const TVector<unsigned int> &arraySizes)
{
for (size_t i = 0u; i < mArraySizes.size(); ++i)
{
if (mArraySizes[i] == 0)
{
if (i < arraySizes.size())
{
mArraySizes[i] = arraySizes[i];
}
else
{
mArraySizes[i] = 1u;
}
}
}
invalidateMangledName();
}
TStructure::TStructure(TSymbolTable *symbolTable, const TString *name, TFieldList *fields) TStructure::TStructure(TSymbolTable *symbolTable, const TString *name, TFieldList *fields)
: TFieldListCollection(name, fields), : TFieldListCollection(name, fields),
mDeepestNesting(0), mDeepestNesting(0),
...@@ -558,8 +628,8 @@ void TType::createSamplerSymbols(const TString &namePrefix, ...@@ -558,8 +628,8 @@ void TType::createSamplerSymbols(const TString &namePrefix,
if (isArray()) if (isArray())
{ {
TType elementType(*this); TType elementType(*this);
elementType.clearArrayness(); elementType.toArrayElementType();
for (unsigned int arrayIndex = 0u; arrayIndex < getArraySize(); ++arrayIndex) for (unsigned int arrayIndex = 0u; arrayIndex < getOutermostArraySize(); ++arrayIndex)
{ {
TStringStream elementName; TStringStream elementName;
elementName << namePrefix << "_" << arrayIndex; elementName << namePrefix << "_" << arrayIndex;
......
...@@ -193,8 +193,6 @@ class TType ...@@ -193,8 +193,6 @@ class TType
layoutQualifier(TLayoutQualifier::create()), layoutQualifier(TLayoutQualifier::create()),
primarySize(0), primarySize(0),
secondarySize(0), secondarySize(0),
array(false),
arraySize(0),
interfaceBlock(nullptr), interfaceBlock(nullptr),
structure(nullptr) structure(nullptr)
{ {
...@@ -208,8 +206,6 @@ class TType ...@@ -208,8 +206,6 @@ class TType
layoutQualifier(TLayoutQualifier::create()), layoutQualifier(TLayoutQualifier::create()),
primarySize(ps), primarySize(ps),
secondarySize(ss), secondarySize(ss),
array(false),
arraySize(0),
interfaceBlock(0), interfaceBlock(0),
structure(0) structure(0)
{ {
...@@ -218,8 +214,7 @@ class TType ...@@ -218,8 +214,7 @@ class TType
TPrecision p, TPrecision p,
TQualifier q = EvqTemporary, TQualifier q = EvqTemporary,
unsigned char ps = 1, unsigned char ps = 1,
unsigned char ss = 1, unsigned char ss = 1)
bool a = false)
: type(t), : type(t),
precision(p), precision(p),
qualifier(q), qualifier(q),
...@@ -228,8 +223,6 @@ class TType ...@@ -228,8 +223,6 @@ class TType
layoutQualifier(TLayoutQualifier::create()), layoutQualifier(TLayoutQualifier::create()),
primarySize(ps), primarySize(ps),
secondarySize(ss), secondarySize(ss),
array(a),
arraySize(0),
interfaceBlock(0), interfaceBlock(0),
structure(0) structure(0)
{ {
...@@ -244,16 +237,13 @@ class TType ...@@ -244,16 +237,13 @@ class TType
layoutQualifier(TLayoutQualifier::create()), layoutQualifier(TLayoutQualifier::create()),
primarySize(1), primarySize(1),
secondarySize(1), secondarySize(1),
array(false),
arraySize(0),
interfaceBlock(0), interfaceBlock(0),
structure(userDef) structure(userDef)
{ {
} }
TType(TInterfaceBlock *interfaceBlockIn, TType(TInterfaceBlock *interfaceBlockIn,
TQualifier qualifierIn, TQualifier qualifierIn,
TLayoutQualifier layoutQualifierIn, TLayoutQualifier layoutQualifierIn)
unsigned int arraySizeIn)
: type(EbtInterfaceBlock), : type(EbtInterfaceBlock),
precision(EbpUndefined), precision(EbpUndefined),
qualifier(qualifierIn), qualifier(qualifierIn),
...@@ -262,8 +252,6 @@ class TType ...@@ -262,8 +252,6 @@ class TType
layoutQualifier(layoutQualifierIn), layoutQualifier(layoutQualifierIn),
primarySize(1), primarySize(1),
secondarySize(1), secondarySize(1),
array(arraySizeIn > 0),
arraySize(arraySizeIn),
interfaceBlock(interfaceBlockIn), interfaceBlock(interfaceBlockIn),
structure(0) structure(0)
{ {
...@@ -337,25 +325,38 @@ class TType ...@@ -337,25 +325,38 @@ class TType
bool isMatrix() const { return primarySize > 1 && secondarySize > 1; } bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; } bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; }
bool isArray() const { return array; } bool isArray() const { return !mArraySizes.empty(); }
bool isUnsizedArray() const { return array && arraySize == 0u; } bool isArrayOfArrays() const { return mArraySizes.size() > 1u; }
unsigned int getArraySize() const { return arraySize; } const TVector<unsigned int> &getArraySizes() const { return mArraySizes; }
void setArraySize(unsigned int s) unsigned int getArraySizeProduct() const;
{ bool isUnsizedArray() const;
if (!array || arraySize != s) unsigned int getOutermostArraySize() const { return mArraySizes.back(); }
void makeArray(unsigned int s)
{
mArraySizes.push_back(s);
invalidateMangledName();
}
// Here, the array dimension value 0 corresponds to the innermost array.
void setArraySize(size_t arrayDimension, unsigned int s)
{
ASSERT(arrayDimension < mArraySizes.size());
if (mArraySizes.at(arrayDimension) != s)
{ {
array = true; mArraySizes[arrayDimension] = s;
arraySize = s;
invalidateMangledName(); invalidateMangledName();
} }
} }
void setArrayUnsized() { setArraySize(0u); }
void clearArrayness() // Will set unsized array sizes according to arraySizes. In case there are more unsized arrays
// than there are sizes in arraySizes, defaults to setting array sizes to 1.
void sizeUnsizedArrays(const TVector<unsigned int> &arraySizes);
// Note that the array element type might still be an array type in GLSL ES version >= 3.10.
void toArrayElementType()
{ {
if (array) if (mArraySizes.size() > 0)
{ {
array = false; mArraySizes.pop_back();
arraySize = 0u;
invalidateMangledName(); invalidateMangledName();
} }
} }
...@@ -372,7 +373,10 @@ class TType ...@@ -372,7 +373,10 @@ class TType
bool isInterfaceBlock() const { return type == EbtInterfaceBlock; } bool isInterfaceBlock() const { return type == EbtInterfaceBlock; }
bool isVector() const { return primarySize > 1 && secondarySize == 1; } bool isVector() const { return primarySize > 1 && secondarySize == 1; }
bool isScalar() const { return primarySize == 1 && secondarySize == 1 && !structure && !array; } bool isScalar() const
{
return primarySize == 1 && secondarySize == 1 && !structure && !isArray();
}
bool isScalarFloat() const { return isScalar() && type == EbtFloat; } bool isScalarFloat() const { return isScalar() && type == EbtFloat; }
bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); } bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); }
...@@ -399,16 +403,16 @@ class TType ...@@ -399,16 +403,16 @@ class TType
return mangled; return mangled;
} }
bool sameElementType(const TType &right) const bool sameNonArrayType(const TType &right) const;
{
return type == right.type && primarySize == right.primarySize && // Returns true if arrayType is an array made of this type.
secondarySize == right.secondarySize && structure == right.structure; bool isElementTypeOf(const TType &arrayType) const;
}
bool operator==(const TType &right) const bool operator==(const TType &right) const
{ {
return type == right.type && primarySize == right.primarySize && return type == right.type && primarySize == right.primarySize &&
secondarySize == right.secondarySize && array == right.array && secondarySize == right.secondarySize && mArraySizes == right.mArraySizes &&
(!array || arraySize == right.arraySize) && structure == right.structure; structure == right.structure;
// don't check the qualifier, it's not ever what's being sought after // don't check the qualifier, it's not ever what's being sought after
} }
bool operator!=(const TType &right) const { return !operator==(right); } bool operator!=(const TType &right) const { return !operator==(right); }
...@@ -420,10 +424,13 @@ class TType ...@@ -420,10 +424,13 @@ class TType
return primarySize < right.primarySize; return primarySize < right.primarySize;
if (secondarySize != right.secondarySize) if (secondarySize != right.secondarySize)
return secondarySize < right.secondarySize; return secondarySize < right.secondarySize;
if (array != right.array) if (mArraySizes.size() != right.mArraySizes.size())
return array < right.array; return mArraySizes.size() < right.mArraySizes.size();
if (arraySize != right.arraySize) for (size_t i = 0; i < mArraySizes.size(); ++i)
return arraySize < right.arraySize; {
if (mArraySizes[i] != right.mArraySizes[i])
return mArraySizes[i] < right.mArraySizes[i];
}
if (structure != right.structure) if (structure != right.structure)
return structure < right.structure; return structure < right.structure;
...@@ -488,8 +495,10 @@ class TType ...@@ -488,8 +495,10 @@ class TType
TLayoutQualifier layoutQualifier; TLayoutQualifier layoutQualifier;
unsigned char primarySize; // size of vector or cols matrix unsigned char primarySize; // size of vector or cols matrix
unsigned char secondarySize; // rows of a matrix unsigned char secondarySize; // rows of a matrix
bool array;
unsigned int arraySize; // Used to make an array type. Outermost array size is stored at the end of the vector. Having 0
// in this vector means an unsized array.
TVector<unsigned int> mArraySizes;
// This is set only in the following two cases: // This is set only in the following two cases:
// 1) Represents an interface block. // 1) Represents an interface block.
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
namespace sh namespace sh
{ {
namespace
{
static const char *UniformRegisterPrefix(const TType &type) static const char *UniformRegisterPrefix(const TType &type)
{ {
if (IsSampler(type.getBasicType())) if (IsSampler(type.getBasicType()))
...@@ -61,6 +64,34 @@ static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) ...@@ -61,6 +64,34 @@ static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
return DecoratePrivate(interfaceBlock.name()) + "_type"; return DecoratePrivate(interfaceBlock.name()) + "_type";
} }
void OutputSamplerIndexArrayInitializer(TInfoSinkBase &out,
const TType &type,
unsigned int startIndex)
{
out << "{";
TType elementType(type);
elementType.toArrayElementType();
for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
{
if (i > 0u)
{
out << ", ";
}
if (elementType.isArray())
{
OutputSamplerIndexArrayInitializer(out, elementType,
startIndex + i * elementType.getArraySizeProduct());
}
else
{
out << (startIndex + i);
}
}
out << "}";
}
} // anonymous namespace
UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL,
ShShaderOutput outputType, ShShaderOutput outputType,
const std::vector<Uniform> &uniforms) const std::vector<Uniform> &uniforms)
...@@ -133,7 +164,7 @@ unsigned int UniformHLSL::assignSamplerInStructUniformRegister(const TType &type ...@@ -133,7 +164,7 @@ unsigned int UniformHLSL::assignSamplerInStructUniformRegister(const TType &type
ASSERT(IsSampler(type.getBasicType())); ASSERT(IsSampler(type.getBasicType()));
unsigned int registerIndex = mSamplerRegister; unsigned int registerIndex = mSamplerRegister;
mUniformRegisterMap[std::string(name.c_str())] = registerIndex; mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
unsigned int registerCount = type.isArray() ? type.getArraySize() : 1u; unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u;
mSamplerRegister += registerCount; mSamplerRegister += registerCount;
if (outRegisterCount) if (outRegisterCount)
{ {
...@@ -179,14 +210,9 @@ void UniformHLSL::outputHLSLSamplerUniformGroup( ...@@ -179,14 +210,9 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(
if (type.isArray()) if (type.isArray())
{ {
out << "static const uint " << DecorateVariableIfNeeded(uniform->getName()) out << "static const uint " << DecorateVariableIfNeeded(uniform->getName())
<< ArrayString(type) << " = {"; << ArrayString(type) << " = ";
for (unsigned int i = 0u; i < type.getArraySize(); ++i) OutputSamplerIndexArrayInitializer(out, type, samplerArrayIndex);
{ out << ";\n";
if (i > 0u)
out << ", ";
out << (samplerArrayIndex + i);
}
out << "};\n";
} }
else else
{ {
...@@ -365,8 +391,11 @@ TString UniformHLSL::uniformBlocksHeader(const ReferencedSymbols &referencedInte ...@@ -365,8 +391,11 @@ TString UniformHLSL::uniformBlocksHeader(const ReferencedSymbols &referencedInte
// nodeType.isInterfaceBlock() == false means the node is a field of a uniform block which // nodeType.isInterfaceBlock() == false means the node is a field of a uniform block which
// doesn't have instance name, so this block cannot be an array. // doesn't have instance name, so this block cannot be an array.
unsigned int interfaceBlockArraySize = unsigned int interfaceBlockArraySize = 0u;
nodeType.isInterfaceBlock() ? nodeType.getArraySize() : 0; if (nodeType.isInterfaceBlock() && nodeType.isArray())
{
interfaceBlockArraySize = nodeType.getOutermostArraySize();
}
unsigned int activeRegister = mUniformBlockRegister; unsigned int activeRegister = mUniformBlockRegister;
mUniformBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister; mUniformBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister;
......
...@@ -95,7 +95,9 @@ void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const ...@@ -95,7 +95,9 @@ void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const
for (const auto &symbol : mOutputs) for (const auto &symbol : mOutputs)
{ {
const TType &type = symbol->getType(); const TType &type = symbol->getType();
const size_t elementCount = static_cast<size_t>(type.isArray() ? type.getArraySize() : 1u); ASSERT(!type.isArrayOfArrays()); // Disallowed in GLSL ES 3.10 section 4.3.6.
const size_t elementCount =
static_cast<size_t>(type.isArray() ? type.getOutermostArraySize() : 1u);
const size_t location = static_cast<size_t>(type.getLayoutQualifier().location); const size_t location = static_cast<size_t>(type.getLayoutQualifier().location);
ASSERT(type.getLayoutQualifier().location != -1); ASSERT(type.getLayoutQualifier().location != -1);
......
...@@ -437,12 +437,14 @@ GLenum GLVariablePrecision(const TType &type) ...@@ -437,12 +437,14 @@ GLenum GLVariablePrecision(const TType &type)
TString ArrayString(const TType &type) TString ArrayString(const TType &type)
{ {
if (!type.isArray()) TStringStream arrayString;
const TVector<unsigned int> &arraySizes = type.getArraySizes();
for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend();
++arraySizeIter)
{ {
return ""; arrayString << "[" << (*arraySizeIter) << "]";
} }
return arrayString.str();
return "[" + str(type.getArraySize()) + "]";
} }
bool IsVaryingOut(TQualifier qualifier) bool IsVaryingOut(TQualifier qualifier)
......
...@@ -39,6 +39,9 @@ bool IsVaryingIn(TQualifier qualifier); ...@@ -39,6 +39,9 @@ bool IsVaryingIn(TQualifier qualifier);
bool IsVaryingOut(TQualifier qualifier); bool IsVaryingOut(TQualifier qualifier);
bool IsVarying(TQualifier qualifier); bool IsVarying(TQualifier qualifier);
InterpolationType GetInterpolationType(TQualifier qualifier); InterpolationType GetInterpolationType(TQualifier qualifier);
// Returns array brackets including size with outermost array size first, as specified in GLSL ES
// 3.10 section 4.1.9.
TString ArrayString(const TType &type); TString ArrayString(const TType &type);
TType GetShaderVariableBasicType(const sh::ShaderVariable &var); TType GetShaderVariableBasicType(const sh::ShaderVariable &var);
......
...@@ -71,7 +71,7 @@ ExpectedLValues CreateIndexedLValueNodeList(const TString &lValueName, ...@@ -71,7 +71,7 @@ ExpectedLValues CreateIndexedLValueNodeList(const TString &lValueName,
unsigned arraySize) unsigned arraySize)
{ {
ASSERT(elementType.isArray() == false); ASSERT(elementType.isArray() == false);
elementType.setArraySize(arraySize); elementType.makeArray(arraySize);
ExpectedLValues expected(arraySize); ExpectedLValues expected(arraySize);
for (unsigned index = 0u; index < arraySize; ++index) for (unsigned index = 0u; index < arraySize; ++index)
......
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