Update glslang

This commit is contained in:
Alex Szpakowski
2019-05-26 15:12:02 -03:00
parent 38cb56f168
commit ee77eef9a9
35 changed files with 7168 additions and 5180 deletions
@@ -66,6 +66,8 @@ enum TBasicType {
EbtAccStructNV,
#endif
EbtReference,
// HLSL types that live only temporarily.
EbtString,
@@ -38,7 +38,7 @@
#define _COMMON_INCLUDED_
#if defined(__ANDROID__) || _MSC_VER < 1700
#if defined(__ANDROID__) || (defined(_MSC_VER) && _MSC_VER < 1700)
#include <sstream>
namespace std {
template<typename T>
@@ -102,6 +102,7 @@ std::string to_string(const T& val) {
#include <algorithm>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include "PoolAlloc.h"
@@ -250,7 +251,8 @@ struct TSourceLoc {
return nullptr;
return name->c_str();
}
TString* name; // descriptive name for this string
const char* getFilenameStr() const { return name == nullptr ? "" : name->c_str(); }
TString* name; // descriptive name for this string, when a textual name is available, otherwise nullptr
int string;
int line;
int column;
+210 -27
View File
@@ -81,6 +81,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler
bool sampler : 1; // true means a pure sampler, other fields should be clear()
bool external : 1; // GL_OES_EGL_image_external
bool yuv : 1; // GL_EXT_YUV_target
unsigned int vectorSize : 3; // vector return type size.
// Some languages support structures as sample results. Storing the whole structure in the
@@ -116,6 +117,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
combined = false;
sampler = false;
external = false;
yuv = false;
structReturnIndex = noReturnStruct;
// by default, returns a single vec4;
@@ -186,6 +188,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
combined == right.combined &&
sampler == right.sampler &&
external == right.external &&
yuv == right.yuv &&
vectorSize == right.vectorSize &&
structReturnIndex == right.structReturnIndex;
}
@@ -233,6 +236,9 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
s.append("ExternalOES");
return s;
}
if (yuv) {
return "__" + s + "External2DY2YEXT";
}
switch (dim) {
case Esd1D: s.append("1D"); break;
case Esd2D: s.append("2D"); break;
@@ -537,6 +543,11 @@ public:
{
return subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly;
}
bool bufferReferenceNeedsVulkanMemoryModel() const
{
// include qualifiers that map to load/store availability/visibility/nonprivate memory access operands
return subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || nonprivate;
}
bool isInterpolation() const
{
@@ -721,6 +732,7 @@ public:
clearUniformLayout();
layoutPushConstant = false;
layoutBufferReference = false;
#ifdef NV_EXTENSIONS
layoutPassthrough = false;
layoutViewportRelative = false;
@@ -729,6 +741,8 @@ public:
layoutShaderRecordNV = false;
#endif
layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd;
clearInterstageLayout();
layoutSpecConstantId = layoutSpecConstantIdEnd;
@@ -763,7 +777,8 @@ public:
#ifdef NV_EXTENSIONS
layoutShaderRecordNV ||
#endif
layoutPushConstant;
layoutPushConstant ||
layoutBufferReference;
}
bool hasLayout() const
{
@@ -808,9 +823,14 @@ public:
unsigned int layoutSpecConstantId : 11;
static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
// stored as log2 of the actual alignment value
unsigned int layoutBufferReferenceAlign : 6;
static const unsigned int layoutBufferReferenceAlignEnd = 0x3F;
TLayoutFormat layoutFormat : 8;
bool layoutPushConstant;
bool layoutBufferReference;
#ifdef NV_EXTENSIONS
bool layoutPassthrough;
@@ -918,6 +938,10 @@ public:
// is just whether or not it was declared with an ID.
return layoutSpecConstantId != layoutSpecConstantIdEnd;
}
bool hasBufferReferenceAlign() const
{
return layoutBufferReferenceAlign != layoutBufferReferenceAlignEnd;
}
bool isSpecConstant() const
{
// True if type is a specialization constant, whether or not it
@@ -1211,9 +1235,11 @@ public:
int vectorSize : 4;
int matrixCols : 4;
int matrixRows : 4;
bool coopmat : 1;
TArraySizes* arraySizes;
const TType* userDef;
TSourceLoc loc;
TArraySizes* typeParameters;
void initType(const TSourceLoc& l)
{
@@ -1224,6 +1250,8 @@ public:
arraySizes = nullptr;
userDef = nullptr;
loc = l;
typeParameters = nullptr;
coopmat = false;
}
void initQualifiers(bool global = false)
@@ -1275,8 +1303,8 @@ public:
// for "empty" type (no args) or simple scalar/vector/matrix
explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0,
bool isVector = false) :
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1), coopmat(false),
arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr)
{
sampler.clear();
qualifier.clear();
@@ -1286,8 +1314,8 @@ public:
// for explicit precision qualifier
TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
bool isVector = false) :
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1), coopmat(false),
arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr)
{
sampler.clear();
qualifier.clear();
@@ -1299,8 +1327,8 @@ public:
// for turning a TPublicType into a TType, using a shallow copy
explicit TType(const TPublicType& p) :
basicType(p.basicType),
vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false),
arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr)
vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false), coopmat(p.coopmat),
arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(p.typeParameters)
{
if (basicType == EbtSampler)
sampler = p.sampler;
@@ -1308,15 +1336,26 @@ public:
sampler.clear();
qualifier = p.qualifier;
if (p.userDef) {
structure = p.userDef->getWritableStruct(); // public type is short-lived; there are no sharing issues
if (p.userDef->basicType == EbtReference) {
basicType = EbtReference;
referentType = p.userDef->referentType;
} else {
structure = p.userDef->getWritableStruct(); // public type is short-lived; there are no sharing issues
}
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
if (p.coopmat && p.basicType == EbtFloat &&
p.typeParameters && p.typeParameters->getNumDims() > 0 &&
p.typeParameters->getDimSize(0) == 16) {
basicType = EbtFloat16;
qualifier.precision = EpqNone;
}
}
// for construction of sampler types
TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) :
basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false),
arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
sampler(sampler)
sampler(sampler), typeParameters(nullptr)
{
qualifier.clear();
qualifier.storage = q;
@@ -1357,13 +1396,16 @@ public:
// dereference from vector to scalar
vectorSize = 1;
vector1 = false;
} else if (isCoopMat()) {
coopmat = false;
typeParameters = nullptr;
}
}
}
// for making structures, ...
TType(TTypeList* userDef, const TString& n) :
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
arraySizes(nullptr), structure(userDef), fieldName(nullptr)
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false),
arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr)
{
sampler.clear();
qualifier.clear();
@@ -1371,12 +1413,23 @@ public:
}
// For interface blocks
TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr)
basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false),
qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr)
{
sampler.clear();
typeName = NewPoolTString(n.c_str());
}
// for block reference (first parameter must be EbtReference)
explicit TType(TBasicType t, const TType &p, const TString& n) :
basicType(t), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
{
assert(t == EbtReference);
typeName = NewPoolTString(n.c_str());
qualifier.clear();
qualifier.storage = p.qualifier.storage;
referentType = p.clone();
}
virtual ~TType() {}
// Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
@@ -1392,9 +1445,15 @@ public:
matrixRows = copyOf.matrixRows;
vector1 = copyOf.vector1;
arraySizes = copyOf.arraySizes; // copying the pointer only, not the contents
structure = copyOf.structure;
fieldName = copyOf.fieldName;
typeName = copyOf.typeName;
if (isStruct()) {
structure = copyOf.structure;
} else {
referentType = copyOf.referentType;
}
typeParameters = copyOf.typeParameters;
coopmat = copyOf.coopmat;
}
// Make complete copy of the whole type graph rooted at 'copyOf'.
@@ -1457,6 +1516,9 @@ public:
virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
virtual const TArraySizes* getArraySizes() const { return arraySizes; }
virtual TArraySizes* getArraySizes() { return arraySizes; }
virtual TType* getReferentType() const { return referentType; }
virtual const TArraySizes* getTypeParameters() const { return typeParameters; }
virtual TArraySizes* getTypeParameters() { return typeParameters; }
virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
virtual bool isScalarOrVec1() const { return isScalar() || vector1; }
@@ -1468,7 +1530,7 @@ public:
virtual bool isArrayVariablyIndexed() const { assert(isArray()); return arraySizes->isVariablyIndexed(); }
virtual void setArrayVariablyIndexed() { assert(isArray()); arraySizes->setVariablyIndexed(); }
virtual void updateImplicitArraySize(int size) { assert(isArray()); arraySizes->updateImplicitSize(size); }
virtual bool isStruct() const { return structure != nullptr; }
virtual bool isStruct() const { return basicType == EbtStruct || basicType == EbtBlock; }
virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
virtual bool isIntegerDomain() const
{
@@ -1499,6 +1561,8 @@ public:
virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); }
virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
virtual bool isTexture() const { return basicType == EbtSampler && getSampler().isTexture(); }
virtual bool isParameterized() const { return typeParameters != nullptr; }
virtual bool isCoopMat() const { return coopmat; }
// return true if this type contains any subtype which satisfies the given predicate.
template <typename P>
@@ -1509,7 +1573,7 @@ public:
const auto hasa = [predicate](const TTypeLoc& tl) { return tl.type->contains(predicate); };
return structure && std::any_of(structure->begin(), structure->end(), hasa);
return isStruct() && std::any_of(structure->begin(), structure->end(), hasa);
}
// Recursively checks if the type contains the given basic type
@@ -1564,6 +1628,7 @@ public:
case EbtInt64:
case EbtUint64:
case EbtBool:
case EbtReference:
return true;
default:
return false;
@@ -1588,6 +1653,11 @@ public:
return containsBasicType(EbtInt8) || containsBasicType(EbtUint8);
}
virtual bool containsCoopMat() const
{
return contains([](const TType* t) { return t->coopmat; } );
}
// Array editing methods. Array descriptors can be shared across
// type instances. This allows all uses of the same array
// to be updated at once. E.g., all nodes can be explicitly sized
@@ -1660,6 +1730,46 @@ public:
}
}
void updateTypeParameters(const TType& type)
{
// For when we may already be sharing existing array descriptors,
// keeping the pointers the same, just updating the contents.
assert(typeParameters != nullptr);
assert(type.typeParameters != nullptr);
*typeParameters = *type.typeParameters;
}
void copyTypeParameters(const TArraySizes& s)
{
// For setting a fresh new set of type parameters, not yet worrying about sharing.
typeParameters = new TArraySizes;
*typeParameters = s;
}
void transferTypeParameters(TArraySizes* s)
{
// For setting an already allocated set of sizes that this type can use
// (no copy made).
typeParameters = s;
}
void clearTypeParameters()
{
typeParameters = nullptr;
}
// Add inner array sizes, to any existing sizes, via copy; the
// sizes passed in can still be reused for other purposes.
void copyTypeParametersInnerSizes(const TArraySizes* s)
{
if (s != nullptr) {
if (typeParameters == nullptr)
copyTypeParameters(*s);
else
typeParameters->addInnerSizes(*s);
}
}
const char* getBasicString() const
{
return TType::getBasicString(basicType);
@@ -1688,6 +1798,7 @@ public:
#ifdef NV_EXTENSIONS
case EbtAccStructNV: return "accelerationStructureNV";
#endif
case EbtReference: return "reference";
default: return "unknown type";
}
}
@@ -1773,6 +1884,12 @@ public:
}
if (qualifier.layoutPushConstant)
appendStr(" push_constant");
if (qualifier.layoutBufferReference)
appendStr(" buffer_reference");
if (qualifier.hasBufferReferenceAlign()) {
appendStr(" buffer_reference_align=");
appendUint(1u << qualifier.layoutBufferReferenceAlign);
}
#ifdef NV_EXTENSIONS
if (qualifier.layoutPassthrough)
@@ -1867,6 +1984,15 @@ public:
}
}
}
if (isParameterized()) {
appendStr("<");
for(int i = 0; i < (int)typeParameters->getNumDims(); ++i) {
appendInt(typeParameters->getDimSize(i));
if (i != (int)typeParameters->getNumDims() - 1)
appendStr(", ");
}
appendStr(">");
}
if (qualifier.precision != EpqNone) {
appendStr(" ");
appendStr(getPrecisionQualifierString());
@@ -1892,7 +2018,7 @@ public:
}
// Add struct/block members
if (structure) {
if (isStruct() && structure) {
appendStr("{");
for (size_t i = 0; i < structure->size(); ++i) {
if (! (*structure)[i].type->hiddenMember()) {
@@ -1920,9 +2046,9 @@ public:
const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
const TTypeList* getStruct() const { return structure; }
void setStruct(TTypeList* s) { structure = s; }
TTypeList* getWritableStruct() const { return structure; } // This should only be used when known to not be sharing with other threads
const TTypeList* getStruct() const { assert(isStruct()); return structure; }
void setStruct(TTypeList* s) { assert(isStruct()); structure = s; }
TTypeList* getWritableStruct() const { assert(isStruct()); return structure; } // This should only be used when known to not be sharing with other threads
int computeNumComponents() const
{
@@ -1961,11 +2087,12 @@ public:
bool sameStructType(const TType& right) const
{
// Most commonly, they are both nullptr, or the same pointer to the same actual structure
if (structure == right.structure)
if ((!isStruct() && !right.isStruct()) ||
(isStruct() && right.isStruct() && structure == right.structure))
return true;
// Both being nullptr was caught above, now they both have to be structures of the same number of elements
if (structure == nullptr || right.structure == nullptr ||
if (!isStruct() || !right.isStruct() ||
structure->size() != right.structure->size())
return false;
@@ -1985,6 +2112,23 @@ public:
return true;
}
bool sameReferenceType(const TType& right) const
{
if ((basicType == EbtReference) != (right.basicType == EbtReference))
return false;
if ((basicType != EbtReference) && (right.basicType != EbtReference))
return true;
assert(referentType != nullptr);
assert(right.referentType != nullptr);
if (referentType == right.referentType)
return true;
return *referentType == *right.referentType;
}
// See if two types match, in all aspects except arrayness
bool sameElementType(const TType& right) const
{
@@ -2005,6 +2149,13 @@ public:
return arraySizes->sameInnerArrayness(*right.arraySizes);
}
// See if two type's parameters match
bool sameTypeParameters(const TType& right) const
{
return ((typeParameters == nullptr && right.typeParameters == nullptr) ||
(typeParameters != nullptr && right.typeParameters != nullptr && *typeParameters == *right.typeParameters));
}
// See if two type's elements match in all ways except basic type
bool sameElementShape(const TType& right) const
{
@@ -2013,13 +2164,23 @@ public:
matrixCols == right.matrixCols &&
matrixRows == right.matrixRows &&
vector1 == right.vector1 &&
sameStructType(right);
coopmat == right.coopmat &&
sameStructType(right) &&
sameReferenceType(right);
}
// See if a cooperative matrix type parameter with unspecified parameters is
// an OK function parameter
bool coopMatParameterOK(const TType& right) const
{
return coopmat && right.coopmat &&
typeParameters == nullptr && right.typeParameters != nullptr;
}
// See if two types match in all ways (just the actual type, not qualification)
bool operator==(const TType& right) const
{
return sameElementType(right) && sameArrayness(right);
return sameElementType(right) && sameArrayness(right) && sameTypeParameters(right);
}
bool operator!=(const TType& right) const
@@ -2027,6 +2188,16 @@ public:
return ! operator==(right);
}
unsigned int getBufferReferenceAlignment() const
{
if (getBasicType() == glslang::EbtReference) {
return getReferentType()->getQualifier().hasBufferReferenceAlign() ?
(1u << getReferentType()->getQualifier().layoutBufferReferenceAlign) : 16u;
} else {
return 0;
}
}
protected:
// Require consumer to pick between deep copy and shallow copy.
TType(const TType& type);
@@ -2044,7 +2215,12 @@ protected:
*arraySizes = *copyOf.arraySizes;
}
if (copyOf.structure) {
if (copyOf.typeParameters) {
typeParameters = new TArraySizes;
*typeParameters = *copyOf.typeParameters;
}
if (copyOf.isStruct() && copyOf.structure) {
auto prevCopy = copiedMap.find(copyOf.structure);
if (prevCopy != copiedMap.end())
structure = prevCopy->second;
@@ -2079,13 +2255,20 @@ protected:
// functionality is added.
// HLSL does have a 1-component vectors, so this will be true to disambiguate
// from a scalar.
bool coopmat : 1;
TQualifier qualifier;
TArraySizes* arraySizes; // nullptr unless an array; can be shared across types
TTypeList* structure; // nullptr unless this is a struct; can be shared across types
// A type can't be both a structure (EbtStruct/EbtBlock) and a reference (EbtReference), so
// conserve space by making these a union
union {
TTypeList* structure; // invalid unless this is a struct; can be shared across types
TType *referentType; // invalid unless this is an EbtReference
};
TString *fieldName; // for structure field names
TString *typeName; // for structure type name
TSampler sampler;
TArraySizes* typeParameters;// nullptr unless a parameterized type; can be shared across types
};
} // end namespace glslang
@@ -254,7 +254,9 @@ struct TArraySizes {
void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); }
void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); }
void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); }
void addInnerSize(TArraySize pair) { sizes.push_back(pair.size, pair.node); }
void addInnerSize(TArraySize pair) {
sizes.push_back(pair.size, pair.node);
}
void addInnerSizes(const TArraySizes& s) { sizes.push_back(s.sizes); }
void changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
int getImplicitSize() const { return implicitArraySize; }
@@ -318,8 +320,8 @@ struct TArraySizes {
void setVariablyIndexed() { variablyIndexed = true; }
bool isVariablyIndexed() const { return variablyIndexed; }
bool operator==(const TArraySizes& rhs) { return sizes == rhs.sizes; }
bool operator!=(const TArraySizes& rhs) { return sizes != rhs.sizes; }
bool operator==(const TArraySizes& rhs) const { return sizes == rhs.sizes; }
bool operator!=(const TArraySizes& rhs) const { return sizes != rhs.sizes; }
protected:
TSmallArrayVector sizes;
@@ -85,6 +85,8 @@ enum TOperator {
EOpPreIncrement,
EOpPreDecrement,
EOpCopyObject,
// (u)int* -> bool
EOpConvInt8ToBool,
EOpConvUint8ToBool,
@@ -269,6 +271,10 @@ enum TOperator {
EOpConvDoubleToFloat16,
EOpConvDoubleToFloat,
// uint64_t <-> pointer
EOpConvUint64ToPtr,
EOpConvPtrToUint64,
//
// binary operations
//
@@ -611,6 +617,10 @@ enum TOperator {
EOpAny,
EOpAll,
EOpCooperativeMatrixLoad,
EOpCooperativeMatrixStore,
EOpCooperativeMatrixMulAdd,
//
// Branch
//
@@ -732,6 +742,8 @@ enum TOperator {
EOpConstructStruct,
EOpConstructTextureSampler,
EOpConstructNonuniform, // expected to be transformed away, not present in final AST
EOpConstructReference,
EOpConstructCooperativeMatrix,
EOpConstructGuardEnd,
//
@@ -1104,7 +1116,12 @@ public:
first(testFirst),
unroll(false),
dontUnroll(false),
dependency(0)
dependency(0),
minIterations(0),
maxIterations(iterationsInfinite),
iterationMultiple(1),
peelCount(0),
partialCount(0)
{ }
virtual TIntermLoop* getAsLoopNode() { return this; }
@@ -1116,14 +1133,36 @@ public:
bool testFirst() const { return first; }
void setUnroll() { unroll = true; }
void setDontUnroll() { dontUnroll = true; }
void setDontUnroll() {
dontUnroll = true;
peelCount = 0;
partialCount = 0;
}
bool getUnroll() const { return unroll; }
bool getDontUnroll() const { return dontUnroll; }
static const unsigned int dependencyInfinite = 0xFFFFFFFF;
static const unsigned int iterationsInfinite = 0xFFFFFFFF;
void setLoopDependency(int d) { dependency = d; }
int getLoopDependency() const { return dependency; }
void setMinIterations(unsigned int v) { minIterations = v; }
unsigned int getMinIterations() const { return minIterations; }
void setMaxIterations(unsigned int v) { maxIterations = v; }
unsigned int getMaxIterations() const { return maxIterations; }
void setIterationMultiple(unsigned int v) { iterationMultiple = v; }
unsigned int getIterationMultiple() const { return iterationMultiple; }
void setPeelCount(unsigned int v) {
peelCount = v;
dontUnroll = false;
}
unsigned int getPeelCount() const { return peelCount; }
void setPartialCount(unsigned int v) {
partialCount = v;
dontUnroll = false;
}
unsigned int getPartialCount() const { return partialCount; }
protected:
TIntermNode* body; // code to loop over
TIntermTyped* test; // exit condition associated with loop, could be 0 for 'for' loops
@@ -1132,6 +1171,11 @@ protected:
bool unroll; // true if unroll requested
bool dontUnroll; // true if request to not unroll
unsigned int dependency; // loop dependency hint; 0 means not set or unknown
unsigned int minIterations; // as per the SPIR-V specification
unsigned int maxIterations; // as per the SPIR-V specification
unsigned int iterationMultiple; // as per the SPIR-V specification
unsigned int peelCount; // as per the SPIR-V specification
unsigned int partialCount; // as per the SPIR-V specification
};
//
@@ -1,3 +1,3 @@
// This header is generated by the make-revision script.
#define GLSLANG_PATCH_LEVEL 3009
#define GLSLANG_PATCH_LEVEL 3226
+7 -1
View File
@@ -941,6 +941,10 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
newConstArray[i].setDConst(unionArray[i].getDConst()); break;
case EOpConvDoubleToFloat:
newConstArray[i].setDConst(unionArray[i].getDConst()); break;
case EOpConvPtrToUint64:
case EOpConvUint64ToPtr:
case EOpConstructReference:
newConstArray[i].setU64Const(unionArray[i].getU64Const()); break;
@@ -1354,7 +1358,9 @@ TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, cons
// arrays, vectors, matrices, all use simple multiplicative math
// while structures need to add up heterogeneous members
int start;
if (node->isArray() || ! node->isStruct())
if (node->getType().isCoopMat())
start = 0;
else if (node->isArray() || ! node->isStruct())
start = size * index;
else {
// it is a structure
+146 -33
View File
@@ -1609,6 +1609,16 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"vec4 texelFetch(samplerExternalOES, ivec2, int lod);" // GL_OES_EGL_image_external_essl3
"\n");
}
commonBuiltins.append(
"highp ivec2 textureSize(__samplerExternal2DY2YEXT, int lod);" // GL_EXT_YUV_target
"vec4 texture(__samplerExternal2DY2YEXT, vec2);" // GL_EXT_YUV_target
"vec4 texture(__samplerExternal2DY2YEXT, vec2, float bias);" // GL_EXT_YUV_target
"vec4 textureProj(__samplerExternal2DY2YEXT, vec3);" // GL_EXT_YUV_target
"vec4 textureProj(__samplerExternal2DY2YEXT, vec3, float bias);" // GL_EXT_YUV_target
"vec4 textureProj(__samplerExternal2DY2YEXT, vec4);" // GL_EXT_YUV_target
"vec4 textureProj(__samplerExternal2DY2YEXT, vec4, float bias);" // GL_EXT_YUV_target
"vec4 texelFetch(__samplerExternal2DY2YEXT sampler, ivec2, int lod);" // GL_EXT_YUV_target
"\n");
commonBuiltins.append(
"vec4 texture2DGradEXT(sampler2D, vec2, vec2, vec2);" // GL_EXT_shader_texture_lod
"vec4 texture2DProjGradEXT(sampler2D, vec3, vec2, vec2);" // GL_EXT_shader_texture_lod
@@ -1869,7 +1879,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
commonBuiltins.append(
"void subgroupBarrier();"
"void subgroupMemoryBarrier();"
@@ -4930,6 +4941,34 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
commonBuiltins.append("void controlBarrier(int, int, int, int);\n"
"void memoryBarrier(int, int, int);\n");
if (profile != EEsProfile && version >= 450) {
// coopMatStoreNV perhaps ought to have "out" on the buf parameter, but
// adding it introduces undesirable tempArgs on the stack. What we want
// is more like "buf" thought of as a pointer value being an in parameter.
stageBuiltins[EShLangCompute].append(
"void coopMatLoadNV(out fcoopmatNV m, volatile coherent float16_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatLoadNV(out fcoopmatNV m, volatile coherent float[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatLoadNV(out fcoopmatNV m, volatile coherent uint8_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatLoadNV(out fcoopmatNV m, volatile coherent uint16_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatLoadNV(out fcoopmatNV m, volatile coherent uint[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatLoadNV(out fcoopmatNV m, volatile coherent uint64_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatLoadNV(out fcoopmatNV m, volatile coherent uvec2[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatLoadNV(out fcoopmatNV m, volatile coherent uvec4[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent float16_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent float[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent float64_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent uint8_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent uint16_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent uint[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent uint64_t[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent uvec2[] buf, uint element, uint stride, bool colMajor);\n"
"void coopMatStoreNV(fcoopmatNV m, volatile coherent uvec4[] buf, uint element, uint stride, bool colMajor);\n"
"fcoopmatNV coopMatMulAddNV(fcoopmatNV A, fcoopmatNV B, fcoopmatNV C);\n"
);
}
//============================================================================
//
// Prototypes for built-in functions seen by fragment shaders only.
@@ -5362,6 +5401,9 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"in highp uvec3 gl_GlobalInvocationID;"
"in highp uint gl_LocalInvocationIndex;"
"in uint gl_MeshViewCountNV;"
"in uint gl_MeshViewIndicesNV[4];"
"\n");
}
@@ -5768,7 +5810,14 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"patch out highp float gl_TessLevelOuter[4];"
"patch out highp float gl_TessLevelInner[2];"
"patch out highp vec4 gl_BoundingBoxOES[2];"
"patch out highp vec4 gl_BoundingBoxEXT[2];"
"\n");
if (profile == EEsProfile && version >= 320) {
stageBuiltins[EShLangTessControl].append(
"patch out highp vec4 gl_BoundingBox[2];"
"\n"
);
}
}
if ((profile != EEsProfile && version >= 140) ||
@@ -6093,7 +6142,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
const char* ballotDecls =
"in mediump uint gl_SubgroupSize;"
"in mediump uint gl_SubgroupInvocationID;"
@@ -6207,7 +6257,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
const char *callableDecls =
"in uvec3 gl_LaunchIDNV;"
"in uvec3 gl_LaunchSizeNV;"
"in uint gl_IncomingRayFlagsNV;"
"\n";
stageBuiltins[EShLangRayGenNV].append(rayGenDecls);
@@ -7752,11 +7801,12 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
{
TSymbol* symbol = symbolTable.find(name);
if (symbol) {
TQualifier& symQualifier = symbol->getWritableType().getQualifier();
symQualifier.storage = qualifier;
symQualifier.builtIn = builtIn;
}
if (symbol == nullptr)
return;
TQualifier& symQualifier = symbol->getWritableType().getQualifier();
symQualifier.storage = qualifier;
symQualifier.builtIn = builtIn;
}
//
@@ -7772,7 +7822,7 @@ static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBui
static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
{
TSymbol* symbol = symbolTable.find(name);
if (! symbol)
if (symbol == nullptr)
return;
TQualifier& symQualifier = symbol->getWritableType().getQualifier();
@@ -7789,7 +7839,7 @@ static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolT
static void BuiltInVariable(const char* blockName, const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
{
TSymbol* symbol = symbolTable.find(blockName);
if (! symbol)
if (symbol == nullptr)
return;
TTypeList& structure = *symbol->getWritableType().getWritableStruct();
@@ -7987,10 +8037,16 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
case EShLangTessControl:
if (profile == EEsProfile && version >= 310) {
BuiltInVariable("gl_BoundingBoxEXT", EbvBoundingBox, symbolTable);
symbolTable.setVariableExtensions("gl_BoundingBoxEXT", 1,
&E_GL_EXT_primitive_bounding_box);
BuiltInVariable("gl_BoundingBoxOES", EbvBoundingBox, symbolTable);
if (version < 320)
symbolTable.setVariableExtensions("gl_BoundingBoxOES", Num_AEP_primitive_bounding_box,
AEP_primitive_bounding_box);
symbolTable.setVariableExtensions("gl_BoundingBoxOES", 1,
&E_GL_OES_primitive_bounding_box);
if (version >= 320) {
BuiltInVariable("gl_BoundingBox", EbvBoundingBox, symbolTable);
}
}
// Fall through
@@ -8045,9 +8101,18 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
BuiltInVariable("gl_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable);
if (language != EShLangVertex) {
symbolTable.setVariableExtensions("gl_in", "gl_SecondaryPositionNV", 1, &E_GL_NV_stereo_view_rendering);
symbolTable.setVariableExtensions("gl_in", "gl_PositionPerViewNV", 1, &E_GL_NVX_multiview_per_view_attributes);
BuiltInVariable("gl_in", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
BuiltInVariable("gl_in", "gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable);
}
symbolTable.setVariableExtensions("gl_out", "gl_ViewportMask", 1, &E_GL_NV_viewport_array2);
symbolTable.setVariableExtensions("gl_out", "gl_SecondaryPositionNV", 1, &E_GL_NV_stereo_view_rendering);
symbolTable.setVariableExtensions("gl_out", "gl_SecondaryViewportMaskNV", 1, &E_GL_NV_stereo_view_rendering);
symbolTable.setVariableExtensions("gl_out", "gl_PositionPerViewNV", 1, &E_GL_NVX_multiview_per_view_attributes);
symbolTable.setVariableExtensions("gl_out", "gl_ViewportMaskPerViewNV", 1, &E_GL_NVX_multiview_per_view_attributes);
BuiltInVariable("gl_out", "gl_ViewportMask", EbvViewportMaskNV, symbolTable);
BuiltInVariable("gl_out", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
@@ -8091,15 +8156,16 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
// gl_PointSize, when it needs to be tied to an extension, is always a member of a block.
// (Sometimes with an instance name, sometimes anonymous).
// However, the current automatic extension scheme does not work per block member,
// so for now check when parsing.
//
// if (profile == EEsProfile) {
// if (language == EShLangGeometry)
// symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
// else if (language == EShLangTessEvaluation || language == EShLangTessControl)
// symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
//}
if (profile == EEsProfile) {
if (language == EShLangGeometry) {
symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
symbolTable.setVariableExtensions("gl_in", "gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
} else if (language == EShLangTessEvaluation || language == EShLangTessControl) {
// gl_in tessellation settings of gl_PointSize are in the context-dependent paths
symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
symbolTable.setVariableExtensions("gl_out", "gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
}
}
if ((profile != EEsProfile && version >= 140) ||
(profile == EEsProfile && version >= 310)) {
@@ -8110,7 +8176,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
symbolTable.setVariableExtensions("gl_SubgroupSize", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupEqMask", 1, &E_GL_KHR_shader_subgroup_ballot);
@@ -8450,7 +8517,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
symbolTable.setVariableExtensions("gl_SubgroupSize", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupEqMask", 1, &E_GL_KHR_shader_subgroup_ballot);
@@ -8634,7 +8702,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
symbolTable.setVariableExtensions("gl_SubgroupSize", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupEqMask", 1, &E_GL_KHR_shader_subgroup_ballot);
@@ -8661,7 +8730,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
symbolTable.setVariableExtensions("gl_NumSubgroups", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupID", 1, &E_GL_KHR_shader_subgroup_basic);
@@ -8670,6 +8740,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setFunctionExtensions("subgroupMemoryBarrierShared", 1, &E_GL_KHR_shader_subgroup_basic);
}
symbolTable.setFunctionExtensions("coopMatLoadNV", 1, &E_GL_NV_cooperative_matrix);
symbolTable.setFunctionExtensions("coopMatStoreNV", 1, &E_GL_NV_cooperative_matrix);
symbolTable.setFunctionExtensions("coopMatMulAddNV", 1, &E_GL_NV_cooperative_matrix);
break;
#ifdef NV_EXTENSIONS
case EShLangRayGenNV:
@@ -8719,25 +8794,44 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
break;
case EShLangMeshNV:
if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) {
// Per-vertex builtins
// per-vertex builtins
symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_Position", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_PointSize", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_ClipDistance", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_CullDistance", 1, &E_GL_NV_mesh_shader);
BuiltInVariable("gl_MeshVerticesNV", "gl_Position", EbvPosition, symbolTable);
BuiltInVariable("gl_MeshVerticesNV", "gl_PointSize", EbvPointSize, symbolTable);
BuiltInVariable("gl_MeshVerticesNV", "gl_ClipDistance", EbvClipDistance, symbolTable);
BuiltInVariable("gl_MeshVerticesNV", "gl_CullDistance", EbvCullDistance, symbolTable);
// Per-view builtins
symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_PositionPerViewNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_ClipDistancePerViewNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_CullDistancePerViewNV", 1, &E_GL_NV_mesh_shader);
BuiltInVariable("gl_MeshVerticesNV", "gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable);
BuiltInVariable("gl_MeshVerticesNV", "gl_ClipDistancePerViewNV", EbvClipDistancePerViewNV, symbolTable);
BuiltInVariable("gl_MeshVerticesNV", "gl_CullDistancePerViewNV", EbvCullDistancePerViewNV, symbolTable);
// Per-primitive builtins
// per-primitive builtins
symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_PrimitiveID", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_Layer", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_ViewportIndex", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_ViewportMask", 1, &E_GL_NV_mesh_shader);
BuiltInVariable("gl_MeshPrimitivesNV", "gl_PrimitiveID", EbvPrimitiveId, symbolTable);
BuiltInVariable("gl_MeshPrimitivesNV", "gl_Layer", EbvLayer, symbolTable);
BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportIndex", EbvViewportIndex, symbolTable);
BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportMask", EbvViewportMaskNV, symbolTable);
// Per-view builtins
// per-view per-primitive builtins
symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_LayerPerViewNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_ViewportMaskPerViewNV", 1, &E_GL_NV_mesh_shader);
BuiltInVariable("gl_MeshPrimitivesNV", "gl_LayerPerViewNV", EbvLayerPerViewNV, symbolTable);
BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable);
// other builtins
symbolTable.setVariableExtensions("gl_PrimitiveCountNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_PrimitiveIndicesNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshViewCountNV", 1, &E_GL_NV_mesh_shader);
@@ -8758,11 +8852,13 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
BuiltInVariable("gl_GlobalInvocationID", EbvGlobalInvocationId, symbolTable);
BuiltInVariable("gl_LocalInvocationIndex", EbvLocalInvocationIndex, symbolTable);
// builtin constants
symbolTable.setVariableExtensions("gl_MaxMeshOutputVerticesNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MaxMeshOutputPrimitivesNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MaxMeshWorkGroupSizeNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MaxMeshViewCountNV", 1, &E_GL_NV_mesh_shader);
// builtin functions
symbolTable.setFunctionExtensions("barrier", 1, &E_GL_NV_mesh_shader);
symbolTable.setFunctionExtensions("memoryBarrierShared", 1, &E_GL_NV_mesh_shader);
symbolTable.setFunctionExtensions("groupMemoryBarrier", 1, &E_GL_NV_mesh_shader);
@@ -8804,7 +8900,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
symbolTable.setVariableExtensions("gl_NumSubgroups", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupID", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupSize", 1, &E_GL_KHR_shader_subgroup_basic);
@@ -8837,6 +8934,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setVariableExtensions("gl_LocalInvocationID", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_GlobalInvocationID", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshViewCountNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MeshViewIndicesNV", 1, &E_GL_NV_mesh_shader);
BuiltInVariable("gl_TaskCountNV", EbvTaskCountNV, symbolTable);
BuiltInVariable("gl_WorkGroupSize", EbvWorkGroupSize, symbolTable);
@@ -8844,8 +8943,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
BuiltInVariable("gl_LocalInvocationID", EbvLocalInvocationId, symbolTable);
BuiltInVariable("gl_GlobalInvocationID", EbvGlobalInvocationId, symbolTable);
BuiltInVariable("gl_LocalInvocationIndex", EbvLocalInvocationIndex, symbolTable);
BuiltInVariable("gl_MeshViewCountNV", EbvMeshViewCountNV, symbolTable);
BuiltInVariable("gl_MeshViewIndicesNV", EbvMeshViewIndicesNV, symbolTable);
symbolTable.setVariableExtensions("gl_MaxTaskWorkGroupSizeNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setVariableExtensions("gl_MaxMeshViewCountNV", 1, &E_GL_NV_mesh_shader);
symbolTable.setFunctionExtensions("barrier", 1, &E_GL_NV_mesh_shader);
symbolTable.setFunctionExtensions("memoryBarrierShared", 1, &E_GL_NV_mesh_shader);
@@ -8888,7 +8990,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
symbolTable.setVariableExtensions("gl_NumSubgroups", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupID", 1, &E_GL_KHR_shader_subgroup_basic);
symbolTable.setVariableExtensions("gl_SubgroupSize", 1, &E_GL_KHR_shader_subgroup_basic);
@@ -9314,7 +9417,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
}
// GL_KHR_shader_subgroup
if (spvVersion.vulkan > 0) {
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 140)) {
symbolTable.relateToOperator("subgroupBarrier", EOpSubgroupBarrier);
symbolTable.relateToOperator("subgroupMemoryBarrier", EOpSubgroupMemoryBarrier);
symbolTable.relateToOperator("subgroupMemoryBarrierBuffer", EOpSubgroupMemoryBarrierBuffer);
@@ -9457,6 +9561,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.relateToOperator("fwidthCoarse",EOpFwidthCoarse);
}
#endif
symbolTable.relateToOperator("coopMatLoadNV", EOpCooperativeMatrixLoad);
symbolTable.relateToOperator("coopMatStoreNV", EOpCooperativeMatrixStore);
symbolTable.relateToOperator("coopMatMulAddNV", EOpCooperativeMatrixMulAdd);
break;
#ifdef NV_EXTENSIONS
@@ -9556,6 +9663,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
BuiltInVariable("gl_in", "gl_BackSecondaryColor", EbvBackSecondaryColor, symbolTable);
BuiltInVariable("gl_in", "gl_TexCoord", EbvTexCoord, symbolTable);
BuiltInVariable("gl_in", "gl_FogFragCoord", EbvFogFragCoord, symbolTable);
// extension requirements
if (profile == EEsProfile) {
symbolTable.setVariableExtensions("gl_in", "gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
}
break;
default:
+190 -4
View File
@@ -119,6 +119,62 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
return nullptr;
// Convert "reference +/- int" and "reference - reference" to integer math
if ((op == EOpAdd || op == EOpSub) && extensionRequested(E_GL_EXT_buffer_reference2)) {
// No addressing math on struct with unsized array.
if ((left->getBasicType() == EbtReference && left->getType().getReferentType()->containsUnsizedArray()) ||
(right->getBasicType() == EbtReference && right->getType().getReferentType()->containsUnsizedArray())) {
return nullptr;
}
if (left->getBasicType() == EbtReference && isTypeInt(right->getBasicType())) {
const TType& referenceType = left->getType();
TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
right = createConversion(EbtInt64, right);
right = addBinaryMath(EOpMul, right, size, loc);
TIntermTyped *node = addBinaryMath(op, left, right, loc);
node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
return node;
}
if (op == EOpAdd && right->getBasicType() == EbtReference && isTypeInt(left->getBasicType())) {
const TType& referenceType = right->getType();
TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(right->getType()), loc, true);
right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
left = createConversion(EbtInt64, left);
left = addBinaryMath(EOpMul, left, size, loc);
TIntermTyped *node = addBinaryMath(op, left, right, loc);
node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
return node;
}
if (op == EOpSub && left->getBasicType() == EbtReference && right->getBasicType() == EbtReference) {
TIntermConstantUnion* size = addConstantUnion((long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
left = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, left, TType(EbtInt64));
right = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, right, TType(EbtInt64));
left = addBinaryMath(EOpSub, left, right, loc);
TIntermTyped *node = addBinaryMath(EOpDiv, left, size, loc);
return node;
}
// No other math operators supported on references
if (left->getBasicType() == EbtReference || right->getBasicType() == EbtReference) {
return nullptr;
}
}
// Try converting the children's base types to compatible types.
auto children = addConversion(op, left, right);
left = std::get<0>(children);
@@ -231,6 +287,26 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm
if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
return nullptr;
// Convert "reference += int" to "reference = reference + int". We need this because the
// "reference + int" calculation involves a cast back to the original type, which makes it
// not an lvalue.
if ((op == EOpAddAssign || op == EOpSubAssign) && left->getBasicType() == EbtReference &&
extensionRequested(E_GL_EXT_buffer_reference2)) {
if (!(right->getType().isScalar() && right->getType().isIntegerDomain()))
return nullptr;
TIntermTyped* node = addBinaryMath(op == EOpAddAssign ? EOpAdd : EOpSub, left, right, loc);
if (!node)
return nullptr;
TIntermSymbol* symbol = left->getAsSymbolNode();
left = addSymbol(*symbol);
node = addAssign(EOpAssign, left, node, loc);
return node;
}
//
// Like adding binary math, except the conversion can only go
// from right to left.
@@ -410,7 +486,7 @@ TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOper
//
// This is the safe way to change the operator on an aggregate, as it
// does lots of error checking and fixing. Especially for establishing
// a function call's operation on it's set of parameters. Sequences
// a function call's operation on its set of parameters. Sequences
// of instructions are also aggregates, but they just directly set
// their operator to EOpSequence.
//
@@ -498,6 +574,58 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped
TOperator newOp = EOpNull;
// Certain explicit conversions are allowed conditionally
bool arithemeticInt8Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int8);
#ifdef AMD_EXTENSIONS
bool arithemeticInt16Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int16) ||
extensionRequested(E_GL_AMD_gpu_shader_int16);
bool arithemeticFloat16Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float16) ||
extensionRequested(E_GL_AMD_gpu_shader_half_float);
#else
bool arithemeticInt16Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int16);
bool arithemeticFloat16Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float16);
#endif
bool convertToIntTypes = (convertTo == EbtInt8 || convertTo == EbtUint8 ||
convertTo == EbtInt16 || convertTo == EbtUint16 ||
convertTo == EbtInt || convertTo == EbtUint ||
convertTo == EbtInt64 || convertTo == EbtUint64);
bool convertFromIntTypes = (node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8 ||
node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16 ||
node->getBasicType() == EbtInt || node->getBasicType() == EbtUint ||
node->getBasicType() == EbtInt64 || node->getBasicType() == EbtUint64);
bool convertToFloatTypes = (convertTo == EbtFloat16 || convertTo == EbtFloat || convertTo == EbtDouble);
bool convertFromFloatTypes = (node->getBasicType() == EbtFloat16 ||
node->getBasicType() == EbtFloat ||
node->getBasicType() == EbtDouble);
if (! arithemeticInt8Enabled) {
if (((convertTo == EbtInt8 || convertTo == EbtUint8) && ! convertFromIntTypes) ||
((node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8) && ! convertToIntTypes))
return nullptr;
}
if (! arithemeticInt16Enabled) {
if (((convertTo == EbtInt16 || convertTo == EbtUint16) && ! convertFromIntTypes) ||
((node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16) && ! convertToIntTypes))
return nullptr;
}
if (! arithemeticFloat16Enabled) {
if ((convertTo == EbtFloat16 && ! convertFromFloatTypes) ||
(node->getBasicType() == EbtFloat16 && ! convertToFloatTypes))
return nullptr;
}
switch (convertTo) {
case EbtDouble:
switch (node->getBasicType()) {
@@ -725,6 +853,11 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped
return newNode;
}
TIntermTyped* TIntermediate::addConversion(TBasicType convertTo, TIntermTyped* node) const
{
return createConversion(convertTo, node);
}
// For converting a pair of operands to a binary operation to compatible
// types with each other, relative to the operation in 'op'.
// This does not cover assignment operations, which is asymmetric in that the
@@ -738,7 +871,7 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped
// Returns the converted pair of nodes.
// Returns <nullptr, nullptr> when there is no conversion.
std::tuple<TIntermTyped*, TIntermTyped*>
TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) const
TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1)
{
if (!isConversionAllowed(op, node0) || !isConversionAllowed(op, node1))
return std::make_tuple(nullptr, nullptr);
@@ -751,6 +884,10 @@ TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* no
// If differing arrays, then no conversions.
if (node0->getType().isArray() || node1->getType().isArray())
return std::make_tuple(nullptr, nullptr);
// No implicit conversions for operations involving cooperative matrices
if (node0->getType().isCoopMat() || node1->getType().isCoopMat())
return std::make_tuple(node0, node1);
}
auto promoteTo = std::make_tuple(EbtNumTypes, EbtNumTypes);
@@ -867,7 +1004,7 @@ TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* no
//
// Return nullptr if a conversion can't be done.
//
TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const
TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
{
if (!isConversionAllowed(op, node))
return nullptr;
@@ -983,6 +1120,15 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
case EOpSequence:
case EOpConstructStruct:
case EOpConstructCooperativeMatrix:
if (type.getBasicType() == EbtReference || node->getType().getBasicType() == EbtReference) {
// types must match to assign a reference
if (type == node->getType())
return node;
else
return nullptr;
}
if (type.getBasicType() == node->getType().getBasicType())
return node;
@@ -990,7 +1136,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
if (canImplicitlyPromote(node->getBasicType(), type.getBasicType(), op))
promoteTo = type.getBasicType();
else
return nullptr;
return nullptr;
break;
// For GLSL, there are no conversions needed; the shift amount just needs to be an
@@ -1839,6 +1985,9 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
if (type.getQualifier().nonUniform)
return EOpConstructNonuniform;
if (type.isCoopMat())
return EOpConstructCooperativeMatrix;
switch (type.getBasicType()) {
case EbtStruct:
op = EOpConstructStruct;
@@ -2131,6 +2280,9 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
}
}
break;
case EbtReference:
op = EOpConstructReference;
break;
default:
break;
}
@@ -3308,6 +3460,40 @@ bool TIntermediate::promoteBinary(TIntermBinary& node)
break;
}
if (left->getType().isCoopMat() || right->getType().isCoopMat()) {
if (left->getType().isCoopMat() && right->getType().isCoopMat() &&
*left->getType().getTypeParameters() != *right->getType().getTypeParameters()) {
return false;
}
switch (op) {
case EOpMul:
case EOpMulAssign:
if (left->getType().isCoopMat() && right->getType().isCoopMat()) {
return false;
}
if (op == EOpMulAssign && right->getType().isCoopMat()) {
return false;
}
node.setOp(op == EOpMulAssign ? EOpMatrixTimesScalarAssign : EOpMatrixTimesScalar);
if (right->getType().isCoopMat()) {
node.setType(right->getType());
}
return true;
case EOpAdd:
case EOpSub:
case EOpDiv:
case EOpAssign:
// These require both to be cooperative matrices
if (!left->getType().isCoopMat() || !right->getType().isCoopMat()) {
return false;
}
return true;
default:
break;
}
return false;
}
// Finish handling the case, for all ops, where both operands are scalars.
if (left->isScalar() && right->isScalar())
return true;
@@ -152,6 +152,10 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
case EvqBuffer:
if (node->getQualifier().readonly)
message = "can't modify a readonly buffer";
#ifdef NV_EXTENSIONS
if (node->getQualifier().layoutShaderRecordNV)
message = "can't modify a shaderrecordnv qualified buffer";
#endif
break;
#ifdef NV_EXTENSIONS
case EvqHitAttrNV:
File diff suppressed because it is too large Load Diff
+5 -4
View File
@@ -299,14 +299,14 @@ public:
void fixIoArraySize(const TSourceLoc&, TType&);
void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier);
void handleIoResizeArrayAccess(const TSourceLoc&, TIntermTyped* base);
void checkIoArraysConsistency(const TSourceLoc&, bool tailOnly = false, bool isPerPrimitive = false);
int getIoArrayImplicitSize(bool isPerPrimitive = false) const;
void checkIoArraysConsistency(const TSourceLoc&, bool tailOnly = false);
int getIoArrayImplicitSize(const TQualifier&, TString* featureString = nullptr) const;
void checkIoArrayConsistency(const TSourceLoc&, int requiredSize, const char* feature, TType&, const TString&);
TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, const TString& field);
void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, int member, const TString& memberName);
TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
@@ -337,7 +337,7 @@ public:
void globalCheck(const TSourceLoc&, const char* token);
bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&);
bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&);
void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&);
void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&, const char *sizeType);
bool arrayQualifierError(const TSourceLoc&, const TQualifier&);
bool arrayError(const TSourceLoc&, const TType&);
void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&);
@@ -370,6 +370,7 @@ public:
void nestedStructCheck(const TSourceLoc&);
void arrayObjectCheck(const TSourceLoc&, const TType&, const char* op);
void opaqueCheck(const TSourceLoc&, const TType&, const char* op);
void referenceCheck(const TSourceLoc&, const TType&, const char* op);
void storage16BitAssignmentCheck(const TSourceLoc&, const TType&, const char* op);
void specializationCheck(const TSourceLoc&, const TType&, const char* op);
void structTypeCheck(const TSourceLoc&, TPublicType&);
@@ -592,6 +592,8 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["samplerExternalOES"] = SAMPLEREXTERNALOES; // GL_OES_EGL_image_external
(*KeywordMap)["__samplerExternal2DY2YEXT"] = SAMPLEREXTERNAL2DY2YEXT; // GL_EXT_YUV_target
(*KeywordMap)["sampler"] = SAMPLER;
(*KeywordMap)["samplerShadow"] = SAMPLERSHADOW;
@@ -712,6 +714,8 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["taskNV"] = PERTASKNV;
#endif
(*KeywordMap)["fcoopmatNV"] = FCOOPMATNV;
ReservedSet = new std::unordered_set<const char*, str_hash, str_eq>;
ReservedSet->insert("common");
@@ -776,7 +780,7 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
loc = ppToken.loc;
parserToken->sType.lex.loc = loc;
switch (token) {
case ';': afterType = false; return SEMICOLON;
case ';': afterType = false; afterBuffer = false; return SEMICOLON;
case ',': afterType = false; return COMMA;
case ':': return COLON;
case '=': afterType = false; return EQUAL;
@@ -798,7 +802,7 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
case '?': return QUESTION;
case '[': return LEFT_BRACKET;
case ']': return RIGHT_BRACKET;
case '{': afterStruct = false; return LEFT_BRACE;
case '{': afterStruct = false; afterBuffer = false; return LEFT_BRACE;
case '}': return RIGHT_BRACE;
case '\\':
parseContext.error(loc, "illegal use of escape character", "\\", "");
@@ -945,6 +949,7 @@ int TScanContext::tokenizeIdentifier()
return keyword;
case BUFFER:
afterBuffer = true;
if ((parseContext.profile == EEsProfile && parseContext.version < 310) ||
(parseContext.profile != EEsProfile && parseContext.version < 430))
return identifierOrType();
@@ -1428,6 +1433,13 @@ int TScanContext::tokenizeIdentifier()
return keyword;
return identifierOrType();
case SAMPLEREXTERNAL2DY2YEXT:
afterType = true;
if (parseContext.symbolTable.atBuiltInLevel() ||
parseContext.extensionTurnedOn(E_GL_EXT_YUV_target))
return keyword;
return identifierOrType();
case TEXTURE2D:
case TEXTURECUBE:
case TEXTURECUBEARRAY:
@@ -1621,6 +1633,13 @@ int TScanContext::tokenizeIdentifier()
return identifierOrType();
#endif
case FCOOPMATNV:
afterType = true;
if (parseContext.symbolTable.atBuiltInLevel() ||
parseContext.extensionTurnedOn(E_GL_NV_cooperative_matrix))
return keyword;
return identifierOrType();
default:
parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
return 0;
@@ -1636,7 +1655,9 @@ int TScanContext::identifierOrType()
parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
if ((afterType == false && afterStruct == false) && parserToken->sType.lex.symbol != nullptr) {
if (const TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
if (variable->isUserType()) {
if (variable->isUserType() &&
// treat redeclaration of forward-declared buffer/uniform reference as an identifier
!(variable->getType().getBasicType() == EbtReference && afterBuffer)) {
afterType = true;
return TYPE_NAME;
@@ -53,7 +53,7 @@ public:
explicit TScanContext(TParseContextBase& pc) :
parseContext(pc),
afterType(false), afterStruct(false),
field(false) { }
field(false), afterBuffer(false) { }
virtual ~TScanContext() { }
static void fillInKeywordMap();
@@ -81,6 +81,7 @@ protected:
bool afterType; // true if we've recognized a type, so can only be looking for an identifier
bool afterStruct; // true if we've recognized the STRUCT keyword, so can only be looking for an identifier
bool field; // true if we're on a field, right after a '.'
bool afterBuffer; // true if we've recognized the BUFFER keyword
TSourceLoc loc;
TParserToken* parserToken;
TPpToken* ppToken;
@@ -377,6 +377,8 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS
infoSink, commonTable, symbolTables);
#endif
return true;
}
@@ -474,6 +476,16 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
glslang::ReleaseGlobalLock();
}
// Function to Print all builtins
void DumpBuiltinSymbolTable(TInfoSink& infoSink, const TSymbolTable& symbolTable)
{
infoSink.debug << "BuiltinSymbolTable {\n";
symbolTable.dump(infoSink, true);
infoSink.debug << "}\n";
}
// Return true if the shader was correctly specified for version/profile/stage.
bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNotFirst, int defaultVersion,
EShSource source, int& version, EProfile& profile, const SpvVersion& spvVersion)
@@ -879,8 +891,11 @@ bool ProcessDeferred(
intermediate.setHlslOffsets();
if (messages & EShMsgDebugInfo) {
intermediate.setSourceFile(names[numPre]);
for (int s = 0; s < numStrings; ++s)
intermediate.addSourceText(strings[numPre + s]);
for (int s = 0; s < numStrings; ++s) {
// The string may not be null-terminated, so make sure we provide
// the length along with the string.
intermediate.addSourceText(strings[numPre + s], lengths[numPre + s]);
}
}
SetupBuiltinSymbolTable(version, profile, spvVersion, source);
@@ -902,6 +917,9 @@ bool ProcessDeferred(
return false;
}
if (messages & EShMsgBuiltinSymbolTable)
DumpBuiltinSymbolTable(compiler->infoSink, *symbolTable);
//
// Now we can process the full shader under proper symbols and rules.
//
@@ -1332,7 +1350,7 @@ void ShDestruct(ShHandle handle)
//
// Cleanup symbol tables
//
int __fastcall ShFinalize()
int ShFinalize()
{
glslang::GetGlobalLock();
--NumberOfClients;
@@ -1963,12 +1981,27 @@ const char* TProgram::getInfoDebugLog()
// Reflection implementation.
//
bool TProgram::buildReflection()
bool TProgram::buildReflection(int opts)
{
if (! linked || reflection)
return false;
reflection = new TReflection;
int firstStage = EShLangVertex, lastStage = EShLangFragment;
if (opts & EShReflectionIntermediateIO) {
// if we're reflecting intermediate I/O, determine the first and last stage linked and use those as the
// boundaries for which stages generate pipeline inputs/outputs
firstStage = EShLangCount;
lastStage = 0;
for (int s = 0; s < EShLangCount; ++s) {
if (intermediate[s]) {
firstStage = std::min(firstStage, s);
lastStage = std::max(lastStage, s);
}
}
}
reflection = new TReflection((EShReflectionOptions)opts, (EShLanguage)firstStage, (EShLanguage)lastStage);
for (int s = 0; s < EShLangCount; ++s) {
if (intermediate[s]) {
@@ -1980,27 +2013,23 @@ bool TProgram::buildReflection()
return true;
}
int TProgram::getNumLiveUniformVariables() const { return reflection->getNumUniforms(); }
int TProgram::getNumLiveUniformBlocks() const { return reflection->getNumUniformBlocks(); }
const char* TProgram::getUniformName(int index) const { return reflection->getUniform(index).name.c_str(); }
const char* TProgram::getUniformBlockName(int index) const { return reflection->getUniformBlock(index).name.c_str(); }
int TProgram::getUniformBlockSize(int index) const { return reflection->getUniformBlock(index).size; }
int TProgram::getUniformIndex(const char* name) const { return reflection->getIndex(name); }
int TProgram::getUniformBinding(int index) const { return reflection->getUniform(index).getBinding(); }
EShLanguageMask TProgram::getUniformStages(int index) const { return reflection->getUniform(index).stages; }
int TProgram::getUniformBlockBinding(int index) const { return reflection->getUniformBlock(index).getBinding(); }
int TProgram::getUniformBlockIndex(int index) const { return reflection->getUniform(index).index; }
int TProgram::getUniformBlockCounterIndex(int index) const { return reflection->getUniformBlock(index).counterIndex; }
int TProgram::getUniformType(int index) const { return reflection->getUniform(index).glDefineType; }
int TProgram::getUniformBufferOffset(int index) const { return reflection->getUniform(index).offset; }
int TProgram::getUniformArraySize(int index) const { return reflection->getUniform(index).size; }
int TProgram::getNumLiveAttributes() const { return reflection->getNumAttributes(); }
const char* TProgram::getAttributeName(int index) const { return reflection->getAttribute(index).name.c_str(); }
int TProgram::getAttributeType(int index) const { return reflection->getAttribute(index).glDefineType; }
const TType* TProgram::getAttributeTType(int index) const { return reflection->getAttribute(index).getType(); }
const TType* TProgram::getUniformTType(int index) const { return reflection->getUniform(index).getType(); }
const TType* TProgram::getUniformBlockTType(int index) const { return reflection->getUniformBlock(index).getType(); }
unsigned TProgram::getLocalSize(int dim) const { return reflection->getLocalSize(dim); }
unsigned TProgram::getLocalSize(int dim) const { return reflection->getLocalSize(dim); }
int TProgram::getReflectionIndex(const char* name) const { return reflection->getIndex(name); }
int TProgram::getNumUniformVariables() const { return reflection->getNumUniforms(); }
const TObjectReflection& TProgram::getUniform(int index) const { return reflection->getUniform(index); }
int TProgram::getNumUniformBlocks() const { return reflection->getNumUniformBlocks(); }
const TObjectReflection& TProgram::getUniformBlock(int index) const { return reflection->getUniformBlock(index); }
int TProgram::getNumPipeInputs() const { return reflection->getNumPipeInputs(); }
const TObjectReflection& TProgram::getPipeInput(int index) const { return reflection->getPipeInput(index); }
int TProgram::getNumPipeOutputs() const { return reflection->getNumPipeOutputs(); }
const TObjectReflection& TProgram::getPipeOutput(int index) const { return reflection->getPipeOutput(index); }
int TProgram::getNumBufferVariables() const { return reflection->getNumBufferVariables(); }
const TObjectReflection& TProgram::getBufferVariable(int index) const { return reflection->getBufferVariable(index); }
int TProgram::getNumBufferBlocks() const { return reflection->getNumStorageBuffers(); }
const TObjectReflection& TProgram::getBufferBlock(int index) const { return reflection->getStorageBufferBlock(index); }
int TProgram::getNumAtomicCounters() const { return reflection->getNumAtomicCounters(); }
const TObjectReflection& TProgram::getAtomicCounter(int index) const { return reflection->getAtomicCounter(index); }
void TProgram::dumpReflection() { reflection->dump(); }
@@ -99,6 +99,8 @@ void TType::buildMangledName(TString& mangledName) const
mangledName += "S";
if (sampler.external)
mangledName += "E";
if (sampler.yuv)
mangledName += "Y";
switch (sampler.dim) {
case Esd1D: mangledName += "1"; break;
case Esd2D: mangledName += "2"; break;
@@ -174,37 +176,77 @@ void TType::buildMangledName(TString& mangledName) const
// Dump functions.
//
void TVariable::dump(TInfoSink& infoSink) const
void TSymbol::dumpExtensions(TInfoSink& infoSink) const
{
infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " " << type.getBasicTypeString();
if (type.isArray()) {
infoSink.debug << "[0]";
int numExtensions = getNumExtensions();
if (numExtensions) {
infoSink.debug << " <";
for (int i = 0; i < numExtensions; i++)
infoSink.debug << getExtensions()[i] << ",";
infoSink.debug << ">";
}
}
void TVariable::dump(TInfoSink& infoSink, bool complete) const
{
if (complete) {
infoSink.debug << getName().c_str() << ": " << type.getCompleteString();
dumpExtensions(infoSink);
} else {
infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " "
<< type.getBasicTypeString();
if (type.isArray())
infoSink.debug << "[0]";
}
infoSink.debug << "\n";
}
void TFunction::dump(TInfoSink& infoSink) const
void TFunction::dump(TInfoSink& infoSink, bool complete) const
{
infoSink.debug << getName().c_str() << ": " << returnType.getBasicTypeString() << " " << getMangledName().c_str() << "\n";
if (complete) {
infoSink.debug << getName().c_str() << ": " << returnType.getCompleteString() << " " << getName().c_str()
<< "(";
int numParams = getParamCount();
for (int i = 0; i < numParams; i++) {
const TParameter &param = parameters[i];
infoSink.debug << param.type->getCompleteString() << " "
<< (param.type->isStruct() ? "of " + param.type->getTypeName() + " " : "")
<< (param.name ? *param.name : "") << (i < numParams - 1 ? "," : "");
}
infoSink.debug << ")";
dumpExtensions(infoSink);
} else {
infoSink.debug << getName().c_str() << ": " << returnType.getBasicTypeString() << " "
<< getMangledName().c_str() << "n";
}
infoSink.debug << "\n";
}
void TAnonMember::dump(TInfoSink& TInfoSink) const
void TAnonMember::dump(TInfoSink& TInfoSink, bool complete) const
{
TInfoSink.debug << "anonymous member " << getMemberNumber() << " of " << getAnonContainer().getName().c_str() << "\n";
TInfoSink.debug << "anonymous member " << getMemberNumber() << " of " << getAnonContainer().getName().c_str()
<< "\n";
}
void TSymbolTableLevel::dump(TInfoSink &infoSink) const
void TSymbolTableLevel::dump(TInfoSink& infoSink, bool complete) const
{
tLevel::const_iterator it;
for (it = level.begin(); it != level.end(); ++it)
(*it).second->dump(infoSink);
(*it).second->dump(infoSink, complete);
}
void TSymbolTable::dump(TInfoSink &infoSink) const
void TSymbolTable::dump(TInfoSink& infoSink, bool complete) const
{
for (int level = currentLevel(); level >= 0; --level) {
infoSink.debug << "LEVEL " << level << "\n";
table[level]->dump(infoSink);
table[level]->dump(infoSink, complete);
}
}
@@ -287,19 +329,25 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
{
type.deepCopy(copyOf.type);
userType = copyOf.userType;
numExtensions = 0;
extensions = 0;
if (copyOf.numExtensions != 0)
setExtensions(copyOf.numExtensions, copyOf.extensions);
// we don't support specialization-constant subtrees in cloned tables, only extensions
constSubtree = nullptr;
extensions = nullptr;
memberExtensions = nullptr;
if (copyOf.getNumExtensions() > 0)
setExtensions(copyOf.getNumExtensions(), copyOf.getExtensions());
if (copyOf.hasMemberExtensions()) {
for (int m = 0; m < (int)copyOf.type.getStruct()->size(); ++m) {
if (copyOf.getNumMemberExtensions(m) > 0)
setMemberExtensions(m, copyOf.getNumMemberExtensions(m), copyOf.getMemberExtensions(m));
}
}
if (! copyOf.constArray.empty()) {
assert(! copyOf.type.isStruct());
TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
constArray = newArray;
}
// don't support specialization-constant subtrees in cloned tables
constSubtree = nullptr;
}
TVariable* TVariable::clone() const
@@ -317,10 +365,9 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
parameters.back().copyParam(copyOf.parameters[i]);
}
numExtensions = 0;
extensions = 0;
if (copyOf.extensions != 0)
setExtensions(copyOf.numExtensions, copyOf.extensions);
extensions = nullptr;
if (copyOf.getNumExtensions() > 0)
setExtensions(copyOf.getNumExtensions(), copyOf.getExtensions());
returnType.deepCopy(copyOf.returnType);
mangledName = copyOf.mangledName;
op = copyOf.op;
@@ -359,12 +406,12 @@ TSymbolTableLevel* TSymbolTableLevel::clone() const
const TAnonMember* anon = iter->second->getAsAnonMember();
if (anon) {
// Insert all the anonymous members of this same container at once,
// avoid inserting the other members in the future, once this has been done,
// avoid inserting the remaining members in the future, once this has been done,
// allowing them to all be part of the same new container.
if (! containerCopied[anon->getAnonId()]) {
TVariable* container = anon->getAnonContainer().clone();
container->changeName(NewPoolTString(""));
// insert the whole container
// insert the container and all its members
symTableLevel->insert(*container, false);
containerCopied[anon->getAnonId()] = true;
}
@@ -79,10 +79,12 @@ class TVariable;
class TFunction;
class TAnonMember;
typedef TVector<const char*> TExtensionList;
class TSymbol {
public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
explicit TSymbol(const TString *n) : name(n), numExtensions(0), extensions(0), writable(true) { }
explicit TSymbol(const TString *n) : name(n), extensions(0), writable(true) { }
virtual TSymbol* clone() const = 0;
virtual ~TSymbol() { } // rely on all symbol owned memory coming from the pool
@@ -104,18 +106,18 @@ public:
virtual TType& getWritableType() = 0;
virtual void setUniqueId(int id) { uniqueId = id; }
virtual int getUniqueId() const { return uniqueId; }
virtual void setExtensions(int num, const char* const exts[])
virtual void setExtensions(int numExts, const char* const exts[])
{
assert(extensions == 0);
assert(num > 0);
numExtensions = num;
extensions = NewPoolObject(exts[0], num);
for (int e = 0; e < num; ++e)
extensions[e] = exts[e];
assert(numExts > 0);
extensions = NewPoolObject(extensions);
for (int e = 0; e < numExts; ++e)
extensions->push_back(exts[e]);
}
virtual int getNumExtensions() const { return numExtensions; }
virtual const char** getExtensions() const { return extensions; }
virtual void dump(TInfoSink &infoSink) const = 0;
virtual int getNumExtensions() const { return extensions == nullptr ? 0 : (int)extensions->size(); }
virtual const char** getExtensions() const { return extensions->data(); }
virtual void dump(TInfoSink& infoSink, bool complete = false) const = 0;
void dumpExtensions(TInfoSink& infoSink) const;
virtual bool isReadOnly() const { return ! writable; }
virtual void makeReadOnly() { writable = false; }
@@ -129,8 +131,7 @@ protected:
// For tracking what extensions must be present
// (don't use if correct version/profile is present).
int numExtensions;
const char** extensions; // an array of pointers to existing constant char strings
TExtensionList* extensions; // an array of pointers to existing constant char strings
//
// N.B.: Non-const functions that will be generally used should assert on this,
@@ -155,7 +156,9 @@ public:
: TSymbol(name),
userType(uT),
constSubtree(nullptr),
anonId(-1) { type.shallowCopy(t); }
memberExtensions(nullptr),
anonId(-1)
{ type.shallowCopy(t); }
virtual TVariable* clone() const;
virtual ~TVariable() { }
@@ -172,7 +175,25 @@ public:
virtual void setAnonId(int i) { anonId = i; }
virtual int getAnonId() const { return anonId; }
virtual void dump(TInfoSink &infoSink) const;
virtual void setMemberExtensions(int member, int numExts, const char* const exts[])
{
assert(type.isStruct());
assert(numExts > 0);
if (memberExtensions == nullptr) {
memberExtensions = NewPoolObject(memberExtensions);
memberExtensions->resize(type.getStruct()->size());
}
for (int e = 0; e < numExts; ++e)
(*memberExtensions)[member].push_back(exts[e]);
}
virtual bool hasMemberExtensions() const { return memberExtensions != nullptr; }
virtual int getNumMemberExtensions(int member) const
{
return memberExtensions == nullptr ? 0 : (int)(*memberExtensions)[member].size();
}
virtual const char** getMemberExtensions(int member) const { return (*memberExtensions)[member].data(); }
virtual void dump(TInfoSink& infoSink, bool complete = false) const;
protected:
explicit TVariable(const TVariable&);
@@ -180,15 +201,14 @@ protected:
TType type;
bool userType;
// we are assuming that Pool Allocator will free the memory allocated to unionArray
// when this object is destroyed
// TODO: these two should be a union
// A variable could be a compile-time constant, or a specialization
// constant, or neither, but never both.
TConstUnionArray constArray; // for compile-time constant value
TIntermTyped* constSubtree; // for specialization constant computation
int anonId; // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
TConstUnionArray constArray; // for compile-time constant value
TIntermTyped* constSubtree; // for specialization constant computation
TVector<TExtensionList>* memberExtensions; // per-member extension list, allocated only when needed
int anonId; // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
};
//
@@ -294,7 +314,7 @@ public:
virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
virtual const TParameter& operator[](int i) const { return parameters[i]; }
virtual void dump(TInfoSink &infoSink) const override;
virtual void dump(TInfoSink& infoSink, bool complete = false) const override;
protected:
explicit TFunction(const TFunction&);
@@ -325,35 +345,42 @@ protected:
//
class TAnonMember : public TSymbol {
public:
TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
virtual TAnonMember* clone() const;
TAnonMember(const TString* n, unsigned int m, TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
virtual TAnonMember* clone() const override;
virtual ~TAnonMember() { }
virtual const TAnonMember* getAsAnonMember() const { return this; }
virtual const TAnonMember* getAsAnonMember() const override { return this; }
virtual const TVariable& getAnonContainer() const { return anonContainer; }
virtual unsigned int getMemberNumber() const { return memberNumber; }
virtual const TType& getType() const
virtual const TType& getType() const override
{
const TTypeList& types = *anonContainer.getType().getStruct();
return *types[memberNumber].type;
}
virtual TType& getWritableType()
virtual TType& getWritableType() override
{
assert(writable);
const TTypeList& types = *anonContainer.getType().getStruct();
return *types[memberNumber].type;
}
virtual void setExtensions(int numExts, const char* const exts[]) override
{
anonContainer.setMemberExtensions(memberNumber, numExts, exts);
}
virtual int getNumExtensions() const override { return anonContainer.getNumMemberExtensions(memberNumber); }
virtual const char** getExtensions() const override { return anonContainer.getMemberExtensions(memberNumber); }
virtual int getAnonId() const { return anonId; }
virtual void dump(TInfoSink &infoSink) const;
virtual void dump(TInfoSink& infoSink, bool complete = false) const override;
protected:
explicit TAnonMember(const TAnonMember&);
TAnonMember& operator=(const TAnonMember&);
const TVariable& anonContainer;
TVariable& anonContainer;
unsigned int memberNumber;
int anonId;
};
@@ -515,7 +542,7 @@ public:
void relateToOperator(const char* name, TOperator op);
void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
void dump(TInfoSink &infoSink) const;
void dump(TInfoSink& infoSink, bool complete = false) const;
TSymbolTableLevel* clone() const;
void readOnly();
@@ -789,15 +816,34 @@ public:
table[level]->setFunctionExtensions(name, num, extensions);
}
void setVariableExtensions(const char* name, int num, const char* const extensions[])
void setVariableExtensions(const char* name, int numExts, const char* const extensions[])
{
TSymbol* symbol = find(TString(name));
if (symbol)
symbol->setExtensions(num, extensions);
if (symbol == nullptr)
return;
symbol->setExtensions(numExts, extensions);
}
void setVariableExtensions(const char* blockName, const char* name, int numExts, const char* const extensions[])
{
TSymbol* symbol = find(TString(blockName));
if (symbol == nullptr)
return;
TVariable* variable = symbol->getAsVariable();
assert(variable != nullptr);
const TTypeList& structure = *variable->getAsVariable()->getType().getStruct();
for (int member = 0; member < (int)structure.size(); ++member) {
if (structure[member].type->getFieldName().compare(name) == 0) {
variable->setMemberExtensions(member, numExts, extensions);
return;
}
}
}
int getMaxSymbolId() { return uniqueId; }
void dump(TInfoSink &infoSink) const;
void dump(TInfoSink& infoSink, bool complete = false) const;
void copyTable(const TSymbolTable& copyOf);
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
+21 -1
View File
@@ -157,6 +157,7 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_EXT_frag_depth] = EBhDisable;
extensionBehavior[E_GL_OES_EGL_image_external] = EBhDisable;
extensionBehavior[E_GL_OES_EGL_image_external_essl3] = EBhDisable;
extensionBehavior[E_GL_EXT_YUV_target] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_texture_lod] = EBhDisable;
extensionBehavior[E_GL_EXT_texture_array] = EBhDisable;
extensionBehavior[E_GL_EXT_shadow_samplers] = EBhDisable;
@@ -208,6 +209,8 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_EXT_samplerless_texture_functions] = EBhDisable;
extensionBehavior[E_GL_EXT_scalar_block_layout] = EBhDisable;
extensionBehavior[E_GL_EXT_fragment_invocation_density] = EBhDisable;
extensionBehavior[E_GL_EXT_buffer_reference] = EBhDisable;
extensionBehavior[E_GL_EXT_buffer_reference2] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_16bit_storage] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_8bit_storage] = EBhDisable;
@@ -247,6 +250,8 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_NV_mesh_shader] = EBhDisable;
#endif
extensionBehavior[E_GL_NV_cooperative_matrix] = EBhDisable;
// AEP
extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisable;
extensionBehavior[E_GL_KHR_blend_equation_advanced] = EBhDisable;
@@ -308,6 +313,7 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_EXT_frag_depth 1\n"
"#define GL_OES_EGL_image_external 1\n"
"#define GL_OES_EGL_image_external_essl3 1\n"
"#define GL_EXT_YUV_target 1\n"
"#define GL_EXT_shader_texture_lod 1\n"
"#define GL_EXT_shadow_samplers 1\n"
@@ -386,6 +392,8 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_EXT_samplerless_texture_functions 1\n"
"#define GL_EXT_scalar_block_layout 1\n"
"#define GL_EXT_fragment_invocation_density 1\n"
"#define GL_EXT_buffer_reference 1\n"
"#define GL_EXT_buffer_reference2 1\n"
// GL_KHR_shader_subgroup
"#define GL_KHR_shader_subgroup_basic 1\n"
@@ -426,6 +434,8 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_NV_shader_texture_footprint 1\n"
"#define GL_NV_mesh_shader 1\n"
#endif
"#define GL_NV_cooperative_matrix 1\n"
"#define GL_EXT_shader_explicit_arithmetic_types 1\n"
"#define GL_EXT_shader_explicit_arithmetic_types_int8 1\n"
"#define GL_EXT_shader_explicit_arithmetic_types_int16 1\n"
@@ -803,6 +813,8 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co
else if (strcmp(extension, "GL_NV_shader_subgroup_partitioned") == 0)
updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
#endif
else if (strcmp(extension, "GL_EXT_buffer_reference2") == 0)
updateExtensionBehavior(line, "GL_EXT_buffer_reference", behaviorString);
}
void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
@@ -1024,7 +1036,7 @@ void TParseVersions::float16OpaqueCheck(const TSourceLoc& loc, const char* op, b
void TParseVersions::explicitInt16Check(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (! builtIn) {
const char* const extensions[] = {
const char* const extensions[] = {
#if AMD_EXTENSIONS
E_GL_AMD_gpu_shader_int16,
#endif
@@ -1082,6 +1094,14 @@ void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool buil
}
}
void TParseVersions::fcoopmatCheck(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
const char* const extensions[] = {E_GL_NV_cooperative_matrix};
requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
}
}
// Call for any operation removed because SPIR-V is in use.
void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op)
{
+6 -1
View File
@@ -74,7 +74,7 @@ inline const char* ProfileName(EProfile profile)
}
//
// What source rules, validation rules, target language, etc. are needed
// What source rules, validation rules, target language, etc. are needed or
// desired for SPIR-V?
//
// 0 means a target or rule set is not enabled (ignore rules from that entity).
@@ -110,6 +110,7 @@ const char* const E_GL_OES_standard_derivatives = "GL_OES_standard_deriv
const char* const E_GL_EXT_frag_depth = "GL_EXT_frag_depth";
const char* const E_GL_OES_EGL_image_external = "GL_OES_EGL_image_external";
const char* const E_GL_OES_EGL_image_external_essl3 = "GL_OES_EGL_image_external_essl3";
const char* const E_GL_EXT_YUV_target = "GL_EXT_YUV_target";
const char* const E_GL_EXT_shader_texture_lod = "GL_EXT_shader_texture_lod";
const char* const E_GL_EXT_shadow_samplers = "GL_EXT_shadow_samplers";
@@ -170,6 +171,8 @@ const char* const E_GL_EXT_nonuniform_qualifier = "GL_EXT_nonuniform
const char* const E_GL_EXT_samplerless_texture_functions = "GL_EXT_samplerless_texture_functions";
const char* const E_GL_EXT_scalar_block_layout = "GL_EXT_scalar_block_layout";
const char* const E_GL_EXT_fragment_invocation_density = "GL_EXT_fragment_invocation_density";
const char* const E_GL_EXT_buffer_reference = "GL_EXT_buffer_reference";
const char* const E_GL_EXT_buffer_reference2 = "GL_EXT_buffer_reference2";
// Arrays of extensions for the above viewportEXTs duplications
@@ -224,6 +227,8 @@ const char* const viewportEXTs[] = { E_GL_ARB_shader_viewport_layer_array, E_GL_
const int Num_viewportEXTs = sizeof(viewportEXTs) / sizeof(viewportEXTs[0]);
#endif
const char* const E_GL_NV_cooperative_matrix = "GL_NV_cooperative_matrix";
// AEP
const char* const E_GL_ANDROID_extension_pack_es31a = "GL_ANDROID_extension_pack_es31a";
const char* const E_GL_KHR_blend_equation_advanced = "GL_KHR_blend_equation_advanced";
@@ -52,6 +52,7 @@ bool TAttributeArgs::getInt(int& value, int argNum) const
return true;
}
// extract strings out of attribute arguments stored in attribute aggregate.
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const
@@ -85,6 +86,9 @@ const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNu
if (argNum >= (int)args->getSequence().size())
return nullptr;
if (args->getSequence()[argNum]->getAsConstantUnion() == nullptr)
return nullptr;
const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
if (constVal == nullptr || constVal->getType() != basicType)
return nullptr;
@@ -107,6 +111,16 @@ TAttributeType TParseContext::attributeFromName(const TString& name) const
return EatDependencyInfinite;
else if (name == "dependency_length")
return EatDependencyLength;
else if (name == "min_iterations")
return EatMinIterations;
else if (name == "max_iterations")
return EatMaxIterations;
else if (name == "iteration_multiple")
return EatIterationMultiple;
else if (name == "peel_count")
return EatPeelCount;
else if (name == "partial_count")
return EatPartialCount;
else
return EatNone;
}
@@ -222,29 +236,101 @@ void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermN
}
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
if (it->name != EatDependencyLength && it->size() > 0) {
warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
continue;
}
int value;
const auto noArgument = [&](const char* feature) {
if (it->size() > 0) {
warn(node->getLoc(), "expected no arguments", feature, "");
return false;
}
return true;
};
const auto positiveSignedArgument = [&](const char* feature, int& value) {
if (it->size() == 1 && it->getInt(value)) {
if (value <= 0) {
error(node->getLoc(), "must be positive", feature, "");
return false;
}
} else {
warn(node->getLoc(), "expected a single integer argument", feature, "");
return false;
}
return true;
};
const auto unsignedArgument = [&](const char* feature, unsigned int& uiValue) {
int value;
if (!(it->size() == 1 && it->getInt(value))) {
warn(node->getLoc(), "expected a single integer argument", feature, "");
return false;
}
uiValue = (unsigned int)value;
return true;
};
const auto positiveUnsignedArgument = [&](const char* feature, unsigned int& uiValue) {
int value;
if (it->size() == 1 && it->getInt(value)) {
if (value == 0) {
error(node->getLoc(), "must be greater than or equal to 1", feature, "");
return false;
}
} else {
warn(node->getLoc(), "expected a single integer argument", feature, "");
return false;
}
uiValue = (unsigned int)value;
return true;
};
const auto spirv14 = [&](const char* feature) {
if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4)
warn(node->getLoc(), "attribute requires a SPIR-V 1.4 target-env", feature, "");
};
int value = 0;
unsigned uiValue = 0;
switch (it->name) {
case EatUnroll:
loop->setUnroll();
if (noArgument("unroll"))
loop->setUnroll();
break;
case EatLoop:
loop->setDontUnroll();
if (noArgument("dont_unroll"))
loop->setDontUnroll();
break;
case EatDependencyInfinite:
loop->setLoopDependency(TIntermLoop::dependencyInfinite);
if (noArgument("dependency_infinite"))
loop->setLoopDependency(TIntermLoop::dependencyInfinite);
break;
case EatDependencyLength:
if (it->size() == 1 && it->getInt(value)) {
if (value <= 0)
error(node->getLoc(), "must be positive", "dependency_length", "");
if (positiveSignedArgument("dependency_length", value))
loop->setLoopDependency(value);
} else
warn(node->getLoc(), "expected a single integer argument", "dependency_length", "");
break;
case EatMinIterations:
spirv14("min_iterations");
if (unsignedArgument("min_iterations", uiValue))
loop->setMinIterations(uiValue);
break;
case EatMaxIterations:
spirv14("max_iterations");
if (unsignedArgument("max_iterations", uiValue))
loop->setMaxIterations(uiValue);
break;
case EatIterationMultiple:
spirv14("iteration_multiple");
if (positiveUnsignedArgument("iteration_multiple", uiValue))
loop->setIterationMultiple(uiValue);
break;
case EatPeelCount:
spirv14("peel_count");
if (unsignedArgument("peel_count", uiValue))
loop->setPeelCount(uiValue);
break;
case EatPartialCount:
spirv14("partial_count");
if (unsignedArgument("partial_count", uiValue))
loop->setPartialCount(uiValue);
break;
default:
warn(node->getLoc(), "attribute does not apply to a loop", "", "");
@@ -71,7 +71,12 @@ namespace glslang {
EatPushConstant,
EatConstantId,
EatDependencyInfinite,
EatDependencyLength
EatDependencyLength,
EatMinIterations,
EatMaxIterations,
EatIterationMultiple,
EatPeelCount,
EatPartialCount
};
class TIntermAggregate;
File diff suppressed because it is too large Load Diff
@@ -220,234 +220,236 @@ extern int yydebug;
F64MAT4X4 = 430,
ATOMIC_UINT = 431,
ACCSTRUCTNV = 432,
SAMPLER1D = 433,
SAMPLER2D = 434,
SAMPLER3D = 435,
SAMPLERCUBE = 436,
SAMPLER1DSHADOW = 437,
SAMPLER2DSHADOW = 438,
SAMPLERCUBESHADOW = 439,
SAMPLER1DARRAY = 440,
SAMPLER2DARRAY = 441,
SAMPLER1DARRAYSHADOW = 442,
SAMPLER2DARRAYSHADOW = 443,
ISAMPLER1D = 444,
ISAMPLER2D = 445,
ISAMPLER3D = 446,
ISAMPLERCUBE = 447,
ISAMPLER1DARRAY = 448,
ISAMPLER2DARRAY = 449,
USAMPLER1D = 450,
USAMPLER2D = 451,
USAMPLER3D = 452,
USAMPLERCUBE = 453,
USAMPLER1DARRAY = 454,
USAMPLER2DARRAY = 455,
SAMPLER2DRECT = 456,
SAMPLER2DRECTSHADOW = 457,
ISAMPLER2DRECT = 458,
USAMPLER2DRECT = 459,
SAMPLERBUFFER = 460,
ISAMPLERBUFFER = 461,
USAMPLERBUFFER = 462,
SAMPLERCUBEARRAY = 463,
SAMPLERCUBEARRAYSHADOW = 464,
ISAMPLERCUBEARRAY = 465,
USAMPLERCUBEARRAY = 466,
SAMPLER2DMS = 467,
ISAMPLER2DMS = 468,
USAMPLER2DMS = 469,
SAMPLER2DMSARRAY = 470,
ISAMPLER2DMSARRAY = 471,
USAMPLER2DMSARRAY = 472,
SAMPLEREXTERNALOES = 473,
F16SAMPLER1D = 474,
F16SAMPLER2D = 475,
F16SAMPLER3D = 476,
F16SAMPLER2DRECT = 477,
F16SAMPLERCUBE = 478,
F16SAMPLER1DARRAY = 479,
F16SAMPLER2DARRAY = 480,
F16SAMPLERCUBEARRAY = 481,
F16SAMPLERBUFFER = 482,
F16SAMPLER2DMS = 483,
F16SAMPLER2DMSARRAY = 484,
F16SAMPLER1DSHADOW = 485,
F16SAMPLER2DSHADOW = 486,
F16SAMPLER1DARRAYSHADOW = 487,
F16SAMPLER2DARRAYSHADOW = 488,
F16SAMPLER2DRECTSHADOW = 489,
F16SAMPLERCUBESHADOW = 490,
F16SAMPLERCUBEARRAYSHADOW = 491,
SAMPLER = 492,
SAMPLERSHADOW = 493,
TEXTURE1D = 494,
TEXTURE2D = 495,
TEXTURE3D = 496,
TEXTURECUBE = 497,
TEXTURE1DARRAY = 498,
TEXTURE2DARRAY = 499,
ITEXTURE1D = 500,
ITEXTURE2D = 501,
ITEXTURE3D = 502,
ITEXTURECUBE = 503,
ITEXTURE1DARRAY = 504,
ITEXTURE2DARRAY = 505,
UTEXTURE1D = 506,
UTEXTURE2D = 507,
UTEXTURE3D = 508,
UTEXTURECUBE = 509,
UTEXTURE1DARRAY = 510,
UTEXTURE2DARRAY = 511,
TEXTURE2DRECT = 512,
ITEXTURE2DRECT = 513,
UTEXTURE2DRECT = 514,
TEXTUREBUFFER = 515,
ITEXTUREBUFFER = 516,
UTEXTUREBUFFER = 517,
TEXTURECUBEARRAY = 518,
ITEXTURECUBEARRAY = 519,
UTEXTURECUBEARRAY = 520,
TEXTURE2DMS = 521,
ITEXTURE2DMS = 522,
UTEXTURE2DMS = 523,
TEXTURE2DMSARRAY = 524,
ITEXTURE2DMSARRAY = 525,
UTEXTURE2DMSARRAY = 526,
F16TEXTURE1D = 527,
F16TEXTURE2D = 528,
F16TEXTURE3D = 529,
F16TEXTURE2DRECT = 530,
F16TEXTURECUBE = 531,
F16TEXTURE1DARRAY = 532,
F16TEXTURE2DARRAY = 533,
F16TEXTURECUBEARRAY = 534,
F16TEXTUREBUFFER = 535,
F16TEXTURE2DMS = 536,
F16TEXTURE2DMSARRAY = 537,
SUBPASSINPUT = 538,
SUBPASSINPUTMS = 539,
ISUBPASSINPUT = 540,
ISUBPASSINPUTMS = 541,
USUBPASSINPUT = 542,
USUBPASSINPUTMS = 543,
F16SUBPASSINPUT = 544,
F16SUBPASSINPUTMS = 545,
IMAGE1D = 546,
IIMAGE1D = 547,
UIMAGE1D = 548,
IMAGE2D = 549,
IIMAGE2D = 550,
UIMAGE2D = 551,
IMAGE3D = 552,
IIMAGE3D = 553,
UIMAGE3D = 554,
IMAGE2DRECT = 555,
IIMAGE2DRECT = 556,
UIMAGE2DRECT = 557,
IMAGECUBE = 558,
IIMAGECUBE = 559,
UIMAGECUBE = 560,
IMAGEBUFFER = 561,
IIMAGEBUFFER = 562,
UIMAGEBUFFER = 563,
IMAGE1DARRAY = 564,
IIMAGE1DARRAY = 565,
UIMAGE1DARRAY = 566,
IMAGE2DARRAY = 567,
IIMAGE2DARRAY = 568,
UIMAGE2DARRAY = 569,
IMAGECUBEARRAY = 570,
IIMAGECUBEARRAY = 571,
UIMAGECUBEARRAY = 572,
IMAGE2DMS = 573,
IIMAGE2DMS = 574,
UIMAGE2DMS = 575,
IMAGE2DMSARRAY = 576,
IIMAGE2DMSARRAY = 577,
UIMAGE2DMSARRAY = 578,
F16IMAGE1D = 579,
F16IMAGE2D = 580,
F16IMAGE3D = 581,
F16IMAGE2DRECT = 582,
F16IMAGECUBE = 583,
F16IMAGE1DARRAY = 584,
F16IMAGE2DARRAY = 585,
F16IMAGECUBEARRAY = 586,
F16IMAGEBUFFER = 587,
F16IMAGE2DMS = 588,
F16IMAGE2DMSARRAY = 589,
STRUCT = 590,
VOID = 591,
WHILE = 592,
IDENTIFIER = 593,
TYPE_NAME = 594,
FLOATCONSTANT = 595,
DOUBLECONSTANT = 596,
INT16CONSTANT = 597,
UINT16CONSTANT = 598,
INT32CONSTANT = 599,
UINT32CONSTANT = 600,
INTCONSTANT = 601,
UINTCONSTANT = 602,
INT64CONSTANT = 603,
UINT64CONSTANT = 604,
BOOLCONSTANT = 605,
FLOAT16CONSTANT = 606,
LEFT_OP = 607,
RIGHT_OP = 608,
INC_OP = 609,
DEC_OP = 610,
LE_OP = 611,
GE_OP = 612,
EQ_OP = 613,
NE_OP = 614,
AND_OP = 615,
OR_OP = 616,
XOR_OP = 617,
MUL_ASSIGN = 618,
DIV_ASSIGN = 619,
ADD_ASSIGN = 620,
MOD_ASSIGN = 621,
LEFT_ASSIGN = 622,
RIGHT_ASSIGN = 623,
AND_ASSIGN = 624,
XOR_ASSIGN = 625,
OR_ASSIGN = 626,
SUB_ASSIGN = 627,
LEFT_PAREN = 628,
RIGHT_PAREN = 629,
LEFT_BRACKET = 630,
RIGHT_BRACKET = 631,
LEFT_BRACE = 632,
RIGHT_BRACE = 633,
DOT = 634,
COMMA = 635,
COLON = 636,
EQUAL = 637,
SEMICOLON = 638,
BANG = 639,
DASH = 640,
TILDE = 641,
PLUS = 642,
STAR = 643,
SLASH = 644,
PERCENT = 645,
LEFT_ANGLE = 646,
RIGHT_ANGLE = 647,
VERTICAL_BAR = 648,
CARET = 649,
AMPERSAND = 650,
QUESTION = 651,
INVARIANT = 652,
PRECISE = 653,
HIGH_PRECISION = 654,
MEDIUM_PRECISION = 655,
LOW_PRECISION = 656,
PRECISION = 657,
PACKED = 658,
RESOURCE = 659,
SUPERP = 660
FCOOPMATNV = 433,
SAMPLER1D = 434,
SAMPLER2D = 435,
SAMPLER3D = 436,
SAMPLERCUBE = 437,
SAMPLER1DSHADOW = 438,
SAMPLER2DSHADOW = 439,
SAMPLERCUBESHADOW = 440,
SAMPLER1DARRAY = 441,
SAMPLER2DARRAY = 442,
SAMPLER1DARRAYSHADOW = 443,
SAMPLER2DARRAYSHADOW = 444,
ISAMPLER1D = 445,
ISAMPLER2D = 446,
ISAMPLER3D = 447,
ISAMPLERCUBE = 448,
ISAMPLER1DARRAY = 449,
ISAMPLER2DARRAY = 450,
USAMPLER1D = 451,
USAMPLER2D = 452,
USAMPLER3D = 453,
USAMPLERCUBE = 454,
USAMPLER1DARRAY = 455,
USAMPLER2DARRAY = 456,
SAMPLER2DRECT = 457,
SAMPLER2DRECTSHADOW = 458,
ISAMPLER2DRECT = 459,
USAMPLER2DRECT = 460,
SAMPLERBUFFER = 461,
ISAMPLERBUFFER = 462,
USAMPLERBUFFER = 463,
SAMPLERCUBEARRAY = 464,
SAMPLERCUBEARRAYSHADOW = 465,
ISAMPLERCUBEARRAY = 466,
USAMPLERCUBEARRAY = 467,
SAMPLER2DMS = 468,
ISAMPLER2DMS = 469,
USAMPLER2DMS = 470,
SAMPLER2DMSARRAY = 471,
ISAMPLER2DMSARRAY = 472,
USAMPLER2DMSARRAY = 473,
SAMPLEREXTERNALOES = 474,
SAMPLEREXTERNAL2DY2YEXT = 475,
F16SAMPLER1D = 476,
F16SAMPLER2D = 477,
F16SAMPLER3D = 478,
F16SAMPLER2DRECT = 479,
F16SAMPLERCUBE = 480,
F16SAMPLER1DARRAY = 481,
F16SAMPLER2DARRAY = 482,
F16SAMPLERCUBEARRAY = 483,
F16SAMPLERBUFFER = 484,
F16SAMPLER2DMS = 485,
F16SAMPLER2DMSARRAY = 486,
F16SAMPLER1DSHADOW = 487,
F16SAMPLER2DSHADOW = 488,
F16SAMPLER1DARRAYSHADOW = 489,
F16SAMPLER2DARRAYSHADOW = 490,
F16SAMPLER2DRECTSHADOW = 491,
F16SAMPLERCUBESHADOW = 492,
F16SAMPLERCUBEARRAYSHADOW = 493,
SAMPLER = 494,
SAMPLERSHADOW = 495,
TEXTURE1D = 496,
TEXTURE2D = 497,
TEXTURE3D = 498,
TEXTURECUBE = 499,
TEXTURE1DARRAY = 500,
TEXTURE2DARRAY = 501,
ITEXTURE1D = 502,
ITEXTURE2D = 503,
ITEXTURE3D = 504,
ITEXTURECUBE = 505,
ITEXTURE1DARRAY = 506,
ITEXTURE2DARRAY = 507,
UTEXTURE1D = 508,
UTEXTURE2D = 509,
UTEXTURE3D = 510,
UTEXTURECUBE = 511,
UTEXTURE1DARRAY = 512,
UTEXTURE2DARRAY = 513,
TEXTURE2DRECT = 514,
ITEXTURE2DRECT = 515,
UTEXTURE2DRECT = 516,
TEXTUREBUFFER = 517,
ITEXTUREBUFFER = 518,
UTEXTUREBUFFER = 519,
TEXTURECUBEARRAY = 520,
ITEXTURECUBEARRAY = 521,
UTEXTURECUBEARRAY = 522,
TEXTURE2DMS = 523,
ITEXTURE2DMS = 524,
UTEXTURE2DMS = 525,
TEXTURE2DMSARRAY = 526,
ITEXTURE2DMSARRAY = 527,
UTEXTURE2DMSARRAY = 528,
F16TEXTURE1D = 529,
F16TEXTURE2D = 530,
F16TEXTURE3D = 531,
F16TEXTURE2DRECT = 532,
F16TEXTURECUBE = 533,
F16TEXTURE1DARRAY = 534,
F16TEXTURE2DARRAY = 535,
F16TEXTURECUBEARRAY = 536,
F16TEXTUREBUFFER = 537,
F16TEXTURE2DMS = 538,
F16TEXTURE2DMSARRAY = 539,
SUBPASSINPUT = 540,
SUBPASSINPUTMS = 541,
ISUBPASSINPUT = 542,
ISUBPASSINPUTMS = 543,
USUBPASSINPUT = 544,
USUBPASSINPUTMS = 545,
F16SUBPASSINPUT = 546,
F16SUBPASSINPUTMS = 547,
IMAGE1D = 548,
IIMAGE1D = 549,
UIMAGE1D = 550,
IMAGE2D = 551,
IIMAGE2D = 552,
UIMAGE2D = 553,
IMAGE3D = 554,
IIMAGE3D = 555,
UIMAGE3D = 556,
IMAGE2DRECT = 557,
IIMAGE2DRECT = 558,
UIMAGE2DRECT = 559,
IMAGECUBE = 560,
IIMAGECUBE = 561,
UIMAGECUBE = 562,
IMAGEBUFFER = 563,
IIMAGEBUFFER = 564,
UIMAGEBUFFER = 565,
IMAGE1DARRAY = 566,
IIMAGE1DARRAY = 567,
UIMAGE1DARRAY = 568,
IMAGE2DARRAY = 569,
IIMAGE2DARRAY = 570,
UIMAGE2DARRAY = 571,
IMAGECUBEARRAY = 572,
IIMAGECUBEARRAY = 573,
UIMAGECUBEARRAY = 574,
IMAGE2DMS = 575,
IIMAGE2DMS = 576,
UIMAGE2DMS = 577,
IMAGE2DMSARRAY = 578,
IIMAGE2DMSARRAY = 579,
UIMAGE2DMSARRAY = 580,
F16IMAGE1D = 581,
F16IMAGE2D = 582,
F16IMAGE3D = 583,
F16IMAGE2DRECT = 584,
F16IMAGECUBE = 585,
F16IMAGE1DARRAY = 586,
F16IMAGE2DARRAY = 587,
F16IMAGECUBEARRAY = 588,
F16IMAGEBUFFER = 589,
F16IMAGE2DMS = 590,
F16IMAGE2DMSARRAY = 591,
STRUCT = 592,
VOID = 593,
WHILE = 594,
IDENTIFIER = 595,
TYPE_NAME = 596,
FLOATCONSTANT = 597,
DOUBLECONSTANT = 598,
INT16CONSTANT = 599,
UINT16CONSTANT = 600,
INT32CONSTANT = 601,
UINT32CONSTANT = 602,
INTCONSTANT = 603,
UINTCONSTANT = 604,
INT64CONSTANT = 605,
UINT64CONSTANT = 606,
BOOLCONSTANT = 607,
FLOAT16CONSTANT = 608,
LEFT_OP = 609,
RIGHT_OP = 610,
INC_OP = 611,
DEC_OP = 612,
LE_OP = 613,
GE_OP = 614,
EQ_OP = 615,
NE_OP = 616,
AND_OP = 617,
OR_OP = 618,
XOR_OP = 619,
MUL_ASSIGN = 620,
DIV_ASSIGN = 621,
ADD_ASSIGN = 622,
MOD_ASSIGN = 623,
LEFT_ASSIGN = 624,
RIGHT_ASSIGN = 625,
AND_ASSIGN = 626,
XOR_ASSIGN = 627,
OR_ASSIGN = 628,
SUB_ASSIGN = 629,
LEFT_PAREN = 630,
RIGHT_PAREN = 631,
LEFT_BRACKET = 632,
RIGHT_BRACKET = 633,
LEFT_BRACE = 634,
RIGHT_BRACE = 635,
DOT = 636,
COMMA = 637,
COLON = 638,
EQUAL = 639,
SEMICOLON = 640,
BANG = 641,
DASH = 642,
TILDE = 643,
PLUS = 644,
STAR = 645,
SLASH = 646,
PERCENT = 647,
LEFT_ANGLE = 648,
RIGHT_ANGLE = 649,
VERTICAL_BAR = 650,
CARET = 651,
AMPERSAND = 652,
QUESTION = 653,
INVARIANT = 654,
PRECISE = 655,
HIGH_PRECISION = 656,
MEDIUM_PRECISION = 657,
LOW_PRECISION = 658,
PRECISION = 659,
PACKED = 660,
RESOURCE = 661,
SUPERP = 662
};
#endif
@@ -456,7 +458,7 @@ extern int yydebug;
union YYSTYPE
{
#line 70 "MachineIndependent/glslang.y" /* yacc.c:1909 */
#line 71 "MachineIndependent/glslang.y" /* yacc.c:1909 */
struct {
glslang::TSourceLoc loc;
@@ -489,9 +491,10 @@ union YYSTYPE
glslang::TArraySizes* arraySizes;
glslang::TIdentifierList* identifierList;
};
glslang::TArraySizes* typeParameters;
} interm;
#line 495 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
#line 498 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
@@ -43,6 +43,7 @@
#else
#include <cmath>
#endif
#include <cstdint>
namespace {
@@ -172,8 +173,12 @@ bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
case EOpIndexDirect: out.debug << "direct index"; break;
case EOpIndexIndirect: out.debug << "indirect index"; break;
case EOpIndexDirectStruct:
out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
out.debug << ": direct index for structure"; break;
{
bool reference = node->getLeft()->getType().getBasicType() == EbtReference;
const TTypeList *members = reference ? node->getLeft()->getType().getReferentType()->getStruct() : node->getLeft()->getType().getStruct();
out.debug << (*members)[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
out.debug << ": direct index for structure"; break;
}
case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
case EOpMatrixSwizzle: out.debug << "matrix swizzle"; break;
@@ -232,6 +237,7 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpPostDecrement: out.debug << "Post-Decrement"; break;
case EOpPreIncrement: out.debug << "Pre-Increment"; break;
case EOpPreDecrement: out.debug << "Pre-Decrement"; break;
case EOpCopyObject: out.debug << "copy object"; break;
// * -> bool
case EOpConvInt8ToBool: out.debug << "Convert int8_t to bool"; break;
@@ -419,6 +425,8 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpConvDoubleToUint: out.debug << "Convert double to uint"; break;
case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break;
case EOpConvUint64ToPtr: out.debug << "Convert uint64_t to pointer"; break;
case EOpConvPtrToUint64: out.debug << "Convert pointer to uint64_t"; break;
case EOpRadians: out.debug << "radians"; break;
case EOpDegrees: out.debug << "degrees"; break;
@@ -674,6 +682,8 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpSubpassLoad: out.debug << "subpassLoad"; break;
case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break;
case EOpConstructReference: out.debug << "Construct reference type"; break;
default: out.debug.message(EPrefixError, "Bad unary op");
}
@@ -808,6 +818,8 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpConstructF16Mat4x4: out.debug << "Construct f16mat4"; break;
case EOpConstructStruct: out.debug << "Construct structure"; break;
case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
case EOpConstructReference: out.debug << "Construct reference"; break;
case EOpConstructCooperativeMatrix: out.debug << "Construct cooperative matrix"; break;
case EOpLessThan: out.debug << "Compare Less Than"; break;
case EOpGreaterThan: out.debug << "Compare Greater Than"; break;
@@ -1057,6 +1069,10 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpWritePackedPrimitiveIndices4x8NV: out.debug << "writePackedPrimitiveIndices4x8NV"; break;
#endif
case EOpCooperativeMatrixLoad: out.debug << "Load cooperative matrix"; break;
case EOpCooperativeMatrixStore: out.debug << "Store cooperative matrix"; break;
case EOpCooperativeMatrixMulAdd: out.debug << "MulAdd cooperative matrices"; break;
default: out.debug.message(EPrefixError, "Bad aggregation op");
}
@@ -1148,8 +1164,11 @@ static void OutputDouble(TInfoSink& out, double value, TOutputTraverser::EExtraO
switch (extra) {
case TOutputTraverser::BinaryDoubleOutput:
{
uint64_t b;
static_assert(sizeof(b) == sizeof(value), "sizeof(uint64_t) != sizeof(double)");
memcpy(&b, &value, sizeof(b));
out.debug << " : ";
long long b = *reinterpret_cast<long long*>(&value);
for (size_t i = 0; i < 8 * sizeof(value); ++i, ++b) {
out.debug << ((b & 0x8000000000000000) != 0 ? "1" : "0");
b <<= 1;
+172 -22
View File
@@ -222,8 +222,14 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
else if (xfbBuffers[b].stride != unit.xfbBuffers[b].stride)
error(infoSink, "Contradictory xfb_stride");
xfbBuffers[b].implicitStride = std::max(xfbBuffers[b].implicitStride, unit.xfbBuffers[b].implicitStride);
if (unit.xfbBuffers[b].containsDouble)
xfbBuffers[b].containsDouble = true;
if (unit.xfbBuffers[b].contains64BitType)
xfbBuffers[b].contains64BitType = true;
#ifdef AMD_EXTENSIONS
if (unit.xfbBuffers[b].contains32BitType)
xfbBuffers[b].contains32BitType = true;
if (unit.xfbBuffers[b].contains16BitType)
xfbBuffers[b].contains16BitType = true;
#endif
// TODO: 4.4 link: enhanced layouts: compare ranges
}
@@ -261,6 +267,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
MERGE_TRUE(needToLegalize);
MERGE_TRUE(binaryDoubleOutput);
MERGE_TRUE(usePhysicalStorageBuffer);
}
//
@@ -633,8 +640,14 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
error(infoSink, "Cannot use both gl_FragColor and gl_FragData");
for (size_t b = 0; b < xfbBuffers.size(); ++b) {
if (xfbBuffers[b].containsDouble)
if (xfbBuffers[b].contains64BitType)
RoundToPow2(xfbBuffers[b].implicitStride, 8);
#ifdef AMD_EXTENSIONS
else if (xfbBuffers[b].contains32BitType)
RoundToPow2(xfbBuffers[b].implicitStride, 4);
else if (xfbBuffers[b].contains16BitType)
RoundToPow2(xfbBuffers[b].implicitStride, 2);
#endif
// "It is a compile-time or link-time error to have
// any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or
@@ -649,18 +662,31 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
xfbBuffers[b].stride = xfbBuffers[b].implicitStride;
// "If the buffer is capturing any
// outputs with double-precision components, the stride must be a multiple of 8, otherwise it must be a
// outputs with double-precision or 64-bit integer components, the stride must be a multiple of 8, otherwise it must be a
// multiple of 4, or a compile-time or link-time error results."
if (xfbBuffers[b].containsDouble && ! IsMultipleOfPow2(xfbBuffers[b].stride, 8)) {
error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double:");
if (xfbBuffers[b].contains64BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 8)) {
error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double or 64-bit integer:");
infoSink.info.prefix(EPrefixError);
infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
#ifdef AMD_EXTENSIONS
} else if (xfbBuffers[b].contains32BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) {
#else
} else if (! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) {
#endif
error(infoSink, "xfb_stride must be multiple of 4:");
infoSink.info.prefix(EPrefixError);
infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
}
#ifdef AMD_EXTENSIONS
// "If the buffer is capturing any
// outputs with half-precision or 16-bit integer components, the stride must be a multiple of 2"
else if (xfbBuffers[b].contains16BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 2)) {
error(infoSink, "xfb_stride must be multiple of 2 for buffer holding a half float or 16-bit integer:");
infoSink.info.prefix(EPrefixError);
infoSink.info << " xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
}
#endif
// "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the
// implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents."
if (xfbBuffers[b].stride > (unsigned int)(4 * resources.maxTransformFeedbackInterleavedComponents)) {
@@ -1259,7 +1285,11 @@ int TIntermediate::addXfbBufferOffset(const TType& type)
TXfbBuffer& buffer = xfbBuffers[qualifier.layoutXfbBuffer];
// compute the range
unsigned int size = computeTypeXfbSize(type, buffer.containsDouble);
#ifdef AMD_EXTENSIONS
unsigned int size = computeTypeXfbSize(type, buffer.contains64BitType, buffer.contains32BitType, buffer.contains16BitType);
#else
unsigned int size = computeTypeXfbSize(type, buffer.contains64BitType);
#endif
buffer.implicitStride = std::max(buffer.implicitStride, qualifier.layoutXfbOffset + size);
TRange range(qualifier.layoutXfbOffset, qualifier.layoutXfbOffset + size - 1);
@@ -1278,11 +1308,18 @@ int TIntermediate::addXfbBufferOffset(const TType& type)
// Recursively figure out how many bytes of xfb buffer are used by the given type.
// Return the size of type, in bytes.
// Sets containsDouble to true if the type contains a double.
// N.B. Caller must set containsDouble to false before calling.
unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& containsDouble) const
// Sets contains64BitType to true if the type contains a 64-bit data type.
#ifdef AMD_EXTENSIONS
// Sets contains32BitType to true if the type contains a 32-bit data type.
// Sets contains16BitType to true if the type contains a 16-bit data type.
// N.B. Caller must set contains64BitType, contains32BitType, and contains16BitType to false before calling.
unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const
#else
// N.B. Caller must set contains64BitType to false before calling.
unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains64BitType) const
#endif
{
// "...if applied to an aggregate containing a double, the offset must also be a multiple of 8,
// "...if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8,
// and the space taken in the buffer will be a multiple of 8.
// ...within the qualified entity, subsequent components are each
// assigned, in order, to the next available offset aligned to a multiple of
@@ -1293,29 +1330,59 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
// TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
assert(type.isSizedArray());
TType elementType(type, 0);
return type.getOuterArraySize() * computeTypeXfbSize(elementType, containsDouble);
#ifdef AMD_EXTENSIONS
return type.getOuterArraySize() * computeTypeXfbSize(elementType, contains64BitType, contains16BitType, contains16BitType);
#else
return type.getOuterArraySize() * computeTypeXfbSize(elementType, contains64BitType);
#endif
}
if (type.isStruct()) {
unsigned int size = 0;
bool structContainsDouble = false;
bool structContains64BitType = false;
#ifdef AMD_EXTENSIONS
bool structContains32BitType = false;
bool structContains16BitType = false;
#endif
for (int member = 0; member < (int)type.getStruct()->size(); ++member) {
TType memberType(type, member);
// "... if applied to
// an aggregate containing a double, the offset must also be a multiple of 8,
// an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8,
// and the space taken in the buffer will be a multiple of 8."
bool memberContainsDouble = false;
int memberSize = computeTypeXfbSize(memberType, memberContainsDouble);
if (memberContainsDouble) {
structContainsDouble = true;
bool memberContains64BitType = false;
#ifdef AMD_EXTENSIONS
bool memberContains32BitType = false;
bool memberContains16BitType = false;
int memberSize = computeTypeXfbSize(memberType, memberContains64BitType, memberContains32BitType, memberContains16BitType);
#else
int memberSize = computeTypeXfbSize(memberType, memberContains64BitType);
#endif
if (memberContains64BitType) {
structContains64BitType = true;
RoundToPow2(size, 8);
#ifdef AMD_EXTENSIONS
} else if (memberContains32BitType) {
structContains32BitType = true;
RoundToPow2(size, 4);
} else if (memberContains16BitType) {
structContains16BitType = true;
RoundToPow2(size, 2);
#endif
}
size += memberSize;
}
if (structContainsDouble) {
containsDouble = true;
if (structContains64BitType) {
contains64BitType = true;
RoundToPow2(size, 8);
#ifdef AMD_EXTENSIONS
} else if (structContains32BitType) {
contains32BitType = true;
RoundToPow2(size, 4);
} else if (structContains16BitType) {
contains16BitType = true;
RoundToPow2(size, 2);
#endif
}
return size;
}
@@ -1332,11 +1399,23 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
numComponents = 1;
}
if (type.getBasicType() == EbtDouble) {
containsDouble = true;
if (type.getBasicType() == EbtDouble || type.getBasicType() == EbtInt64 || type.getBasicType() == EbtUint64) {
contains64BitType = true;
return 8 * numComponents;
#ifdef AMD_EXTENSIONS
} else if (type.getBasicType() == EbtFloat16 || type.getBasicType() == EbtInt16 || type.getBasicType() == EbtUint16) {
contains16BitType = true;
return 2 * numComponents;
} else if (type.getBasicType() == EbtInt8 || type.getBasicType() == EbtUint8)
return numComponents;
else {
contains32BitType = true;
return 4 * numComponents;
}
#else
} else
return 4 * numComponents;
#endif
}
const int baseAlignmentVec4Std140 = 16;
@@ -1355,6 +1434,7 @@ int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size)
case EbtUint8: size = 1; return 1;
case EbtInt16:
case EbtUint16: size = 2; return 2;
case EbtReference: size = 8; return 8;
default: size = 4; return 4;
}
}
@@ -1603,4 +1683,74 @@ int TIntermediate::getMemberAlignment(const TType& type, int& size, int& stride,
}
}
// shared calculation by getOffset and getOffsets
void TIntermediate::updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize)
{
int dummyStride;
// modify just the children's view of matrix layout, if there is one for this member
TLayoutMatrix subMatrixLayout = memberType.getQualifier().layoutMatrix;
int memberAlignment = getMemberAlignment(memberType, memberSize, dummyStride,
parentType.getQualifier().layoutPacking,
subMatrixLayout != ElmNone
? subMatrixLayout == ElmRowMajor
: parentType.getQualifier().layoutMatrix == ElmRowMajor);
RoundToPow2(offset, memberAlignment);
}
// Lookup or calculate the offset of a block member, using the recursively
// defined block offset rules.
int TIntermediate::getOffset(const TType& type, int index)
{
const TTypeList& memberList = *type.getStruct();
// Don't calculate offset if one is present, it could be user supplied
// and different than what would be calculated. That is, this is faster,
// but not just an optimization.
if (memberList[index].type->getQualifier().hasOffset())
return memberList[index].type->getQualifier().layoutOffset;
int memberSize = 0;
int offset = 0;
for (int m = 0; m <= index; ++m) {
updateOffset(type, *memberList[m].type, offset, memberSize);
if (m < index)
offset += memberSize;
}
return offset;
}
// Calculate the block data size.
// Block arrayness is not taken into account, each element is backed by a separate buffer.
int TIntermediate::getBlockSize(const TType& blockType)
{
const TTypeList& memberList = *blockType.getStruct();
int lastIndex = (int)memberList.size() - 1;
int lastOffset = getOffset(blockType, lastIndex);
int lastMemberSize;
int dummyStride;
getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
blockType.getQualifier().layoutPacking,
blockType.getQualifier().layoutMatrix == ElmRowMajor);
return lastOffset + lastMemberSize;
}
int TIntermediate::computeBufferReferenceTypeSize(const TType& type)
{
assert(type.getBasicType() == EbtReference);
int size = getBlockSize(*type.getReferentType());
int align = type.getBufferReferenceAlignment();
if (align) {
size = (size + align - 1) & ~(align-1);
}
return size;
}
} // end namespace glslang
+75 -8
View File
@@ -149,11 +149,20 @@ struct TOffsetRange {
// Things that need to be tracked per xfb buffer.
struct TXfbBuffer {
TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { }
#ifdef AMD_EXTENSIONS
TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), contains64BitType(false),
contains32BitType(false), contains16BitType(false) { }
#else
TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), contains64BitType(false) { }
#endif
std::vector<TRange> ranges; // byte offsets that have already been assigned
unsigned int stride;
unsigned int implicitStride;
bool containsDouble;
bool contains64BitType;
#ifdef AMD_EXTENSIONS
bool contains32BitType;
bool contains16BitType;
#endif
};
// Track a set of strings describing how the module was processed.
@@ -252,9 +261,11 @@ public:
useStorageBuffer(false),
useVulkanMemoryModel(false),
hlslIoMapping(false),
useVariablePointers(false),
textureSamplerTransformMode(EShTexSampTransKeep),
needToLegalize(false),
binaryDoubleOutput(false),
usePhysicalStorageBuffer(false),
uniformLocationBase(0)
{
localSize[0] = 1;
@@ -390,6 +401,17 @@ public:
processes.addProcess("use-vulkan-memory-model");
}
bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
void setUsePhysicalStorageBuffer()
{
usePhysicalStorageBuffer = true;
}
bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
void setUseVariablePointers()
{
useVariablePointers = true;
processes.addProcess("use-variable-pointers");
}
bool usingVariablePointers() const { return useVariablePointers; }
template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
bool hasCounterBufferName(const TString& name) const {
@@ -414,11 +436,40 @@ public:
if (spvVersion.openGl > 0)
processes.addProcess("client opengl100");
// target SPV
switch (spvVersion.spv) {
case 0:
break;
case EShTargetSpv_1_0:
break;
case EShTargetSpv_1_1:
processes.addProcess("target-env spirv1.1");
break;
case EShTargetSpv_1_2:
processes.addProcess("target-env spirv1.2");
break;
case EShTargetSpv_1_3:
processes.addProcess("target-env spirv1.3");
break;
default:
processes.addProcess("target-env spirvUnknown");
break;
}
// target-environment processes
if (spvVersion.vulkan > 0)
switch (spvVersion.vulkan) {
case 0:
break;
case EShTargetVulkan_1_0:
processes.addProcess("target-env vulkan1.0");
else if (spvVersion.vulkan > 0)
break;
case EShTargetVulkan_1_1:
processes.addProcess("target-env vulkan1.1");
break;
default:
processes.addProcess("target-env vulkanUnknown");
break;
}
if (spvVersion.openGl > 0)
processes.addProcess("target-env opengl");
}
@@ -444,9 +495,10 @@ public:
TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
TIntermSymbol* addSymbol(const TIntermSymbol&);
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
std::tuple<TIntermTyped*, TIntermTyped*> addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) const;
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
std::tuple<TIntermTyped*, TIntermTyped*> addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1);
TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
TIntermTyped* addConversion(TBasicType convertTo, TIntermTyped* node) const;
void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
@@ -634,12 +686,20 @@ public:
}
unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
int addXfbBufferOffset(const TType&);
unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
#ifdef AMD_EXTENSIONS
unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const;
#else
unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType) const;
#endif
static int getBaseAlignmentScalar(const TType&, int& size);
static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
static bool improperStraddle(const TType& type, int size, int offset);
static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize);
static int getOffset(const TType& type, int index);
static int getBlockSize(const TType& blockType);
static int computeBufferReferenceTypeSize(const TType&);
bool promote(TIntermOperator*);
#ifdef NV_EXTENSIONS
@@ -666,8 +726,10 @@ public:
void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
const std::string& getSourceFile() const { return sourceFile; }
void addSourceText(const char* text) { sourceText = sourceText + text; }
void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
const std::string& getSourceText() const { return sourceText; }
const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
void addProcesses(const std::vector<std::string>& p)
{
for (int i = 0; i < (int)p.size(); ++i)
@@ -802,6 +864,7 @@ protected:
bool useStorageBuffer;
bool useVulkanMemoryModel;
bool hlslIoMapping;
bool useVariablePointers;
std::set<TString> ioAccessed; // set of names of statically read/written I/O that might need extra checking
std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers
@@ -815,11 +878,15 @@ protected:
std::string sourceFile;
std::string sourceText;
// Included text. First string is a name, second is the included text
std::map<std::string, std::string> includeText;
// for OpModuleProcessed, or equivalent
TProcesses processes;
bool needToLegalize;
bool binaryDoubleOutput;
bool usePhysicalStorageBuffer;
std::unordered_map<std::string, int> uniformLocationOverrides;
int uniformLocationBase;
@@ -104,6 +104,7 @@ public:
virtual bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
virtual void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
virtual void checkExtensionStage(const TSourceLoc&, const char* const extension);
virtual void fcoopmatCheck(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...) = 0;
@@ -147,6 +147,10 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
}
token = scanToken(ppToken);
} else if (token != '\n' && token != EndOfInput && !ppToken->space) {
parseContext.ppWarn(ppToken->loc, "missing space after macro name", "#define", "");
return token;
}
// record the definition of the macro
@@ -162,29 +166,43 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
if (existing != nullptr) {
if (! existing->undef) {
// Already defined -- need to make sure they are identical:
// "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
// ordering, spelling, and white-space separation, where all white-space separations are considered identical."
if (existing->functionLike != mac.functionLike)
parseContext.ppError(defineLoc, "Macro redefined; function-like versus object-like:", "#define", atomStrings.getString(defAtom));
else if (existing->args.size() != mac.args.size())
parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", atomStrings.getString(defAtom));
else {
if (existing->args != mac.args)
parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", atomStrings.getString(defAtom));
// "Two replacement lists are identical if and only if the
// preprocessing tokens in both have the same number,
// ordering, spelling, and white-space separation, where all
// white-space separations are considered identical."
if (existing->functionLike != mac.functionLike) {
parseContext.ppError(defineLoc, "Macro redefined; function-like versus object-like:", "#define",
atomStrings.getString(defAtom));
} else if (existing->args.size() != mac.args.size()) {
parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define",
atomStrings.getString(defAtom));
} else {
if (existing->args != mac.args) {
parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define",
atomStrings.getString(defAtom));
}
// set up to compare the two
existing->body.reset();
mac.body.reset();
int newToken;
bool firstToken = true;
do {
int oldToken;
TPpToken oldPpToken;
TPpToken newPpToken;
oldToken = existing->body.getToken(parseContext, &oldPpToken);
newToken = mac.body.getToken(parseContext, &newPpToken);
// for the first token, preceding spaces don't matter
if (firstToken) {
newPpToken.space = oldPpToken.space;
firstToken = false;
}
if (oldToken != newToken || oldPpToken != newPpToken) {
parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", atomStrings.getString(defAtom));
parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define",
atomStrings.getString(defAtom));
break;
}
} while (newToken > 0);
} while (newToken != EndOfInput);
}
}
*existing = mac;
@@ -653,6 +671,7 @@ int TPpContext::CPPinclude(TPpToken* ppToken)
epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
"#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
parseContext.intermediate.addIncludeText(res->headerName.c_str(), res->headerData, res->headerLength);
// There's no "current" location anymore.
parseContext.setCurrentColumn(0);
} else {
@@ -861,8 +880,7 @@ int TPpContext::CPPextension(TPpToken* ppToken)
if (token != PpAtomIdentifier)
parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
assert(strlen(ppToken->name) <= MaxTokenLength);
strcpy(extensionName, ppToken->name);
snprintf(extensionName, sizeof(extensionName), "%s", ppToken->name);
token = scanToken(ppToken);
if (token != ':') {
@@ -1022,7 +1040,9 @@ TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken*
case MacroExpandNotStarted:
break;
case MacroExpandError:
token = EndOfInput;
// toss the rest of the pushed-input argument by scanning until tMarkerInput
while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput)
;
break;
case MacroExpandStarted:
case MacroExpandUndef:
@@ -1034,13 +1054,10 @@ TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken*
expandedArg->putToken(token, ppToken);
}
if (token == EndOfInput) {
if (token != tMarkerInput::marker) {
// Error, or MacroExpand ate the marker, so had bad input, recover
delete expandedArg;
expandedArg = nullptr;
} else {
// remove the marker
popInput();
}
return expandedArg;
@@ -1257,7 +1274,7 @@ MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, b
if (token == ')') {
// closing paren of call
if (in->mac->args.size() == 1 && tokenRecorded == 0)
if (in->mac->args.size() == 1 && !tokenRecorded)
break;
arg++;
break;
+81 -15
View File
@@ -84,6 +84,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sstream>
#include "../ParseHelper.h"
#include "PpTokens.h"
/* windows only pragma */
#ifdef _MSC_VER
@@ -212,7 +213,8 @@ public:
virtual int scan(TPpToken*) = 0;
virtual int getch() = 0;
virtual void ungetch() = 0;
virtual bool peekPasting() { return false; } // true when about to see ##
virtual bool peekPasting() { return false; } // true when about to see ##
virtual bool peekContinuedPasting(int) { return false; } // true when non-spaced tokens can paste
virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define)
virtual bool isMacroInput() { return false; }
@@ -243,24 +245,79 @@ public:
// From PpTokens.cpp
//
// Capture the needed parts of a token stream for macro recording/playback.
class TokenStream {
public:
TokenStream() : current(0) { }
// Manage a stream of these 'Token', which capture the relevant parts
// of a TPpToken, plus its atom.
class Token {
public:
Token(int atom, const TPpToken& ppToken) :
atom(atom),
space(ppToken.space),
i64val(ppToken.i64val),
name(ppToken.name) { }
int get(TPpToken& ppToken)
{
ppToken.clear();
ppToken.space = space;
ppToken.i64val = i64val;
snprintf(ppToken.name, sizeof(ppToken.name), "%s", name.c_str());
return atom;
}
bool isAtom(int a) const { return atom == a; }
int getAtom() const { return atom; }
bool nonSpaced() const { return !space; }
protected:
Token() {}
int atom;
bool space; // did a space precede the token?
long long i64val;
TString name;
};
TokenStream() : currentPos(0) { }
void putToken(int token, TPpToken* ppToken);
bool peekToken(int atom) { return !atEnd() && stream[currentPos].isAtom(atom); }
bool peekContinuedPasting(int atom)
{
// This is basically necessary because, for example, the PP
// tokenizer only accepts valid numeric-literals plus suffixes, so
// separates numeric-literals plus bad suffix into two tokens, which
// should get both pasted together as one token when token pasting.
//
// The following code is a bit more generalized than the above example.
if (!atEnd() && atom == PpAtomIdentifier && stream[currentPos].nonSpaced()) {
switch(stream[currentPos].getAtom()) {
case PpAtomConstInt:
case PpAtomConstUint:
case PpAtomConstInt64:
case PpAtomConstUint64:
case PpAtomConstInt16:
case PpAtomConstUint16:
case PpAtomConstFloat:
case PpAtomConstDouble:
case PpAtomConstFloat16:
case PpAtomConstString:
case PpAtomIdentifier:
return true;
default:
break;
}
}
return false;
}
int getToken(TParseContextBase&, TPpToken*);
bool atEnd() { return current >= data.size(); }
bool atEnd() { return currentPos >= stream.size(); }
bool peekTokenizedPasting(bool lastTokenPastes);
bool peekUntokenizedPasting();
void reset() { current = 0; }
void reset() { currentPos = 0; }
protected:
void putSubtoken(char);
int getSubtoken();
void ungetSubtoken();
TVector<unsigned char> data;
size_t current;
TVector<Token> stream;
size_t currentPos;
};
//
@@ -320,6 +377,10 @@ protected:
int getChar() { return inputStack.back()->getch(); }
void ungetChar() { inputStack.back()->ungetch(); }
bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); }
bool peekContinuedPasting(int a)
{
return !inputStack.empty() && inputStack.back()->peekContinuedPasting(a);
}
bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); }
bool isMacroInput() { return inputStack.size() > 0 && inputStack.back()->isMacroInput(); }
@@ -344,6 +405,7 @@ protected:
virtual int getch() override { assert(0); return EndOfInput; }
virtual void ungetch() override { assert(0); }
bool peekPasting() override { return prepaste; }
bool peekContinuedPasting(int a) override { return mac->body.peekContinuedPasting(a); }
bool endOfReplacementList() override { return mac->body.atEnd(); }
bool isMacroInput() override { return true; }
@@ -418,14 +480,18 @@ protected:
class tTokenInput : public tInput {
public:
tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) : tInput(pp), tokens(t), lastTokenPastes(prepasting) { }
tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) :
tInput(pp),
tokens(t),
lastTokenPastes(prepasting) { }
virtual int scan(TPpToken *ppToken) override { return tokens->getToken(pp->parseContext, ppToken); }
virtual int getch() override { assert(0); return EndOfInput; }
virtual void ungetch() override { assert(0); }
virtual bool peekPasting() override { return tokens->peekTokenizedPasting(lastTokenPastes); }
bool peekContinuedPasting(int a) override { return tokens->peekContinuedPasting(a); }
protected:
TokenStream* tokens;
bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token
bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token
};
class tUngotTokenInput : public tInput {
@@ -549,9 +615,9 @@ protected:
scanner.setLine(startLoc.line);
scanner.setString(startLoc.string);
scanner.setFile(startLoc.name->c_str(), 0);
scanner.setFile(startLoc.name->c_str(), 1);
scanner.setFile(startLoc.name->c_str(), 2);
scanner.setFile(startLoc.getFilenameStr(), 0);
scanner.setFile(startLoc.getFilenameStr(), 1);
scanner.setFile(startLoc.getFilenameStr(), 2);
}
// tInput methods:
@@ -96,12 +96,19 @@ namespace glslang {
/////////////////////////////////// Floating point constants: /////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
/*
* lFloatConst() - Scan a single- or double-precision floating point constant. Assumes that the scanner
* has seen at least one digit, followed by either a decimal '.' or the
* letter 'e', or a precision ending (e.g., F or LF).
*/
//
// Scan a single- or double-precision floating point constant.
// Assumes that the scanner has seen at least one digit,
// followed by either a decimal '.' or the letter 'e', or a
// precision ending (e.g., F or LF).
//
// This is technically not correct, as the preprocessor should just
// accept the numeric literal along with whatever suffix it has, but
// currently, it stops on seeing a bad suffix, treating that as the
// next token. This effects things like token pasting, where it is
// relevant how many tokens something was broken into.
//
// See peekContinuedPasting().
int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
{
const auto saveName = [&](int ch) {
@@ -435,6 +442,14 @@ int TPpContext::characterLiteral(TPpToken* ppToken)
//
// Scanner used to tokenize source stream.
//
// N.B. Invalid numeric suffixes are not consumed.//
// This is technically not correct, as the preprocessor should just
// accept the numeric literal along with whatever suffix it has, but
// currently, it stops on seeing a bad suffix, treating that as the
// next token. This effects things like token pasting, where it is
// relevant how many tokens something was broken into.
// See peekContinuedPasting().
//
int TPpContext::tStringInput::scan(TPpToken* ppToken)
{
int AlreadyComplained = 0;
@@ -1116,7 +1131,7 @@ int TPpContext::tokenize(TPpToken& ppToken)
parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
continue;
default:
strcpy(ppToken.name, atomStrings.getString(token));
snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(token));
break;
}
@@ -1153,61 +1168,69 @@ int TPpContext::tokenPaste(int token, TPpToken& ppToken)
break;
}
// get the token after the ##
token = scanToken(&pastedPpToken);
// Get the token(s) after the ##.
// Because of "space" semantics, and prior tokenization, what
// appeared a single token, e.g. "3A", might have been tokenized
// into two tokens "3" and "A", but the "A" will have 'space' set to
// false. Accumulate all of these to recreate the original lexical
// appearing token.
do {
token = scanToken(&pastedPpToken);
// This covers end of argument expansion
if (token == tMarkerInput::marker) {
parseContext.ppError(ppToken.loc, "unexpected location; end of argument", "##", "");
break;
}
// This covers end of argument expansion
if (token == tMarkerInput::marker) {
parseContext.ppError(ppToken.loc, "unexpected location; end of argument", "##", "");
return resultToken;
}
// get the token text
switch (resultToken) {
case PpAtomIdentifier:
// already have the correct text in token.names
break;
case '=':
case '!':
case '-':
case '~':
case '+':
case '*':
case '/':
case '%':
case '<':
case '>':
case '|':
case '^':
case '&':
case PpAtomRight:
case PpAtomLeft:
case PpAtomAnd:
case PpAtomOr:
case PpAtomXor:
strcpy(ppToken.name, atomStrings.getString(resultToken));
strcpy(pastedPpToken.name, atomStrings.getString(token));
break;
default:
parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", "");
return resultToken;
}
// get the token text
switch (resultToken) {
case PpAtomIdentifier:
// already have the correct text in token.names
break;
case '=':
case '!':
case '-':
case '~':
case '+':
case '*':
case '/':
case '%':
case '<':
case '>':
case '|':
case '^':
case '&':
case PpAtomRight:
case PpAtomLeft:
case PpAtomAnd:
case PpAtomOr:
case PpAtomXor:
snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(resultToken));
snprintf(pastedPpToken.name, sizeof(pastedPpToken.name), "%s", atomStrings.getString(token));
break;
default:
parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", "");
return resultToken;
}
// combine the tokens
if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) {
parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", "");
return resultToken;
}
strncat(ppToken.name, pastedPpToken.name, MaxTokenLength - strlen(ppToken.name));
// combine the tokens
if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) {
parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", "");
return resultToken;
}
snprintf(&ppToken.name[0] + strlen(ppToken.name), sizeof(ppToken.name) - strlen(ppToken.name),
"%s", pastedPpToken.name);
// correct the kind of token we are making, if needed (identifiers stay identifiers)
if (resultToken != PpAtomIdentifier) {
int newToken = atomStrings.getAtom(ppToken.name);
if (newToken > 0)
resultToken = newToken;
else
parseContext.ppError(ppToken.loc, "combined token is invalid", "##", "");
}
// correct the kind of token we are making, if needed (identifiers stay identifiers)
if (resultToken != PpAtomIdentifier) {
int newToken = atomStrings.getAtom(ppToken.name);
if (newToken > 0)
resultToken = newToken;
else
parseContext.ppError(ppToken.loc, "combined token is invalid", "##", "");
}
} while (peekContinuedPasting(resultToken));
}
return resultToken;
@@ -99,151 +99,33 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace glslang {
namespace {
// When recording (and playing back) should the backing name string
// be saved (restored)?
bool SaveName(int atom)
{
switch (atom) {
case PpAtomIdentifier:
case PpAtomConstString:
case PpAtomConstInt:
case PpAtomConstUint:
case PpAtomConstInt64:
case PpAtomConstUint64:
#ifdef AMD_EXTENSIONS
case PpAtomConstInt16:
case PpAtomConstUint16:
#endif
case PpAtomConstFloat:
case PpAtomConstDouble:
case PpAtomConstFloat16:
return true;
default:
return false;
}
}
// When recording (and playing back) should the numeric value
// be saved (restored)?
bool SaveValue(int atom)
{
switch (atom) {
case PpAtomConstInt:
case PpAtomConstUint:
case PpAtomConstInt64:
case PpAtomConstUint64:
#ifdef AMD_EXTENSIONS
case PpAtomConstInt16:
case PpAtomConstUint16:
#endif
case PpAtomConstFloat:
case PpAtomConstDouble:
case PpAtomConstFloat16:
return true;
default:
return false;
}
}
}
// push onto back of stream
void TPpContext::TokenStream::putSubtoken(char subtoken)
{
data.push_back(static_cast<unsigned char>(subtoken));
}
// get the next token in stream
int TPpContext::TokenStream::getSubtoken()
{
if (current < data.size())
return data[current++];
else
return EndOfInput;
}
// back up one position in the stream
void TPpContext::TokenStream::ungetSubtoken()
{
if (current > 0)
--current;
}
// Add a complete token (including backing string) to the end of a list
// for later playback.
// Add a token (including backing string) to the end of a macro
// token stream, for later playback.
void TPpContext::TokenStream::putToken(int atom, TPpToken* ppToken)
{
// save the atom
assert((atom & ~0xff) == 0);
putSubtoken(static_cast<char>(atom));
// save the backing name string
if (SaveName(atom)) {
const char* s = ppToken->name;
while (*s)
putSubtoken(*s++);
putSubtoken(0);
}
// save the numeric value
if (SaveValue(atom)) {
const char* n = reinterpret_cast<const char*>(&ppToken->i64val);
for (size_t i = 0; i < sizeof(ppToken->i64val); ++i)
putSubtoken(*n++);
}
TokenStream::Token streamToken(atom, *ppToken);
stream.push_back(streamToken);
}
// Read the next token from a token stream.
// (Not the source stream, but a stream used to hold a tokenized macro).
// Read the next token from a macro token stream.
int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken)
{
// get the atom
int atom = getSubtoken();
if (atom == EndOfInput)
return atom;
if (atEnd())
return EndOfInput;
// init the token
ppToken->clear();
int atom = stream[currentPos++].get(*ppToken);
ppToken->loc = parseContext.getCurrentLoc();
// get the backing name string
if (SaveName(atom)) {
int ch = getSubtoken();
int len = 0;
while (ch != 0 && ch != EndOfInput) {
if (len < MaxTokenLength) {
ppToken->name[len] = (char)ch;
len++;
ch = getSubtoken();
} else {
parseContext.error(ppToken->loc, "token too long", "", "");
break;
}
}
ppToken->name[len] = 0;
}
// Check for ##, unless the current # is the last character
if (atom == '#') {
if (current < data.size()) {
if (getSubtoken() == '#') {
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
atom = PpAtomPaste;
} else
ungetSubtoken();
if (peekToken('#')) {
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
currentPos++;
atom = PpAtomPaste;
}
}
// get the numeric value
if (SaveValue(atom)) {
char* n = reinterpret_cast<char*>(&ppToken->i64val);
for (size_t i = 0; i < sizeof(ppToken->i64val); ++i)
*n++ = (char)getSubtoken();
}
return atom;
}
@@ -256,15 +138,14 @@ bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
{
// 1. preceding ##?
size_t savePos = current;
int subtoken;
size_t savePos = currentPos;
// skip white space
do {
subtoken = getSubtoken();
} while (subtoken == ' ');
current = savePos;
if (subtoken == PpAtomPaste)
while (peekToken(' '))
++currentPos;
if (peekToken(PpAtomPaste)) {
currentPos = savePos;
return true;
}
// 2. last token and we've been told after this there will be a ##
@@ -273,18 +154,18 @@ bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
// Getting here means the last token will be pasted, after this
// Are we at the last non-whitespace token?
savePos = current;
savePos = currentPos;
bool moreTokens = false;
do {
subtoken = getSubtoken();
if (subtoken == EndOfInput)
if (atEnd())
break;
if (subtoken != ' ') {
if (!peekToken(' ')) {
moreTokens = true;
break;
}
++currentPos;
} while (true);
current = savePos;
currentPos = savePos;
return !moreTokens;
}
@@ -293,23 +174,21 @@ bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
bool TPpContext::TokenStream::peekUntokenizedPasting()
{
// don't return early, have to restore this
size_t savePos = current;
size_t savePos = currentPos;
// skip white-space
int subtoken;
do {
subtoken = getSubtoken();
} while (subtoken == ' ');
while (peekToken(' '))
++currentPos;
// check for ##
bool pasting = false;
if (subtoken == '#') {
subtoken = getSubtoken();
if (subtoken == '#')
if (peekToken('#')) {
++currentPos;
if (peekToken('#'))
pasting = true;
}
current = savePos;
currentPos = savePos;
return pasting;
}
@@ -93,72 +93,128 @@ public:
// Use a degenerate (empty) set of dereferences to immediately put as at the end of
// the dereference change expected by blowUpActiveAggregate.
TList<TIntermBinary*> derefs;
blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0);
blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0, 0,
base.getQualifier().storage, true);
}
}
void addAttribute(const TIntermSymbol& base)
void addPipeIOVariable(const TIntermSymbol& base)
{
if (processedDerefs.find(&base) == processedDerefs.end()) {
processedDerefs.insert(&base);
const TString &name = base.getName();
const TType &type = base.getType();
const bool input = base.getQualifier().isPipeInput();
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
if (it == reflection.nameToIndex.end()) {
reflection.nameToIndex[name] = (int)reflection.indexToAttribute.size();
reflection.indexToAttribute.push_back(TObjectReflection(name, type, 0, mapToGlType(type), 0, 0));
TReflection::TMapIndexToReflection &ioItems =
input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
if (reflection.options & EShReflectionUnwrapIOBlocks) {
bool anonymous = IsAnonymous(name);
TString baseName;
if (type.getBasicType() == EbtBlock) {
baseName = anonymous ? TString() : type.getTypeName();
} else {
baseName = anonymous ? TString() : name;
}
// by convention if this is an arrayed block we ignore the array in the reflection
if (type.isArray() && type.getBasicType() == EbtBlock) {
blowUpIOAggregate(input, baseName, TType(type, 0));
} else {
blowUpIOAggregate(input, baseName, type);
}
} else {
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
if (it == reflection.nameToIndex.end()) {
reflection.nameToIndex[name.c_str()] = (int)ioItems.size();
ioItems.push_back(
TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
EShLanguageMask& stages = ioItems.back().stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
} else {
EShLanguageMask& stages = ioItems[it->second].stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
}
}
}
// Lookup or calculate the offset of a block member, using the recursively
// Lookup or calculate the offset of all block members at once, using the recursively
// defined block offset rules.
int getOffset(const TType& type, int index)
void getOffsets(const TType& type, TVector<int>& offsets)
{
const TTypeList& memberList = *type.getStruct();
// Don't calculate offset if one is present, it could be user supplied
// and different than what would be calculated. That is, this is faster,
// but not just an optimization.
if (memberList[index].type->getQualifier().hasOffset())
return memberList[index].type->getQualifier().layoutOffset;
int memberSize;
int dummyStride;
int memberSize = 0;
int offset = 0;
for (int m = 0; m <= index; ++m) {
// modify just the children's view of matrix layout, if there is one for this member
TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
int memberAlignment = intermediate.getMemberAlignment(*memberList[m].type, memberSize, dummyStride,
type.getQualifier().layoutPacking,
subMatrixLayout != ElmNone
? subMatrixLayout == ElmRowMajor
: type.getQualifier().layoutMatrix == ElmRowMajor);
RoundToPow2(offset, memberAlignment);
if (m < index)
offset += memberSize;
}
for (size_t m = 0; m < offsets.size(); ++m) {
// if the user supplied an offset, snap to it now
if (memberList[m].type->getQualifier().hasOffset())
offset = memberList[m].type->getQualifier().layoutOffset;
return offset;
// calculate the offset of the next member and align the current offset to this member
intermediate.updateOffset(type, *memberList[m].type, offset, memberSize);
// save the offset of this member
offsets[m] = offset;
// update for the next member
offset += memberSize;
}
}
// Calculate the block data size.
// Block arrayness is not taken into account, each element is backed by a separate buffer.
int getBlockSize(const TType& blockType)
// Calculate the stride of an array type
int getArrayStride(const TType& baseType, const TType& type)
{
const TTypeList& memberList = *blockType.getStruct();
int lastIndex = (int)memberList.size() - 1;
int lastOffset = getOffset(blockType, lastIndex);
int dummySize;
int stride;
int lastMemberSize;
int dummyStride;
intermediate.getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
blockType.getQualifier().layoutPacking,
blockType.getQualifier().layoutMatrix == ElmRowMajor);
// consider blocks to have 0 stride, so that all offsets are relative to the start of their block
if (type.getBasicType() == EbtBlock)
return 0;
return lastOffset + lastMemberSize;
TLayoutMatrix subMatrixLayout = type.getQualifier().layoutMatrix;
intermediate.getMemberAlignment(type, dummySize, stride,
baseType.getQualifier().layoutPacking,
subMatrixLayout != ElmNone
? subMatrixLayout == ElmRowMajor
: baseType.getQualifier().layoutMatrix == ElmRowMajor);
return stride;
}
// count the total number of leaf members from iterating out of a block type
int countAggregateMembers(const TType& parentType)
{
if (! parentType.isStruct())
return 1;
const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);
bool blockParent = (parentType.getBasicType() == EbtBlock && parentType.getQualifier().storage == EvqBuffer);
const TTypeList &memberList = *parentType.getStruct();
int ret = 0;
for (size_t i = 0; i < memberList.size(); i++)
{
const TType &memberType = *memberList[i].type;
int numMembers = countAggregateMembers(memberType);
// for sized arrays of structs, apply logic to expand out the same as we would below in
// blowUpActiveAggregate
if (memberType.isArray() && ! memberType.getArraySizes()->hasUnsized() && memberType.isStruct()) {
if (! strictArraySuffix || ! blockParent)
numMembers *= memberType.getArraySizes()->getCumulativeSize();
}
ret += numMembers;
}
return ret;
}
// Traverse the provided deref chain, including the base, and
@@ -169,8 +225,19 @@ public:
// arraySize tracks, just for the final dereference in the chain, if there was a specific known size.
// A value of 0 for arraySize will mean to use the full array's size.
void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize)
TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize,
int topLevelArrayStride, TStorageQualifier baseStorage, bool active)
{
// when strictArraySuffix is enabled, we closely follow the rules from ARB_program_interface_query.
// Broadly:
// * arrays-of-structs always have a [x] suffix.
// * with array-of-struct variables in the root of a buffer block, only ever return [0].
// * otherwise, array suffixes are added whenever we iterate, even if that means expanding out an array.
const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);
// is this variable inside a buffer block. This flag is set back to false after we iterate inside the first array element.
bool blockParent = (baseType.getBasicType() == EbtBlock && baseType.getQualifier().storage == EvqBuffer);
// process the part of the dereference chain that was explicit in the shader
TString name = baseName;
const TType* terminalType = &baseType;
@@ -179,29 +246,54 @@ public:
terminalType = &visitNode->getType();
int index;
switch (visitNode->getOp()) {
case EOpIndexIndirect:
case EOpIndexIndirect: {
int stride = getArrayStride(baseType, visitNode->getLeft()->getType());
if (topLevelArrayStride == 0)
topLevelArrayStride = stride;
// Visit all the indices of this array, and for each one add on the remaining dereferencing
for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) {
TString newBaseName = name;
if (baseType.getBasicType() != EbtBlock)
if (strictArraySuffix && blockParent)
newBaseName.append(TString("[0]"));
else if (strictArraySuffix || baseType.getBasicType() != EbtBlock)
newBaseName.append(TString("[") + String(i) + "]");
TList<TIntermBinary*>::const_iterator nextDeref = deref;
++nextDeref;
TType derefType(*terminalType, 0);
blowUpActiveAggregate(derefType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize);
blowUpActiveAggregate(*terminalType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize,
topLevelArrayStride, baseStorage, active);
if (offset >= 0)
offset += stride;
}
// it was all completed in the recursive calls above
return;
case EOpIndexDirect:
}
case EOpIndexDirect: {
int stride = getArrayStride(baseType, visitNode->getLeft()->getType());
index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
if (baseType.getBasicType() != EbtBlock)
if (strictArraySuffix && blockParent) {
name.append(TString("[0]"));
} else if (strictArraySuffix || baseType.getBasicType() != EbtBlock) {
name.append(TString("[") + String(index) + "]");
if (offset >= 0)
offset += stride * index;
}
if (topLevelArrayStride == 0)
topLevelArrayStride = stride;
blockParent = false;
break;
}
case EOpIndexDirectStruct:
index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
if (offset >= 0)
offset += getOffset(visitNode->getLeft()->getType(), index);
offset += intermediate.getOffset(visitNode->getLeft()->getType(), index);
if (name.size() > 0)
name.append(".");
name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());
@@ -213,24 +305,65 @@ public:
// if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it...
if (! isReflectionGranularity(*terminalType)) {
// the base offset of this node, that children are relative to
int baseOffset = offset;
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 < std::max(terminalType->getOuterArraySize(), 1); ++i) {
int stride = 0;
if (offset >= 0)
stride = getArrayStride(baseType, *terminalType);
if (topLevelArrayStride == 0)
topLevelArrayStride = stride;
int arrayIterateSize = std::max(terminalType->getOuterArraySize(), 1);
// for top-level arrays in blocks, only expand [0] to avoid explosion of items
if (strictArraySuffix && blockParent)
arrayIterateSize = 1;
for (int i = 0; i < arrayIterateSize; ++i) {
TString newBaseName = name;
newBaseName.append(TString("[") + String(i) + "]");
TType derefType(*terminalType, 0);
blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
if (offset >= 0)
offset = baseOffset + stride * i;
blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
topLevelArrayStride, baseStorage, active);
}
} else {
// Visit all members of this aggregate, and for each one,
// fully explode the remaining aggregate to dereference
const TTypeList& typeList = *terminalType->getStruct();
TVector<int> memberOffsets;
if (baseOffset >= 0) {
memberOffsets.resize(typeList.size());
getOffsets(*terminalType, memberOffsets);
}
for (int i = 0; i < (int)typeList.size(); ++i) {
TString newBaseName = name;
newBaseName.append(TString(".") + typeList[i].type->getFieldName());
if (newBaseName.size() > 0)
newBaseName.append(".");
newBaseName.append(typeList[i].type->getFieldName());
TType derefType(*terminalType, i);
blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
if (offset >= 0)
offset = baseOffset + memberOffsets[i];
int arrayStride = topLevelArrayStride;
if (terminalType->getBasicType() == EbtBlock && terminalType->getQualifier().storage == EvqBuffer &&
derefType.isArray()) {
arrayStride = getArrayStride(baseType, derefType);
}
blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
arrayStride, baseStorage, active);
}
}
@@ -238,6 +371,10 @@ public:
return;
}
if ((reflection.options & EShReflectionBasicArraySuffix) && terminalType->isArray()) {
name.append(TString("[0]"));
}
// Finally, add a full string to the reflection database, and update the array size if necessary.
// If the dereferenced entity to record is an array, compute the size and update the maximum size.
@@ -245,15 +382,100 @@ public:
if (arraySize == 0)
arraySize = mapToGlArraySize(*terminalType);
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
TReflection::TMapIndexToReflection& variables = reflection.GetVariableMapForStorage(baseStorage);
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
if (it == reflection.nameToIndex.end()) {
reflection.nameToIndex[name] = (int)reflection.indexToUniform.size();
reflection.indexToUniform.push_back(TObjectReflection(name, *terminalType, offset,
mapToGlType(*terminalType),
arraySize, blockIndex));
} else if (arraySize > 1) {
int& reflectedArraySize = reflection.indexToUniform[it->second].size;
reflectedArraySize = std::max(arraySize, reflectedArraySize);
int uniformIndex = (int)variables.size();
reflection.nameToIndex[name.c_str()] = uniformIndex;
variables.push_back(TObjectReflection(name.c_str(), *terminalType, offset, mapToGlType(*terminalType),
arraySize, blockIndex));
if (terminalType->isArray()) {
variables.back().arrayStride = getArrayStride(baseType, *terminalType);
if (topLevelArrayStride == 0)
topLevelArrayStride = variables.back().arrayStride;
}
if ((reflection.options & EShReflectionSeparateBuffers) && terminalType->getBasicType() == EbtAtomicUint)
reflection.atomicCounterUniformIndices.push_back(uniformIndex);
variables.back().topLevelArrayStride = topLevelArrayStride;
if ((reflection.options & EShReflectionAllBlockVariables) && active) {
EShLanguageMask& stages = variables.back().stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
} else {
if (arraySize > 1) {
int& reflectedArraySize = variables[it->second].size;
reflectedArraySize = std::max(arraySize, reflectedArraySize);
}
if ((reflection.options & EShReflectionAllBlockVariables) && active) {
EShLanguageMask& stages = variables[it->second].stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
}
}
// similar to blowUpActiveAggregate, but with simpler rules and no dereferences to follow.
void blowUpIOAggregate(bool input, const TString &baseName, const TType &type)
{
TString name = baseName;
// if the type is still too coarse a granularity, this is still an aggregate to expand, expand it...
if (! isReflectionGranularity(type)) {
if (type.isArray()) {
// Visit all the indices of this array, and for each one,
// fully explode the remaining aggregate to dereference
for (int i = 0; i < std::max(type.getOuterArraySize(), 1); ++i) {
TString newBaseName = name;
newBaseName.append(TString("[") + String(i) + "]");
TType derefType(type, 0);
blowUpIOAggregate(input, newBaseName, derefType);
}
} else {
// Visit all members of this aggregate, and for each one,
// fully explode the remaining aggregate to dereference
const TTypeList& typeList = *type.getStruct();
for (int i = 0; i < (int)typeList.size(); ++i) {
TString newBaseName = name;
if (newBaseName.size() > 0)
newBaseName.append(".");
newBaseName.append(typeList[i].type->getFieldName());
TType derefType(type, i);
blowUpIOAggregate(input, newBaseName, derefType);
}
}
// it was all completed in the recursive calls above
return;
}
if ((reflection.options & EShReflectionBasicArraySuffix) && type.isArray()) {
name.append(TString("[0]"));
}
TReflection::TMapIndexToReflection &ioItems =
input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
std::string namespacedName = input ? "in " : "out ";
namespacedName += name.c_str();
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(namespacedName);
if (it == reflection.nameToIndex.end()) {
reflection.nameToIndex[namespacedName] = (int)ioItems.size();
ioItems.push_back(
TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
EShLanguageMask& stages = ioItems.back().stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
} else {
EShLanguageMask& stages = ioItems[it->second].stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
}
@@ -303,6 +525,10 @@ public:
anonymous = IsAnonymous(base->getName());
const TString& blockName = base->getType().getTypeName();
TString baseName;
if (! anonymous)
baseName = blockName;
if (base->getType().isArray()) {
TType derefType(base->getType(), 0);
@@ -310,9 +536,57 @@ public:
assert(! anonymous);
for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType,
getBlockSize(base->getType()));
intermediate.getBlockSize(base->getType()));
baseName.append(TString("[0]"));
} else
blockIndex = addBlockName(blockName, base->getType(), getBlockSize(base->getType()));
blockIndex = addBlockName(blockName, base->getType(), intermediate.getBlockSize(base->getType()));
if (reflection.options & EShReflectionAllBlockVariables) {
// Use a degenerate (empty) set of dereferences to immediately put as at the end of
// the dereference change expected by blowUpActiveAggregate.
TList<TIntermBinary*> derefs;
// because we don't have any derefs, the first thing blowUpActiveAggregate will do is iterate over each
// member in the struct definition. This will lose any information about whether the parent was a buffer
// block. So if we're using strict array rules which don't expand the first child of a buffer block we
// instead iterate over the children here.
const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);
bool blockParent = (base->getType().getBasicType() == EbtBlock && base->getQualifier().storage == EvqBuffer);
if (strictArraySuffix && blockParent) {
const TTypeList& typeList = *base->getType().getStruct();
TVector<int> memberOffsets;
memberOffsets.resize(typeList.size());
getOffsets(base->getType(), memberOffsets);
for (int i = 0; i < (int)typeList.size(); ++i) {
TType derefType(base->getType(), i);
TString name = baseName;
if (name.size() > 0)
name.append(".");
name.append(typeList[i].type->getFieldName());
// if this member is an array, store the top-level array stride but start the explosion from
// the inner struct type.
if (derefType.isArray() && derefType.isStruct()) {
name.append("[0]");
blowUpActiveAggregate(TType(derefType, 0), name, derefs, derefs.end(), memberOffsets[i],
blockIndex, 0, getArrayStride(base->getType(), derefType),
base->getQualifier().storage, false);
} else {
blowUpActiveAggregate(derefType, name, derefs, derefs.end(), memberOffsets[i], blockIndex,
0, 0, base->getQualifier().storage, false);
}
}
} else {
// otherwise - if we're not using strict array suffix rules, or this isn't a block so we are
// expanding root arrays anyway, just start the iteration from the base block type.
blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.end(), 0, blockIndex, 0, 0,
base->getQualifier().storage, false);
}
}
}
// Process the dereference chain, backward, accumulating the pieces for later forward traversal.
@@ -342,27 +616,39 @@ public:
else
baseName = base->getName();
}
blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize);
blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize, 0,
base->getQualifier().storage, true);
}
int addBlockName(const TString& name, const TType& type, int size)
{
TReflection::TMapIndexToReflection& blocks = reflection.GetBlockMapForStorage(type.getQualifier().storage);
int blockIndex;
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {
blockIndex = (int)reflection.indexToUniformBlock.size();
reflection.nameToIndex[name] = blockIndex;
reflection.indexToUniformBlock.push_back(TObjectReflection(name, type, -1, -1, size, -1));
} else
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
if (reflection.nameToIndex.find(name.c_str()) == reflection.nameToIndex.end()) {
blockIndex = (int)blocks.size();
reflection.nameToIndex[name.c_str()] = blockIndex;
blocks.push_back(TObjectReflection(name.c_str(), type, -1, -1, size, -1));
blocks.back().numMembers = countAggregateMembers(type);
EShLanguageMask& stages = blocks.back().stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
} else {
blockIndex = it->second;
EShLanguageMask& stages = blocks[blockIndex].stages;
stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
}
return blockIndex;
}
// Are we at a level in a dereference chain at which individual active uniform queries are made?
bool isReflectionGranularity(const TType& type)
{
return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct;
return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct && !type.isArrayOfArrays();
}
// For a binary operation indexing into an aggregate, chase down the base of the aggregate.
@@ -746,8 +1032,47 @@ void TReflectionTraverser::visitSymbol(TIntermSymbol* base)
if (base->getQualifier().storage == EvqUniform)
addUniform(*base);
if (intermediate.getStage() == EShLangVertex && base->getQualifier().isPipeInput())
addAttribute(*base);
if ((intermediate.getStage() == reflection.firstStage && base->getQualifier().isPipeInput()) ||
(intermediate.getStage() == reflection.lastStage && base->getQualifier().isPipeOutput()))
addPipeIOVariable(*base);
}
//
// Implement TObjectReflection methods.
//
TObjectReflection::TObjectReflection(const std::string &pName, const TType &pType, int pOffset, int pGLDefineType,
int pSize, int pIndex)
: name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1),
numMembers(-1), arrayStride(0), topLevelArrayStride(0), stages(EShLanguageMask(0)), type(pType.clone())
{
}
int TObjectReflection::getBinding() const
{
if (type == nullptr || !type->getQualifier().hasBinding())
return -1;
return type->getQualifier().layoutBinding;
}
void TObjectReflection::dump() const
{
printf("%s: offset %d, type %x, size %d, index %d, binding %d, stages %d", name.c_str(), offset, glDefineType, size,
index, getBinding(), stages);
if (counterIndex != -1)
printf(", counter %d", counterIndex);
if (numMembers != -1)
printf(", numMembers %d", numMembers);
if (arrayStride != 0)
printf(", arrayStride %d", arrayStride);
if (topLevelArrayStride != 0)
printf(", topLevelArrayStride %d", topLevelArrayStride);
printf("\n");
}
//
@@ -770,7 +1095,7 @@ void TReflection::buildCounterIndices(const TIntermediate& intermediate)
{
// search for ones that have counters
for (int i = 0; i < int(indexToUniformBlock.size()); ++i) {
const TString counterName(intermediate.addCounterBufferName(indexToUniformBlock[i].name));
const TString counterName(intermediate.addCounterBufferName(indexToUniformBlock[i].name).c_str());
const int index = getIndex(counterName);
if (index >= 0)
@@ -781,9 +1106,17 @@ void TReflection::buildCounterIndices(const TIntermediate& intermediate)
// build Shader Stages mask for all uniforms
void TReflection::buildUniformStageMask(const TIntermediate& intermediate)
{
if (options & EShReflectionAllBlockVariables)
return;
for (int i = 0; i < int(indexToUniform.size()); ++i) {
indexToUniform[i].stages = static_cast<EShLanguageMask>(indexToUniform[i].stages | 1 << intermediate.getStage());
}
for (int i = 0; i < int(indexToBufferVariable.size()); ++i) {
indexToBufferVariable[i].stages =
static_cast<EShLanguageMask>(indexToBufferVariable[i].stages | 1 << intermediate.getStage());
}
}
// Merge live symbols from 'intermediate' into the existing reflection database.
@@ -828,9 +1161,24 @@ void TReflection::dump()
indexToUniformBlock[i].dump();
printf("\n");
printf("Vertex attribute reflection:\n");
for (size_t i = 0; i < indexToAttribute.size(); ++i)
indexToAttribute[i].dump();
printf("Buffer variable reflection:\n");
for (size_t i = 0; i < indexToBufferVariable.size(); ++i)
indexToBufferVariable[i].dump();
printf("\n");
printf("Buffer block reflection:\n");
for (size_t i = 0; i < indexToBufferBlock.size(); ++i)
indexToBufferBlock[i].dump();
printf("\n");
printf("Pipeline input reflection:\n");
for (size_t i = 0; i < indexToPipeInput.size(); ++i)
indexToPipeInput[i].dump();
printf("\n");
printf("Pipeline output reflection:\n");
for (size_t i = 0; i < indexToPipeOutput.size(); ++i)
indexToPipeOutput[i].dump();
printf("\n");
if (getLocalSize(0) > 1) {
@@ -52,50 +52,11 @@ class TIntermediate;
class TIntermAggregate;
class TReflectionTraverser;
// Data needed for just a single object at the granularity exchanged by the reflection API
class TObjectReflection {
public:
TObjectReflection(const TString& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex) :
name(pName), offset(pOffset),
glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1), stages(EShLanguageMask(0)), type(pType.clone()) { }
const TType* getType() const { return type; }
int getBinding() const
{
if (type == nullptr || !type->getQualifier().hasBinding())
return -1;
return type->getQualifier().layoutBinding;
}
void dump() const
{
printf("%s: offset %d, type %x, size %d, index %d, binding %d, stages %d",
name.c_str(), offset, glDefineType, size, index, getBinding(), stages );
if (counterIndex != -1)
printf(", counter %d", counterIndex);
printf("\n");
}
static TObjectReflection badReflection() { return TObjectReflection(); }
TString name;
int offset;
int glDefineType;
int size; // data size in bytes for a block, array size for a (non-block) object that's an array
int index;
int counterIndex;
EShLanguageMask stages;
protected:
TObjectReflection() : offset(-1), glDefineType(-1), size(-1), index(-1), type(nullptr) { }
const TType* type;
};
// The full reflection database
class TReflection {
public:
TReflection() : badReflection(TObjectReflection::badReflection())
TReflection(EShReflectionOptions opts, EShLanguage first, EShLanguage last)
: options(opts), firstStage(first), lastStage(last), badReflection(TObjectReflection::badReflection())
{
for (int dim=0; dim<3; ++dim)
localSize[dim] = 0;
@@ -126,17 +87,57 @@ public:
return badReflection;
}
// for mapping an attribute index to the attribute's description
int getNumAttributes() { return (int)indexToAttribute.size(); }
const TObjectReflection& getAttribute(int i) const
// for mapping an pipeline input index to the input's description
int getNumPipeInputs() { return (int)indexToPipeInput.size(); }
const TObjectReflection& getPipeInput(int i) const
{
if (i >= 0 && i < (int)indexToAttribute.size())
return indexToAttribute[i];
if (i >= 0 && i < (int)indexToPipeInput.size())
return indexToPipeInput[i];
else
return badReflection;
}
// for mapping any name to its index (block names, uniform names and attribute names)
// for mapping an pipeline output index to the output's description
int getNumPipeOutputs() { return (int)indexToPipeOutput.size(); }
const TObjectReflection& getPipeOutput(int i) const
{
if (i >= 0 && i < (int)indexToPipeOutput.size())
return indexToPipeOutput[i];
else
return badReflection;
}
// for mapping from an atomic counter to the uniform index
int getNumAtomicCounters() const { return (int)atomicCounterUniformIndices.size(); }
const TObjectReflection& getAtomicCounter(int i) const
{
if (i >= 0 && i < (int)atomicCounterUniformIndices.size())
return getUniform(atomicCounterUniformIndices[i]);
else
return badReflection;
}
// for mapping a buffer variable index to a buffer variable object's description
int getNumBufferVariables() { return (int)indexToBufferVariable.size(); }
const TObjectReflection& getBufferVariable(int i) const
{
if (i >= 0 && i < (int)indexToBufferVariable.size())
return indexToBufferVariable[i];
else
return badReflection;
}
// for mapping a storage block index to the storage block's description
int getNumStorageBuffers() const { return (int)indexToBufferBlock.size(); }
const TObjectReflection& getStorageBufferBlock(int i) const
{
if (i >= 0 && i < (int)indexToBufferBlock.size())
return indexToBufferBlock[i];
else
return badReflection;
}
// for mapping any name to its index (block names, uniform names and input/output names)
int getIndex(const char* name) const
{
TNameToIndex::const_iterator it = nameToIndex.find(name);
@@ -162,14 +163,37 @@ protected:
void buildAttributeReflection(EShLanguage, const TIntermediate&);
// Need a TString hash: typedef std::unordered_map<TString, int> TNameToIndex;
typedef std::map<TString, int> TNameToIndex;
typedef std::map<std::string, int> TNameToIndex;
typedef std::vector<TObjectReflection> TMapIndexToReflection;
typedef std::vector<int> TIndices;
TMapIndexToReflection& GetBlockMapForStorage(TStorageQualifier storage)
{
if ((options & EShReflectionSeparateBuffers) && storage == EvqBuffer)
return indexToBufferBlock;
return indexToUniformBlock;
}
TMapIndexToReflection& GetVariableMapForStorage(TStorageQualifier storage)
{
if ((options & EShReflectionSeparateBuffers) && storage == EvqBuffer)
return indexToBufferVariable;
return indexToUniform;
}
EShReflectionOptions options;
EShLanguage firstStage;
EShLanguage lastStage;
TObjectReflection badReflection; // return for queries of -1 or generally out of range; has expected descriptions with in it for this
TNameToIndex nameToIndex; // maps names to indexes; can hold all types of data: uniform/buffer and which function names have been processed
TMapIndexToReflection indexToUniform;
TMapIndexToReflection indexToUniformBlock;
TMapIndexToReflection indexToAttribute;
TMapIndexToReflection indexToBufferVariable;
TMapIndexToReflection indexToBufferBlock;
TMapIndexToReflection indexToPipeInput;
TMapIndexToReflection indexToPipeOutput;
TIndices atomicCounterUniformIndices;
unsigned int localSize[3];
};
@@ -45,7 +45,10 @@
#include <stdint.h>
#include <cstdio>
#include <sys/time.h>
#if !defined(__Fuchsia__)
#include <sys/resource.h>
#endif
namespace glslang {
@@ -70,7 +73,7 @@ static void DetachThreadLinux(void *)
//
void OS_CleanupThreadData(void)
{
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(__Fuchsia__)
DetachThreadLinux(NULL);
#else
int old_cancel_state, old_cancel_type;
+133 -26
View File
@@ -53,9 +53,6 @@
#define SH_IMPORT_EXPORT
#else
#define SH_IMPORT_EXPORT
#ifndef __fastcall
#define __fastcall
#endif
#define C_DECL
#endif
@@ -71,7 +68,7 @@
// This should always increase, as some paths to do not consume
// a more major number.
// It should increment by one when new functionality is added.
#define GLSLANG_MINOR_VERSION 11
#define GLSLANG_MINOR_VERSION 12
//
// Call before doing any other compiler/linker operations.
@@ -83,7 +80,7 @@ SH_IMPORT_EXPORT int ShInitialize();
//
// Call this at process shutdown to clean up memory.
//
SH_IMPORT_EXPORT int __fastcall ShFinalize();
SH_IMPORT_EXPORT int ShFinalize();
//
// Types of languages the compiler can consume.
@@ -237,8 +234,22 @@ enum EShMessages {
EShMsgHlslEnable16BitTypes = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL
EShMsgHlslLegalization = (1 << 12), // enable HLSL Legalization messages
EShMsgHlslDX9Compatible = (1 << 13), // enable HLSL DX9 compatible mode (right now only for samplers)
EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table
};
//
// Options for building reflection
//
typedef enum {
EShReflectionDefault = 0, // default is original behaviour before options were added
EShReflectionStrictArraySuffix = (1 << 0), // reflection will follow stricter rules for array-of-structs suffixes
EShReflectionBasicArraySuffix = (1 << 1), // arrays of basic types will be appended with [0] as in GL reflection
EShReflectionIntermediateIO = (1 << 2), // reflect inputs and outputs to program, even with no vertex shader
EShReflectionSeparateBuffers = (1 << 3), // buffer variables and buffer blocks are reflected separately
EShReflectionAllBlockVariables = (1 << 4), // reflect all variables in blocks, even if they are inactive
EShReflectionUnwrapIOBlocks = (1 << 5), // unwrap input/output blocks the same as with uniform blocks
} EShReflectionOptions;
//
// Build a table for bindings. This can be used for locating
// attributes, uniforms, globals, etc., as needed.
@@ -599,6 +610,41 @@ private:
TShader& operator=(TShader&);
};
//
// A reflection database and its interface, consistent with the OpenGL API reflection queries.
//
// Data needed for just a single object at the granularity exchanged by the reflection API
class TObjectReflection {
public:
TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex);
const TType* getType() const { return type; }
int getBinding() const;
void dump() const;
static TObjectReflection badReflection() { return TObjectReflection(); }
std::string name;
int offset;
int glDefineType;
int size; // data size in bytes for a block, array size for a (non-block) object that's an array
int index;
int counterIndex;
int numMembers;
int arrayStride; // stride of an array variable
int topLevelArrayStride; // stride of the top-level variable in a storage buffer member
EShLanguageMask stages;
protected:
TObjectReflection()
: offset(-1), glDefineType(-1), size(-1), index(-1), counterIndex(-1), numMembers(-1), arrayStride(0),
topLevelArrayStride(0), stages(EShLanguageMask(0)), type(nullptr)
{
}
const TType* type;
};
class TReflection;
class TIoMapper;
@@ -688,28 +734,89 @@ public:
TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; }
// Reflection Interface
bool buildReflection(); // call first, to do liveness analysis, index mapping, etc.; returns false on failure
int getNumLiveUniformVariables() const; // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
int getNumLiveUniformBlocks() const; // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
const char* getUniformName(int index) const; // can be used for "name" part of glGetActiveUniform()
const char* getUniformBlockName(int blockIndex) const; // can be used for glGetActiveUniformBlockName()
int getUniformBlockSize(int blockIndex) const; // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
int getUniformIndex(const char* name) const; // can be used for glGetUniformIndices()
int getUniformBinding(int index) const; // returns the binding number
EShLanguageMask getUniformStages(int index) const; // returns Shaders Stages where a Uniform is present
int getUniformBlockBinding(int index) const; // returns the block binding number
int getUniformBlockIndex(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
int getUniformBlockCounterIndex(int index) const; // returns block index of associated counter.
int getUniformType(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
int getUniformBufferOffset(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
int getUniformArraySize(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
int getNumLiveAttributes() const; // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
// call first, to do liveness analysis, index mapping, etc.; returns false on failure
bool buildReflection(int opts = EShReflectionDefault);
unsigned getLocalSize(int dim) const; // return dim'th local size
const char *getAttributeName(int index) const; // can be used for glGetActiveAttrib()
int getAttributeType(int index) const; // can be used for glGetActiveAttrib()
const TType* getUniformTType(int index) const; // returns a TType*
const TType* getUniformBlockTType(int index) const; // returns a TType*
const TType* getAttributeTType(int index) const; // returns a TType*
int getReflectionIndex(const char *name) const;
int getNumUniformVariables() const;
const TObjectReflection& getUniform(int index) const;
int getNumUniformBlocks() const;
const TObjectReflection& getUniformBlock(int index) const;
int getNumPipeInputs() const;
const TObjectReflection& getPipeInput(int index) const;
int getNumPipeOutputs() const;
const TObjectReflection& getPipeOutput(int index) const;
int getNumBufferVariables() const;
const TObjectReflection& getBufferVariable(int index) const;
int getNumBufferBlocks() const;
const TObjectReflection& getBufferBlock(int index) const;
int getNumAtomicCounters() const;
const TObjectReflection& getAtomicCounter(int index) const;
// Legacy Reflection Interface - expressed in terms of above interface
// can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
int getNumLiveUniformVariables() const { return getNumUniformVariables(); }
// can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
int getNumLiveUniformBlocks() const { return getNumUniformBlocks(); }
// can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
int getNumLiveAttributes() const { return getNumPipeInputs(); }
// can be used for glGetUniformIndices()
int getUniformIndex(const char *name) const { return getReflectionIndex(name); }
// can be used for "name" part of glGetActiveUniform()
const char *getUniformName(int index) const { return getUniform(index).name.c_str(); }
// returns the binding number
int getUniformBinding(int index) const { return getUniform(index).getBinding(); }
// returns Shaders Stages where a Uniform is present
EShLanguageMask getUniformStages(int index) const { return getUniform(index).stages; }
// can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
int getUniformBlockIndex(int index) const { return getUniform(index).index; }
// can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
int getUniformType(int index) const { return getUniform(index).glDefineType; }
// can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
int getUniformBufferOffset(int index) const { return getUniform(index).offset; }
// can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
int getUniformArraySize(int index) const { return getUniform(index).size; }
// returns a TType*
const TType *getUniformTType(int index) const { return getUniform(index).getType(); }
// can be used for glGetActiveUniformBlockName()
const char *getUniformBlockName(int index) const { return getUniformBlock(index).name.c_str(); }
// can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
int getUniformBlockSize(int index) const { return getUniformBlock(index).size; }
// returns the block binding number
int getUniformBlockBinding(int index) const { return getUniformBlock(index).getBinding(); }
// returns block index of associated counter.
int getUniformBlockCounterIndex(int index) const { return getUniformBlock(index).counterIndex; }
// returns a TType*
const TType *getUniformBlockTType(int index) const { return getUniformBlock(index).getType(); }
// can be used for glGetActiveAttrib()
const char *getAttributeName(int index) const { return getPipeInput(index).name.c_str(); }
// can be used for glGetActiveAttrib()
int getAttributeType(int index) const { return getPipeInput(index).glDefineType; }
// returns a TType*
const TType *getAttributeTType(int index) const { return getPipeInput(index).getType(); }
void dumpReflection();