Support arrays of arrays in the API
The ShaderVariable class that is used as an interface between the
compiler and the rest of the code gets arrays of arrays support.
Array of array variables are passed from the compiler just like any
other variables. However, when stored in Program state each innermost
array constitutes a separate variable. This is done to make the
implementation match the GLES specification for program interface
query APIs.
This will be tested more fully once support for parsing arrays of
arrays lands in the compiler.
TEST=angle_end2end_tests, angle_unittests
BUG=angleproject:2125
Change-Id: I0f7159000f039be92a87a52b3b68cd9a215a21cb
Reviewed-on: https://chromium-review.googlesource.com/684742
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/CollectVariables.cpp b/src/compiler/translator/CollectVariables.cpp
index 0e92f9d..1fa86bb 100644
--- a/src/compiler/translator/CollectVariables.cpp
+++ b/src/compiler/translator/CollectVariables.cpp
@@ -262,8 +262,7 @@
info->name = name;
info->mappedName = name;
info->type = GLVariableType(type);
- ASSERT(!type.isArrayOfArrays());
- info->arraySize = type.isArray() ? type.getOutermostArraySize() : 0;
+ info->arraySizes.assign(type.getArraySizes().begin(), type.getArraySizes().end());
info->precision = GLVariablePrecision(type);
}
@@ -485,7 +484,8 @@
setBuiltInInfoFromSymbolTable("gl_FragData", &info);
if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
{
- info.arraySize = 1;
+ ASSERT(info.arraySizes.size() == 1u);
+ info.arraySizes.back() = 1u;
}
info.staticUse = true;
mOutputVariables->push_back(info);
@@ -581,10 +581,7 @@
variableOut->name = name.getString().c_str();
variableOut->mappedName = getMappedName(name);
- // 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;
+ variableOut->arraySizes.assign(type.getArraySizes().begin(), type.getArraySizes().end());
}
Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
@@ -677,7 +674,6 @@
setCommonVariableProperties(fieldType, TName(field->name()), &fieldVariable);
fieldVariable.isRowMajorLayout =
(fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
- fieldVariable.isUnsizedArray = fieldType.isUnsizedArray();
interfaceBlock->fields.push_back(fieldVariable);
}
}
diff --git a/src/compiler/translator/EmulateGLFragColorBroadcast.cpp b/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
index 554f0aa..189ea34 100644
--- a/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
+++ b/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
@@ -119,7 +119,8 @@
// TODO(zmo): Find a way to keep the original variable information.
var.name = "gl_FragData";
var.mappedName = "gl_FragData";
- var.arraySize = maxDrawBuffers;
+ var.arraySizes.push_back(maxDrawBuffers);
+ ASSERT(var.arraySizes.size() == 1u);
}
}
}
diff --git a/src/compiler/translator/ShaderVars.cpp b/src/compiler/translator/ShaderVars.cpp
index ae8027e..4ab574e 100644
--- a/src/compiler/translator/ShaderVars.cpp
+++ b/src/compiler/translator/ShaderVars.cpp
@@ -10,6 +10,7 @@
#include <GLSLANG/ShaderLang.h>
#include "common/debug.h"
+#include "common/utilities.h"
namespace sh
{
@@ -31,19 +32,20 @@
}
ShaderVariable::ShaderVariable()
- : type(0), precision(0), arraySize(0), staticUse(false), isUnsizedArray(false)
+ : type(0), precision(0), flattenedOffsetInParentArrays(0), staticUse(false)
{
}
ShaderVariable::ShaderVariable(GLenum typeIn)
- : type(typeIn), precision(0), arraySize(0), staticUse(false), isUnsizedArray(false)
+ : type(typeIn), precision(0), flattenedOffsetInParentArrays(0), staticUse(false)
{
}
ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn)
- : type(typeIn), precision(0), arraySize(arraySizeIn), staticUse(false), isUnsizedArray(false)
+ : type(typeIn), precision(0), flattenedOffsetInParentArrays(0), staticUse(false)
{
ASSERT(arraySizeIn != 0);
+ arraySizes.push_back(arraySizeIn);
}
ShaderVariable::~ShaderVariable()
@@ -55,11 +57,11 @@
precision(other.precision),
name(other.name),
mappedName(other.mappedName),
- arraySize(other.arraySize),
+ arraySizes(other.arraySizes),
+ flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays),
staticUse(other.staticUse),
fields(other.fields),
- structName(other.structName),
- isUnsizedArray(other.isUnsizedArray)
+ structName(other.structName)
{
}
@@ -69,20 +71,20 @@
precision = other.precision;
name = other.name;
mappedName = other.mappedName;
- arraySize = other.arraySize;
+ arraySizes = other.arraySizes;
staticUse = other.staticUse;
+ flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
fields = other.fields;
structName = other.structName;
- isUnsizedArray = other.isUnsizedArray;
return *this;
}
bool ShaderVariable::operator==(const ShaderVariable &other) const
{
if (type != other.type || precision != other.precision || name != other.name ||
- mappedName != other.mappedName || arraySize != other.arraySize ||
+ mappedName != other.mappedName || arraySizes != other.arraySizes ||
staticUse != other.staticUse || fields.size() != other.fields.size() ||
- structName != other.structName || isUnsizedArray != other.isUnsizedArray)
+ structName != other.structName)
{
return false;
}
@@ -94,6 +96,49 @@
return true;
}
+void ShaderVariable::setArraySize(unsigned int size)
+{
+ arraySizes.clear();
+ if (size != 0)
+ {
+ arraySizes.push_back(size);
+ }
+}
+
+unsigned int ShaderVariable::getArraySizeProduct() const
+{
+ return gl::ArraySizeProduct(arraySizes);
+}
+
+void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
+{
+ ASSERT(isArray());
+ flattenedOffsetInParentArrays =
+ arrayIndex + getOutermostArraySize() * flattenedOffsetInParentArrays;
+ arraySizes.pop_back();
+}
+
+unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const
+{
+ ASSERT(arraySizes.size() > arrayNestingIndex);
+ return arraySizes[arraySizes.size() - 1u - arrayNestingIndex];
+}
+
+unsigned int ShaderVariable::getBasicTypeElementCount() const
+{
+ // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated
+ // for each array element when dealing with an array of arrays or an array of structs.
+ ASSERT(!isArrayOfArrays());
+ ASSERT(!isStruct() || !isArray());
+
+ // GLES 3.1 Nov 2016 page 82.
+ if (isArray())
+ {
+ return getOutermostArraySize();
+ }
+ return 1u;
+}
+
bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName,
const ShaderVariable **leafVar,
std::string *originalFullName) const
@@ -180,7 +225,7 @@
if (matchName && name != other.name)
return false;
ASSERT(!matchName || mappedName == other.mappedName);
- if (arraySize != other.arraySize)
+ if (arraySizes != other.arraySizes)
return false;
if (fields.size() != other.fields.size())
return false;
@@ -197,10 +242,6 @@
}
if (structName != other.structName)
return false;
- if (isUnsizedArray != other.isUnsizedArray)
- {
- return false;
- }
return true;
}
diff --git a/src/compiler/translator/VariablePacker.cpp b/src/compiler/translator/VariablePacker.cpp
index ae66008..6dd396f 100644
--- a/src/compiler/translator/VariablePacker.cpp
+++ b/src/compiler/translator/VariablePacker.cpp
@@ -41,14 +41,24 @@
}
void ExpandStructArrayVariable(const ShaderVariable &variable,
+ unsigned int arrayNestingIndex,
const std::string &name,
std::vector<ShaderVariable> *expanded)
{
- for (unsigned int arrayElement = 0u; arrayElement < variable.getOutermostArraySize();
- ++arrayElement)
+ // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
+ // innermost.
+ const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex);
+ for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
{
const std::string elementName = name + ArrayString(arrayElement);
- ExpandStructVariable(variable, elementName, expanded);
+ if (arrayNestingIndex + 1u < variable.arraySizes.size())
+ {
+ ExpandStructArrayVariable(variable, arrayNestingIndex + 1u, elementName, expanded);
+ }
+ else
+ {
+ ExpandStructVariable(variable, elementName, expanded);
+ }
}
}
@@ -60,7 +70,7 @@
{
if (variable.isArray())
{
- ExpandStructArrayVariable(variable, name, expanded);
+ ExpandStructArrayVariable(variable, 0u, name, expanded);
}
else
{
@@ -70,7 +80,6 @@
else
{
ShaderVariable expandedVar = variable;
-
expandedVar.name = name;
expanded->push_back(expandedVar);
@@ -79,7 +88,7 @@
int GetVariablePackingRows(const ShaderVariable &variable)
{
- return GetTypePackingRows(variable.type) * variable.elementCount();
+ return GetTypePackingRows(variable.type) * variable.getArraySizeProduct();
}
class VariablePacker
@@ -113,7 +122,7 @@
return lhsSortOrder < rhsSortOrder;
}
// Sort by largest first.
- return lhs.arraySize > rhs.arraySize;
+ return lhs.getArraySizeProduct() > rhs.getArraySizeProduct();
}
};
@@ -208,7 +217,7 @@
{
// Structs should have been expanded before reaching here.
ASSERT(!variable.isStruct());
- if (variable.elementCount() > maxVectors / GetTypePackingRows(variable.type))
+ if (variable.getArraySizeProduct() > maxVectors / GetTypePackingRows(variable.type))
{
return false;
}
diff --git a/src/compiler/translator/blocklayout.cpp b/src/compiler/translator/blocklayout.cpp
index 8488a28..e309e92 100644
--- a/src/compiler/translator/blocklayout.cpp
+++ b/src/compiler/translator/blocklayout.cpp
@@ -26,6 +26,46 @@
{
return false;
}
+
+template <typename VarT>
+void GetUniformBlockStructMemberInfo(const std::vector<VarT> &fields,
+ const std::string &fieldName,
+ sh::BlockLayoutEncoder *encoder,
+ bool inRowMajorLayout,
+ BlockLayoutMap *blockInfoOut)
+{
+ encoder->enterAggregateType();
+ GetUniformBlockInfo(fields, fieldName, encoder, inRowMajorLayout, blockInfoOut);
+ encoder->exitAggregateType();
+}
+
+template <typename VarT>
+void GetUniformBlockStructArrayMemberInfo(const VarT &field,
+ unsigned int arrayNestingIndex,
+ const std::string &prefix,
+ sh::BlockLayoutEncoder *encoder,
+ bool inRowMajorLayout,
+ BlockLayoutMap *blockInfoOut)
+{
+ // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
+ // innermost.
+ const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex);
+ for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
+ {
+ const std::string elementName = prefix + ArrayString(arrayElement);
+ if (arrayNestingIndex + 1u < field.arraySizes.size())
+ {
+ GetUniformBlockStructArrayMemberInfo(field, arrayNestingIndex + 1u, elementName,
+ encoder, inRowMajorLayout, blockInfoOut);
+ }
+ else
+ {
+ GetUniformBlockStructMemberInfo(field.fields, elementName, encoder, inRowMajorLayout,
+ blockInfoOut);
+ }
+ }
+}
+
} // anonymous namespace
BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0)
@@ -33,20 +73,20 @@
}
BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix)
{
int arrayStride;
int matrixStride;
- getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride);
+ getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride);
const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * BytesPerComponent),
static_cast<int>(arrayStride * BytesPerComponent),
static_cast<int>(matrixStride * BytesPerComponent),
isRowMajorMatrix);
- advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
+ advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride);
return memberInfo;
}
@@ -83,7 +123,7 @@
}
void Std140BlockEncoder::getBlockLayoutInfo(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int *arrayStrideOut,
int *matrixStrideOut)
@@ -100,13 +140,13 @@
baseAlignment = ComponentsPerRegister;
matrixStride = ComponentsPerRegister;
- if (arraySize > 0)
+ if (!arraySizes.empty())
{
const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
arrayStride = ComponentsPerRegister * numRegisters;
}
}
- else if (arraySize > 0)
+ else if (!arraySizes.empty())
{
baseAlignment = ComponentsPerRegister;
arrayStride = ComponentsPerRegister;
@@ -124,14 +164,14 @@
}
void Std140BlockEncoder::advanceOffset(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int arrayStride,
int matrixStride)
{
- if (arraySize > 0)
+ if (!arraySizes.empty())
{
- mCurrentOffset += arrayStride * arraySize;
+ mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes);
}
else if (gl::IsMatrixType(type))
{
@@ -148,13 +188,14 @@
template <typename VarT>
void GetUniformBlockInfo(const std::vector<VarT> &fields,
const std::string &prefix,
- BlockLayoutEncoder *encoder,
+ sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
- BlockLayoutMap *blockLayoutMap)
+ BlockLayoutMap *blockInfoOut)
{
for (const VarT &field : fields)
{
- // Skip samplers.
+ // Skip samplers. On Vulkan we use this for the default uniform block, so samplers may be
+ // included.
if (gl::IsSamplerType(field.type))
{
continue;
@@ -166,25 +207,22 @@
{
bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
- for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
+ if (field.isArray())
{
- encoder->enterAggregateType();
-
- const std::string uniformElementName =
- fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
- GetUniformBlockInfo(field.fields, uniformElementName, encoder, rowMajorLayout,
- blockLayoutMap);
-
- encoder->exitAggregateType();
+ GetUniformBlockStructArrayMemberInfo(field, 0u, fieldName, encoder, rowMajorLayout,
+ blockInfoOut);
+ }
+ else
+ {
+ GetUniformBlockStructMemberInfo(field.fields, fieldName, encoder, rowMajorLayout,
+ blockInfoOut);
}
}
else
{
bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout);
- const BlockMemberInfo &blockMemberInfo =
- encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
-
- (*blockLayoutMap)[fieldName] = blockMemberInfo;
+ (*blockInfoOut)[fieldName] =
+ encoder->encodeType(field.type, field.arraySizes, isRowMajorMatrix);
}
}
}
diff --git a/src/compiler/translator/blocklayout.h b/src/compiler/translator/blocklayout.h
index 9cefa8b..2b7acf4 100644
--- a/src/compiler/translator/blocklayout.h
+++ b/src/compiler/translator/blocklayout.h
@@ -73,7 +73,9 @@
BlockLayoutEncoder();
virtual ~BlockLayoutEncoder() {}
- BlockMemberInfo encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix);
+ BlockMemberInfo encodeType(GLenum type,
+ const std::vector<unsigned int> &arraySizes,
+ bool isRowMajorMatrix);
size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; }
@@ -92,15 +94,15 @@
void nextRegister();
virtual void getBlockLayoutInfo(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int *arrayStrideOut,
int *matrixStrideOut) = 0;
virtual void advanceOffset(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int arrayStride,
- int matrixStride) = 0;
+ int matrixStride) = 0;
};
// Block layout according to the std140 block layout
@@ -116,12 +118,12 @@
protected:
void getBlockLayoutInfo(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int *arrayStrideOut,
int *matrixStrideOut) override;
void advanceOffset(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int arrayStride,
int matrixStride) override;
diff --git a/src/compiler/translator/blocklayoutHLSL.cpp b/src/compiler/translator/blocklayoutHLSL.cpp
index 39b1a5b..867821f 100644
--- a/src/compiler/translator/blocklayoutHLSL.cpp
+++ b/src/compiler/translator/blocklayoutHLSL.cpp
@@ -30,7 +30,7 @@
}
void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int *arrayStrideOut,
int *matrixStrideOut)
@@ -46,7 +46,7 @@
// if variables are not to be packed, or we're about to
// pack a matrix or array, skip to the start of the next
// register
- if (!isPacked() || gl::IsMatrixType(type) || arraySize > 0)
+ if (!isPacked() || gl::IsMatrixType(type) || !arraySizes.empty())
{
nextRegister();
}
@@ -55,13 +55,13 @@
{
matrixStride = ComponentsPerRegister;
- if (arraySize > 0)
+ if (!arraySizes.empty())
{
const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
arrayStride = ComponentsPerRegister * numRegisters;
}
}
- else if (arraySize > 0)
+ else if (!arraySizes.empty())
{
arrayStride = ComponentsPerRegister;
}
@@ -79,16 +79,16 @@
}
void HLSLBlockEncoder::advanceOffset(GLenum typeIn,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int arrayStride,
int matrixStride)
{
GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn);
- if (arraySize > 0)
+ if (!arraySizes.empty())
{
- mCurrentOffset += arrayStride * (arraySize - 1);
+ mCurrentOffset += arrayStride * (gl::ArraySizeProduct(arraySizes) - 1);
}
if (gl::IsMatrixType(type))
@@ -135,7 +135,7 @@
{
if (variable.isStruct())
{
- for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++)
+ for (size_t arrayElement = 0; arrayElement < variable.getArraySizeProduct(); arrayElement++)
{
encoder->enterAggregateType();
@@ -150,7 +150,7 @@
else
{
// We operate only on varyings and uniforms, which do not have matrix layout qualifiers
- encoder->encodeType(variable.type, variable.arraySize, false);
+ encoder->encodeType(variable.type, variable.arraySizes, false);
}
}
diff --git a/src/compiler/translator/blocklayoutHLSL.h b/src/compiler/translator/blocklayoutHLSL.h
index d1a98c8..8f4a51a 100644
--- a/src/compiler/translator/blocklayoutHLSL.h
+++ b/src/compiler/translator/blocklayoutHLSL.h
@@ -45,12 +45,12 @@
protected:
void getBlockLayoutInfo(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int *arrayStrideOut,
int *matrixStrideOut) override;
void advanceOffset(GLenum type,
- unsigned int arraySize,
+ const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int arrayStride,
int matrixStride) override;