mirror of
https://github.com/love2d/love.git
synced 2026-08-14 01:20:56 +02:00
Update glslang
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Executable → Regular
+7
-1
@@ -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
|
||||
|
||||
Executable → Regular
+146
-33
@@ -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:
|
||||
|
||||
Executable → Regular
+190
-4
@@ -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:
|
||||
|
||||
Executable → Regular
+503
-117
File diff suppressed because it is too large
Load Diff
Executable → Regular
+5
-4
@@ -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 ¶m = 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); }
|
||||
|
||||
Executable → Regular
+21
-1
@@ -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)
|
||||
{
|
||||
|
||||
Executable → Regular
+6
-1
@@ -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;
|
||||
|
||||
Executable → Regular
+172
-22
@@ -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
|
||||
|
||||
Executable → Regular
+75
-8
@@ -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;
|
||||
|
||||
Executable → Regular
+81
-15
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user