Array of array: Implement the core functionality: types, constructors, operations.
There will be subsequent commits to refine semantics, esp. version-specific semantics, as well as I/O functionality and restrictions. Note: I'm getting white-space differences in the preprocessor test results, which I'm not checking in. I think they need to be tagged as binary or something.
This commit is contained in:
parent
b35483587f
commit
65c78a0b62
23 changed files with 1344 additions and 185 deletions
|
|
@ -896,15 +896,32 @@ public:
|
|||
// and using only shallow copy
|
||||
TType(const TType& type, int derefIndex, bool rowMajor = false)
|
||||
{
|
||||
if (! type.isArray() && (type.basicType == EbtStruct || type.basicType == EbtBlock)) {
|
||||
if (type.isArray()) {
|
||||
shallowCopy(type);
|
||||
if (type.getArraySizes()->getNumDims() == 1) {
|
||||
arraySizes = nullptr;
|
||||
} else {
|
||||
// want our own copy of the array, so we can edit it
|
||||
arraySizes = new TArraySizes;
|
||||
arraySizes->copyDereferenced(*type.arraySizes);
|
||||
}
|
||||
} else if (type.basicType == EbtStruct || type.basicType == EbtBlock) {
|
||||
// do a structure dereference
|
||||
const TTypeList& memberList = *type.getStruct();
|
||||
shallowCopy(*memberList[derefIndex].type);
|
||||
return;
|
||||
} else {
|
||||
// do an array/vector/matrix dereference
|
||||
// do a vector/matrix dereference
|
||||
shallowCopy(type);
|
||||
dereference(rowMajor);
|
||||
if (matrixCols > 0) {
|
||||
if (rowMajor)
|
||||
vectorSize = matrixCols;
|
||||
else
|
||||
vectorSize = matrixRows;
|
||||
matrixCols = 0;
|
||||
matrixRows = 0;
|
||||
} else if (vectorSize > 1)
|
||||
vectorSize = 1;
|
||||
}
|
||||
}
|
||||
// for making structures, ...
|
||||
|
|
@ -990,28 +1007,13 @@ public:
|
|||
qualifier = parentType.qualifier;
|
||||
sampler = parentType.sampler;
|
||||
if (parentType.arraySizes)
|
||||
setArraySizes(parentType.arraySizes);
|
||||
newArraySizes(*parentType.arraySizes);
|
||||
if (parentType.userDef) {
|
||||
structure = parentType.userDef->getWritableStruct();
|
||||
setTypeName(parentType.userDef->getTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void dereference(bool rowMajor = false)
|
||||
{
|
||||
if (arraySizes)
|
||||
arraySizes = nullptr;
|
||||
else if (matrixCols > 0) {
|
||||
if (rowMajor)
|
||||
vectorSize = matrixCols;
|
||||
else
|
||||
vectorSize = matrixRows;
|
||||
matrixCols = 0;
|
||||
matrixRows = 0;
|
||||
} else if (vectorSize > 1)
|
||||
vectorSize = 1;
|
||||
}
|
||||
|
||||
virtual void hideMember() { basicType = EbtVoid; vectorSize = 1; }
|
||||
virtual bool hiddenMember() const { return basicType == EbtVoid; }
|
||||
|
||||
|
|
@ -1038,17 +1040,20 @@ public:
|
|||
virtual int getVectorSize() const { return vectorSize; }
|
||||
virtual int getMatrixCols() const { return matrixCols; }
|
||||
virtual int getMatrixRows() const { return matrixRows; }
|
||||
virtual int getArraySize() const { return arraySizes->getOuterSize(); }
|
||||
virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); }
|
||||
virtual int getCumulativeArraySize() const { return arraySizes->getCumulativeSize(); }
|
||||
virtual bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; }
|
||||
virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
|
||||
virtual const TArraySizes* getArraySizes() const { return arraySizes; }
|
||||
virtual TArraySizes& getArraySizes() { assert(arraySizes != nullptr); return *arraySizes; }
|
||||
|
||||
virtual bool isScalar() const { return vectorSize == 1 && ! isStruct() && ! isArray(); }
|
||||
virtual bool isVector() const { return vectorSize > 1; }
|
||||
virtual bool isMatrix() const { return matrixCols ? true : false; }
|
||||
virtual bool isArray() const { return arraySizes != nullptr; }
|
||||
virtual bool isExplicitlySizedArray() const { return isArray() && getArraySize() != UnsizedArraySize; }
|
||||
virtual bool isImplicitlySizedArray() const { return isArray() && getArraySize() == UnsizedArraySize && qualifier.storage != EvqBuffer; }
|
||||
virtual bool isRuntimeSizedArray() const { return isArray() && getArraySize() == UnsizedArraySize && qualifier.storage == EvqBuffer; }
|
||||
virtual bool isExplicitlySizedArray() const { return isArray() && getOuterArraySize() != UnsizedArraySize; }
|
||||
virtual bool isImplicitlySizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage != EvqBuffer; }
|
||||
virtual bool isRuntimeSizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage == EvqBuffer; }
|
||||
virtual bool isStruct() const { return structure != nullptr; }
|
||||
virtual bool isImage() const { return basicType == EbtSampler && getSampler().image; }
|
||||
|
||||
|
|
@ -1125,22 +1130,27 @@ public:
|
|||
assert(type.arraySizes != nullptr);
|
||||
*arraySizes = *type.arraySizes;
|
||||
}
|
||||
void setArraySizes(TArraySizes* s)
|
||||
void newArraySizes(const TArraySizes& s)
|
||||
{
|
||||
// For setting a fresh new set of array sizes, not yet worrying about sharing.
|
||||
arraySizes = new TArraySizes;
|
||||
assert(s != nullptr);
|
||||
*arraySizes = *s;
|
||||
*arraySizes = s;
|
||||
}
|
||||
void setArraySizes(const TType& type) { setArraySizes(type.arraySizes); }
|
||||
void changeArraySize(int s) { arraySizes->changeOuterSize(s); }
|
||||
void addArrayOuterSizes(const TArraySizes& s)
|
||||
{
|
||||
if (arraySizes == nullptr)
|
||||
newArraySizes(s);
|
||||
else
|
||||
arraySizes->addOuterSizes(s);
|
||||
}
|
||||
void changeOuterArraySize(int s) { arraySizes->changeOuterSize(s); }
|
||||
void setImplicitArraySize (int s) { arraySizes->setImplicitSize(s); }
|
||||
|
||||
// Recursively make the implicit array size the explicit array size, through the type tree.
|
||||
void adoptImplicitArraySizes()
|
||||
{
|
||||
if (isImplicitlySizedArray())
|
||||
changeArraySize(getImplicitArraySize());
|
||||
changeOuterArraySize(getImplicitArraySize());
|
||||
if (isStruct()) {
|
||||
for (int i = 0; i < (int)structure->size(); ++i)
|
||||
(*structure)[i].type->adoptImplicitArraySizes();
|
||||
|
|
@ -1151,7 +1161,7 @@ public:
|
|||
{
|
||||
return TType::getBasicString(basicType);
|
||||
}
|
||||
|
||||
|
||||
static const char* getBasicString(TBasicType t)
|
||||
{
|
||||
switch (t) {
|
||||
|
|
@ -1242,12 +1252,12 @@ public:
|
|||
p += snprintf(p, end - p, "writeonly ");
|
||||
p += snprintf(p, end - p, "%s ", getStorageQualifierString());
|
||||
if (arraySizes) {
|
||||
if (arraySizes->getOuterSize() == UnsizedArraySize) {
|
||||
p += snprintf(p, end - p, "implicitly-sized array of ");
|
||||
} else {
|
||||
for(int i = 0; i < (int)arraySizes->getNumDims() ; ++i) {
|
||||
p += snprintf(p, end - p, "%d-element array of ", (*arraySizes)[i]);
|
||||
}
|
||||
for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) {
|
||||
int size = arraySizes->getDimSize(i);
|
||||
if (size == 0)
|
||||
p += snprintf(p, end - p, "implicitly-sized array of ");
|
||||
else
|
||||
p += snprintf(p, end - p, "%d-element array of ", arraySizes->getDimSize(i));
|
||||
}
|
||||
}
|
||||
if (qualifier.precision != EpqNone)
|
||||
|
|
@ -1310,10 +1320,8 @@ public:
|
|||
else
|
||||
components = vectorSize;
|
||||
|
||||
if (isArray()) {
|
||||
// this function can only be used in paths that have a known array size
|
||||
assert(isExplicitlySizedArray());
|
||||
components *= getArraySize();
|
||||
if (arraySizes != nullptr) {
|
||||
components *= arraySizes->getCumulativeSize();
|
||||
}
|
||||
|
||||
return components;
|
||||
|
|
@ -1371,7 +1379,14 @@ public:
|
|||
bool sameArrayness(const TType& right) const
|
||||
{
|
||||
return ((arraySizes == nullptr && right.arraySizes == nullptr) ||
|
||||
(arraySizes && right.arraySizes && *arraySizes == *right.arraySizes));
|
||||
(arraySizes != nullptr && right.arraySizes != nullptr && *arraySizes == *right.arraySizes));
|
||||
}
|
||||
|
||||
// See if two type's arrayness match in everything except their outer dimension
|
||||
bool sameInnerArrayness(const TType& right) const
|
||||
{
|
||||
assert(arraySizes != nullptr && right.arraySizes != nullptr);
|
||||
return arraySizes->sameInnerArrayness(*right.arraySizes);
|
||||
}
|
||||
|
||||
// See if two type's elements match in all ways except basic type
|
||||
|
|
|
|||
|
|
@ -43,13 +43,13 @@
|
|||
|
||||
namespace glslang {
|
||||
|
||||
// This is used to mean there is no size yet, it is waiting to get a size from somewhere else.
|
||||
// Historically, this is not fully encapsulated, trying to catch them all...
|
||||
// This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else.
|
||||
const int UnsizedArraySize = 0;
|
||||
|
||||
//
|
||||
// TSmallArrayVector is used as the container for the set of sizes in TArraySizes.
|
||||
// It has generic-container semantics, while TArraySizes has array-of-array semantics.
|
||||
// That is, TSmallArrayVector should be more focused on mechanism and TArraySizes on policy.
|
||||
//
|
||||
struct TSmallArrayVector {
|
||||
//
|
||||
|
|
@ -101,9 +101,43 @@ struct TSmallArrayVector {
|
|||
sizes->push_back(e);
|
||||
}
|
||||
|
||||
void push_front(const TSmallArrayVector& newDims)
|
||||
{
|
||||
alloc();
|
||||
sizes->insert(sizes->begin(), newDims.sizes->begin(), newDims.sizes->end());
|
||||
}
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
assert(sizes != nullptr && sizes->size() > 0);
|
||||
if (sizes->size() == 1)
|
||||
dealloc();
|
||||
else
|
||||
sizes->erase(sizes->begin());
|
||||
}
|
||||
|
||||
// 'this' should currently not be holding anything, and copyNonFront
|
||||
// will make it hold a copy of all but the first element of rhs.
|
||||
// (This would be useful for making a type that is dereferenced by
|
||||
// one dimension.)
|
||||
void copyNonFront(const TSmallArrayVector& rhs)
|
||||
{
|
||||
assert(sizes == nullptr);
|
||||
if (rhs.size() > 1) {
|
||||
alloc();
|
||||
sizes->insert(sizes->begin(), rhs.sizes->begin() + 1, rhs.sizes->end());
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int operator[](int i) const
|
||||
{
|
||||
assert(sizes && (int)sizes->size() > i);
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
return (*sizes)[i];
|
||||
}
|
||||
|
||||
unsigned int& operator[](int i)
|
||||
{
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
return (*sizes)[i];
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +149,7 @@ struct TSmallArrayVector {
|
|||
return false;
|
||||
return *sizes == *rhs.sizes;
|
||||
}
|
||||
bool operator!=(const TSmallArrayVector& rhs) const { return ! operator==(rhs); }
|
||||
|
||||
protected:
|
||||
TSmallArrayVector(const TSmallArrayVector&);
|
||||
|
|
@ -127,6 +162,7 @@ protected:
|
|||
void dealloc()
|
||||
{
|
||||
delete sizes;
|
||||
sizes = nullptr;
|
||||
}
|
||||
|
||||
TVector<unsigned int>* sizes; // will either hold such a pointer, or in the future, hold the two array sizes
|
||||
|
|
@ -134,11 +170,17 @@ protected:
|
|||
|
||||
//
|
||||
// Represent an array, or array of arrays, to arbitrary depth. This is not
|
||||
// done through a hierarchy of types, but localized into this single cumulative object.
|
||||
// done through a hierarchy of types in a type tree, rather all contiguous arrayness
|
||||
// in the type hierarchy is localized into this single cumulative object.
|
||||
//
|
||||
// The arrayness in TTtype is a pointer, so that it can be non-allocated and zero
|
||||
// for the vast majority of types that are non-array types.
|
||||
//
|
||||
// Order Policy: these are all identical:
|
||||
// - left to right order within a contiguous set of ...[..][..][..]... in the source language
|
||||
// - index order 0, 1, 2, ... within the 'sizes' member below
|
||||
// - outer-most to inner-most
|
||||
//
|
||||
struct TArraySizes {
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
|
||||
|
|
@ -155,13 +197,57 @@ struct TArraySizes {
|
|||
|
||||
// translate from array-of-array semantics to container semantics
|
||||
int getNumDims() const { return sizes.size(); }
|
||||
int getDimSize(int dim) const { return sizes[dim]; }
|
||||
void setDimSize(int dim, int size) { sizes[dim] = size; }
|
||||
int getOuterSize() const { return sizes.front(); }
|
||||
void setOuterSize(int s) { sizes.push_back((unsigned)s); }
|
||||
int getCumulativeSize() const
|
||||
{
|
||||
int size = 1;
|
||||
for (int d = 0; d < sizes.size(); ++d) {
|
||||
// this only makes sense in paths that have a known array size
|
||||
assert(sizes[d] != UnsizedArraySize);
|
||||
size *= sizes[d];
|
||||
}
|
||||
return size;
|
||||
}
|
||||
void addInnerSize() { sizes.push_back((unsigned)UnsizedArraySize); }
|
||||
void addInnerSize(int s) { sizes.push_back((unsigned)s); }
|
||||
void changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
|
||||
int getImplicitSize() const { return (int)implicitArraySize; }
|
||||
void setImplicitSize(int s) { implicitArraySize = s; }
|
||||
int operator[](int i) const { return sizes[i]; }
|
||||
bool operator==(const TArraySizes& rhs) const { return sizes == rhs.sizes; }
|
||||
bool isInnerImplicit() const
|
||||
{
|
||||
for (int d = 1; d < sizes.size(); ++d) {
|
||||
if (sizes[d] == (unsigned)UnsizedArraySize)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
void addOuterSizes(const TArraySizes& s) { sizes.push_front(s.sizes); }
|
||||
void dereference() { sizes.pop_front(); }
|
||||
void copyDereferenced(const TArraySizes& rhs)
|
||||
{
|
||||
assert(sizes.size() == 0);
|
||||
if (rhs.sizes.size() > 1)
|
||||
sizes.copyNonFront(rhs.sizes);
|
||||
}
|
||||
|
||||
bool sameInnerArrayness(const TArraySizes& rhs) const
|
||||
{
|
||||
if (sizes.size() != rhs.sizes.size())
|
||||
return false;
|
||||
|
||||
for (int d = 1; d < sizes.size(); ++d) {
|
||||
if (sizes[d] != rhs.sizes[d])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator==(const TArraySizes& rhs) { return sizes == rhs.sizes; }
|
||||
bool operator!=(const TArraySizes& rhs) { return sizes != rhs.sizes; }
|
||||
|
||||
protected:
|
||||
TSmallArrayVector sizes;
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@
|
|||
// For the date, it uses the current date (when then script is run).
|
||||
|
||||
#define GLSLANG_REVISION "2.3.706"
|
||||
#define GLSLANG_DATE "09-Aug-2015"
|
||||
#define GLSLANG_DATE "10-Aug-2015"
|
||||
|
|
|
|||
|
|
@ -3276,9 +3276,9 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb
|
|||
if (version == 100 || IncludeLegacy(version, profile) || (! ForwardCompatibility && profile != EEsProfile && version < 420)) {
|
||||
TPrecisionQualifier pq = profile == EEsProfile ? EpqMedium : EpqNone;
|
||||
TType fragData(EbtFloat, EvqFragColor, pq, 4);
|
||||
TArraySizes* arraySizes = new TArraySizes;
|
||||
arraySizes->setOuterSize(resources.maxDrawBuffers);
|
||||
fragData.setArraySizes(arraySizes);
|
||||
TArraySizes& arraySizes = *new TArraySizes;
|
||||
arraySizes.addInnerSize(resources.maxDrawBuffers);
|
||||
fragData.newArraySizes(arraySizes);
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
|
||||
SpecialQualifier("gl_FragData", EvqFragColor, EbvFragData, symbolTable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -558,9 +558,9 @@ void TParseContext::checkIndex(const TSourceLoc& loc, const TType& type, int& in
|
|||
error(loc, "", "[", "index out of range '%d'", index);
|
||||
index = 0;
|
||||
} else if (type.isArray()) {
|
||||
if (type.isExplicitlySizedArray() && index >= type.getArraySize()) {
|
||||
if (type.isExplicitlySizedArray() && index >= type.getOuterArraySize()) {
|
||||
error(loc, "", "[", "array index out of range '%d'", index);
|
||||
index = type.getArraySize() - 1;
|
||||
index = type.getOuterArraySize() - 1;
|
||||
}
|
||||
} else if (type.isVector()) {
|
||||
if (index >= type.getVectorSize()) {
|
||||
|
|
@ -629,10 +629,10 @@ void TParseContext::fixIoArraySize(const TSourceLoc& loc, TType& type)
|
|||
return;
|
||||
|
||||
if (language == EShLangTessControl || language == EShLangTessEvaluation) {
|
||||
if (type.getArraySize() != resources.maxPatchVertices) {
|
||||
if (type.getOuterArraySize() != resources.maxPatchVertices) {
|
||||
if (type.isExplicitlySizedArray())
|
||||
error(loc, "tessellation input array size must be gl_MaxPatchVertices or implicitly sized", "[]", "");
|
||||
type.changeArraySize(resources.maxPatchVertices);
|
||||
type.changeOuterArraySize(resources.maxPatchVertices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -662,7 +662,7 @@ void TParseContext::handleIoResizeArrayAccess(const TSourceLoc& /*loc*/, TInterm
|
|||
if (symbolNode->getType().isImplicitlySizedArray()) {
|
||||
int newSize = getIoArrayImplicitSize();
|
||||
if (newSize)
|
||||
symbolNode->getWritableType().changeArraySize(newSize);
|
||||
symbolNode->getWritableType().changeOuterArraySize(newSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -710,8 +710,8 @@ int TParseContext::getIoArrayImplicitSize() const
|
|||
void TParseContext::checkIoArrayConsistency(const TSourceLoc& loc, int requiredSize, const char* feature, TType& type, const TString& name)
|
||||
{
|
||||
if (type.isImplicitlySizedArray())
|
||||
type.changeArraySize(requiredSize);
|
||||
else if (type.getArraySize() != requiredSize) {
|
||||
type.changeOuterArraySize(requiredSize);
|
||||
else if (type.getOuterArraySize() != requiredSize) {
|
||||
if (language == EShLangGeometry)
|
||||
error(loc, "inconsistent input primitive for array size of", feature, name.c_str());
|
||||
else if (language == EShLangTessControl)
|
||||
|
|
@ -1203,7 +1203,7 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction
|
|||
error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method");
|
||||
}
|
||||
} else
|
||||
length = type.getArraySize();
|
||||
length = type.getOuterArraySize();
|
||||
} else if (type.isMatrix())
|
||||
length = type.getMatrixCols();
|
||||
else if (type.isVector())
|
||||
|
|
@ -1993,17 +1993,41 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||
error(loc, "array constructor must have at least one argument", "constructor", "");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.isImplicitlySizedArray()) {
|
||||
// auto adapt the constructor type to the number of arguments
|
||||
type.changeArraySize(function.getParamCount());
|
||||
} else if (type.getArraySize() != function.getParamCount()) {
|
||||
type.changeOuterArraySize(function.getParamCount());
|
||||
} else if (type.getOuterArraySize() != function.getParamCount()) {
|
||||
error(loc, "array constructor needs one argument per array element", "constructor", "");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.isArrayOfArrays()) {
|
||||
// Types have to match, but we're still making the type.
|
||||
// Finish making the type, and the comparison is done later
|
||||
// when checking for conversion.
|
||||
TArraySizes& arraySizes = type.getArraySizes();
|
||||
|
||||
// At least the dimensionalities have to match.
|
||||
if (! function[0].type->isArray() || arraySizes.getNumDims() != function[0].type->getArraySizes().getNumDims() + 1) {
|
||||
error(loc, "array constructor argument not correct type to construct array element", "constructior", "");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (arraySizes.isInnerImplicit()) {
|
||||
// "Arrays of arrays ..., and the size for any dimension is optional"
|
||||
// That means we need to adopt (from the first argument) the other array sizes into the type.
|
||||
for (int d = 1; d < arraySizes.getNumDims(); ++d) {
|
||||
if (arraySizes.getDimSize(d) == UnsizedArraySize) {
|
||||
arraySizes.setDimSize(d, function[0].type->getArraySizes().getDimSize(d - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arrayArg && op != EOpConstructStruct) {
|
||||
error(loc, "constructing from a non-dereferenced array", "constructor", "");
|
||||
if (arrayArg && op != EOpConstructStruct && ! type.isArrayOfArrays()) {
|
||||
error(loc, "constructing non-array constituent from array argument", "constructor", "");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2490,13 +2514,13 @@ bool TParseContext::arrayError(const TSourceLoc& loc, const TType& type)
|
|||
if (type.getQualifier().storage == EvqVaryingOut && language == EShLangVertex) {
|
||||
if (type.isArrayOfArrays())
|
||||
requireProfile(loc, ~EEsProfile, "vertex-shader array-of-array output");
|
||||
else if (type.getArraySize() && type.isStruct())
|
||||
else if (type.isStruct())
|
||||
requireProfile(loc, ~EEsProfile, "vertex-shader array-of-struct output");
|
||||
}
|
||||
if (type.getQualifier().storage == EvqVaryingIn && language == EShLangFragment) {
|
||||
if (type.isArrayOfArrays())
|
||||
requireProfile(loc, ~EEsProfile, "fragment-shader array-of-array input");
|
||||
else if (type.getArraySize() && type.isStruct())
|
||||
else if (type.isStruct())
|
||||
requireProfile(loc, ~EEsProfile, "fragment-shader array-of-struct input");
|
||||
}
|
||||
|
||||
|
|
@ -2522,11 +2546,24 @@ void TParseContext::structArrayCheck(const TSourceLoc& /*loc*/, const TType& typ
|
|||
}
|
||||
}
|
||||
|
||||
void TParseContext::arrayUnsizedCheck(const TSourceLoc& loc, const TQualifier& qualifier, int size, bool initializer)
|
||||
void TParseContext::arrayUnsizedCheck(const TSourceLoc& loc, const TQualifier& qualifier, const TArraySizes* arraySizes, bool initializer)
|
||||
{
|
||||
// desktop always allows unsized variable arrays,
|
||||
// ES always allows them if there is an initializer present to get the size from
|
||||
if (parsingBuiltins || profile != EEsProfile || initializer)
|
||||
assert(arraySizes);
|
||||
|
||||
// always allow special built-in ins/outs sized to topologies
|
||||
if (parsingBuiltins)
|
||||
return;
|
||||
|
||||
// always allow an initializer to set any unknown array sizes
|
||||
if (initializer)
|
||||
return;
|
||||
|
||||
// No environment lets any non-outer-dimension that's to be implicitly sized
|
||||
if (arraySizes->isInnerImplicit())
|
||||
error(loc, "only outermost dimension of an array of arrays can be implicitly sized", "[]", "");
|
||||
|
||||
// desktop always allows outer-dimension-unsized variable arrays,
|
||||
if (profile != EEsProfile)
|
||||
return;
|
||||
|
||||
// for ES, if size isn't coming from an initializer, it has to be explicitly declared now,
|
||||
|
|
@ -2553,7 +2590,7 @@ void TParseContext::arrayUnsizedCheck(const TSourceLoc& loc, const TQualifier& q
|
|||
break;
|
||||
}
|
||||
|
||||
arraySizeRequiredCheck(loc, size);
|
||||
arraySizeRequiredCheck(loc, arraySizes->getOuterSize());
|
||||
}
|
||||
|
||||
void TParseContext::arrayOfArrayVersionCheck(const TSourceLoc& loc)
|
||||
|
|
@ -2563,15 +2600,9 @@ void TParseContext::arrayOfArrayVersionCheck(const TSourceLoc& loc)
|
|||
requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
|
||||
profileRequires(loc, EEsProfile, 310, nullptr, feature);
|
||||
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, feature);
|
||||
|
||||
static int once = false;
|
||||
if (! once) {
|
||||
warn(loc, feature, "Not supported yet.", "");
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
|
||||
void TParseContext::arrayDimCheck(const TSourceLoc& loc, TArraySizes* sizes1, TArraySizes* sizes2)
|
||||
void TParseContext::arrayDimCheck(const TSourceLoc& loc, const TArraySizes* sizes1, const TArraySizes* sizes2)
|
||||
{
|
||||
if ((sizes1 && sizes2) ||
|
||||
(sizes1 && sizes1->getNumDims() > 1) ||
|
||||
|
|
@ -2579,13 +2610,28 @@ void TParseContext::arrayDimCheck(const TSourceLoc& loc, TArraySizes* sizes1, TA
|
|||
arrayOfArrayVersionCheck(loc);
|
||||
}
|
||||
|
||||
void TParseContext::arrayDimCheck(const TSourceLoc& loc, const TType* type, TArraySizes* sizes2)
|
||||
void TParseContext::arrayDimCheck(const TSourceLoc& loc, const TType* type, const TArraySizes* sizes2)
|
||||
{
|
||||
// skip checking for multiple dimensions on the type; it was caught earlier
|
||||
if ((type && type->isArray() && sizes2) ||
|
||||
(sizes2 && sizes2->getNumDims() > 1))
|
||||
arrayOfArrayVersionCheck(loc);
|
||||
}
|
||||
|
||||
// Merge array dimensions listed in 'sizes' onto the type's array dimensions.
|
||||
//
|
||||
// From the spec: "vec4[2] a[3]; // size-3 array of size-2 array of vec4"
|
||||
//
|
||||
// That means, the 'sizes' go in front of the 'type' as outermost sizes.
|
||||
// 'type' is the type part of the declaration (to the left)
|
||||
// 'sizes' is the arrayness tagged on the identifier (to the right)
|
||||
//
|
||||
void TParseContext::arrayDimMerge(TType& type, const TArraySizes* sizes)
|
||||
{
|
||||
if (sizes)
|
||||
type.addArrayOuterSizes(*sizes);
|
||||
}
|
||||
|
||||
//
|
||||
// Do all the semantic checking for declaring or redeclaring an array, with and
|
||||
// without a size, and make the right changes to the symbol table.
|
||||
|
|
@ -2642,19 +2688,25 @@ void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, con
|
|||
error(loc, "redeclaring non-array as array", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
if (! existingType.sameElementType(type)) {
|
||||
error(loc, "redeclaration of array with a different element type", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
if (! existingType.sameInnerArrayness(type)) {
|
||||
error(loc, "redeclaration of array with a different array dimensions or sizes", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingType.isExplicitlySizedArray()) {
|
||||
// be more leniant for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size
|
||||
if (! (isIoResizeArray(type) && existingType.getArraySize() == type.getArraySize()))
|
||||
if (! (isIoResizeArray(type) && existingType.getOuterArraySize() == type.getOuterArraySize()))
|
||||
error(loc, "redeclaration of array with size", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
if (! existingType.sameElementType(type)) {
|
||||
error(loc, "redeclaration of array with a different type", identifier.c_str(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
arrayLimitCheck(loc, identifier, type.getArraySize());
|
||||
arrayLimitCheck(loc, identifier, type.getOuterArraySize());
|
||||
|
||||
existingType.updateArraySizes(type);
|
||||
|
||||
|
|
@ -2954,7 +3006,7 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
|
|||
else if (! oldType.sameArrayness(newType) && oldType.isExplicitlySizedArray())
|
||||
error(memberLoc, "cannot change array size of redeclared block member", member->type->getFieldName().c_str(), "");
|
||||
else if (newType.isArray())
|
||||
arrayLimitCheck(loc, member->type->getFieldName(), newType.getArraySize());
|
||||
arrayLimitCheck(loc, member->type->getFieldName(), newType.getOuterArraySize());
|
||||
if (newType.getQualifier().isMemory())
|
||||
error(memberLoc, "cannot add memory qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
|
||||
if (newType.getQualifier().hasLayout())
|
||||
|
|
@ -2990,10 +3042,10 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
|
|||
else if (type.isArray()) {
|
||||
if (type.isExplicitlySizedArray() && arraySizes->getOuterSize() == UnsizedArraySize)
|
||||
error(loc, "block already declared with size, can't redeclare as implicitly-sized", blockName.c_str(), "");
|
||||
else if (type.isExplicitlySizedArray() && type.getArraySize() != arraySizes->getOuterSize())
|
||||
else if (type.isExplicitlySizedArray() && type.getArraySizes() != *arraySizes)
|
||||
error(loc, "cannot change array size of redeclared block", blockName.c_str(), "");
|
||||
else if (type.isImplicitlySizedArray() && arraySizes->getOuterSize() != UnsizedArraySize)
|
||||
type.changeArraySize(arraySizes->getOuterSize());
|
||||
type.changeOuterArraySize(arraySizes->getOuterSize());
|
||||
}
|
||||
|
||||
symbolTable.insert(*block);
|
||||
|
|
@ -3224,7 +3276,7 @@ void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init,
|
|||
inductiveLoopBodyCheck(loop->getBody(), loopIndex, symbolTable);
|
||||
}
|
||||
|
||||
// Do limit checks against for all built-in arrays.
|
||||
// Do limit checks for built-in arrays.
|
||||
void TParseContext::arrayLimitCheck(const TSourceLoc& loc, const TString& identifier, int size)
|
||||
{
|
||||
if (identifier.compare("gl_TexCoord") == 0)
|
||||
|
|
@ -3806,7 +3858,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
if (type.getBasicType() == EbtSampler) {
|
||||
int lastBinding = qualifier.layoutBinding;
|
||||
if (type.isArray())
|
||||
lastBinding += type.getArraySize();
|
||||
lastBinding += type.getCumulativeArraySize();
|
||||
if (lastBinding >= resources.maxCombinedTextureImageUnits)
|
||||
error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : "");
|
||||
}
|
||||
|
|
@ -3990,7 +4042,7 @@ void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol)
|
|||
// Check for overlap
|
||||
int numOffsets = 4;
|
||||
if (symbol.getType().isArray())
|
||||
numOffsets *= symbol.getType().getArraySize();
|
||||
numOffsets *= symbol.getType().getCumulativeArraySize();
|
||||
int repeated = intermediate.addUsedOffsets(qualifier.layoutBinding, offset, numOffsets);
|
||||
if (repeated >= 0)
|
||||
error(loc, "atomic counters sharing the same offset:", "offset", "%d", repeated);
|
||||
|
|
@ -4138,6 +4190,9 @@ void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType
|
|||
// Returns a subtree node that computes an initializer, if needed.
|
||||
// Returns nullptr if there is no code to execute for initialization.
|
||||
//
|
||||
// 'publicType' is the type part of the declaration (to the left)
|
||||
// 'arraySizes' is the arrayness tagged on the identifier (to the right)
|
||||
//
|
||||
TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& identifier, const TPublicType& publicType, TArraySizes* arraySizes, TIntermTyped* initializer)
|
||||
{
|
||||
TType type(publicType);
|
||||
|
|
@ -4170,13 +4225,12 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|||
if (arraySizes || type.isArray()) {
|
||||
// Arrayness is potentially coming both from the type and from the
|
||||
// variable: "int[] a[];" or just one or the other.
|
||||
// For now, arrays of arrays aren't supported, so it's just one or the
|
||||
// other. Move it to the type, so all arrayness is part of the type.
|
||||
// Merge it all to the type, so all arrayness is part of the type.
|
||||
arrayDimCheck(loc, &type, arraySizes);
|
||||
if (arraySizes)
|
||||
type.setArraySizes(arraySizes);
|
||||
arrayDimMerge(type, arraySizes);
|
||||
|
||||
arrayUnsizedCheck(loc, type.getQualifier(), type.getArraySize(), initializer != nullptr);
|
||||
// Check that implicit sizing is only where allowed.
|
||||
arrayUnsizedCheck(loc, type.getQualifier(), &type.getArraySizes(), initializer != nullptr);
|
||||
|
||||
if (! arrayQualifierError(loc, type.getQualifier()) && ! arrayError(loc, type))
|
||||
declareArray(loc, identifier, type, symbol, newDeclaration);
|
||||
|
|
@ -4299,10 +4353,21 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Fix arrayness if variable is unsized, getting size from the initializer
|
||||
if (initializer->getType().isArray() && initializer->getType().isExplicitlySizedArray() &&
|
||||
// Fix outer arrayness if variable is unsized, getting size from the initializer
|
||||
if (initializer->getType().isExplicitlySizedArray() &&
|
||||
variable->getType().isImplicitlySizedArray())
|
||||
variable->getWritableType().changeArraySize(initializer->getType().getArraySize());
|
||||
variable->getWritableType().changeOuterArraySize(initializer->getType().getOuterArraySize());
|
||||
|
||||
// Inner arrayness can also get set by an initializer
|
||||
if (initializer->getType().isArrayOfArrays() && variable->getType().isArrayOfArrays() &&
|
||||
initializer->getType().getArraySizes()->getNumDims() ==
|
||||
variable->getType().getArraySizes()->getNumDims()) {
|
||||
// adopt unsized sizes from the initializer's sizes
|
||||
for (int d = 1; d < variable->getType().getArraySizes()->getNumDims(); ++d) {
|
||||
if (variable->getType().getArraySizes()->getDimSize(d) == UnsizedArraySize)
|
||||
variable->getWritableType().getArraySizes().setDimSize(d, initializer->getType().getArraySizes()->getDimSize(d));
|
||||
}
|
||||
}
|
||||
|
||||
// Uniform and global consts require a constant initializer
|
||||
if (qualifier == EvqUniform && initializer->getType().getQualifier().storage != EvqConst) {
|
||||
|
|
@ -4390,9 +4455,20 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const
|
|||
// The type's array might be unsized, which could be okay, so base sizes on the size of the aggregate.
|
||||
// Later on, initializer execution code will deal with array size logic.
|
||||
TType arrayType;
|
||||
arrayType.shallowCopy(type);
|
||||
arrayType.setArraySizes(type);
|
||||
arrayType.changeArraySize((int)initList->getSequence().size());
|
||||
arrayType.shallowCopy(type); // sharing struct stuff is fine
|
||||
arrayType.newArraySizes(*type.getArraySizes()); // but get a fresh copy of the array information, to edit below
|
||||
|
||||
// edit array sizes to fill in unsized dimensions
|
||||
arrayType.changeOuterArraySize((int)initList->getSequence().size());
|
||||
TIntermTyped* firstInit = initList->getSequence()[0]->getAsTyped();
|
||||
if (arrayType.isArrayOfArrays() && firstInit->getType().isArray() &&
|
||||
arrayType.getArraySizes().getNumDims() == firstInit->getType().getArraySizes()->getNumDims() + 1) {
|
||||
for (int d = 1; d < arrayType.getArraySizes().getNumDims(); ++d) {
|
||||
if (arrayType.getArraySizes().getDimSize(d) == UnsizedArraySize)
|
||||
arrayType.getArraySizes().setDimSize(d, firstInit->getType().getArraySizes()->getDimSize(d - 1));
|
||||
}
|
||||
}
|
||||
|
||||
TType elementType(arrayType, 0); // dereferenced type
|
||||
for (size_t i = 0; i < initList->getSequence().size(); ++i) {
|
||||
initList->getSequence()[i] = convertInitializerList(loc, elementType, initList->getSequence()[i]->getAsTyped());
|
||||
|
|
@ -4455,9 +4531,11 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||
memberTypes = type.getStruct()->begin();
|
||||
|
||||
TType elementType;
|
||||
elementType.shallowCopy(type);
|
||||
if (type.isArray())
|
||||
elementType.dereference();
|
||||
if (type.isArray()) {
|
||||
TType dereferenced(type, 0);
|
||||
elementType.shallowCopy(dereferenced);
|
||||
} else
|
||||
elementType.shallowCopy(type);
|
||||
|
||||
bool singleArg;
|
||||
if (aggrNode) {
|
||||
|
|
@ -4471,11 +4549,11 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||
TIntermTyped *newNode;
|
||||
if (singleArg) {
|
||||
// If structure constructor or array constructor is being called
|
||||
// for only one parameter inside the structure, we need to call constructStruct function once.
|
||||
// for only one parameter inside the structure, we need to call constructAggregate function once.
|
||||
if (type.isArray())
|
||||
newNode = constructStruct(node, elementType, 1, node->getLoc());
|
||||
newNode = constructAggregate(node, elementType, 1, node->getLoc());
|
||||
else if (op == EOpConstructStruct)
|
||||
newNode = constructStruct(node, *(*memberTypes).type, 1, node->getLoc());
|
||||
newNode = constructAggregate(node, *(*memberTypes).type, 1, node->getLoc());
|
||||
else
|
||||
newNode = constructBuiltIn(type, op, node->getAsTyped(), node->getLoc(), false);
|
||||
|
||||
|
|
@ -4501,9 +4579,9 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||
for (TIntermSequence::iterator p = sequenceVector.begin();
|
||||
p != sequenceVector.end(); p++, paramCount++) {
|
||||
if (type.isArray())
|
||||
newNode = constructStruct(*p, elementType, paramCount+1, node->getLoc());
|
||||
newNode = constructAggregate(*p, elementType, paramCount+1, node->getLoc());
|
||||
else if (op == EOpConstructStruct)
|
||||
newNode = constructStruct(*p, *(memberTypes[paramCount]).type, paramCount+1, node->getLoc());
|
||||
newNode = constructAggregate(*p, *(memberTypes[paramCount]).type, paramCount+1, node->getLoc());
|
||||
else
|
||||
newNode = constructBuiltIn(type, op, (*p)->getAsTyped(), node->getLoc(), true);
|
||||
|
||||
|
|
@ -4610,12 +4688,12 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
|
|||
return intermediate.setAggregateOperator(newNode, op, type, loc);
|
||||
}
|
||||
|
||||
// This function tests for the type of the parameters to the structures constructors. Raises
|
||||
// This function tests for the type of the parameters to the structure or array constructor. Raises
|
||||
// an error message if the expected type does not match the parameter passed to the constructor.
|
||||
//
|
||||
// Returns nullptr for an error or the input node itself if the expected and the given parameter types match.
|
||||
//
|
||||
TIntermTyped* TParseContext::constructStruct(TIntermNode* node, const TType& type, int paramCount, const TSourceLoc& loc)
|
||||
TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType& type, int paramCount, const TSourceLoc& loc)
|
||||
{
|
||||
TIntermTyped* converted = intermediate.addConversion(EOpConstructStruct, type, node->getAsTyped());
|
||||
if (! converted || converted->getType() != type) {
|
||||
|
|
@ -4635,9 +4713,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|||
{
|
||||
blockStageIoCheck(loc, currentBlockQualifier);
|
||||
blockQualifierCheck(loc, currentBlockQualifier);
|
||||
if (arraySizes)
|
||||
arrayUnsizedCheck(loc, currentBlockQualifier, arraySizes->getOuterSize(), false);
|
||||
arrayDimCheck(loc, arraySizes, nullptr);
|
||||
if (arraySizes) {
|
||||
arrayUnsizedCheck(loc, currentBlockQualifier, arraySizes, false);
|
||||
arrayDimCheck(loc, arraySizes, 0);
|
||||
}
|
||||
|
||||
// fix and check for member storage qualifiers and types that don't belong within a block
|
||||
for (unsigned int member = 0; member < typeList.size(); ++member) {
|
||||
|
|
@ -4766,7 +4845,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|||
|
||||
TType blockType(&typeList, *blockName, currentBlockQualifier);
|
||||
if (arraySizes)
|
||||
blockType.setArraySizes(arraySizes);
|
||||
blockType.newArraySizes(*arraySizes);
|
||||
else
|
||||
ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName);
|
||||
|
||||
|
|
|
|||
|
|
@ -138,10 +138,11 @@ public:
|
|||
bool arrayError(const TSourceLoc&, const TType&);
|
||||
void arraySizeRequiredCheck(const TSourceLoc&, int size);
|
||||
void structArrayCheck(const TSourceLoc&, const TType& structure);
|
||||
void arrayUnsizedCheck(const TSourceLoc&, const TQualifier&, int size, bool initializer);
|
||||
void arrayUnsizedCheck(const TSourceLoc&, const TQualifier&, const TArraySizes*, bool initializer);
|
||||
void arrayOfArrayVersionCheck(const TSourceLoc&);
|
||||
void arrayDimCheck(const TSourceLoc&, TArraySizes* sizes1, TArraySizes* sizes2);
|
||||
void arrayDimCheck(const TSourceLoc&, const TType*, TArraySizes*);
|
||||
void arrayDimCheck(const TSourceLoc&, const TArraySizes* sizes1, const TArraySizes* sizes2);
|
||||
void arrayDimCheck(const TSourceLoc&, const TType*, const TArraySizes*);
|
||||
void arrayDimMerge(TType& type, const TArraySizes* sizes);
|
||||
bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType);
|
||||
void boolCheck(const TSourceLoc&, const TIntermTyped*);
|
||||
void boolCheck(const TSourceLoc&, const TPublicType&);
|
||||
|
|
@ -189,7 +190,7 @@ public:
|
|||
void declareTypeDefaults(const TSourceLoc&, const TPublicType&);
|
||||
TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0);
|
||||
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&, TOperator);
|
||||
TIntermTyped* constructStruct(TIntermNode*, const TType&, int, const TSourceLoc&);
|
||||
TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
|
||||
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
|
||||
void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
|
||||
void blockStageIoCheck(const TSourceLoc&, const TQualifier&);
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ void TType::buildMangledName(TString& mangledName)
|
|||
const int maxSize = 11;
|
||||
char buf[maxSize];
|
||||
for (int i = 0; i < arraySizes->getNumDims(); ++i) {
|
||||
snprintf(buf, maxSize, "%d", (*arraySizes)[i]);
|
||||
snprintf(buf, maxSize, "%d", arraySizes->getDimSize(i));
|
||||
mangledName += '[';
|
||||
mangledName += buf;
|
||||
mangledName += ']';
|
||||
|
|
|
|||
|
|
@ -691,7 +691,7 @@ declaration
|
|||
|
||||
// lazy setting of the previous scope's defaults, has effect only the first time it is called in a particular scope
|
||||
parseContext.symbolTable.setPreviousDefaultPrecisions(&parseContext.defaultPrecision[0]);
|
||||
parseContext.setDefaultPrecision($1.loc, $3, $2.qualifier.precision);
|
||||
parseContext.setDefaultPrecision($1.loc, $3, $2.qualifier.precision);
|
||||
$$ = 0;
|
||||
}
|
||||
| block_structure SEMICOLON {
|
||||
|
|
@ -1240,7 +1240,7 @@ array_specifier
|
|||
: LEFT_BRACKET RIGHT_BRACKET {
|
||||
$$.loc = $1.loc;
|
||||
$$.arraySizes = new TArraySizes;
|
||||
$$.arraySizes->setOuterSize(0);
|
||||
$$.arraySizes->addInnerSize();
|
||||
}
|
||||
| LEFT_BRACKET constant_expression RIGHT_BRACKET {
|
||||
$$.loc = $1.loc;
|
||||
|
|
@ -1248,18 +1248,18 @@ array_specifier
|
|||
|
||||
int size;
|
||||
parseContext.arraySizeCheck($2->getLoc(), $2, size);
|
||||
$$.arraySizes->setOuterSize(size);
|
||||
$$.arraySizes->addInnerSize(size);
|
||||
}
|
||||
| array_specifier LEFT_BRACKET RIGHT_BRACKET {
|
||||
$$ = $1;
|
||||
$$.arraySizes->setOuterSize(0);
|
||||
$$.arraySizes->addInnerSize();
|
||||
}
|
||||
| array_specifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
|
||||
$$ = $1;
|
||||
|
||||
int size;
|
||||
parseContext.arraySizeCheck($3->getLoc(), $3, size);
|
||||
$$.arraySizes->setOuterSize(size);
|
||||
$$.arraySizes->addInnerSize(size);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -1903,19 +1903,19 @@ precision_qualifier
|
|||
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "highp precision qualifier");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
if (parseContext.profile == EEsProfile)
|
||||
$$.qualifier.precision = EpqHigh;
|
||||
$$.qualifier.precision = EpqHigh;
|
||||
}
|
||||
| MEDIUM_PRECISION {
|
||||
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "mediump precision qualifier");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
if (parseContext.profile == EEsProfile)
|
||||
$$.qualifier.precision = EpqMedium;
|
||||
$$.qualifier.precision = EpqMedium;
|
||||
}
|
||||
| LOW_PRECISION {
|
||||
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "lowp precision qualifier");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
if (parseContext.profile == EEsProfile)
|
||||
$$.qualifier.precision = EpqLow;
|
||||
$$.qualifier.precision = EpqLow;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -2020,7 +2020,7 @@ struct_declarator
|
|||
$$.type = new TType(EbtVoid);
|
||||
$$.loc = $1.loc;
|
||||
$$.type->setFieldName(*$1.string);
|
||||
$$.type->setArraySizes($2.arraySizes);
|
||||
$$.type->newArraySizes(*$2.arraySizes);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -2354,7 +2354,7 @@ jump_statement
|
|||
$$ = parseContext.intermediate.addBranch(EOpReturn, $2, $1.loc);
|
||||
}
|
||||
} else
|
||||
$$ = parseContext.intermediate.addBranch(EOpReturn, $2, $1.loc);
|
||||
$$ = parseContext.intermediate.addBranch(EOpReturn, $2, $1.loc);
|
||||
}
|
||||
| DISCARD SEMICOLON {
|
||||
parseContext.requireStage($1.loc, EShLangFragment, "discard");
|
||||
|
|
|
|||
|
|
@ -240,9 +240,7 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin
|
|||
void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType)
|
||||
{
|
||||
if (type.isImplicitlySizedArray() && unitType.isArray()) {
|
||||
int newImplicitArraySize = unitType.getArraySize();
|
||||
if (newImplicitArraySize == 0)
|
||||
newImplicitArraySize = unitType.getImplicitArraySize();
|
||||
int newImplicitArraySize = unitType.isImplicitlySizedArray() ? unitType.getImplicitArraySize() : unitType.getOuterArraySize();
|
||||
if (newImplicitArraySize > type.getImplicitArraySize ())
|
||||
type.setImplicitArraySize(newImplicitArraySize);
|
||||
}
|
||||
|
|
@ -623,7 +621,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
|
|||
int size;
|
||||
if (qualifier.isUniformOrBuffer()) {
|
||||
if (type.isArray())
|
||||
size = type.getArraySize();
|
||||
size = type.getCumulativeArraySize();
|
||||
else
|
||||
size = 1;
|
||||
} else {
|
||||
|
|
@ -693,12 +691,13 @@ int TIntermediate::computeTypeLocationSize(const TType& type) const
|
|||
// "If the declared input is an array of size n and each element takes m locations, it will be assigned m * n
|
||||
// consecutive locations..."
|
||||
if (type.isArray()) {
|
||||
// TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
|
||||
TType elementType(type, 0);
|
||||
if (type.isImplicitlySizedArray()) {
|
||||
// TODO: are there valid cases of having an implicitly-sized array with a location? If so, running this code too early.
|
||||
return computeTypeLocationSize(elementType);
|
||||
} else
|
||||
return type.getArraySize() * computeTypeLocationSize(elementType);
|
||||
return type.getOuterArraySize() * computeTypeLocationSize(elementType);
|
||||
}
|
||||
|
||||
// "The locations consumed by block and structure members are determined by applying the rules above
|
||||
|
|
@ -783,10 +782,11 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
|
|||
// that component's size. Aggregate types are flattened down to the component
|
||||
// level to get this sequence of components."
|
||||
|
||||
if (type.isArray()) {
|
||||
if (type.isArray()) {
|
||||
// TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
|
||||
assert(type.isExplicitlySizedArray());
|
||||
TType elementType(type, 0);
|
||||
return type.getArraySize() * computeTypeXfbSize(elementType, containsDouble);
|
||||
return type.getOuterArraySize() * computeTypeXfbSize(elementType, containsDouble);
|
||||
}
|
||||
|
||||
if (type.isStruct()) {
|
||||
|
|
@ -913,12 +913,13 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, bool std140)
|
|||
|
||||
// rules 4, 6, and 8
|
||||
if (type.isArray()) {
|
||||
// TODO: perf: this might be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
|
||||
TType derefType(type, 0);
|
||||
alignment = getBaseAlignment(derefType, size, std140);
|
||||
if (std140)
|
||||
alignment = std::max(baseAlignmentVec4Std140, alignment);
|
||||
RoundToPow2(size, alignment);
|
||||
size *= type.getArraySize();
|
||||
size *= type.getOuterArraySize();
|
||||
return alignment;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ public:
|
|||
switch (visitNode->getOp()) {
|
||||
case EOpIndexIndirect:
|
||||
// Visit all the indices of this array, and for each one add on the remaining dereferencing
|
||||
for (int i = 0; i < visitNode->getLeft()->getType().getArraySize(); ++i) {
|
||||
for (int i = 0; i < visitNode->getLeft()->getType().getOuterArraySize(); ++i) {
|
||||
TString newBaseName = name;
|
||||
if (baseType.getBasicType() != EbtBlock)
|
||||
newBaseName.append(TString("[") + String(i) + "]");
|
||||
|
|
@ -201,7 +201,7 @@ public:
|
|||
if (terminalType->isArray()) {
|
||||
// Visit all the indices of this array, and for each one,
|
||||
// fully explode the remaining aggregate to dereference
|
||||
for (int i = 0; i < terminalType->getArraySize(); ++i) {
|
||||
for (int i = 0; i < terminalType->getOuterArraySize(); ++i) {
|
||||
TString newBaseName = name;
|
||||
newBaseName.append(TString("[") + String(i) + "]");
|
||||
TType derefType(*terminalType, 0);
|
||||
|
|
@ -286,7 +286,7 @@ public:
|
|||
anonymous = IsAnonymous(base->getName());
|
||||
if (base->getType().isArray()) {
|
||||
assert(! anonymous);
|
||||
for (int e = 0; e < base->getType().getArraySize(); ++e)
|
||||
for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
|
||||
blockIndex = addBlockName(base->getType().getTypeName() + "[" + String(e) + "]", getBlockSize(base->getType()));
|
||||
} else
|
||||
blockIndex = addBlockName(base->getType().getTypeName(), getBlockSize(base->getType()));
|
||||
|
|
@ -610,7 +610,7 @@ public:
|
|||
|
||||
int mapToGlArraySize(const TType& type)
|
||||
{
|
||||
return type.isArray() ? type.getArraySize() : 1;
|
||||
return type.isArray() ? type.getOuterArraySize() : 1;
|
||||
}
|
||||
|
||||
typedef std::list<TIntermAggregate*> TFunctionStack;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue