SPV: Implement Vulkan version of GLSL (KHR_vulkan_glsl).
This commit is contained in:
parent
019f08fcd8
commit
6c292d3ba7
200 changed files with 7841 additions and 5577 deletions
|
|
@ -130,6 +130,8 @@ enum TBuiltInVariable {
|
|||
EbvLocalInvocationIndex,
|
||||
EbvVertexId,
|
||||
EbvInstanceId,
|
||||
EbvVertexIndex,
|
||||
EbvInstanceIndex,
|
||||
EbvBaseVertex,
|
||||
EbvBaseInstance,
|
||||
EbvDrawId,
|
||||
|
|
@ -221,6 +223,8 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v)
|
|||
case EbvLocalInvocationIndex: return "LocalInvocationIndex";
|
||||
case EbvVertexId: return "VertexId";
|
||||
case EbvInstanceId: return "InstanceId";
|
||||
case EbvVertexIndex: return "VertexIndex";
|
||||
case EbvInstanceIndex: return "InstanceIndex";
|
||||
case EbvBaseVertex: return "BaseVertex";
|
||||
case EbvBaseInstance: return "BaseInstance";
|
||||
case EbvDrawId: return "DrawId";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//Copyright (C) 2012-2015 LunarG, Inc.
|
||||
//Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
|
|
@ -63,6 +64,7 @@ enum TSamplerDim {
|
|||
EsdCube,
|
||||
EsdRect,
|
||||
EsdBuffer,
|
||||
EsdSubpass, // goes only with non-sampled image (image is true)
|
||||
EsdNumDims
|
||||
};
|
||||
|
||||
|
|
@ -73,8 +75,16 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||
bool shadow : 1;
|
||||
bool ms : 1;
|
||||
bool image : 1; // image, combined should be false
|
||||
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 isImage() const { return image && dim != EsdSubpass; }
|
||||
bool isSubpass() const { return dim == EsdSubpass; }
|
||||
bool isCombined() const { return combined; }
|
||||
bool isPureSampler() const { return sampler; }
|
||||
bool isTexture() const { return !sampler && !image; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
type = EbtVoid;
|
||||
|
|
@ -83,6 +93,8 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||
shadow = false;
|
||||
ms = false;
|
||||
image = false;
|
||||
combined = false;
|
||||
sampler = false;
|
||||
external = false;
|
||||
}
|
||||
|
||||
|
|
@ -95,6 +107,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||
arrayed = a;
|
||||
shadow = s;
|
||||
ms = m;
|
||||
combined = true;
|
||||
}
|
||||
|
||||
// make an image
|
||||
|
|
@ -109,6 +122,35 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||
image = true;
|
||||
}
|
||||
|
||||
// make a texture with no sampler
|
||||
void setTexture(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
|
||||
{
|
||||
clear();
|
||||
type = t;
|
||||
dim = d;
|
||||
arrayed = a;
|
||||
shadow = s;
|
||||
ms = m;
|
||||
}
|
||||
|
||||
// make a subpass input attachment
|
||||
void setSubpass(TBasicType t, bool m = false)
|
||||
{
|
||||
clear();
|
||||
type = t;
|
||||
image = true;
|
||||
dim = EsdSubpass;
|
||||
ms = m;
|
||||
}
|
||||
|
||||
// make a pure sampler, no texture, no image, nothing combined, the 'sampler' keyword
|
||||
void setPureSampler(bool s)
|
||||
{
|
||||
clear();
|
||||
sampler = true;
|
||||
shadow = s;
|
||||
}
|
||||
|
||||
bool operator==(const TSampler& right) const
|
||||
{
|
||||
return type == right.type &&
|
||||
|
|
@ -117,6 +159,8 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||
shadow == right.shadow &&
|
||||
ms == right.ms &&
|
||||
image == right.image &&
|
||||
combined == right.combined &&
|
||||
sampler == right.sampler &&
|
||||
external == right.external;
|
||||
}
|
||||
|
||||
|
|
@ -129,6 +173,11 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||
{
|
||||
TString s;
|
||||
|
||||
if (sampler) {
|
||||
s.append("sampler");
|
||||
return s;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case EbtFloat: break;
|
||||
case EbtInt: s.append("i"); break;
|
||||
|
|
@ -136,9 +185,14 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||
default: break; // some compilers want this
|
||||
}
|
||||
if (image) {
|
||||
s.append("image");
|
||||
} else {
|
||||
if (dim == EsdSubpass)
|
||||
s.append("subpass");
|
||||
else
|
||||
s.append("image");
|
||||
} else if (combined) {
|
||||
s.append("sampler");
|
||||
} else {
|
||||
s.append("texture");
|
||||
}
|
||||
if (external) {
|
||||
s.append("ExternalOES");
|
||||
|
|
@ -151,6 +205,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
|
|||
case EsdCube: s.append("Cube"); break;
|
||||
case EsdRect: s.append("2DRect"); break;
|
||||
case EsdBuffer: s.append("Buffer"); break;
|
||||
case EsdSubpass: s.append("Input"); break;
|
||||
default: break; // some compilers want this
|
||||
}
|
||||
if (ms)
|
||||
|
|
@ -352,6 +407,7 @@ public:
|
|||
restrict = false;
|
||||
readonly = false;
|
||||
writeonly = false;
|
||||
specConstant = false;
|
||||
clearLayout();
|
||||
}
|
||||
|
||||
|
|
@ -370,6 +426,7 @@ public:
|
|||
bool restrict : 1;
|
||||
bool readonly : 1;
|
||||
bool writeonly : 1;
|
||||
bool specConstant : 1; // having a constant_id is not sufficient: expressions have no id, but are still specConstant
|
||||
|
||||
bool isMemory() const
|
||||
{
|
||||
|
|
@ -505,8 +562,12 @@ public:
|
|||
layoutXfbBuffer = layoutXfbBufferEnd;
|
||||
layoutXfbStride = layoutXfbStrideEnd;
|
||||
layoutXfbOffset = layoutXfbOffsetEnd;
|
||||
layoutAttachment = layoutAttachmentEnd;
|
||||
layoutSpecConstantId = layoutSpecConstantIdEnd;
|
||||
|
||||
layoutFormat = ElfNone;
|
||||
|
||||
layoutPushConstant = false;
|
||||
}
|
||||
bool hasLayout() const
|
||||
{
|
||||
|
|
@ -515,7 +576,8 @@ public:
|
|||
hasBinding() ||
|
||||
hasStream() ||
|
||||
hasXfb() ||
|
||||
hasFormat();
|
||||
hasFormat() ||
|
||||
layoutPushConstant;
|
||||
}
|
||||
TLayoutMatrix layoutMatrix : 3;
|
||||
TLayoutPacking layoutPacking : 4;
|
||||
|
|
@ -549,8 +611,16 @@ public:
|
|||
unsigned int layoutXfbOffset : 10;
|
||||
static const unsigned int layoutXfbOffsetEnd = 0x3FF;
|
||||
|
||||
unsigned int layoutAttachment : 8; // for input_attachment_index
|
||||
static const unsigned int layoutAttachmentEnd = 0XFF;
|
||||
|
||||
unsigned int layoutSpecConstantId : 11;
|
||||
static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
|
||||
|
||||
TLayoutFormat layoutFormat : 8;
|
||||
|
||||
bool layoutPushConstant;
|
||||
|
||||
bool hasUniformLayout() const
|
||||
{
|
||||
return hasMatrix() ||
|
||||
|
|
@ -627,6 +697,38 @@ public:
|
|||
{
|
||||
return layoutXfbOffset != layoutXfbOffsetEnd;
|
||||
}
|
||||
bool hasAttachment() const
|
||||
{
|
||||
return layoutAttachment != layoutAttachmentEnd;
|
||||
}
|
||||
bool hasSpecConstantId() const
|
||||
{
|
||||
// Not the same thing as being a specialization constant, this
|
||||
// is just whether or not it was declared with an ID.
|
||||
return layoutSpecConstantId != layoutSpecConstantIdEnd;
|
||||
}
|
||||
bool isSpecConstant() const
|
||||
{
|
||||
// True if type is a specialization constant, whether or not it
|
||||
// had a specialization-constant ID, and false if it is not a
|
||||
// true front-end constant.
|
||||
return specConstant;
|
||||
}
|
||||
bool isFrontEndConstant() const
|
||||
{
|
||||
// True if the front-end knows the final constant value.
|
||||
// This allows front-end constant folding.
|
||||
return storage == EvqConst && ! specConstant;
|
||||
}
|
||||
bool isConstant() const
|
||||
{
|
||||
// True if is either kind of constant; specialization or regular.
|
||||
return isFrontEndConstant() || isSpecConstant();
|
||||
}
|
||||
void makeSpecConstant()
|
||||
{
|
||||
specConstant = true;
|
||||
}
|
||||
static const char* getLayoutPackingString(TLayoutPacking packing)
|
||||
{
|
||||
switch (packing) {
|
||||
|
|
@ -781,6 +883,7 @@ struct TShaderQualifiers {
|
|||
TVertexOrder order;
|
||||
bool pointMode;
|
||||
int localSize[3]; // compute shader
|
||||
int localSizeSpecId[3]; // compute shader specialization id for gl_WorkGroupSize
|
||||
bool earlyFragmentTests; // fragment input
|
||||
TLayoutDepth layoutDepth;
|
||||
bool blendEquation; // true if any blend equation was specified
|
||||
|
|
@ -798,6 +901,9 @@ struct TShaderQualifiers {
|
|||
localSize[0] = 1;
|
||||
localSize[1] = 1;
|
||||
localSize[2] = 1;
|
||||
localSizeSpecId[0] = TQualifier::layoutNotSet;
|
||||
localSizeSpecId[1] = TQualifier::layoutNotSet;
|
||||
localSizeSpecId[2] = TQualifier::layoutNotSet;
|
||||
earlyFragmentTests = false;
|
||||
layoutDepth = EldNone;
|
||||
blendEquation = false;
|
||||
|
|
@ -827,6 +933,10 @@ struct TShaderQualifiers {
|
|||
if (src.localSize[i] > 1)
|
||||
localSize[i] = src.localSize[i];
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (src.localSizeSpecId[i] != TQualifier::layoutNotSet)
|
||||
localSizeSpecId[i] = src.localSizeSpecId[i];
|
||||
}
|
||||
if (src.earlyFragmentTests)
|
||||
earlyFragmentTests = true;
|
||||
if (src.layoutDepth)
|
||||
|
|
@ -902,7 +1012,9 @@ public:
|
|||
return matrixCols == 0 && vectorSize == 1 && arraySizes == nullptr && userDef == nullptr;
|
||||
}
|
||||
|
||||
bool isImage() const { return basicType == EbtSampler && sampler.image; }
|
||||
// "Image" is a superset of "Subpass"
|
||||
bool isImage() const { return basicType == EbtSampler && sampler.isImage(); }
|
||||
bool isSubpass() const { return basicType == EbtSampler && sampler.isSubpass(); }
|
||||
};
|
||||
|
||||
//
|
||||
|
|
@ -1112,7 +1224,9 @@ public:
|
|||
virtual bool isRuntimeSizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage == EvqBuffer; }
|
||||
virtual bool isStruct() const { return structure != nullptr; }
|
||||
|
||||
virtual bool isImage() const { return basicType == EbtSampler && getSampler().image; }
|
||||
// "Image" is a superset of "Subpass"
|
||||
virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); }
|
||||
virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
|
||||
|
||||
// Recursively checks if the type contains the given basic type
|
||||
virtual bool containsBasicType(TBasicType checkType) const
|
||||
|
|
@ -1181,6 +1295,42 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool containsNonOpaque() const
|
||||
{
|
||||
// list all non-opaque types
|
||||
switch (basicType) {
|
||||
case EbtVoid:
|
||||
case EbtFloat:
|
||||
case EbtDouble:
|
||||
case EbtInt:
|
||||
case EbtUint:
|
||||
case EbtBool:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (! structure)
|
||||
return false;
|
||||
for (unsigned int i = 0; i < structure->size(); ++i) {
|
||||
if ((*structure)[i].type->containsNonOpaque())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool containsSpecializationSize() const
|
||||
{
|
||||
if (isArray() && arraySizes->containsNode())
|
||||
return true;
|
||||
if (! structure)
|
||||
return false;
|
||||
for (unsigned int i = 0; i < structure->size(); ++i) {
|
||||
if ((*structure)[i].type->containsSpecializationSize())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -1218,7 +1368,7 @@ public:
|
|||
arraySizes->addOuterSizes(s);
|
||||
}
|
||||
void changeOuterArraySize(int s) { arraySizes->changeOuterSize(s); }
|
||||
void setImplicitArraySize (int s) { arraySizes->setImplicitSize(s); }
|
||||
void setImplicitArraySize(int s) { arraySizes->setImplicitSize(s); }
|
||||
|
||||
// Recursively make the implicit array size the explicit array size, through the type tree.
|
||||
void adoptImplicitArraySizes()
|
||||
|
|
@ -1296,6 +1446,12 @@ public:
|
|||
p += snprintf(p, end - p, "xfb_offset=%d ", qualifier.layoutXfbOffset);
|
||||
if (qualifier.hasXfbStride())
|
||||
p += snprintf(p, end - p, "xfb_stride=%d ", qualifier.layoutXfbStride);
|
||||
if (qualifier.hasAttachment())
|
||||
p += snprintf(p, end - p, "input_attachment_index=%d ", qualifier.layoutAttachment);
|
||||
if (qualifier.hasSpecConstantId())
|
||||
p += snprintf(p, end - p, "constant_id=%d ", qualifier.layoutSpecConstantId);
|
||||
if (qualifier.layoutPushConstant)
|
||||
p += snprintf(p, end - p, "push_constant ");
|
||||
p += snprintf(p, end - p, ") ");
|
||||
}
|
||||
}
|
||||
|
|
@ -1324,6 +1480,8 @@ public:
|
|||
p += snprintf(p, end - p, "readonly ");
|
||||
if (qualifier.writeonly)
|
||||
p += snprintf(p, end - p, "writeonly ");
|
||||
if (qualifier.specConstant)
|
||||
p += snprintf(p, end - p, "specialization-constant ");
|
||||
p += snprintf(p, end - p, "%s ", getStorageQualifierString());
|
||||
if (arraySizes) {
|
||||
for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,26 @@ namespace glslang {
|
|||
// This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else.
|
||||
const int UnsizedArraySize = 0;
|
||||
|
||||
class TIntermTyped;
|
||||
extern bool SameSpecializationConstants(TIntermTyped*, TIntermTyped*);
|
||||
|
||||
// Specialization constants need both a nominal size and a node that defines
|
||||
// the specialization constant being used. Array types are the same when their
|
||||
// size and specialization constant nodes are the same.
|
||||
struct TArraySize {
|
||||
unsigned int size;
|
||||
TIntermTyped* node; // nullptr means no specialization constant node
|
||||
bool operator==(const TArraySize& rhs) const
|
||||
{
|
||||
if (size != rhs.size)
|
||||
return false;
|
||||
if (node == nullptr || rhs.node == nullptr)
|
||||
return node == rhs.node;
|
||||
|
||||
return SameSpecializationConstants(node, rhs.node);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// TSmallArrayVector is used as the container for the set of sizes in TArraySizes.
|
||||
// It has generic-container semantics, while TArraySizes has array-of-array semantics.
|
||||
|
|
@ -83,22 +103,31 @@ struct TSmallArrayVector {
|
|||
return (int)sizes->size();
|
||||
}
|
||||
|
||||
unsigned int front() const
|
||||
unsigned int frontSize() const
|
||||
{
|
||||
assert(sizes != nullptr && sizes->size() > 0);
|
||||
return sizes->front();
|
||||
return sizes->front().size;
|
||||
}
|
||||
|
||||
TIntermTyped* frontNode() const
|
||||
{
|
||||
assert(sizes != nullptr && sizes->size() > 0);
|
||||
return sizes->front().node;
|
||||
}
|
||||
|
||||
void changeFront(unsigned int s)
|
||||
{
|
||||
assert(sizes != nullptr);
|
||||
sizes->front() = s;
|
||||
// this should only happen for implicitly sized arrays, not specialization constants
|
||||
assert(sizes->front().node == nullptr);
|
||||
sizes->front().size = s;
|
||||
}
|
||||
|
||||
void push_back(unsigned int e)
|
||||
void push_back(unsigned int e, TIntermTyped* n)
|
||||
{
|
||||
alloc();
|
||||
sizes->push_back(e);
|
||||
TArraySize pair = { e, n };
|
||||
sizes->push_back(pair);
|
||||
}
|
||||
|
||||
void push_front(const TSmallArrayVector& newDims)
|
||||
|
|
@ -129,16 +158,23 @@ struct TSmallArrayVector {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned int operator[](int i) const
|
||||
unsigned int getDimSize(int i) const
|
||||
{
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
return (*sizes)[i];
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
return (*sizes)[i].size;
|
||||
}
|
||||
|
||||
unsigned int& operator[](int i)
|
||||
void setDimSize(int i, unsigned int size) const
|
||||
{
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
return (*sizes)[i];
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
assert((*sizes)[i].node == nullptr);
|
||||
(*sizes)[i].size = size;
|
||||
}
|
||||
|
||||
TIntermTyped* getDimNode(int i) const
|
||||
{
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
return (*sizes)[i].node;
|
||||
}
|
||||
|
||||
bool operator==(const TSmallArrayVector& rhs) const
|
||||
|
|
@ -157,7 +193,7 @@ protected:
|
|||
void alloc()
|
||||
{
|
||||
if (sizes == nullptr)
|
||||
sizes = new TVector<unsigned int>;
|
||||
sizes = new TVector<TArraySize>;
|
||||
}
|
||||
void dealloc()
|
||||
{
|
||||
|
|
@ -165,7 +201,7 @@ protected:
|
|||
sizes = nullptr;
|
||||
}
|
||||
|
||||
TVector<unsigned int>* sizes; // will either hold such a pointer, or in the future, hold the two array sizes
|
||||
TVector<TArraySize>* sizes; // will either hold such a pointer, or in the future, hold the two array sizes
|
||||
};
|
||||
|
||||
//
|
||||
|
|
@ -197,28 +233,32 @@ struct TArraySizes {
|
|||
|
||||
// translate from array-of-array semantics to container semantics
|
||||
int getNumDims() const { return sizes.size(); }
|
||||
int getDimSize(int dim) const { return sizes[dim]; }
|
||||
void setDimSize(int dim, int size) { sizes[dim] = size; }
|
||||
int getOuterSize() const { return sizes.front(); }
|
||||
int getDimSize(int dim) const { return sizes.getDimSize(dim); }
|
||||
TIntermTyped* getDimNode(int dim) const { return sizes.getDimNode(dim); }
|
||||
void setDimSize(int dim, int size) { sizes.setDimSize(dim, size); }
|
||||
int getOuterSize() const { return sizes.frontSize(); }
|
||||
TIntermTyped* getOuterNode() const { return sizes.frontNode(); }
|
||||
int getCumulativeSize() const
|
||||
{
|
||||
int size = 1;
|
||||
for (int d = 0; d < sizes.size(); ++d) {
|
||||
// this only makes sense in paths that have a known array size
|
||||
assert(sizes[d] != UnsizedArraySize);
|
||||
size *= sizes[d];
|
||||
assert(sizes.getDimSize(d) != UnsizedArraySize);
|
||||
size *= sizes.getDimSize(d);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
void addInnerSize() { sizes.push_back((unsigned)UnsizedArraySize); }
|
||||
void addInnerSize(int s) { sizes.push_back((unsigned)s); }
|
||||
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 changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
|
||||
int getImplicitSize() const { return (int)implicitArraySize; }
|
||||
void setImplicitSize(int s) { implicitArraySize = s; }
|
||||
bool isInnerImplicit() const
|
||||
{
|
||||
for (int d = 1; d < sizes.size(); ++d) {
|
||||
if (sizes[d] == (unsigned)UnsizedArraySize)
|
||||
if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -240,13 +280,26 @@ struct TArraySizes {
|
|||
return false;
|
||||
|
||||
for (int d = 1; d < sizes.size(); ++d) {
|
||||
if (sizes[d] != rhs.sizes[d])
|
||||
if (sizes.getDimSize(d) != rhs.sizes.getDimSize(d) ||
|
||||
sizes.getDimNode(d) != rhs.sizes.getDimNode(d))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if any of the dimensions of the array is sized with a node
|
||||
// instead of a front-end compile-time constant.
|
||||
bool containsNode()
|
||||
{
|
||||
for (int d = 0; d < sizes.size(); ++d) {
|
||||
if (sizes.getDimNode(d) != nullptr)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const TArraySizes& rhs) { return sizes == rhs.sizes; }
|
||||
bool operator!=(const TArraySizes& rhs) { return sizes != rhs.sizes; }
|
||||
|
||||
|
|
|
|||
|
|
@ -324,6 +324,7 @@ enum TOperator {
|
|||
EOpConstructDMat4x3,
|
||||
EOpConstructDMat4x4,
|
||||
EOpConstructStruct,
|
||||
EOpConstructTextureSampler,
|
||||
EOpConstructGuardEnd,
|
||||
|
||||
//
|
||||
|
|
@ -371,6 +372,8 @@ enum TOperator {
|
|||
EOpImageAtomicExchange,
|
||||
EOpImageAtomicCompSwap,
|
||||
|
||||
EOpSubpassLoad,
|
||||
EOpSubpassLoadMS,
|
||||
EOpSparseImageLoad,
|
||||
|
||||
EOpImageGuardEnd,
|
||||
|
|
@ -606,7 +609,7 @@ protected:
|
|||
//
|
||||
class TIntermSymbol : public TIntermTyped {
|
||||
public:
|
||||
// if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
|
||||
// if symbol is initialized as symbol(sym), the memory comes from the pool allocator of sym. If sym comes from
|
||||
// per process threadPoolAllocator, then it causes increased memory usage per compile
|
||||
// it is essential to use "symbol = sym" to assign to symbol
|
||||
TIntermSymbol(int i, const TString& n, const TType& t) :
|
||||
|
|
@ -619,9 +622,9 @@ public:
|
|||
void setConstArray(const TConstUnionArray& c) { unionArray = c; }
|
||||
const TConstUnionArray& getConstArray() const { return unionArray; }
|
||||
protected:
|
||||
int id;
|
||||
TString name;
|
||||
TConstUnionArray unionArray;
|
||||
int id; // the unique id of the symbol this node represents
|
||||
TString name; // the name of the symbol this node represents
|
||||
TConstUnionArray unionArray; // if the symbol is a front-end compile-time constant, this is its value
|
||||
};
|
||||
|
||||
class TIntermConstantUnion : public TIntermTyped {
|
||||
|
|
@ -651,6 +654,7 @@ struct TCrackedTextureOp {
|
|||
bool offsets;
|
||||
bool gather;
|
||||
bool grad;
|
||||
bool subpass;
|
||||
bool lodClamp;
|
||||
};
|
||||
|
||||
|
|
@ -681,6 +685,7 @@ public:
|
|||
cracked.offsets = false;
|
||||
cracked.gather = false;
|
||||
cracked.grad = false;
|
||||
cracked.subpass = false;
|
||||
cracked.lodClamp = false;
|
||||
|
||||
switch (op) {
|
||||
|
|
@ -790,6 +795,10 @@ public:
|
|||
cracked.gather = true;
|
||||
cracked.offsets = true;
|
||||
break;
|
||||
case EOpSubpassLoad:
|
||||
case EOpSubpassLoadMS:
|
||||
cracked.subpass = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -937,7 +946,7 @@ enum TVisit
|
|||
//
|
||||
// Explicitly set postVisit to true if you want post visiting, otherwise,
|
||||
// filled in methods will only be called at pre-visit time (before processing
|
||||
// the subtree). Similary for inVisit for in-order visiting of nodes with
|
||||
// the subtree). Similarly for inVisit for in-order visiting of nodes with
|
||||
// multiple children.
|
||||
//
|
||||
// If you only want post-visits, explicitly turn off preVisit (and inVisit)
|
||||
|
|
@ -970,7 +979,7 @@ public:
|
|||
void incrementDepth(TIntermNode *current)
|
||||
{
|
||||
depth++;
|
||||
maxDepth = std::max(maxDepth, depth);
|
||||
maxDepth = (std::max)(maxDepth, depth);
|
||||
path.push_back(current);
|
||||
}
|
||||
|
||||
|
|
@ -1000,6 +1009,14 @@ protected:
|
|||
TVector<TIntermNode *> path;
|
||||
};
|
||||
|
||||
// KHR_vulkan_glsl says "Two arrays sized with specialization constants are the same type only if
|
||||
// sized with the same symbol, involving no operations"
|
||||
inline bool SameSpecializationConstants(TIntermTyped* node1, TIntermTyped* node2)
|
||||
{
|
||||
return node1->getAsSymbolNode() && node2->getAsSymbolNode() &&
|
||||
node1->getAsSymbolNode()->getId() == node2->getAsSymbolNode()->getId();
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // __INTERMEDIATE_H
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@
|
|||
// For the version, it uses the latest git tag followed by the number of commits.
|
||||
// For the date, it uses the current date (when then script is run).
|
||||
|
||||
#define GLSLANG_REVISION "SPIRV99.866"
|
||||
#define GLSLANG_DATE "24-Dec-2015"
|
||||
#define GLSLANG_REVISION "SPIRV99.947"
|
||||
#define GLSLANG_DATE "15-Feb-2016"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//Copyright (C) 2012-2015 LunarG, Inc.
|
||||
//Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
|
|
@ -85,6 +86,7 @@ TBuiltIns::TBuiltIns()
|
|||
dimMap[Esd3D] = 3;
|
||||
dimMap[EsdCube] = 3;
|
||||
dimMap[EsdBuffer] = 1;
|
||||
dimMap[EsdSubpass] = 2; // potientially unused for now
|
||||
}
|
||||
|
||||
TBuiltIns::~TBuiltIns()
|
||||
|
|
@ -99,7 +101,7 @@ TBuiltIns::~TBuiltIns()
|
|||
// Most built-ins variables can be added as simple text strings. Some need to
|
||||
// be added programmatically, which is done later in IdentifyBuiltIns() below.
|
||||
//
|
||||
void TBuiltIns::initialize(int version, EProfile profile, int spv)
|
||||
void TBuiltIns::initialize(int version, EProfile profile, int spv, int vulkan)
|
||||
{
|
||||
//============================================================================
|
||||
//
|
||||
|
|
@ -1080,17 +1082,19 @@ void TBuiltIns::initialize(int version, EProfile profile, int spv)
|
|||
"\n");
|
||||
}
|
||||
|
||||
//
|
||||
// Atomic counter functions.
|
||||
//
|
||||
if ((profile != EEsProfile && version >= 300) ||
|
||||
(profile == EEsProfile && version >= 310)) {
|
||||
commonBuiltins.append(
|
||||
"uint atomicCounterIncrement(atomic_uint x);"
|
||||
"uint atomicCounterDecrement(atomic_uint x);"
|
||||
"uint atomicCounter(atomic_uint x);"
|
||||
if (vulkan == 0) {
|
||||
//
|
||||
// Atomic counter functions.
|
||||
//
|
||||
if ((profile != EEsProfile && version >= 300) ||
|
||||
(profile == EEsProfile && version >= 310)) {
|
||||
commonBuiltins.append(
|
||||
"uint atomicCounterIncrement(atomic_uint x);"
|
||||
"uint atomicCounterDecrement(atomic_uint x);"
|
||||
"uint atomicCounter(atomic_uint x);"
|
||||
|
||||
"\n");
|
||||
"\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Bitfield
|
||||
|
|
@ -1434,28 +1438,31 @@ void TBuiltIns::initialize(int version, EProfile profile, int spv)
|
|||
//
|
||||
// Depth range in window coordinates, p. 33
|
||||
//
|
||||
commonBuiltins.append(
|
||||
"struct gl_DepthRangeParameters {"
|
||||
);
|
||||
if (profile == EEsProfile) {
|
||||
if (vulkan == 0) {
|
||||
commonBuiltins.append(
|
||||
"highp float near;" // n
|
||||
"highp float far;" // f
|
||||
"highp float diff;" // f - n
|
||||
"struct gl_DepthRangeParameters {"
|
||||
);
|
||||
} else {
|
||||
commonBuiltins.append(
|
||||
"float near;" // n
|
||||
"float far;" // f
|
||||
"float diff;" // f - n
|
||||
);
|
||||
}
|
||||
commonBuiltins.append(
|
||||
"};"
|
||||
"uniform gl_DepthRangeParameters gl_DepthRange;"
|
||||
"\n");
|
||||
if (profile == EEsProfile) {
|
||||
commonBuiltins.append(
|
||||
"highp float near;" // n
|
||||
"highp float far;" // f
|
||||
"highp float diff;" // f - n
|
||||
);
|
||||
} else {
|
||||
commonBuiltins.append(
|
||||
"float near;" // n
|
||||
"float far;" // f
|
||||
"float diff;" // f - n
|
||||
);
|
||||
}
|
||||
|
||||
if (IncludeLegacy(version, profile, spv)) {
|
||||
commonBuiltins.append(
|
||||
"};"
|
||||
"uniform gl_DepthRangeParameters gl_DepthRange;"
|
||||
"\n");
|
||||
}
|
||||
|
||||
if (vulkan == 0 && IncludeLegacy(version, profile, spv)) {
|
||||
//
|
||||
// Matrix state. p. 31, 32, 37, 39, 40.
|
||||
//
|
||||
|
|
@ -1693,14 +1700,19 @@ void TBuiltIns::initialize(int version, EProfile profile, int spv)
|
|||
"};"
|
||||
"\n");
|
||||
}
|
||||
if (version >= 130)
|
||||
if (version >= 130 && vulkan == 0)
|
||||
stageBuiltins[EShLangVertex].append(
|
||||
"int gl_VertexID;" // needs qualifier fixed later
|
||||
);
|
||||
if (version >= 140)
|
||||
if (version >= 140 && vulkan == 0)
|
||||
stageBuiltins[EShLangVertex].append(
|
||||
"int gl_InstanceID;" // needs qualifier fixed later
|
||||
);
|
||||
if (spv > 0 && version >= 140)
|
||||
stageBuiltins[EShLangVertex].append(
|
||||
"in int gl_VertexIndex;"
|
||||
"in int gl_InstanceIndex;"
|
||||
);
|
||||
if (version >= 440) {
|
||||
stageBuiltins[EShLangVertex].append(
|
||||
"in int gl_BaseVertexARB;"
|
||||
|
|
@ -1716,10 +1728,16 @@ void TBuiltIns::initialize(int version, EProfile profile, int spv)
|
|||
"mediump float gl_PointSize;" // needs qualifier fixed later
|
||||
);
|
||||
} else {
|
||||
stageBuiltins[EShLangVertex].append(
|
||||
"highp int gl_VertexID;" // needs qualifier fixed later
|
||||
"highp int gl_InstanceID;" // needs qualifier fixed later
|
||||
);
|
||||
if (vulkan == 0)
|
||||
stageBuiltins[EShLangVertex].append(
|
||||
"in highp int gl_VertexID;" // needs qualifier fixed later
|
||||
"in highp int gl_InstanceID;" // needs qualifier fixed later
|
||||
);
|
||||
if (spv > 0)
|
||||
stageBuiltins[EShLangVertex].append(
|
||||
"in highp int gl_VertexIndex;"
|
||||
"in highp int gl_InstanceIndex;"
|
||||
);
|
||||
if (version < 310)
|
||||
stageBuiltins[EShLangVertex].append(
|
||||
"highp vec4 gl_Position;" // needs qualifier fixed later
|
||||
|
|
@ -2071,7 +2089,7 @@ void TBuiltIns::initialize(int version, EProfile profile, int spv)
|
|||
stageBuiltins[EShLangFragment].append("\n");
|
||||
|
||||
if (version >= 130)
|
||||
add2ndGenerationSamplingImaging(version, profile, spv);
|
||||
add2ndGenerationSamplingImaging(version, profile, spv, vulkan);
|
||||
|
||||
//printf("%s\n", commonBuiltins.c_str());
|
||||
//printf("%s\n", stageBuiltins[EShLangFragment].c_str());
|
||||
|
|
@ -2081,7 +2099,7 @@ void TBuiltIns::initialize(int version, EProfile profile, int spv)
|
|||
// Helper function for initialize(), to add the second set of names for texturing,
|
||||
// when adding context-independent built-in functions.
|
||||
//
|
||||
void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, int spv)
|
||||
void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, int /*spv*/, int vulkan)
|
||||
{
|
||||
//
|
||||
// In this function proper, enumerate the types, then calls the next set of functions
|
||||
|
|
@ -2108,9 +2126,13 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, i
|
|||
|
||||
for (int arrayed = 0; arrayed <= 1; ++arrayed) { // loop over "bool" arrayed or not
|
||||
for (int dim = Esd1D; dim < EsdNumDims; ++dim) { // 1D, 2D, ..., buffer
|
||||
if (dim == EsdSubpass && vulkan == 0)
|
||||
continue;
|
||||
if (dim == EsdSubpass && (image || shadow || arrayed))
|
||||
continue;
|
||||
if ((dim == Esd1D || dim == EsdRect) && profile == EEsProfile)
|
||||
continue;
|
||||
if (dim != Esd2D && ms)
|
||||
if (dim != Esd2D && dim != EsdSubpass && ms)
|
||||
continue;
|
||||
if ((dim == Esd3D || dim == EsdRect) && arrayed)
|
||||
continue;
|
||||
|
|
@ -2138,7 +2160,9 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, i
|
|||
//
|
||||
|
||||
TSampler sampler;
|
||||
if (image) {
|
||||
if (dim == EsdSubpass) {
|
||||
sampler.setSubpass(bTypes[bType], ms ? true : false);
|
||||
} else if (image) {
|
||||
sampler.setImage(bTypes[bType], (TSamplerDim)dim, arrayed ? true : false,
|
||||
shadow ? true : false,
|
||||
ms ? true : false);
|
||||
|
|
@ -2150,6 +2174,11 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, i
|
|||
|
||||
TString typeName = sampler.getString();
|
||||
|
||||
if (dim == EsdSubpass) {
|
||||
addSubpassSampling(sampler, typeName, version, profile);
|
||||
continue;
|
||||
}
|
||||
|
||||
addQueryFunctions(sampler, typeName, version, profile);
|
||||
|
||||
if (image)
|
||||
|
|
@ -2342,6 +2371,23 @@ void TBuiltIns::addImageFunctions(TSampler sampler, TString& typeName, int versi
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Helper function for initialize(),
|
||||
// when adding context-independent built-in functions.
|
||||
//
|
||||
// Add all the subpass access functions for the given type.
|
||||
//
|
||||
void TBuiltIns::addSubpassSampling(TSampler sampler, TString& typeName, int /*version*/, EProfile /*profile*/)
|
||||
{
|
||||
stageBuiltins[EShLangFragment].append(prefixes[sampler.type]);
|
||||
stageBuiltins[EShLangFragment].append("vec4 subpassLoad");
|
||||
stageBuiltins[EShLangFragment].append("(");
|
||||
stageBuiltins[EShLangFragment].append(typeName.c_str());
|
||||
if (sampler.ms)
|
||||
stageBuiltins[EShLangFragment].append(", int");
|
||||
stageBuiltins[EShLangFragment].append(");\n");
|
||||
}
|
||||
|
||||
//
|
||||
// Helper function for add2ndGenerationSamplingImaging(),
|
||||
// when adding context-independent built-in functions.
|
||||
|
|
@ -2682,7 +2728,7 @@ void TBuiltIns::addGatherFunctions(TSampler sampler, TString& typeName, int vers
|
|||
// add stage-specific entries to the commonBuiltins, and only if that stage
|
||||
// was requested.
|
||||
//
|
||||
void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProfile profile, int spv, EShLanguage language)
|
||||
void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProfile profile, int spv, int vulkan, EShLanguage language)
|
||||
{
|
||||
//
|
||||
// Initialize the context-dependent (resource-dependent) built-in strings for parsing.
|
||||
|
|
@ -2845,7 +2891,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
|
|||
snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentUniformComponents = %d;", resources.maxFragmentUniformComponents);
|
||||
s.append(builtInConstant);
|
||||
|
||||
if (IncludeLegacy(version, profile, spv)) {
|
||||
if (vulkan == 0 && IncludeLegacy(version, profile, spv)) {
|
||||
//
|
||||
// OpenGL'uniform' state. Page numbers are in reference to version
|
||||
// 1.4 of the OpenGL specification.
|
||||
|
|
@ -3189,7 +3235,7 @@ void BuiltInVariable(const char* blockName, const char* name, TBuiltInVariable b
|
|||
// 3) Tag extension-related symbols added to their base version with their extensions, so
|
||||
// that if an early version has the extension turned off, there is an error reported on use.
|
||||
//
|
||||
void IdentifyBuiltIns(int version, EProfile profile, int spv, EShLanguage language, TSymbolTable& symbolTable)
|
||||
void IdentifyBuiltIns(int version, EProfile profile, int spv, int vulkan, EShLanguage language, TSymbolTable& symbolTable)
|
||||
{
|
||||
//
|
||||
// Tag built-in variables and functions with additional qualifier and extension information
|
||||
|
|
@ -3254,6 +3300,14 @@ void IdentifyBuiltIns(int version, EProfile profile, int spv, EShLanguage langua
|
|||
symbolTable.setFunctionExtensions("imageAtomicCompSwap", 1, &E_GL_OES_shader_image_atomic);
|
||||
}
|
||||
|
||||
if (vulkan == 0) {
|
||||
SpecialQualifier("gl_VertexID", EvqVertexId, EbvVertexId, symbolTable);
|
||||
SpecialQualifier("gl_InstanceID", EvqInstanceId, EbvInstanceId, symbolTable);
|
||||
}
|
||||
|
||||
BuiltInVariable("gl_VertexIndex", EbvVertexIndex, symbolTable);
|
||||
BuiltInVariable("gl_InstanceIndex", EbvInstanceIndex, symbolTable);
|
||||
|
||||
// Fall through
|
||||
|
||||
case EShLangTessControl:
|
||||
|
|
@ -3269,8 +3323,6 @@ void IdentifyBuiltIns(int version, EProfile profile, int spv, EShLanguage langua
|
|||
SpecialQualifier("gl_Position", EvqPosition, EbvPosition, symbolTable);
|
||||
SpecialQualifier("gl_PointSize", EvqPointSize, EbvPointSize, symbolTable);
|
||||
SpecialQualifier("gl_ClipVertex", EvqClipVertex, EbvClipVertex, symbolTable);
|
||||
SpecialQualifier("gl_VertexID", EvqVertexId, EbvVertexId, symbolTable);
|
||||
SpecialQualifier("gl_InstanceID", EvqInstanceId, EbvInstanceId, symbolTable);
|
||||
|
||||
BuiltInVariable("gl_in", "gl_Position", EbvPosition, symbolTable);
|
||||
BuiltInVariable("gl_in", "gl_PointSize", EbvPointSize, symbolTable);
|
||||
|
|
@ -3674,6 +3726,9 @@ void IdentifyBuiltIns(int version, EProfile profile, int spv, EShLanguage langua
|
|||
symbolTable.relateToOperator("imageAtomicExchange", EOpImageAtomicExchange);
|
||||
symbolTable.relateToOperator("imageAtomicCompSwap", EOpImageAtomicCompSwap);
|
||||
|
||||
symbolTable.relateToOperator("subpassLoad", EOpSubpassLoad);
|
||||
symbolTable.relateToOperator("subpassLoadMS", EOpSubpassLoadMS);
|
||||
|
||||
symbolTable.relateToOperator("textureSize", EOpTextureQuerySize);
|
||||
symbolTable.relateToOperator("textureQueryLod", EOpTextureQueryLod);
|
||||
symbolTable.relateToOperator("textureQueryLevels", EOpTextureQueryLevels);
|
||||
|
|
@ -3834,7 +3889,7 @@ void IdentifyBuiltIns(int version, EProfile profile, int spv, EShLanguage langua
|
|||
// 2) Tag extension-related symbols added to their base version with their extensions, so
|
||||
// that if an early version has the extension turned off, there is an error reported on use.
|
||||
//
|
||||
void IdentifyBuiltIns(int version, EProfile profile, int spv, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources)
|
||||
void IdentifyBuiltIns(int version, EProfile profile, int spv, int /*vulkan*/, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources)
|
||||
{
|
||||
if (profile != EEsProfile && version >= 430 && version < 440) {
|
||||
symbolTable.setVariableExtensions("gl_MaxTransformFeedbackBuffers", 1, &E_GL_ARB_enhanced_layouts);
|
||||
|
|
|
|||
|
|
@ -59,13 +59,14 @@ public:
|
|||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
TBuiltIns();
|
||||
virtual ~TBuiltIns();
|
||||
void initialize(int version, EProfile, int spv);
|
||||
void initialize(const TBuiltInResource& resources, int version, EProfile, int spv, EShLanguage);
|
||||
void initialize(int version, EProfile, int spv, int vulkan);
|
||||
void initialize(const TBuiltInResource& resources, int version, EProfile, int spv, int vulkan, EShLanguage);
|
||||
const TString& getCommonString() const { return commonBuiltins; }
|
||||
const TString& getStageString(EShLanguage language) const { return stageBuiltins[language]; }
|
||||
|
||||
protected:
|
||||
void add2ndGenerationSamplingImaging(int version, EProfile profile, int spv);
|
||||
void add2ndGenerationSamplingImaging(int version, EProfile profile, int spv, int vulkan);
|
||||
void addSubpassSampling(TSampler, TString& typeName, int version, EProfile profile);
|
||||
void addQueryFunctions(TSampler, TString& typeName, int version, EProfile profile);
|
||||
void addImageFunctions(TSampler, TString& typeName, int version, EProfile profile);
|
||||
void addSamplingFunctions(TSampler, TString& typeName, int version, EProfile profile);
|
||||
|
|
@ -81,8 +82,8 @@ protected:
|
|||
int dimMap[EsdNumDims];
|
||||
};
|
||||
|
||||
void IdentifyBuiltIns(int version, EProfile profile, int spv, EShLanguage, TSymbolTable&);
|
||||
void IdentifyBuiltIns(int version, EProfile profile, int spv, EShLanguage, TSymbolTable&, const TBuiltInResource &resources);
|
||||
void IdentifyBuiltIns(int version, EProfile profile, int spv, int vulkan, EShLanguage, TSymbolTable&);
|
||||
void IdentifyBuiltIns(int version, EProfile profile, int spv, int vulkan, EShLanguage, TSymbolTable&, const TBuiltInResource &resources);
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ namespace glslang {
|
|||
//
|
||||
|
||||
//
|
||||
// Traversal functions for terminals are straighforward....
|
||||
// Traversal functions for terminals are straightforward....
|
||||
//
|
||||
void TIntermMethod::traverse(TIntermTraverser*)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//Copyright (C) 2012-2015 LunarG, Inc.
|
||||
//Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
|
|
@ -59,6 +60,7 @@ namespace glslang {
|
|||
//
|
||||
// Returns the added node.
|
||||
//
|
||||
|
||||
TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& loc)
|
||||
{
|
||||
TIntermSymbol* node = new TIntermSymbol(id, name, type);
|
||||
|
|
@ -67,9 +69,17 @@ TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType
|
|||
return node;
|
||||
}
|
||||
|
||||
TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TConstUnionArray& constArray, const TSourceLoc& loc)
|
||||
{
|
||||
TIntermSymbol* node = addSymbol(id, name, type, loc);
|
||||
node->setConstArray(constArray);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
|
||||
{
|
||||
return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), loc);
|
||||
return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), loc);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -112,10 +122,9 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
|
|||
node->updatePrecision();
|
||||
|
||||
//
|
||||
// If they are both constants, they must be folded.
|
||||
// If they are both (non-specialization) constants, they must be folded.
|
||||
// (Unless it's the sequence (comma) operator, but that's handled in addComma().)
|
||||
//
|
||||
|
||||
TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
|
||||
TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
|
||||
if (leftTempConstant && rightTempConstant) {
|
||||
|
|
@ -124,6 +133,13 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
|
|||
return folded;
|
||||
}
|
||||
|
||||
// If either is a specialization constant, while the other is
|
||||
// a constant (or specialization constant), the result is still
|
||||
// a specialization constant.
|
||||
if (( left->getType().getQualifier().isSpecConstant() && right->getType().getQualifier().isConstant()) ||
|
||||
(right->getType().getQualifier().isSpecConstant() && left->getType().getQualifier().isConstant()))
|
||||
node->getWritableType().getQualifier().makeSpecConstant();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
@ -261,9 +277,14 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, TSo
|
|||
|
||||
node->updatePrecision();
|
||||
|
||||
// If it's a (non-specialization) constant, it must be folded.
|
||||
if (child->getAsConstantUnion())
|
||||
return child->getAsConstantUnion()->fold(op, node->getType());
|
||||
|
||||
// If it's a specialiation constant, the result is too.
|
||||
if (child->getType().getQualifier().isSpecConstant())
|
||||
node->getWritableType().getQualifier().makeSpecConstant();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
@ -379,35 +400,37 @@ TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator o
|
|||
TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const
|
||||
{
|
||||
//
|
||||
// Does the base type allow operation?
|
||||
// Does the base type even allow the operation?
|
||||
//
|
||||
switch (node->getBasicType()) {
|
||||
case EbtVoid:
|
||||
return 0;
|
||||
case EbtAtomicUint:
|
||||
case EbtSampler:
|
||||
if (op != EOpFunctionCall)
|
||||
return 0;
|
||||
break;
|
||||
// opaque types can be passed to functions
|
||||
if (op == EOpFunction)
|
||||
break;
|
||||
// samplers can get assigned via a sampler constructor
|
||||
// (well, not yet, but code in the rest of this function is ready for it)
|
||||
if (node->getBasicType() == EbtSampler && op == EOpAssign &&
|
||||
node->getAsOperator() != nullptr && node->getAsOperator()->getOp() == EOpConstructTextureSampler)
|
||||
break;
|
||||
|
||||
// otherwise, opaque types can't even be operated on, let alone converted
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Otherwise, if types are identical, no problem
|
||||
//
|
||||
if (type == node->getType())
|
||||
return node;
|
||||
|
||||
//
|
||||
// If one's a structure, then no conversions.
|
||||
//
|
||||
if (type.isStruct() || node->isStruct())
|
||||
return 0;
|
||||
|
||||
//
|
||||
// If one's an array, then no conversions.
|
||||
//
|
||||
if (type.isArray() || node->getType().isArray())
|
||||
return 0;
|
||||
|
||||
|
|
@ -1144,13 +1167,19 @@ bool TIntermBinary::promote()
|
|||
setType(left->getType());
|
||||
type.getQualifier().clear();
|
||||
|
||||
// Finish all array and structure operations.
|
||||
if (left->isArray() || left->getBasicType() == EbtStruct) {
|
||||
// Composite and opaque types don't having pending operator changes, e.g.,
|
||||
// array, structure, and samplers. Just establish final type and correctness.
|
||||
if (left->isArray() || left->getBasicType() == EbtStruct || left->getBasicType() == EbtSampler) {
|
||||
switch (op) {
|
||||
case EOpEqual:
|
||||
case EOpNotEqual:
|
||||
// Promote to conditional
|
||||
setType(TType(EbtBool));
|
||||
if (left->getBasicType() == EbtSampler) {
|
||||
// can't compare samplers
|
||||
return false;
|
||||
} else {
|
||||
// Promote to conditional
|
||||
setType(TType(EbtBool));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//Copyright (C) 2012-2015 LunarG, Inc.
|
||||
//Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
|
|
@ -47,10 +48,10 @@ extern int yyparse(glslang::TParseContext*);
|
|||
|
||||
namespace glslang {
|
||||
|
||||
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb, int v, EProfile p, int spv, EShLanguage L, TInfoSink& is,
|
||||
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb, int v, EProfile p, int spv, int vulkan, EShLanguage L, TInfoSink& is,
|
||||
bool fc, EShMessages m) :
|
||||
intermediate(interm), symbolTable(symt), infoSink(is), language(L),
|
||||
version(v), profile(p), spv(spv), forwardCompatible(fc),
|
||||
version(v), profile(p), spv(spv), vulkan(vulkan), forwardCompatible(fc),
|
||||
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
|
||||
postMainReturn(false),
|
||||
tokensBeforeEOF(false), limits(resources.limits), messages(m), currentScanner(nullptr),
|
||||
|
|
@ -97,11 +98,11 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
|
|||
|
||||
globalUniformDefaults.clear();
|
||||
globalUniformDefaults.layoutMatrix = ElmColumnMajor;
|
||||
globalUniformDefaults.layoutPacking = ElpShared;
|
||||
globalUniformDefaults.layoutPacking = vulkan > 0 ? ElpStd140 : ElpShared;
|
||||
|
||||
globalBufferDefaults.clear();
|
||||
globalBufferDefaults.layoutMatrix = ElmColumnMajor;
|
||||
globalBufferDefaults.layoutPacking = ElpShared;
|
||||
globalBufferDefaults.layoutPacking = vulkan > 0 ? ElpStd430 : ElpShared;
|
||||
|
||||
globalInputDefaults.clear();
|
||||
globalOutputDefaults.clear();
|
||||
|
|
@ -463,7 +464,7 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
|
|||
if (! variable)
|
||||
variable = new TVariable(string, TType(EbtVoid));
|
||||
|
||||
if (variable->getType().getQualifier().storage == EvqConst)
|
||||
if (variable->getType().getQualifier().isFrontEndConstant())
|
||||
node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc);
|
||||
else
|
||||
node = intermediate.addSymbol(*variable, loc);
|
||||
|
|
@ -610,6 +611,16 @@ void TParseContext::makeEditable(TSymbol*& symbol)
|
|||
intermediate.addSymbolLinkageNode(linkage, *symbol);
|
||||
}
|
||||
|
||||
TVariable* TParseContext::getEditableVariable(const char* name)
|
||||
{
|
||||
bool builtIn;
|
||||
TSymbol* symbol = symbolTable.find(name, &builtIn);
|
||||
if (builtIn)
|
||||
makeEditable(symbol);
|
||||
|
||||
return symbol->getAsVariable();
|
||||
}
|
||||
|
||||
// Return true if this is a geometry shader input array or tessellation control output array.
|
||||
bool TParseContext::isIoResizeArray(const TType& type) const
|
||||
{
|
||||
|
|
@ -813,7 +824,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|||
}
|
||||
}
|
||||
|
||||
if (base->getType().getQualifier().storage == EvqConst)
|
||||
if (base->getType().getQualifier().isFrontEndConstant())
|
||||
result = intermediate.foldSwizzle(base, fields, loc);
|
||||
else {
|
||||
if (fields.num == 1) {
|
||||
|
|
@ -1682,6 +1693,8 @@ TOperator TParseContext::mapTypeToConstructorOp(const TType& type) const
|
|||
op = EOpConstructStruct;
|
||||
break;
|
||||
case EbtSampler:
|
||||
if (type.getSampler().combined)
|
||||
op = EOpConstructTextureSampler;
|
||||
break;
|
||||
case EbtFloat:
|
||||
if (type.isMatrix()) {
|
||||
|
|
@ -2154,6 +2167,8 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||
|
||||
bool constructingMatrix = false;
|
||||
switch(op) {
|
||||
case EOpConstructTextureSampler:
|
||||
return constructorTextureSamplerError(loc, function);
|
||||
case EOpConstructMat2x2:
|
||||
case EOpConstructMat2x3:
|
||||
case EOpConstructMat2x4:
|
||||
|
|
@ -2309,6 +2324,66 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||
return false;
|
||||
}
|
||||
|
||||
// Verify all the correct semantics for constructing a combined texture/sampler.
|
||||
// Return true if the semantics are incorrect.
|
||||
bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const TFunction& function)
|
||||
{
|
||||
TString constructorName = function.getType().getBasicTypeString(); // TODO: performance: should not be making copy; interface needs to change
|
||||
const char* token = constructorName.c_str();
|
||||
|
||||
// exactly two arguments needed
|
||||
if (function.getParamCount() != 2) {
|
||||
error(loc, "sampler-constructor requires two arguments", token, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
// For now, not allowing arrayed constructors, the rest of this function
|
||||
// is set up to allow them, if this test is removed:
|
||||
if (function.getType().isArray()) {
|
||||
error(loc, "sampler-constructor cannot make an array of samplers", token, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
// first argument
|
||||
// * the constructor's first argument must be a texture type
|
||||
// * the dimensionality (1D, 2D, 3D, Cube, Rect, Buffer, MS, and Array)
|
||||
// of the texture type must match that of the constructed sampler type
|
||||
// (that is, the suffixes of the type of the first argument and the
|
||||
// type of the constructor will be spelled the same way)
|
||||
if (function[0].type->getBasicType() != EbtSampler ||
|
||||
! function[0].type->getSampler().isTexture() ||
|
||||
function[0].type->isArray()) {
|
||||
error(loc, "sampler-constructor first argument must be a scalar textureXXX type", token, "");
|
||||
return true;
|
||||
}
|
||||
// simulate the first argument's impact on the result type, so it can be compared with the encapsulated operator!=()
|
||||
TSampler texture = function.getType().getSampler();
|
||||
texture.combined = false;
|
||||
texture.shadow = false;
|
||||
if (texture != function[0].type->getSampler()) {
|
||||
error(loc, "sampler-constructor first argument must match type and dimensionality of constructor type", token, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
// second argument
|
||||
// * the constructor's second argument must be a scalar of type
|
||||
// *sampler* or *samplerShadow*
|
||||
// * the presence or absence of depth comparison (Shadow) must match
|
||||
// between the constructed sampler type and the type of the second argument
|
||||
if ( function[1].type->getBasicType() != EbtSampler ||
|
||||
! function[1].type->getSampler().isPureSampler() ||
|
||||
function[1].type->isArray()) {
|
||||
error(loc, "sampler-constructor second argument must be a scalar type 'sampler'", token, "");
|
||||
return true;
|
||||
}
|
||||
if (function.getType().getSampler().shadow != function[1].type->getSampler().shadow) {
|
||||
error(loc, "sampler-constructor second argument presence of shadow must match constructor presence of shadow", token, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks to see if a void variable has been declared and raise an error message for such a case
|
||||
//
|
||||
// returns true in case of an error
|
||||
|
|
@ -2337,7 +2412,7 @@ void TParseContext::boolCheck(const TSourceLoc& loc, const TPublicType& pType)
|
|||
error(loc, "boolean expression expected", "", "");
|
||||
}
|
||||
|
||||
void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
|
||||
void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const TString& identifier, TIntermTyped* /*initializer*/)
|
||||
{
|
||||
if (type.getQualifier().storage == EvqUniform)
|
||||
return;
|
||||
|
|
@ -2345,6 +2420,9 @@ void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const
|
|||
if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtSampler))
|
||||
error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str());
|
||||
else if (type.getBasicType() == EbtSampler && type.getQualifier().storage != EvqUniform) {
|
||||
// non-uniform sampler
|
||||
// not yet: okay if it has an initializer
|
||||
// if (! initializer)
|
||||
error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
|
||||
}
|
||||
}
|
||||
|
|
@ -2360,6 +2438,19 @@ void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, co
|
|||
error(loc, "atomic_uints can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
|
||||
}
|
||||
|
||||
void TParseContext::transparentCheck(const TSourceLoc& loc, const TType& type, const TString& /*identifier*/)
|
||||
{
|
||||
// double standard due to gl_NumSamples
|
||||
if (parsingBuiltins)
|
||||
return;
|
||||
|
||||
// Vulkan doesn't allow transparent uniforms outside of blocks
|
||||
if (vulkan == 0 || type.getQualifier().storage != EvqUniform)
|
||||
return;
|
||||
if (type.containsNonOpaque())
|
||||
vulkanRemoved(loc, "non-opaque uniforms outside a block");
|
||||
}
|
||||
|
||||
//
|
||||
// Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
|
||||
//
|
||||
|
|
@ -2605,6 +2696,7 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
|
|||
MERGE_SINGLETON(restrict);
|
||||
MERGE_SINGLETON(readonly);
|
||||
MERGE_SINGLETON(writeonly);
|
||||
MERGE_SINGLETON(specConstant);
|
||||
|
||||
if (repeated)
|
||||
error(loc, "replicated qualifiers", "", "");
|
||||
|
|
@ -2707,22 +2799,35 @@ bool TParseContext::containsFieldWithBasicType(const TType& type, TBasicType bas
|
|||
//
|
||||
// Do size checking for an array type's size.
|
||||
//
|
||||
void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, int& size)
|
||||
void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair)
|
||||
{
|
||||
TIntermConstantUnion* constant = expr->getAsConstantUnion();
|
||||
if (constant == nullptr || (constant->getBasicType() != EbtInt && constant->getBasicType() != EbtUint)) {
|
||||
error(loc, "array size must be a constant integer expression", "", "");
|
||||
size = 1;
|
||||
bool isConst = false;
|
||||
sizePair.size = 1;
|
||||
sizePair.node = nullptr;
|
||||
|
||||
TIntermConstantUnion* constant = expr->getAsConstantUnion();
|
||||
if (constant) {
|
||||
// handle true (non-specialization) constant
|
||||
sizePair.size = constant->getConstArray()[0].getIConst();
|
||||
isConst = true;
|
||||
} else {
|
||||
// see if it's a specialization constant instead
|
||||
if (expr->getQualifier().isSpecConstant()) {
|
||||
isConst = true;
|
||||
sizePair.node = expr;
|
||||
TIntermSymbol* symbol = expr->getAsSymbolNode();
|
||||
if (symbol && symbol->getConstArray().size() > 0)
|
||||
sizePair.size = symbol->getConstArray()[0].getIConst();
|
||||
}
|
||||
}
|
||||
|
||||
if (! isConst || (expr->getBasicType() != EbtInt && expr->getBasicType() != EbtUint)) {
|
||||
error(loc, "array size must be a constant integer expression", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
size = constant->getConstArray()[0].getIConst();
|
||||
|
||||
if (size <= 0) {
|
||||
if (sizePair.size <= 0) {
|
||||
error(loc, "array size must be a positive integer", "", "");
|
||||
size = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -3390,6 +3495,12 @@ void TParseContext::opaqueCheck(const TSourceLoc& loc, const TType& type, const
|
|||
error(loc, "can't use with samplers or structs containing samplers", op, "");
|
||||
}
|
||||
|
||||
void TParseContext::specializationCheck(const TSourceLoc& loc, const TType& type, const char* op)
|
||||
{
|
||||
if (type.containsSpecializationSize())
|
||||
error(loc, "can't use with types containing arrays sized with a specialization constant", op, "");
|
||||
}
|
||||
|
||||
void TParseContext::structTypeCheck(const TSourceLoc& /*loc*/, TPublicType& publicType)
|
||||
{
|
||||
const TTypeList& typeList = *publicType.userDef->getStruct();
|
||||
|
|
@ -3605,10 +3716,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
return;
|
||||
}
|
||||
if (id == TQualifier::getLayoutPackingString(ElpPacked)) {
|
||||
if (vulkan > 0)
|
||||
vulkanRemoved(loc, "packed");
|
||||
publicType.qualifier.layoutPacking = ElpPacked;
|
||||
return;
|
||||
}
|
||||
if (id == TQualifier::getLayoutPackingString(ElpShared)) {
|
||||
if (vulkan > 0)
|
||||
vulkanRemoved(loc, "shared");
|
||||
publicType.qualifier.layoutPacking = ElpShared;
|
||||
return;
|
||||
}
|
||||
|
|
@ -3636,6 +3751,11 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (id == "push_constant") {
|
||||
requireVulkan(loc, "push_constant");
|
||||
publicType.qualifier.layoutPushConstant = true;
|
||||
return;
|
||||
}
|
||||
if (language == EShLangGeometry || language == EShLangTessEvaluation) {
|
||||
if (id == TQualifier::getGeometryString(ElgTriangles)) {
|
||||
publicType.shaderQualifiers.geometry = ElgTriangles;
|
||||
|
|
@ -3874,6 +3994,27 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
}
|
||||
}
|
||||
|
||||
if (id == "input_attachment_index") {
|
||||
requireVulkan(loc, "input_attachment_index");
|
||||
if (value >= (int)TQualifier::layoutAttachmentEnd)
|
||||
error(loc, "attachment index is too large", id.c_str(), "");
|
||||
else
|
||||
publicType.qualifier.layoutAttachment = value;
|
||||
return;
|
||||
}
|
||||
if (id == "constant_id") {
|
||||
requireSpv(loc, "constant_id");
|
||||
if (value >= (int)TQualifier::layoutSpecConstantIdEnd) {
|
||||
error(loc, "specialization-constant id is too large", id.c_str(), "");
|
||||
} else {
|
||||
publicType.qualifier.layoutSpecConstantId = value;
|
||||
publicType.qualifier.specConstant = true;
|
||||
if (! intermediate.addUsedConstantId(value))
|
||||
error(loc, "specialization-constant id already used", id.c_str(), "");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (language) {
|
||||
case EShLangVertex:
|
||||
break;
|
||||
|
|
@ -3924,17 +4065,33 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
break;
|
||||
|
||||
case EShLangCompute:
|
||||
if (id == "local_size_x") {
|
||||
publicType.shaderQualifiers.localSize[0] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_y") {
|
||||
publicType.shaderQualifiers.localSize[1] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_z") {
|
||||
publicType.shaderQualifiers.localSize[2] = value;
|
||||
return;
|
||||
if (id.compare(0, 11, "local_size_") == 0) {
|
||||
if (id == "local_size_x") {
|
||||
publicType.shaderQualifiers.localSize[0] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_y") {
|
||||
publicType.shaderQualifiers.localSize[1] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_z") {
|
||||
publicType.shaderQualifiers.localSize[2] = value;
|
||||
return;
|
||||
}
|
||||
if (spv > 0) {
|
||||
if (id == "local_size_x_id") {
|
||||
publicType.shaderQualifiers.localSizeSpecId[0] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_y_id") {
|
||||
publicType.shaderQualifiers.localSizeSpecId[1] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_z_id") {
|
||||
publicType.shaderQualifiers.localSizeSpecId[2] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -3999,6 +4156,13 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie
|
|||
dst.layoutXfbStride = src.layoutXfbStride;
|
||||
if (src.hasXfbOffset())
|
||||
dst.layoutXfbOffset = src.layoutXfbOffset;
|
||||
if (src.hasAttachment())
|
||||
dst.layoutAttachment = src.layoutAttachment;
|
||||
if (src.hasSpecConstantId())
|
||||
dst.layoutSpecConstantId = src.layoutSpecConstantId;
|
||||
|
||||
if (src.layoutPushConstant)
|
||||
dst.layoutPushConstant = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4041,6 +4205,8 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb
|
|||
// "The align qualifier can only be used on blocks or block members..."
|
||||
if (qualifier.hasAlign())
|
||||
error(loc, "cannot specify on a variable declaration", "align", "");
|
||||
if (qualifier.layoutPushConstant)
|
||||
error(loc, "can only specify on a uniform block", "push_constant", "");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -4055,7 +4221,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
{
|
||||
const TQualifier& qualifier = type.getQualifier();
|
||||
|
||||
// first, intra layout qualifier-only error checking
|
||||
// first, intra-layout qualifier-only error checking
|
||||
layoutQualifierCheck(loc, qualifier);
|
||||
|
||||
// now, error checking combining type and qualifier
|
||||
|
|
@ -4087,7 +4253,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
case EvqBuffer:
|
||||
break;
|
||||
default:
|
||||
error(loc, "can only appy to uniform, buffer, in, or out storage qualifiers", "location", "");
|
||||
error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", "");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4181,6 +4347,38 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
}
|
||||
} else if (type.isImage() && ! qualifier.writeonly)
|
||||
error(loc, "image variables not declared 'writeonly' must have a format layout qualifier", "", "");
|
||||
|
||||
if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock)
|
||||
error(loc, "can only be used with a block", "push_constant", "");
|
||||
|
||||
// input attachment
|
||||
if (type.isSubpass()) {
|
||||
if (! qualifier.hasAttachment())
|
||||
error(loc, "requires an input_attachment_index layout qualifier", "subpass", "");
|
||||
} else {
|
||||
if (qualifier.hasAttachment())
|
||||
error(loc, "can only be used with a subpass", "input_attachment_index", "");
|
||||
}
|
||||
|
||||
// specialization-constant id
|
||||
if (qualifier.hasSpecConstantId()) {
|
||||
if (type.getQualifier().storage != EvqConst)
|
||||
error(loc, "can only be applied to 'const'-qualified scalar", "constant_id", "");
|
||||
if (! type.isScalar())
|
||||
error(loc, "can only be applied to a scalar", "constant_id", "");
|
||||
switch (type.getBasicType())
|
||||
{
|
||||
case EbtInt:
|
||||
case EbtUint:
|
||||
case EbtBool:
|
||||
case EbtFloat:
|
||||
case EbtDouble:
|
||||
break;
|
||||
default:
|
||||
error(loc, "cannot be applied to this type", "constant_id", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do layout error checking that can be done within a layout qualifier proper, not needing to know
|
||||
|
|
@ -4275,6 +4473,10 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
|
|||
error(loc, "offset/align can only be used on a uniform or buffer", "layout", "");
|
||||
}
|
||||
}
|
||||
if (qualifier.layoutPushConstant) {
|
||||
if (qualifier.storage != EvqUniform)
|
||||
error(loc, "can only be used with a uniform", "push_constant", "");
|
||||
}
|
||||
}
|
||||
|
||||
// For places that can't have shader-level layout qualifiers
|
||||
|
|
@ -4297,6 +4499,8 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua
|
|||
for (int i = 0; i < 3; ++i) {
|
||||
if (shaderQualifiers.localSize[i] > 1)
|
||||
error(loc, message, "local_size", "");
|
||||
if (shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet)
|
||||
error(loc, message, "local_size id", "");
|
||||
}
|
||||
if (shaderQualifiers.blendEquation)
|
||||
error(loc, message, "blend equation", "");
|
||||
|
|
@ -4490,8 +4694,9 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|||
else
|
||||
nonInitConstCheck(loc, identifier, type);
|
||||
|
||||
samplerCheck(loc, type, identifier);
|
||||
samplerCheck(loc, type, identifier, initializer);
|
||||
atomicUintCheck(loc, type, identifier);
|
||||
transparentCheck(loc, type, identifier);
|
||||
|
||||
if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
|
||||
error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
|
||||
|
|
@ -4690,7 +4895,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
}
|
||||
|
||||
if (qualifier == EvqConst || qualifier == EvqUniform) {
|
||||
// Compile-time tagging of the variable with it's constant value...
|
||||
// Compile-time tagging of the variable with its constant value...
|
||||
|
||||
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
|
||||
if (! initializer || ! initializer->getAsConstantUnion() || variable->getType() != initializer->getType()) {
|
||||
|
|
@ -4703,6 +4908,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
variable->setConstArray(initializer->getAsConstantUnion()->getConstArray());
|
||||
} else {
|
||||
// normal assigning of a value to a variable...
|
||||
specializationCheck(loc, initializer->getType(), "initializer");
|
||||
TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
|
||||
TIntermNode* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc);
|
||||
if (! initNode)
|
||||
|
|
@ -4716,7 +4922,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
|
||||
//
|
||||
// Reprocess any initializer-list { ... } parts of the initializer.
|
||||
// Need to heirarchically assign correct types and implicit
|
||||
// Need to hierarchically assign correct types and implicit
|
||||
// conversions. Will do this mimicking the same process used for
|
||||
// creating a constructor-style initializer, ensuring we get the
|
||||
// same form.
|
||||
|
|
@ -4811,6 +5017,11 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||
|
||||
TIntermAggregate* aggrNode = node->getAsAggregate();
|
||||
|
||||
// Combined texture-sampler constructors are completely semantic checked
|
||||
// in constructorTextureSamplerError()
|
||||
if (op == EOpConstructTextureSampler)
|
||||
return intermediate.setAggregateOperator(aggrNode, op, type, loc);
|
||||
|
||||
TTypeList::const_iterator memberTypes;
|
||||
if (op == EOpConstructStruct)
|
||||
memberTypes = type.getStruct()->begin();
|
||||
|
|
@ -4997,7 +5208,7 @@ TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType&
|
|||
void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes)
|
||||
{
|
||||
blockStageIoCheck(loc, currentBlockQualifier);
|
||||
blockQualifierCheck(loc, currentBlockQualifier);
|
||||
blockQualifierCheck(loc, currentBlockQualifier, instanceName != nullptr);
|
||||
if (arraySizes) {
|
||||
arrayUnsizedCheck(loc, currentBlockQualifier, arraySizes, false, false);
|
||||
arrayDimCheck(loc, arraySizes, 0);
|
||||
|
|
@ -5052,6 +5263,11 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|||
default: defaultQualification.clear(); break;
|
||||
}
|
||||
|
||||
// Special case for "push_constant uniform", which has a default of std430,
|
||||
// contrary to normal uniform defaults, and can't have a default tracked for it.
|
||||
if (currentBlockQualifier.layoutPushConstant && !currentBlockQualifier.hasPacking())
|
||||
currentBlockQualifier.layoutPacking = ElpStd430;
|
||||
|
||||
// fix and check for member layout qualifiers
|
||||
|
||||
mergeObjectLayoutQualifiers(defaultQualification, currentBlockQualifier, true);
|
||||
|
|
@ -5197,7 +5413,7 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q
|
|||
case EvqUniform:
|
||||
profileRequires(loc, EEsProfile, 300, nullptr, "uniform block");
|
||||
profileRequires(loc, ENoProfile, 140, nullptr, "uniform block");
|
||||
if (currentBlockQualifier.layoutPacking == ElpStd430)
|
||||
if (currentBlockQualifier.layoutPacking == ElpStd430 && ! currentBlockQualifier.layoutPushConstant)
|
||||
error(loc, "requires the 'buffer' storage qualifier", "std430", "");
|
||||
break;
|
||||
case EvqBuffer:
|
||||
|
|
@ -5227,7 +5443,7 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q
|
|||
}
|
||||
|
||||
// Do all block-declaration checking regarding its qualifers.
|
||||
void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier)
|
||||
void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier, bool instanceName)
|
||||
{
|
||||
// The 4.5 specification says:
|
||||
//
|
||||
|
|
@ -5254,6 +5470,11 @@ void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier&
|
|||
error(loc, "cannot use sample qualifier on an interface block", "sample", "");
|
||||
if (qualifier.invariant)
|
||||
error(loc, "cannot use invariant qualifier on an interface block", "invariant", "");
|
||||
if (qualifier.layoutPushConstant) {
|
||||
intermediate.addPushConstantCount();
|
||||
if (! instanceName)
|
||||
error(loc, "requires an instance name", "push_constant", "");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -5541,16 +5762,22 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|||
error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", "");
|
||||
|
||||
// Fix the existing constant gl_WorkGroupSize with this new information.
|
||||
bool builtIn;
|
||||
TSymbol* symbol = symbolTable.find("gl_WorkGroupSize", &builtIn);
|
||||
if (builtIn)
|
||||
makeEditable(symbol);
|
||||
TVariable* workGroupSize = symbol->getAsVariable();
|
||||
TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
|
||||
workGroupSize->getWritableConstArray()[i].setUConst(intermediate.getLocalSize(i));
|
||||
}
|
||||
} else
|
||||
error(loc, "can only apply to 'in'", "local_size", "");
|
||||
}
|
||||
if (publicType.shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet) {
|
||||
if (publicType.qualifier.storage == EvqVaryingIn) {
|
||||
if (! intermediate.setLocalSizeSpecId(i, publicType.shaderQualifiers.localSizeSpecId[i]))
|
||||
error(loc, "cannot change previously set size", "local_size", "");
|
||||
} else
|
||||
error(loc, "can only apply to 'in'", "local_size id", "");
|
||||
// Set the workgroup built-in variable as a specialization constant
|
||||
TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
|
||||
workGroupSize->getWritableType().getQualifier().specConstant = true;
|
||||
}
|
||||
}
|
||||
if (publicType.shaderQualifiers.earlyFragmentTests) {
|
||||
if (publicType.qualifier.storage == EvqVaryingIn)
|
||||
|
|
@ -5614,6 +5841,10 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|||
error(loc, "cannot declare a default, use a full declaration", "location/component/index", "");
|
||||
if (qualifier.hasXfbOffset())
|
||||
error(loc, "cannot declare a default, use a full declaration", "xfb_offset", "");
|
||||
if (qualifier.layoutPushConstant)
|
||||
error(loc, "cannot declare a default, can only be used on a block", "push_constant", "");
|
||||
if (qualifier.hasSpecConstantId())
|
||||
error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", "");
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ typedef std::set<int> TIdSetType;
|
|||
//
|
||||
class TParseContext {
|
||||
public:
|
||||
TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, int spv, EShLanguage, TInfoSink&,
|
||||
TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, int spv, int vulkan, EShLanguage, TInfoSink&,
|
||||
bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
|
||||
virtual ~TParseContext();
|
||||
|
||||
|
|
@ -98,6 +98,7 @@ public:
|
|||
void handleIndexLimits(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
|
||||
|
||||
void makeEditable(TSymbol*&);
|
||||
TVariable* getEditableVariable(const char* name);
|
||||
bool isIoResizeArray(const TType&) const;
|
||||
void fixIoArraySize(const TSourceLoc&, TType&);
|
||||
void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier);
|
||||
|
|
@ -132,7 +133,8 @@ public:
|
|||
void integerCheck(const TIntermTyped* node, const char* token);
|
||||
void globalCheck(const TSourceLoc&, const char* token);
|
||||
bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&);
|
||||
void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, int& size);
|
||||
bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&);
|
||||
void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&);
|
||||
bool arrayQualifierError(const TSourceLoc&, const TQualifier&);
|
||||
bool arrayError(const TSourceLoc&, const TType&);
|
||||
void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&);
|
||||
|
|
@ -145,8 +147,9 @@ public:
|
|||
bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType);
|
||||
void boolCheck(const TSourceLoc&, const TIntermTyped*);
|
||||
void boolCheck(const TSourceLoc&, const TPublicType&);
|
||||
void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier);
|
||||
void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier, TIntermTyped* initializer);
|
||||
void atomicUintCheck(const TSourceLoc&, const TType&, const TString& identifier);
|
||||
void transparentCheck(const TSourceLoc&, const TType&, const TString& identifier);
|
||||
void globalQualifierFixCheck(const TSourceLoc&, TQualifier&);
|
||||
void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&);
|
||||
bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
|
||||
|
|
@ -165,6 +168,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 specializationCheck(const TSourceLoc&, const TType&, const char* op);
|
||||
void structTypeCheck(const TSourceLoc&, TPublicType&);
|
||||
void inductiveLoopCheck(const TSourceLoc&, TIntermNode* init, TIntermLoop* loop);
|
||||
void arrayLimitCheck(const TSourceLoc&, const TString&, int size);
|
||||
|
|
@ -193,7 +197,7 @@ public:
|
|||
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
|
||||
void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
|
||||
void blockStageIoCheck(const TSourceLoc&, const TQualifier&);
|
||||
void blockQualifierCheck(const TSourceLoc&, const TQualifier&);
|
||||
void blockQualifierCheck(const TSourceLoc&, const TQualifier&, bool instanceName);
|
||||
void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation);
|
||||
void fixBlockXfbOffsets(TQualifier&, TTypeList&);
|
||||
void fixBlockUniformOffsets(TQualifier&, TTypeList&);
|
||||
|
|
@ -244,6 +248,10 @@ public:
|
|||
void updateExtensionBehavior(int line, const char* const extension, const char* behavior);
|
||||
void fullIntegerCheck(const TSourceLoc&, const char* op);
|
||||
void doubleCheck(const TSourceLoc&, const char* op);
|
||||
void spvRemoved(const TSourceLoc&, const char* op);
|
||||
void vulkanRemoved(const TSourceLoc&, const char* op);
|
||||
void requireVulkan(const TSourceLoc&, const char* op);
|
||||
void requireSpv(const TSourceLoc&, const char* op);
|
||||
|
||||
void setVersionCallback(const std::function<void(int, int, const char*)>& func) { versionCallback = func; }
|
||||
void setPragmaCallback(const std::function<void(int, const TVector<TString>&)>& func) { pragmaCallback = func; }
|
||||
|
|
@ -281,6 +289,7 @@ public:
|
|||
int version; // version, updated by #version in the shader
|
||||
EProfile profile; // the declared profile in the shader (core by default)
|
||||
int spv; // SPIR-V version; 0 means not SPIR-V
|
||||
int vulkan; // Vulkan version; 0 means not vulkan
|
||||
bool forwardCompatible; // true if errors are to be given for use of deprecated features
|
||||
|
||||
// Current state of parsing
|
||||
|
|
|
|||
|
|
@ -494,6 +494,50 @@ void TScanContext::fillInKeywordMap()
|
|||
|
||||
(*KeywordMap)["samplerExternalOES"] = SAMPLEREXTERNALOES; // GL_OES_EGL_image_external
|
||||
|
||||
(*KeywordMap)["sampler"] = SAMPLER;
|
||||
(*KeywordMap)["samplerShadow"] = SAMPLERSHADOW;
|
||||
|
||||
(*KeywordMap)["texture2D"] = TEXTURE2D;
|
||||
(*KeywordMap)["textureCube"] = TEXTURECUBE;
|
||||
(*KeywordMap)["textureCubeArray"] = TEXTURECUBEARRAY;
|
||||
(*KeywordMap)["itextureCubeArray"] = ITEXTURECUBEARRAY;
|
||||
(*KeywordMap)["utextureCubeArray"] = UTEXTURECUBEARRAY;
|
||||
(*KeywordMap)["itexture1DArray"] = ITEXTURE1DARRAY;
|
||||
(*KeywordMap)["utexture1D"] = UTEXTURE1D;
|
||||
(*KeywordMap)["itexture1D"] = ITEXTURE1D;
|
||||
(*KeywordMap)["utexture1DArray"] = UTEXTURE1DARRAY;
|
||||
(*KeywordMap)["textureBuffer"] = TEXTUREBUFFER;
|
||||
(*KeywordMap)["texture2DArray"] = TEXTURE2DARRAY;
|
||||
(*KeywordMap)["itexture2D"] = ITEXTURE2D;
|
||||
(*KeywordMap)["itexture3D"] = ITEXTURE3D;
|
||||
(*KeywordMap)["itextureCube"] = ITEXTURECUBE;
|
||||
(*KeywordMap)["itexture2DArray"] = ITEXTURE2DARRAY;
|
||||
(*KeywordMap)["utexture2D"] = UTEXTURE2D;
|
||||
(*KeywordMap)["utexture3D"] = UTEXTURE3D;
|
||||
(*KeywordMap)["utextureCube"] = UTEXTURECUBE;
|
||||
(*KeywordMap)["utexture2DArray"] = UTEXTURE2DARRAY;
|
||||
(*KeywordMap)["itexture2DRect"] = ITEXTURE2DRECT;
|
||||
(*KeywordMap)["utexture2DRect"] = UTEXTURE2DRECT;
|
||||
(*KeywordMap)["itextureBuffer"] = ITEXTUREBUFFER;
|
||||
(*KeywordMap)["utextureBuffer"] = UTEXTUREBUFFER;
|
||||
(*KeywordMap)["texture2DMS"] = TEXTURE2DMS;
|
||||
(*KeywordMap)["itexture2DMS"] = ITEXTURE2DMS;
|
||||
(*KeywordMap)["utexture2DMS"] = UTEXTURE2DMS;
|
||||
(*KeywordMap)["texture2DMSArray"] = TEXTURE2DMSARRAY;
|
||||
(*KeywordMap)["itexture2DMSArray"] = ITEXTURE2DMSARRAY;
|
||||
(*KeywordMap)["utexture2DMSArray"] = UTEXTURE2DMSARRAY;
|
||||
(*KeywordMap)["texture1D"] = TEXTURE1D;
|
||||
(*KeywordMap)["texture3D"] = TEXTURE3D;
|
||||
(*KeywordMap)["texture2DRect"] = TEXTURE2DRECT;
|
||||
(*KeywordMap)["texture1DArray"] = TEXTURE1DARRAY;
|
||||
|
||||
(*KeywordMap)["subpassInput"] = SUBPASSINPUT;
|
||||
(*KeywordMap)["subpassInputMS"] = SUBPASSINPUTMS;
|
||||
(*KeywordMap)["isubpassInput"] = ISUBPASSINPUT;
|
||||
(*KeywordMap)["isubpassInputMS"] = ISUBPASSINPUTMS;
|
||||
(*KeywordMap)["usubpassInput"] = USUBPASSINPUT;
|
||||
(*KeywordMap)["usubpassInputMS"] = USUBPASSINPUTMS;
|
||||
|
||||
(*KeywordMap)["noperspective"] = NOPERSPECTIVE;
|
||||
(*KeywordMap)["smooth"] = SMOOTH;
|
||||
(*KeywordMap)["flat"] = FLAT;
|
||||
|
|
@ -987,6 +1031,57 @@ int TScanContext::tokenizeIdentifier()
|
|||
return keyword;
|
||||
return identifierOrType();
|
||||
|
||||
case TEXTURE2D:
|
||||
case TEXTURECUBE:
|
||||
case TEXTURECUBEARRAY:
|
||||
case ITEXTURECUBEARRAY:
|
||||
case UTEXTURECUBEARRAY:
|
||||
case ITEXTURE1DARRAY:
|
||||
case UTEXTURE1D:
|
||||
case ITEXTURE1D:
|
||||
case UTEXTURE1DARRAY:
|
||||
case TEXTUREBUFFER:
|
||||
case TEXTURE2DARRAY:
|
||||
case ITEXTURE2D:
|
||||
case ITEXTURE3D:
|
||||
case ITEXTURECUBE:
|
||||
case ITEXTURE2DARRAY:
|
||||
case UTEXTURE2D:
|
||||
case UTEXTURE3D:
|
||||
case UTEXTURECUBE:
|
||||
case UTEXTURE2DARRAY:
|
||||
case ITEXTURE2DRECT:
|
||||
case UTEXTURE2DRECT:
|
||||
case ITEXTUREBUFFER:
|
||||
case UTEXTUREBUFFER:
|
||||
case TEXTURE2DMS:
|
||||
case ITEXTURE2DMS:
|
||||
case UTEXTURE2DMS:
|
||||
case TEXTURE2DMSARRAY:
|
||||
case ITEXTURE2DMSARRAY:
|
||||
case UTEXTURE2DMSARRAY:
|
||||
case TEXTURE1D:
|
||||
case TEXTURE3D:
|
||||
case TEXTURE2DRECT:
|
||||
case TEXTURE1DARRAY:
|
||||
case SAMPLER:
|
||||
case SAMPLERSHADOW:
|
||||
if (parseContext.spv > 0)
|
||||
return keyword;
|
||||
else
|
||||
return identifierOrType();
|
||||
|
||||
case SUBPASSINPUT:
|
||||
case SUBPASSINPUTMS:
|
||||
case ISUBPASSINPUT:
|
||||
case ISUBPASSINPUTMS:
|
||||
case USUBPASSINPUT:
|
||||
case USUBPASSINPUTMS:
|
||||
if (parseContext.spv > 0)
|
||||
return keyword;
|
||||
else
|
||||
return identifierOrType();
|
||||
|
||||
case NOPERSPECTIVE:
|
||||
return es30ReservedFromGLSL(130);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//Copyright (C) 2013-2015 LunarG, Inc.
|
||||
//Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
|
|
@ -124,12 +125,12 @@ TPoolAllocator* PerProcessGPA = 0;
|
|||
//
|
||||
// Parse and add to the given symbol table the content of the given shader string.
|
||||
//
|
||||
bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, int spv, EShLanguage language, TInfoSink& infoSink,
|
||||
bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, int spv, int vulkan, EShLanguage language, TInfoSink& infoSink,
|
||||
TSymbolTable& symbolTable)
|
||||
{
|
||||
TIntermediate intermediate(language, version, profile);
|
||||
|
||||
TParseContext parseContext(symbolTable, intermediate, true, version, profile, spv, language, infoSink);
|
||||
TParseContext parseContext(symbolTable, intermediate, true, version, profile, spv, vulkan, language, infoSink);
|
||||
TPpContext ppContext(parseContext, TShader::ForbidInclude());
|
||||
TScanContext scanContext(parseContext);
|
||||
parseContext.setScanContext(&scanContext);
|
||||
|
|
@ -168,11 +169,11 @@ int CommonIndex(EProfile profile, EShLanguage language)
|
|||
//
|
||||
// To initialize per-stage shared tables, with the common table already complete.
|
||||
//
|
||||
void InitializeStageSymbolTable(TBuiltIns& builtIns, int version, EProfile profile, int spv, EShLanguage language, TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables)
|
||||
void InitializeStageSymbolTable(TBuiltIns& builtIns, int version, EProfile profile, int spv, int vulkan, EShLanguage language, TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables)
|
||||
{
|
||||
(*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]);
|
||||
InitializeSymbolTable(builtIns.getStageString(language), version, profile, spv, language, infoSink, *symbolTables[language]);
|
||||
IdentifyBuiltIns(version, profile, spv, language, *symbolTables[language]);
|
||||
InitializeSymbolTable(builtIns.getStageString(language), version, profile, spv, vulkan, language, infoSink, *symbolTables[language]);
|
||||
IdentifyBuiltIns(version, profile, spv, vulkan, language, *symbolTables[language]);
|
||||
if (profile == EEsProfile && version >= 300)
|
||||
(*symbolTables[language]).setNoBuiltInRedeclarations();
|
||||
if (version == 110)
|
||||
|
|
@ -183,49 +184,49 @@ void InitializeStageSymbolTable(TBuiltIns& builtIns, int version, EProfile profi
|
|||
// Initialize the full set of shareable symbol tables;
|
||||
// The common (cross-stage) and those shareable per-stage.
|
||||
//
|
||||
bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables, int version, EProfile profile, int spv)
|
||||
bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables, int version, EProfile profile, int spv, int vulkan)
|
||||
{
|
||||
TBuiltIns builtIns;
|
||||
builtIns.initialize(version, profile, spv);
|
||||
builtIns.initialize(version, profile, spv, vulkan);
|
||||
|
||||
// do the common tables
|
||||
InitializeSymbolTable(builtIns.getCommonString(), version, profile, spv, EShLangVertex, infoSink, *commonTable[EPcGeneral]);
|
||||
InitializeSymbolTable(builtIns.getCommonString(), version, profile, spv, vulkan, EShLangVertex, infoSink, *commonTable[EPcGeneral]);
|
||||
if (profile == EEsProfile)
|
||||
InitializeSymbolTable(builtIns.getCommonString(), version, profile, spv, EShLangFragment, infoSink, *commonTable[EPcFragment]);
|
||||
InitializeSymbolTable(builtIns.getCommonString(), version, profile, spv, vulkan, EShLangFragment, infoSink, *commonTable[EPcFragment]);
|
||||
|
||||
// do the per-stage tables
|
||||
|
||||
// always have vertex and fragment
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, EShLangVertex, infoSink, commonTable, symbolTables);
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, EShLangFragment, infoSink, commonTable, symbolTables);
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, vulkan, EShLangVertex, infoSink, commonTable, symbolTables);
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, vulkan, EShLangFragment, infoSink, commonTable, symbolTables);
|
||||
|
||||
// check for tessellation
|
||||
if ((profile != EEsProfile && version >= 150) ||
|
||||
(profile == EEsProfile && version >= 310)) {
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, EShLangTessControl, infoSink, commonTable, symbolTables);
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, EShLangTessEvaluation, infoSink, commonTable, symbolTables);
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, vulkan, EShLangTessControl, infoSink, commonTable, symbolTables);
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, vulkan, EShLangTessEvaluation, infoSink, commonTable, symbolTables);
|
||||
}
|
||||
|
||||
// check for geometry
|
||||
if ((profile != EEsProfile && version >= 150) ||
|
||||
(profile == EEsProfile && version >= 310))
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, EShLangGeometry, infoSink, commonTable, symbolTables);
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, vulkan, EShLangGeometry, infoSink, commonTable, symbolTables);
|
||||
|
||||
// check for compute
|
||||
if ((profile != EEsProfile && version >= 430) ||
|
||||
(profile == EEsProfile && version >= 310))
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, EShLangCompute, infoSink, commonTable, symbolTables);
|
||||
InitializeStageSymbolTable(builtIns, version, profile, spv, vulkan, EShLangCompute, infoSink, commonTable, symbolTables);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable& symbolTable, int version, EProfile profile, int spv, EShLanguage language)
|
||||
bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable& symbolTable, int version, EProfile profile, int spv, int vulkan, EShLanguage language)
|
||||
{
|
||||
TBuiltIns builtIns;
|
||||
|
||||
builtIns.initialize(*resources, version, profile, spv, language);
|
||||
InitializeSymbolTable(builtIns.getCommonString(), version, profile, spv, language, infoSink, symbolTable);
|
||||
IdentifyBuiltIns(version, profile, spv, language, symbolTable, *resources);
|
||||
builtIns.initialize(*resources, version, profile, spv, vulkan, language);
|
||||
InitializeSymbolTable(builtIns.getCommonString(), version, profile, spv, vulkan, language, infoSink, symbolTable);
|
||||
IdentifyBuiltIns(version, profile, spv, vulkan, language, symbolTable, *resources);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -242,7 +243,7 @@ bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& inf
|
|||
// This only gets done the first time any thread needs a particular symbol table
|
||||
// (lazy evaluation).
|
||||
//
|
||||
void SetupBuiltinSymbolTable(int version, EProfile profile, int spv)
|
||||
void SetupBuiltinSymbolTable(int version, EProfile profile, int spv, int vulkan)
|
||||
{
|
||||
TInfoSink infoSink;
|
||||
|
||||
|
|
@ -272,7 +273,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, int spv)
|
|||
stageTables[stage] = new TSymbolTable;
|
||||
|
||||
// Generate the local symbol tables using the new pool
|
||||
InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spv);
|
||||
InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spv, vulkan);
|
||||
|
||||
// Switch to the process-global pool
|
||||
SetThreadPoolAllocator(*PerProcessGPA);
|
||||
|
|
@ -471,7 +472,7 @@ bool ProcessDeferred(
|
|||
const char* customPreamble,
|
||||
const EShOptimizationLevel optLevel,
|
||||
const TBuiltInResource* resources,
|
||||
int defaultVersion, // use 100 for ES environment, 110 for desktop
|
||||
int defaultVersion, // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan
|
||||
EProfile defaultProfile,
|
||||
// set version/profile to defaultVersion/defaultProfile regardless of the #version
|
||||
// directive in the source code
|
||||
|
|
@ -550,7 +551,7 @@ bool ProcessDeferred(
|
|||
profile = defaultProfile;
|
||||
}
|
||||
|
||||
int spv = (messages & EShMsgSpvRules) ? 100 : 0;
|
||||
int spv = (messages & EShMsgSpvRules) ? 100 : 0; // TODO find path to get real version number here, for now non-0 is what matters
|
||||
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile, spv);
|
||||
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
|
||||
bool warnVersionNotFirst = false;
|
||||
|
|
@ -561,10 +562,13 @@ bool ProcessDeferred(
|
|||
versionWillBeError = true;
|
||||
}
|
||||
|
||||
int vulkan = (messages & EShMsgVulkanRules) ? 100 : 0; // TODO find path to get real version number here, for now non-0 is what matters
|
||||
intermediate.setVersion(version);
|
||||
intermediate.setProfile(profile);
|
||||
intermediate.setSpv(spv);
|
||||
SetupBuiltinSymbolTable(version, profile, spv);
|
||||
if (vulkan)
|
||||
intermediate.setOriginUpperLeft();
|
||||
SetupBuiltinSymbolTable(version, profile, spv, vulkan);
|
||||
|
||||
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
|
||||
[MapProfileToIndex(profile)]
|
||||
|
|
@ -578,13 +582,13 @@ bool ProcessDeferred(
|
|||
|
||||
// Add built-in symbols that are potentially context dependent;
|
||||
// they get popped again further down.
|
||||
AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spv, compiler->getLanguage());
|
||||
AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spv, vulkan, compiler->getLanguage());
|
||||
|
||||
//
|
||||
// Now we can process the full shader under proper symbols and rules.
|
||||
//
|
||||
|
||||
TParseContext parseContext(symbolTable, intermediate, false, version, profile, spv, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
||||
TParseContext parseContext(symbolTable, intermediate, false, version, profile, spv, vulkan, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
||||
glslang::TScanContext scanContext(parseContext);
|
||||
TPpContext ppContext(parseContext, includer);
|
||||
parseContext.setScanContext(&scanContext);
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ void TType::buildMangledName(TString& mangledName)
|
|||
case EsdCube: mangledName += "C"; break;
|
||||
case EsdRect: mangledName += "R2"; break;
|
||||
case EsdBuffer: mangledName += "B"; break;
|
||||
case EsdSubpass: mangledName += "P"; break;
|
||||
default: break; // some compilers want this
|
||||
}
|
||||
if (sampler.ms)
|
||||
|
|
@ -115,7 +116,13 @@ void TType::buildMangledName(TString& mangledName)
|
|||
const int maxSize = 11;
|
||||
char buf[maxSize];
|
||||
for (int i = 0; i < arraySizes->getNumDims(); ++i) {
|
||||
snprintf(buf, maxSize, "%d", arraySizes->getDimSize(i));
|
||||
if (arraySizes->getDimNode(i)) {
|
||||
if (arraySizes->getDimNode(i)->getAsSymbolNode())
|
||||
snprintf(buf, maxSize, "s%d", arraySizes->getDimNode(i)->getAsSymbolNode()->getId());
|
||||
else
|
||||
snprintf(buf, maxSize, "s%x", arraySizes->getDimNode(i));
|
||||
} else
|
||||
snprintf(buf, maxSize, "%d", arraySizes->getDimSize(i));
|
||||
mangledName += '[';
|
||||
mangledName += buf;
|
||||
mangledName += ']';
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ void TParseContext::initializeExtensionBehavior()
|
|||
extensionBehavior[E_GL_ARB_derivative_control] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shader_texture_image_samples] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_viewport_array] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_gl_spirv] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_sparse_texture2] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_sparse_texture_clamp] = EBhDisable;
|
||||
// extensionBehavior[E_GL_ARB_cull_distance] = EBhDisable; // present for 4.5, but need extension control over block members
|
||||
|
|
@ -276,6 +277,7 @@ const char* TParseContext::getPreamble()
|
|||
"#define GL_ARB_derivative_control 1\n"
|
||||
"#define GL_ARB_shader_texture_image_samples 1\n"
|
||||
"#define GL_ARB_viewport_array 1\n"
|
||||
"#define GL_ARB_gl_spirv 1\n"
|
||||
"#define GL_ARB_sparse_texture2 1\n"
|
||||
"#define GL_ARB_sparse_texture_clamp 1\n"
|
||||
|
||||
|
|
@ -564,6 +566,9 @@ void TParseContext::updateExtensionBehavior(int line, const char* extension, con
|
|||
updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
|
||||
else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0)
|
||||
updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString);
|
||||
// SPIR-V
|
||||
else if (strcmp(extension, "GL_ARB_gl_spirv") == 0)
|
||||
spv = 100;
|
||||
}
|
||||
|
||||
void TParseContext::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
|
||||
|
|
@ -606,18 +611,14 @@ void TParseContext::updateExtensionBehavior(const char* extension, TExtensionBeh
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Call for any operation needing full GLSL integer data-type support.
|
||||
//
|
||||
void TParseContext::fullIntegerCheck(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
profileRequires(loc, ENoProfile, 130, nullptr, op);
|
||||
profileRequires(loc, EEsProfile, 300, nullptr, op);
|
||||
}
|
||||
|
||||
//
|
||||
// Call for any operation needing GLSL double data-type support.
|
||||
//
|
||||
void TParseContext::doubleCheck(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
|
||||
|
|
@ -625,4 +626,32 @@ void TParseContext::doubleCheck(const TSourceLoc& loc, const char* op)
|
|||
profileRequires(loc, ECompatibilityProfile, 400, nullptr, op);
|
||||
}
|
||||
|
||||
// Call for any operation removed because SPIR-V is in use.
|
||||
void TParseContext::spvRemoved(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
if (spv > 0)
|
||||
error(loc, "not allowed when generating SPIR-V", op, "");
|
||||
}
|
||||
|
||||
// Call for any operation removed because Vulkan SPIR-V is being generated.
|
||||
void TParseContext::vulkanRemoved(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
if (vulkan > 0)
|
||||
error(loc, "not allowed when using GLSL for Vulkan", op, "");
|
||||
}
|
||||
|
||||
// Call for any operation that requires Vulkan.
|
||||
void TParseContext::requireVulkan(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
if (vulkan == 0)
|
||||
error(loc, "only allowed when using GLSL for Vulkan", op, "");
|
||||
}
|
||||
|
||||
// Call for any operation that requires SPIR-V.
|
||||
void TParseContext::requireSpv(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
if (spv == 0)
|
||||
error(loc, "only allowed when generating SPIR-V", op, "");
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ const char* const E_GL_ARB_shader_draw_parameters = "GL_ARB_shader_draw_pa
|
|||
const char* const E_GL_ARB_derivative_control = "GL_ARB_derivative_control";
|
||||
const char* const E_GL_ARB_shader_texture_image_samples = "GL_ARB_shader_texture_image_samples";
|
||||
const char* const E_GL_ARB_viewport_array = "GL_ARB_viewport_array";
|
||||
const char* const E_GL_ARB_gl_spirv = "GL_ARB_gl_spirv";
|
||||
const char* const E_GL_ARB_sparse_texture2 = "GL_ARB_sparse_texture2";
|
||||
const char* const E_GL_ARB_sparse_texture_clamp = "GL_ARB_sparse_texture_clamp";
|
||||
//const char* const E_GL_ARB_cull_distance = "GL_ARB_cull_distance"; // present for 4.5, but need extension control over block members
|
||||
|
|
|
|||
|
|
@ -148,6 +148,24 @@ extern int yylex(YYSTYPE*, TParseContext&);
|
|||
%token <lex> SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
|
||||
%token <lex> SAMPLEREXTERNALOES
|
||||
|
||||
// pure sampler
|
||||
%token <lex> SAMPLER SAMPLERSHADOW
|
||||
|
||||
// texture without sampler
|
||||
%token <lex> TEXTURE1D TEXTURE2D TEXTURE3D TEXTURECUBE
|
||||
%token <lex> TEXTURE1DARRAY TEXTURE2DARRAY
|
||||
%token <lex> ITEXTURE1D ITEXTURE2D ITEXTURE3D ITEXTURECUBE
|
||||
%token <lex> ITEXTURE1DARRAY ITEXTURE2DARRAY UTEXTURE1D UTEXTURE2D UTEXTURE3D
|
||||
%token <lex> UTEXTURECUBE UTEXTURE1DARRAY UTEXTURE2DARRAY
|
||||
%token <lex> TEXTURE2DRECT ITEXTURE2DRECT UTEXTURE2DRECT
|
||||
%token <lex> TEXTUREBUFFER ITEXTUREBUFFER UTEXTUREBUFFER
|
||||
%token <lex> TEXTURECUBEARRAY ITEXTURECUBEARRAY UTEXTURECUBEARRAY
|
||||
%token <lex> TEXTURE2DMS ITEXTURE2DMS UTEXTURE2DMS
|
||||
%token <lex> TEXTURE2DMSARRAY ITEXTURE2DMSARRAY UTEXTURE2DMSARRAY
|
||||
|
||||
// input attachments
|
||||
%token <lex> SUBPASSINPUT SUBPASSINPUTMS ISUBPASSINPUT ISUBPASSINPUTMS USUBPASSINPUT USUBPASSINPUTMS
|
||||
|
||||
%token <lex> IMAGE1D IIMAGE1D UIMAGE1D IMAGE2D IIMAGE2D
|
||||
%token <lex> UIMAGE2D IMAGE3D IIMAGE3D UIMAGE3D
|
||||
%token <lex> IMAGE2DRECT IIMAGE2DRECT UIMAGE2DRECT
|
||||
|
|
@ -503,6 +521,7 @@ equality_expression
|
|||
| equality_expression EQ_OP relational_expression {
|
||||
parseContext.arrayObjectCheck($2.loc, $1->getType(), "array comparison");
|
||||
parseContext.opaqueCheck($2.loc, $1->getType(), "==");
|
||||
parseContext.specializationCheck($2.loc, $1->getType(), "==");
|
||||
$$ = parseContext.handleBinaryMath($2.loc, "==", EOpEqual, $1, $3);
|
||||
if ($$ == 0)
|
||||
$$ = parseContext.intermediate.addConstantUnion(false, $2.loc);
|
||||
|
|
@ -510,6 +529,7 @@ equality_expression
|
|||
| equality_expression NE_OP relational_expression {
|
||||
parseContext.arrayObjectCheck($2.loc, $1->getType(), "array comparison");
|
||||
parseContext.opaqueCheck($2.loc, $1->getType(), "!=");
|
||||
parseContext.specializationCheck($2.loc, $1->getType(), "!=");
|
||||
$$ = parseContext.handleBinaryMath($2.loc, "!=", EOpNotEqual, $1, $3);
|
||||
if ($$ == 0)
|
||||
$$ = parseContext.intermediate.addConstantUnion(false, $2.loc);
|
||||
|
|
@ -597,6 +617,7 @@ assignment_expression
|
|||
| unary_expression assignment_operator assignment_expression {
|
||||
parseContext.arrayObjectCheck($2.loc, $1->getType(), "array assignment");
|
||||
parseContext.opaqueCheck($2.loc, $1->getType(), "=");
|
||||
parseContext.specializationCheck($2.loc, $1->getType(), "=");
|
||||
parseContext.lValueErrorCheck($2.loc, "assign", $1);
|
||||
parseContext.rValueErrorCheck($2.loc, "assign", $3);
|
||||
$$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.loc);
|
||||
|
|
@ -1201,11 +1222,13 @@ storage_qualifier
|
|||
$$.qualifier.writeonly = true;
|
||||
}
|
||||
| SUBROUTINE {
|
||||
parseContext.spvRemoved($1.loc, "subroutine");
|
||||
parseContext.globalCheck($1.loc, "subroutine");
|
||||
$$.init($1.loc);
|
||||
$$.qualifier.storage = EvqUniform;
|
||||
}
|
||||
| SUBROUTINE LEFT_PAREN type_name_list RIGHT_PAREN {
|
||||
parseContext.spvRemoved($1.loc, "subroutine");
|
||||
parseContext.globalCheck($1.loc, "subroutine");
|
||||
$$.init($1.loc);
|
||||
$$.qualifier.storage = EvqUniform;
|
||||
|
|
@ -1242,11 +1265,11 @@ array_specifier
|
|||
$$.arraySizes = new TArraySizes;
|
||||
$$.arraySizes->addInnerSize();
|
||||
}
|
||||
| LEFT_BRACKET constant_expression RIGHT_BRACKET {
|
||||
| LEFT_BRACKET conditional_expression RIGHT_BRACKET {
|
||||
$$.loc = $1.loc;
|
||||
$$.arraySizes = new TArraySizes;
|
||||
|
||||
int size;
|
||||
TArraySize size;
|
||||
parseContext.arraySizeCheck($2->getLoc(), $2, size);
|
||||
$$.arraySizes->addInnerSize(size);
|
||||
}
|
||||
|
|
@ -1254,10 +1277,10 @@ array_specifier
|
|||
$$ = $1;
|
||||
$$.arraySizes->addInnerSize();
|
||||
}
|
||||
| array_specifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
|
||||
| array_specifier LEFT_BRACKET conditional_expression RIGHT_BRACKET {
|
||||
$$ = $1;
|
||||
|
||||
int size;
|
||||
TArraySize size;
|
||||
parseContext.arraySizeCheck($3->getLoc(), $3, size);
|
||||
$$.arraySizes->addInnerSize(size);
|
||||
}
|
||||
|
|
@ -1504,6 +1527,7 @@ type_specifier_nonarray
|
|||
$$.setMatrix(4, 4);
|
||||
}
|
||||
| ATOMIC_UINT {
|
||||
parseContext.vulkanRemoved($1.loc, "atomic counter types");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtAtomicUint;
|
||||
}
|
||||
|
|
@ -1707,6 +1731,181 @@ type_specifier_nonarray
|
|||
$$.basicType = EbtSampler;
|
||||
$$.sampler.set(EbtUint, Esd2D, true, false, true);
|
||||
}
|
||||
| SAMPLER {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setPureSampler(false);
|
||||
}
|
||||
| SAMPLERSHADOW {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setPureSampler(true);
|
||||
}
|
||||
| TEXTURE1D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, Esd1D);
|
||||
}
|
||||
| TEXTURE2D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, Esd2D);
|
||||
}
|
||||
| TEXTURE3D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, Esd3D);
|
||||
}
|
||||
| TEXTURECUBE {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, EsdCube);
|
||||
}
|
||||
| TEXTURE1DARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, Esd1D, true);
|
||||
}
|
||||
| TEXTURE2DARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, Esd2D, true);
|
||||
}
|
||||
| TEXTURECUBEARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, EsdCube, true);
|
||||
}
|
||||
| ITEXTURE1D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, Esd1D);
|
||||
}
|
||||
| ITEXTURE2D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, Esd2D);
|
||||
}
|
||||
| ITEXTURE3D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, Esd3D);
|
||||
}
|
||||
| ITEXTURECUBE {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, EsdCube);
|
||||
}
|
||||
| ITEXTURE1DARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, Esd1D, true);
|
||||
}
|
||||
| ITEXTURE2DARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, Esd2D, true);
|
||||
}
|
||||
| ITEXTURECUBEARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, EsdCube, true);
|
||||
}
|
||||
| UTEXTURE1D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, Esd1D);
|
||||
}
|
||||
| UTEXTURE2D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, Esd2D);
|
||||
}
|
||||
| UTEXTURE3D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, Esd3D);
|
||||
}
|
||||
| UTEXTURECUBE {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, EsdCube);
|
||||
}
|
||||
| UTEXTURE1DARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, Esd1D, true);
|
||||
}
|
||||
| UTEXTURE2DARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, Esd2D, true);
|
||||
}
|
||||
| UTEXTURECUBEARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, EsdCube, true);
|
||||
}
|
||||
| TEXTURE2DRECT {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, EsdRect);
|
||||
}
|
||||
| ITEXTURE2DRECT {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, EsdRect);
|
||||
}
|
||||
| UTEXTURE2DRECT {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, EsdRect);
|
||||
}
|
||||
| TEXTUREBUFFER {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, EsdBuffer);
|
||||
}
|
||||
| ITEXTUREBUFFER {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, EsdBuffer);
|
||||
}
|
||||
| UTEXTUREBUFFER {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, EsdBuffer);
|
||||
}
|
||||
| TEXTURE2DMS {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, Esd2D, false, false, true);
|
||||
}
|
||||
| ITEXTURE2DMS {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, Esd2D, false, false, true);
|
||||
}
|
||||
| UTEXTURE2DMS {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, Esd2D, false, false, true);
|
||||
}
|
||||
| TEXTURE2DMSARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtFloat, Esd2D, true, false, true);
|
||||
}
|
||||
| ITEXTURE2DMSARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtInt, Esd2D, true, false, true);
|
||||
}
|
||||
| UTEXTURE2DMSARRAY {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setTexture(EbtUint, Esd2D, true, false, true);
|
||||
}
|
||||
| IMAGE1D {
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
|
|
@ -1878,6 +2077,42 @@ type_specifier_nonarray
|
|||
$$.sampler.set(EbtFloat, Esd2D);
|
||||
$$.sampler.external = true;
|
||||
}
|
||||
| SUBPASSINPUT {
|
||||
parseContext.requireStage($1.loc, EShLangFragment, "subpass input");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setSubpass(EbtFloat);
|
||||
}
|
||||
| SUBPASSINPUTMS {
|
||||
parseContext.requireStage($1.loc, EShLangFragment, "subpass input");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setSubpass(EbtFloat, true);
|
||||
}
|
||||
| ISUBPASSINPUT {
|
||||
parseContext.requireStage($1.loc, EShLangFragment, "subpass input");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setSubpass(EbtInt);
|
||||
}
|
||||
| ISUBPASSINPUTMS {
|
||||
parseContext.requireStage($1.loc, EShLangFragment, "subpass input");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setSubpass(EbtInt, true);
|
||||
}
|
||||
| USUBPASSINPUT {
|
||||
parseContext.requireStage($1.loc, EShLangFragment, "subpass input");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setSubpass(EbtUint);
|
||||
}
|
||||
| USUBPASSINPUTMS {
|
||||
parseContext.requireStage($1.loc, EShLangFragment, "subpass input");
|
||||
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
|
||||
$$.basicType = EbtSampler;
|
||||
$$.sampler.setSubpass(EbtUint, true);
|
||||
}
|
||||
| struct_specifier {
|
||||
$$ = $1;
|
||||
$$.qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
|
||||
|
|
|
|||
|
|
@ -385,6 +385,7 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
|
|||
case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break;
|
||||
case EOpConstructDMat4x4: out.debug << "Construct dmat4"; break;
|
||||
case EOpConstructStruct: out.debug << "Construct structure"; break;
|
||||
case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
|
||||
|
||||
case EOpLessThan: out.debug << "Compare Less Than"; break;
|
||||
case EOpGreaterThan: out.debug << "Compare Greater Than"; break;
|
||||
|
|
@ -755,6 +756,20 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
|
|||
|
||||
case EShLangCompute:
|
||||
infoSink.debug << "local_size = (" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] << ")\n";
|
||||
{
|
||||
bool dumpSpecIds = false;
|
||||
for (auto c : localSizeSpecId) {
|
||||
if (c != TQualifier::layoutNotSet)
|
||||
dumpSpecIds = true;
|
||||
}
|
||||
|
||||
if (dumpSpecIds) {
|
||||
infoSink.debug << "local_size ids = (" <<
|
||||
localSizeSpecId[0] << ", " <<
|
||||
localSizeSpecId[1] << ", " <<
|
||||
localSizeSpecId[2] << ")\n";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
|
|||
{
|
||||
numMains += unit.numMains;
|
||||
numErrors += unit.numErrors;
|
||||
numPushConstants += unit.numPushConstants;
|
||||
callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end());
|
||||
|
||||
if ((profile != EEsProfile && unit.profile == EEsProfile) ||
|
||||
|
|
@ -129,6 +130,11 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
|
|||
localSize[i] = unit.localSize[i];
|
||||
else if (localSize[i] != unit.localSize[i])
|
||||
error(infoSink, "Contradictory local size");
|
||||
|
||||
if (localSizeSpecId[i] != TQualifier::layoutNotSet)
|
||||
localSizeSpecId[i] = unit.localSizeSpecId[i];
|
||||
else if (localSizeSpecId[i] != unit.localSizeSpecId[i])
|
||||
error(infoSink, "Contradictory local size specialization ids");
|
||||
}
|
||||
|
||||
if (unit.xfbMode)
|
||||
|
|
@ -353,6 +359,9 @@ void TIntermediate::finalCheck(TInfoSink& infoSink)
|
|||
if (numMains < 1)
|
||||
error(infoSink, "Missing entry point: Each stage requires one \"void main()\" entry point");
|
||||
|
||||
if (numPushConstants > 1)
|
||||
error(infoSink, "Only one push_constant block is allowed per stage");
|
||||
|
||||
// recursion checking
|
||||
checkCallGraphCycles(infoSink);
|
||||
|
||||
|
|
@ -690,6 +699,19 @@ int TIntermediate::addUsedOffsets(int binding, int offset, int numOffsets)
|
|||
return -1; // no collision
|
||||
}
|
||||
|
||||
// Accumulate used constant_id values.
|
||||
//
|
||||
// Return false is one was already used.
|
||||
bool TIntermediate::addUsedConstantId(int id)
|
||||
{
|
||||
if (usedConstantId.find(id) != usedConstantId.end())
|
||||
return false;
|
||||
|
||||
usedConstantId.insert(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Recursively figure out how many locations are used up by an input or output type.
|
||||
// Return the size of type, as measured by "locations".
|
||||
int TIntermediate::computeTypeLocationSize(const TType& type) const
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ struct TIoRange {
|
|||
int index;
|
||||
};
|
||||
|
||||
// An IO range is a 2-D rectangle; the set of (binding, offset) pairs all lying
|
||||
// An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying
|
||||
// within the same binding and offset range.
|
||||
struct TOffsetRange {
|
||||
TOffsetRange(TRange binding, TRange offset)
|
||||
|
|
@ -125,7 +125,7 @@ class TVariable;
|
|||
class TIntermediate {
|
||||
public:
|
||||
explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : language(l), treeRoot(0), profile(p), version(v), spv(0),
|
||||
numMains(0), numErrors(0), recursive(false),
|
||||
numMains(0), numErrors(0), numPushConstants(0), recursive(false),
|
||||
invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone),
|
||||
pixelCenterInteger(false), originUpperLeft(false),
|
||||
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), depthReplacing(false), blendEquations(0), xfbMode(false)
|
||||
|
|
@ -133,6 +133,9 @@ public:
|
|||
localSize[0] = 1;
|
||||
localSize[1] = 1;
|
||||
localSize[2] = 1;
|
||||
localSizeSpecId[0] = TQualifier::layoutNotSet;
|
||||
localSizeSpecId[1] = TQualifier::layoutNotSet;
|
||||
localSizeSpecId[2] = TQualifier::layoutNotSet;
|
||||
xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
|
||||
}
|
||||
void setLimits(const TBuiltInResource& r) { resources = r; }
|
||||
|
|
@ -156,8 +159,10 @@ public:
|
|||
void addMainCount() { ++numMains; }
|
||||
int getNumMains() const { return numMains; }
|
||||
int getNumErrors() const { return numErrors; }
|
||||
void addPushConstantCount() { ++numPushConstants; }
|
||||
bool isRecursive() const { return recursive; }
|
||||
|
||||
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, const TSourceLoc&);
|
||||
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TSourceLoc&);
|
||||
TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
|
||||
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
|
||||
|
|
@ -255,6 +260,15 @@ public:
|
|||
}
|
||||
unsigned int getLocalSize(int dim) const { return localSize[dim]; }
|
||||
|
||||
bool setLocalSizeSpecId(int dim, int id)
|
||||
{
|
||||
if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
|
||||
return id == localSizeSpecId[dim];
|
||||
localSizeSpecId[dim] = id;
|
||||
return true;
|
||||
}
|
||||
unsigned int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
|
||||
|
||||
void setXfbMode() { xfbMode = true; }
|
||||
bool getXfbMode() const { return xfbMode; }
|
||||
bool setOutputPrimitive(TLayoutGeometry p)
|
||||
|
|
@ -294,6 +308,7 @@ public:
|
|||
|
||||
int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
|
||||
int addUsedOffsets(int binding, int offset, int numOffsets);
|
||||
bool addUsedConstantId(int id);
|
||||
int computeTypeLocationSize(const TType&) const;
|
||||
|
||||
bool setXfbBufferStride(int buffer, unsigned stride)
|
||||
|
|
@ -328,6 +343,7 @@ protected:
|
|||
TBuiltInResource resources;
|
||||
int numMains;
|
||||
int numErrors;
|
||||
int numPushConstants;
|
||||
bool recursive;
|
||||
int invocations;
|
||||
int vertices;
|
||||
|
|
@ -339,6 +355,7 @@ protected:
|
|||
TVertexOrder vertexOrder;
|
||||
bool pointMode;
|
||||
int localSize[3];
|
||||
int localSizeSpecId[3];
|
||||
bool earlyFragmentTests;
|
||||
TLayoutDepth depthLayout;
|
||||
bool depthReplacing;
|
||||
|
|
@ -352,6 +369,7 @@ protected:
|
|||
std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers
|
||||
std::vector<TOffsetRange> usedAtomics; // sets of bindings used by atomic counters
|
||||
std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer
|
||||
std::unordered_set<int> usedConstantId; // specialization constant ids used
|
||||
|
||||
private:
|
||||
void operator=(TIntermediate&); // prevent assignments
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ public:
|
|||
// Returns an error message for any #include directive.
|
||||
class ForbidInclude : public Includer {
|
||||
public:
|
||||
std::pair<std::string, std::string> include(const char* filename) const override
|
||||
std::pair<std::string, std::string> include(const char* /*filename*/) const override
|
||||
{
|
||||
return std::make_pair<std::string, std::string>("", "unexpected include directive");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue