
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@23874 e7fa87d3-cd2b-0410-9028-fcbf551c1848
922 lines
29 KiB
C++
922 lines
29 KiB
C++
//
|
|
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
|
//Copyright (C) 2012-2013 LunarG, Inc.
|
|
//
|
|
//All rights reserved.
|
|
//
|
|
//Redistribution and use in source and binary forms, with or without
|
|
//modification, are permitted provided that the following conditions
|
|
//are met:
|
|
//
|
|
// Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following
|
|
// disclaimer in the documentation and/or other materials provided
|
|
// with the distribution.
|
|
//
|
|
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
|
// contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
//POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
|
|
#ifndef _TYPES_INCLUDED
|
|
#define _TYPES_INCLUDED
|
|
|
|
#include "../Include/Common.h"
|
|
#include "../Include/BaseTypes.h"
|
|
|
|
namespace glslang {
|
|
|
|
const int GlslangMaxTypeLength = 200;
|
|
|
|
//
|
|
// Details within a sampler type
|
|
//
|
|
enum TSamplerDim {
|
|
EsdNone,
|
|
Esd1D,
|
|
Esd2D,
|
|
Esd3D,
|
|
EsdCube,
|
|
EsdRect,
|
|
EsdBuffer,
|
|
EsdNumDims
|
|
};
|
|
|
|
struct TSampler {
|
|
TBasicType type : 8; // type returned by sampler
|
|
TSamplerDim dim : 8;
|
|
bool arrayed : 1;
|
|
bool shadow : 1;
|
|
bool ms : 1;
|
|
bool image : 1;
|
|
|
|
void clear()
|
|
{
|
|
type = EbtVoid;
|
|
dim = EsdNone;
|
|
arrayed = false;
|
|
shadow = false;
|
|
ms = false;
|
|
image = false;
|
|
}
|
|
|
|
void set(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
|
|
{
|
|
type = t;
|
|
dim = d;
|
|
arrayed = a;
|
|
shadow = s;
|
|
ms = m;
|
|
image = false;
|
|
}
|
|
|
|
void setImage(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
|
|
{
|
|
type = t;
|
|
dim = d;
|
|
arrayed = a;
|
|
shadow = s;
|
|
ms = m;
|
|
image = true;
|
|
}
|
|
|
|
bool operator==(const TSampler& right) const
|
|
{
|
|
return type == right.type &&
|
|
dim == right.dim &&
|
|
arrayed == right.arrayed &&
|
|
shadow == right.shadow &&
|
|
ms == right.ms &&
|
|
image == right.image;
|
|
}
|
|
|
|
TString getString() const
|
|
{
|
|
TString s;
|
|
|
|
switch (type) {
|
|
case EbtFloat: break;
|
|
case EbtInt: s.append("i"); break;
|
|
case EbtUint: s.append("u"); break;
|
|
default: break; // some compilers want this
|
|
}
|
|
if (image)
|
|
s.append("image");
|
|
else
|
|
s.append("sampler");
|
|
switch (dim) {
|
|
case Esd1D: s.append("1D"); break;
|
|
case Esd2D: s.append("2D"); break;
|
|
case Esd3D: s.append("3D"); break;
|
|
case EsdCube: s.append("Cube"); break;
|
|
case EsdRect: s.append("2DRect"); break;
|
|
case EsdBuffer: s.append("Buffer"); break;
|
|
default: break; // some compilers want this
|
|
}
|
|
if (ms)
|
|
s.append("MS");
|
|
if (arrayed)
|
|
s.append("Array");
|
|
if (shadow)
|
|
s.append("Shadow");
|
|
|
|
return s;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Need to have association of line numbers to types in a list for building structs.
|
|
//
|
|
class TType;
|
|
struct TTypeLoc {
|
|
TType* type;
|
|
TSourceLoc loc;
|
|
};
|
|
typedef TVector<TTypeLoc> TTypeList;
|
|
|
|
typedef TVector<TString*> TIdentifierList;
|
|
|
|
//
|
|
// TODO: memory: TArraySizes can be replaced by something smaller.
|
|
// Almost all arrays could be handled by two sizes each fitting
|
|
// in 16 bits, needing a real vector only in the cases where there
|
|
// are more than 3 sizes or a size needing more than 16 bits.
|
|
//
|
|
// The type is a pointer, so that it can be non-allocated and zero
|
|
// for the vast majority of non-array types. Note that means if it
|
|
// is used, it will be containing at least one size.
|
|
|
|
struct TArraySizes {
|
|
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
|
|
|
TArraySizes() : maxArraySize(0) { }
|
|
int getSize() { return sizes.front(); } // TArraySizes only exists if there is at least one dimension
|
|
void setSize(int s) { sizes.push_back(s); }
|
|
bool isArrayOfArrays() { return sizes.size() > 1; }
|
|
protected:
|
|
TVector<int> sizes;
|
|
friend class TType;
|
|
int maxArraySize; // for tracking maximum referenced index, before an explicit size is given
|
|
};
|
|
|
|
//
|
|
// Following are a series of helper enums for managing layouts and qualifiers,
|
|
// used for TPublicType, TType, others.
|
|
//
|
|
|
|
enum TLayoutPacking {
|
|
ElpNone,
|
|
ElpShared, // default, but different than saying nothing
|
|
ElpStd140,
|
|
ElpStd430,
|
|
ElpPacked
|
|
// If expanding, see bitfield width below
|
|
};
|
|
|
|
enum TLayoutMatrix {
|
|
ElmNone,
|
|
ElmRowMajor,
|
|
ElmColumnMajor // default, but different than saying nothing
|
|
// If expanding, see bitfield width below
|
|
};
|
|
|
|
// Union of geometry shader and tessellation shader geometry types.
|
|
// They don't go into TType, but rather have current state per shader or
|
|
// active parser type (TPublicType).
|
|
enum TLayoutGeometry {
|
|
ElgNone,
|
|
ElgPoints,
|
|
ElgLines,
|
|
ElgLinesAdjacency,
|
|
ElgLineStrip,
|
|
ElgTriangles,
|
|
ElgTrianglesAdjacency,
|
|
ElgTriangleStrip,
|
|
ElgQuads,
|
|
ElgIsolines,
|
|
};
|
|
|
|
class TQualifier {
|
|
public:
|
|
void clear()
|
|
{
|
|
storage = EvqTemporary;
|
|
precision = EpqNone;
|
|
invariant = false;
|
|
centroid = false;
|
|
smooth = false;
|
|
flat = false;
|
|
nopersp = false;
|
|
patch = false;
|
|
sample = false;
|
|
shared = false;
|
|
coherent = false;
|
|
volatil = false;
|
|
restrict = false;
|
|
readonly = false;
|
|
writeonly = false;
|
|
clearLayout();
|
|
}
|
|
TStorageQualifier storage : 6;
|
|
TPrecisionQualifier precision : 3;
|
|
bool invariant : 1;
|
|
bool centroid : 1;
|
|
bool smooth : 1;
|
|
bool flat : 1;
|
|
bool nopersp : 1;
|
|
bool patch : 1;
|
|
bool sample : 1;
|
|
bool shared : 1;
|
|
bool coherent : 1;
|
|
bool volatil : 1;
|
|
bool restrict : 1;
|
|
bool readonly : 1;
|
|
bool writeonly : 1;
|
|
|
|
bool isMemory() const
|
|
{
|
|
return shared || coherent || volatil || restrict || readonly || writeonly;
|
|
}
|
|
bool isInterpolation() const
|
|
{
|
|
return flat || smooth || nopersp;
|
|
}
|
|
bool isAuxiliary() const
|
|
{
|
|
return centroid || patch || sample;
|
|
}
|
|
|
|
bool isPipeInput() const
|
|
{
|
|
switch (storage) {
|
|
case EvqVaryingIn:
|
|
case EvqFragCoord:
|
|
case EvqPointCoord:
|
|
case EvqFace:
|
|
case EvqVertexId:
|
|
case EvqInstanceId:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isPipeOutput() const
|
|
{
|
|
switch (storage) {
|
|
case EvqPosition:
|
|
case EvqPointSize:
|
|
case EvqClipVertex:
|
|
case EvqVaryingOut:
|
|
case EvqFragColor:
|
|
case EvqFragDepth:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isUniform() const
|
|
{
|
|
switch (storage) {
|
|
case EvqUniform:
|
|
case EvqBuffer:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Implementing an embedded layout-qualifier class here, since C++ can't have a real class bitfield
|
|
void clearLayout()
|
|
{
|
|
layoutMatrix = ElmNone;
|
|
layoutPacking = ElpNone;
|
|
layoutSlotLocation = layoutLocationEnd;
|
|
layoutBinding = layoutBindingEnd;
|
|
layoutStream = layoutStreamEnd;
|
|
}
|
|
bool hasLayout() const
|
|
{
|
|
return layoutMatrix != ElmNone ||
|
|
layoutPacking != ElpNone ||
|
|
hasLocation() ||
|
|
hasBinding() ||
|
|
hasStream();
|
|
}
|
|
TLayoutMatrix layoutMatrix : 3;
|
|
TLayoutPacking layoutPacking : 4;
|
|
unsigned int layoutSlotLocation : 7; // ins/outs should have small numbers, buffer offsets could be large
|
|
static const unsigned int layoutLocationEnd = 0x3F;
|
|
unsigned int layoutBinding : 8;
|
|
static const unsigned int layoutBindingEnd = 0xFF;
|
|
unsigned int layoutStream : 8;
|
|
static const unsigned int layoutStreamEnd = 0xFF;
|
|
bool hasLocation() const
|
|
{
|
|
return layoutSlotLocation != layoutLocationEnd;
|
|
}
|
|
bool hasBinding() const
|
|
{
|
|
return layoutBinding != layoutBindingEnd;
|
|
}
|
|
bool hasStream() const
|
|
{
|
|
return layoutStream != layoutStreamEnd;
|
|
}
|
|
static const char* getLayoutPackingString(TLayoutPacking packing)
|
|
{
|
|
switch (packing) {
|
|
case ElpPacked: return "packed";
|
|
case ElpShared: return "shared";
|
|
case ElpStd140: return "std140";
|
|
case ElpStd430: return "std430";
|
|
default: return "none";
|
|
}
|
|
}
|
|
static const char* getLayoutMatrixString(TLayoutMatrix m)
|
|
{
|
|
switch (m) {
|
|
case ElmColumnMajor: return "column_major";
|
|
case ElmRowMajor: return "row_major";
|
|
default: return "none";
|
|
}
|
|
}
|
|
static const char* getGeometryString(TLayoutGeometry geometry)
|
|
{
|
|
switch (geometry) {
|
|
case ElgPoints: return "points";
|
|
case ElgLines: return "lines";
|
|
case ElgLinesAdjacency: return "lines_adjancency";
|
|
case ElgLineStrip: return "line_strip";
|
|
case ElgTriangles: return "triangles";
|
|
case ElgTrianglesAdjacency: return "triangles_adjacency";
|
|
case ElgTriangleStrip: return "triangle_strip";
|
|
case ElgQuads: return "quads";
|
|
case ElgIsolines: return "isolines";
|
|
default: return "none";
|
|
}
|
|
}
|
|
static int mapGeometryToSize(TLayoutGeometry geometry)
|
|
{
|
|
switch (geometry) {
|
|
case ElgPoints: return 1;
|
|
case ElgLines: return 2;
|
|
case ElgLinesAdjacency: return 4;
|
|
case ElgTriangles: return 3;
|
|
case ElgTrianglesAdjacency: return 6;
|
|
default: return 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Qualifiers that don't need to be keep per object. They have shader scope, not object scope.
|
|
// So, they will not be part of TType, TQualifier, etc.
|
|
struct TShaderQualifiers {
|
|
TLayoutGeometry geometry; // geometry shader in/out primitives
|
|
bool pixelCenterInteger; // fragment shader
|
|
bool originUpperLeft; // fragment shader
|
|
int invocations; // 0 means no declaration
|
|
int maxVertices;
|
|
|
|
void init()
|
|
{
|
|
geometry = ElgNone;
|
|
originUpperLeft = false;
|
|
pixelCenterInteger = false;
|
|
invocations = 0; // 0 means no declaration
|
|
maxVertices = 0;
|
|
}
|
|
};
|
|
|
|
//
|
|
// TPublicType is just temporarily used while parsing and not quite the same
|
|
// information kept per node in TType. Due to the bison stack, it can't have
|
|
// types that it thinks have non-trivial constructors. It should
|
|
// just be used while recognizing the grammar, not anything else.
|
|
// Once enough is known about the situation, the proper information
|
|
// moved into a TType, or the parse context, etc.
|
|
//
|
|
class TPublicType {
|
|
public:
|
|
TBasicType basicType;
|
|
TSampler sampler;
|
|
TQualifier qualifier;
|
|
TShaderQualifiers shaderQualifiers;
|
|
int vectorSize : 4;
|
|
int matrixCols : 4;
|
|
int matrixRows : 4;
|
|
TArraySizes* arraySizes;
|
|
const TType* userDef;
|
|
TSourceLoc loc;
|
|
|
|
void initType(TSourceLoc l)
|
|
{
|
|
basicType = EbtVoid;
|
|
vectorSize = 1;
|
|
matrixRows = 0;
|
|
matrixCols = 0;
|
|
arraySizes = 0;
|
|
userDef = 0;
|
|
loc = l;
|
|
}
|
|
|
|
void initQualifiers(bool global = false)
|
|
{
|
|
qualifier.clear();
|
|
if (global)
|
|
qualifier.storage = EvqGlobal;
|
|
}
|
|
|
|
void init(TSourceLoc loc, bool global = false)
|
|
{
|
|
initType(loc);
|
|
sampler.clear();
|
|
initQualifiers(global);
|
|
shaderQualifiers.init();
|
|
}
|
|
|
|
void setVector(int s)
|
|
{
|
|
matrixRows = 0;
|
|
matrixCols = 0;
|
|
vectorSize = s;
|
|
}
|
|
|
|
void setMatrix(int c, int r)
|
|
{
|
|
matrixRows = r;
|
|
matrixCols = c;
|
|
vectorSize = 0;
|
|
}
|
|
|
|
bool isScalar()
|
|
{
|
|
return matrixCols == 0 && vectorSize == 1 && arraySizes == 0 && userDef == 0;
|
|
}
|
|
};
|
|
|
|
typedef std::map<TTypeList*, TTypeList*> TStructureMap;
|
|
typedef std::map<TTypeList*, TTypeList*>::const_iterator TStructureMapIterator;
|
|
|
|
//
|
|
// Base class for things that have a type.
|
|
//
|
|
class TType {
|
|
public:
|
|
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
|
explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) :
|
|
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
|
|
structure(0), structureSize(0), fieldName(0), typeName(0)
|
|
{
|
|
sampler.clear();
|
|
qualifier.clear();
|
|
qualifier.storage = q;
|
|
}
|
|
TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) :
|
|
basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
|
|
structure(0), structureSize(0), fieldName(0), typeName(0)
|
|
{
|
|
sampler.clear();
|
|
qualifier.clear();
|
|
qualifier.storage = q;
|
|
qualifier.precision = p;
|
|
assert(p >= 0 && p <= EpqHigh);
|
|
}
|
|
explicit TType(const TPublicType &p) :
|
|
basicType(p.basicType), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), arraySizes(p.arraySizes),
|
|
structure(0), structureSize(0), fieldName(0), typeName(0)
|
|
{
|
|
if (basicType == EbtSampler)
|
|
sampler = p.sampler;
|
|
else
|
|
sampler.clear();
|
|
qualifier = p.qualifier;
|
|
if (p.userDef) {
|
|
structure = p.userDef->getStruct();
|
|
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
|
|
}
|
|
}
|
|
TType(TTypeList* userDef, const TString& n) :
|
|
basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0),
|
|
arraySizes(0), structure(userDef), fieldName(0)
|
|
{
|
|
sampler.clear();
|
|
qualifier.clear();
|
|
typeName = NewPoolTString(n.c_str());
|
|
}
|
|
// For interface blocks
|
|
TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
|
|
basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0),
|
|
qualifier(q), arraySizes(0), structure(userDef), fieldName(0)
|
|
{
|
|
sampler.clear();
|
|
typeName = NewPoolTString(n.c_str());
|
|
}
|
|
virtual ~TType() {}
|
|
|
|
// Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
|
|
// This only works if that information (like a structure's list of types) does not change and
|
|
// the instances are sharing the same pool.
|
|
void shallowCopy(const TType& copyOf)
|
|
{
|
|
basicType = copyOf.basicType;
|
|
sampler = copyOf.sampler;
|
|
qualifier = copyOf.qualifier;
|
|
vectorSize = copyOf.vectorSize;
|
|
matrixCols = copyOf.matrixCols;
|
|
matrixRows = copyOf.matrixRows;
|
|
arraySizes = copyOf.arraySizes;
|
|
structure = copyOf.structure;
|
|
structureSize = copyOf.structureSize;
|
|
fieldName = copyOf.fieldName;
|
|
typeName = copyOf.typeName;
|
|
}
|
|
|
|
void deepCopy(const TType& copyOf)
|
|
{
|
|
shallowCopy(copyOf);
|
|
|
|
if (arraySizes) {
|
|
arraySizes = new TArraySizes;
|
|
*arraySizes = *copyOf.arraySizes;
|
|
}
|
|
|
|
if (structure) {
|
|
structure = new TTypeList;
|
|
TStructureMapIterator iter;
|
|
for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
|
|
TTypeLoc typeLoc;
|
|
typeLoc.loc = (*copyOf.structure)[i].loc;
|
|
typeLoc.type = new TType();
|
|
typeLoc.type->deepCopy(*(*copyOf.structure)[i].type);
|
|
structure->push_back(typeLoc);
|
|
}
|
|
}
|
|
|
|
if (fieldName)
|
|
fieldName = NewPoolTString(copyOf.fieldName->c_str());
|
|
if (typeName)
|
|
typeName = NewPoolTString(copyOf.typeName->c_str());
|
|
}
|
|
|
|
TType* clone()
|
|
{
|
|
TType *newType = new TType();
|
|
newType->deepCopy(*this);
|
|
|
|
return newType;
|
|
}
|
|
|
|
// Merge type from parent, where a parentType is at the beginning of a declaration,
|
|
// establishing some charastics for all subsequent names, while this type
|
|
// is on the individual names.
|
|
void mergeType(const TPublicType& parentType)
|
|
{
|
|
// arrayness is currently the only child aspect that has to be preserved
|
|
setElementType(parentType.basicType, parentType.vectorSize, parentType.matrixCols, parentType.matrixRows, parentType.userDef);
|
|
qualifier = parentType.qualifier;
|
|
sampler = parentType.sampler;
|
|
if (parentType.arraySizes)
|
|
setArraySizes(parentType.arraySizes);
|
|
if (parentType.userDef)
|
|
setTypeName(parentType.userDef->getTypeName());
|
|
}
|
|
|
|
virtual void dereference()
|
|
{
|
|
if (arraySizes)
|
|
arraySizes = 0;
|
|
else if (matrixCols > 0) {
|
|
vectorSize = matrixRows;
|
|
matrixCols = 0;
|
|
matrixRows = 0;
|
|
} else if (vectorSize > 1)
|
|
vectorSize = 1;
|
|
}
|
|
|
|
virtual void setElementType(TBasicType t, int s, int mc, int mr, const TType* userDef)
|
|
{
|
|
basicType = t;
|
|
vectorSize = s;
|
|
matrixCols = mc;
|
|
matrixRows = mr;
|
|
if (userDef)
|
|
structure = userDef->getStruct();
|
|
// leave array information intact.
|
|
}
|
|
virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); }
|
|
virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); }
|
|
virtual const TString& getTypeName() const
|
|
{
|
|
assert(typeName);
|
|
return *typeName;
|
|
}
|
|
|
|
virtual const TString& getFieldName() const
|
|
{
|
|
assert(fieldName);
|
|
return *fieldName;
|
|
}
|
|
|
|
virtual TBasicType getBasicType() const { return basicType; }
|
|
virtual const TSampler& getSampler() const { return sampler; }
|
|
virtual TQualifier& getQualifier() { return qualifier; }
|
|
virtual const TQualifier& getQualifier() const { return qualifier; }
|
|
|
|
virtual int getVectorSize() const { return vectorSize; }
|
|
virtual int getMatrixCols() const { return matrixCols; }
|
|
virtual int getMatrixRows() const { return matrixRows; }
|
|
|
|
virtual bool isScalar() const { return vectorSize == 1 && ! getStruct() && ! isArray(); }
|
|
virtual bool isVector() const { return vectorSize > 1; }
|
|
virtual bool isMatrix() const { return matrixCols ? true : false; }
|
|
virtual bool isArray() const { return arraySizes != 0; }
|
|
|
|
// Recursively check the structure for any arrays, needed for some error checks
|
|
virtual bool containsArray() const
|
|
{
|
|
if (isArray())
|
|
return true;
|
|
if (! structure)
|
|
return false;
|
|
for (unsigned int i = 0; i < structure->size(); ++i) {
|
|
if ((*structure)[i].type->containsArray())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
int getArraySize() const { return arraySizes->sizes.front(); }
|
|
void shareArraySizes(const TType& type)
|
|
{
|
|
// For when we are sharing existing array descriptors.
|
|
// This allows all references to the same unsized array
|
|
// to be updated at once, by having all of them share the
|
|
// array description.
|
|
*arraySizes = *type.arraySizes;
|
|
}
|
|
void setArraySizes(TArraySizes* s)
|
|
{
|
|
// For when we don't want distinct types sharing the same descriptor.
|
|
arraySizes = new TArraySizes;
|
|
*arraySizes = *s;
|
|
}
|
|
void setArraySizes(const TType& type) { setArraySizes(type.arraySizes); }
|
|
|
|
void changeArraySize(int s) { arraySizes->sizes.front() = s; }
|
|
void setMaxArraySize (int s) { arraySizes->maxArraySize = s; }
|
|
int getMaxArraySize () const { return arraySizes->maxArraySize; }
|
|
const char* getBasicString() const
|
|
{
|
|
return TType::getBasicString(basicType);
|
|
}
|
|
|
|
static const char* getBasicString(TBasicType t)
|
|
{
|
|
switch (t) {
|
|
case EbtVoid: return "void";
|
|
case EbtFloat: return "float";
|
|
case EbtDouble: return "double";
|
|
case EbtInt: return "int";
|
|
case EbtUint: return "uint";
|
|
case EbtBool: return "bool";
|
|
case EbtSampler: return "sampler/image";
|
|
case EbtStruct: return "structure";
|
|
case EbtBlock: return "block";
|
|
default: return "unknown type";
|
|
}
|
|
}
|
|
|
|
TString getCompleteString() const
|
|
{
|
|
const int maxSize = GlslangMaxTypeLength;
|
|
char buf[maxSize];
|
|
char *p = &buf[0];
|
|
char *end = &buf[maxSize];
|
|
|
|
if (qualifier.hasLayout()) {
|
|
p += snprintf(p, end - p, "layout(");
|
|
if (qualifier.hasLocation())
|
|
p += snprintf(p, end - p, "location=%d ", qualifier.layoutSlotLocation);
|
|
if (qualifier.hasBinding())
|
|
p += snprintf(p, end - p, "binding=%d ", qualifier.layoutBinding);
|
|
if (qualifier.hasStream())
|
|
p += snprintf(p, end - p, "stream=%d ", qualifier.layoutStream);
|
|
if (qualifier.layoutMatrix != ElmNone)
|
|
p += snprintf(p, end - p, "%s ", TQualifier::getLayoutMatrixString(qualifier.layoutMatrix));
|
|
if (qualifier.layoutPacking != ElpNone)
|
|
p += snprintf(p, end - p, "%s ", TQualifier::getLayoutPackingString(qualifier.layoutPacking));
|
|
p += snprintf(p, end - p, ") ");
|
|
}
|
|
|
|
if (qualifier.invariant)
|
|
p += snprintf(p, end - p, "invariant ");
|
|
if (qualifier.centroid)
|
|
p += snprintf(p, end - p, "centroid ");
|
|
if (qualifier.smooth)
|
|
p += snprintf(p, end - p, "smooth ");
|
|
if (qualifier.flat)
|
|
p += snprintf(p, end - p, "flat ");
|
|
if (qualifier.nopersp)
|
|
p += snprintf(p, end - p, "noperspective ");
|
|
if (qualifier.patch)
|
|
p += snprintf(p, end - p, "patch ");
|
|
if (qualifier.sample)
|
|
p += snprintf(p, end - p, "sample ");
|
|
if (qualifier.shared)
|
|
p += snprintf(p, end - p, "shared ");
|
|
if (qualifier.coherent)
|
|
p += snprintf(p, end - p, "coherent ");
|
|
if (qualifier.volatil)
|
|
p += snprintf(p, end - p, "volatile ");
|
|
if (qualifier.restrict)
|
|
p += snprintf(p, end - p, "restrict ");
|
|
if (qualifier.readonly)
|
|
p += snprintf(p, end - p, "readonly ");
|
|
if (qualifier.writeonly)
|
|
p += snprintf(p, end - p, "writeonly ");
|
|
if (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal)
|
|
p += snprintf(p, end - p, "%s ", getStorageQualifierString());
|
|
if (arraySizes) {
|
|
if (arraySizes->sizes.front() == 0)
|
|
p += snprintf(p, end - p, "unsized array of ");
|
|
else
|
|
p += snprintf(p, end - p, "%d-element array of ", arraySizes->sizes.front());
|
|
}
|
|
if (qualifier.precision != EpqNone)
|
|
p += snprintf(p, end - p, "%s ", getPrecisionQualifierString());
|
|
if (matrixCols > 0)
|
|
p += snprintf(p, end - p, "%dX%d matrix of ", matrixCols, matrixRows);
|
|
else if (vectorSize > 1)
|
|
p += snprintf(p, end - p, "%d-component vector of ", vectorSize);
|
|
|
|
*p = 0;
|
|
TString s(buf);
|
|
s.append(getCompleteTypeString());
|
|
|
|
// Add struct/block members
|
|
if (structure) {
|
|
s.append("{");
|
|
for (size_t i = 0; i < structure->size(); ++i) {
|
|
s.append((*structure)[i].type->getFieldName());
|
|
if (i < structure->size()-1)
|
|
s.append(",");
|
|
}
|
|
s.append("}");
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
TString getCompleteTypeString() const
|
|
{
|
|
if (basicType == EbtSampler)
|
|
return sampler.getString();
|
|
else
|
|
return getBasicString();
|
|
}
|
|
|
|
const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
|
|
const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
|
|
TTypeList* getStruct() { return structure; }
|
|
TTypeList* getStruct() const { return structure; }
|
|
|
|
int getObjectSize() const
|
|
{
|
|
int totalSize;
|
|
|
|
if (getBasicType() == EbtStruct || getBasicType() == EbtBlock)
|
|
totalSize = getStructSize();
|
|
else if (matrixCols)
|
|
totalSize = matrixCols * matrixRows;
|
|
else
|
|
totalSize = vectorSize;
|
|
|
|
if (isArray()) {
|
|
// this function can only be used in paths that don't allow unsized arrays
|
|
assert(getArraySize() > 0);
|
|
totalSize *= getArraySize();
|
|
}
|
|
|
|
return totalSize;
|
|
}
|
|
|
|
// append this type's mangled name to the passed in 'name'
|
|
void appendMangledName(TString& name)
|
|
{
|
|
buildMangledName(name);
|
|
name += ';' ;
|
|
}
|
|
|
|
// Do two structure types match? They could be declared independently,
|
|
// in different places, but still might satisfy the definition of matching.
|
|
// From the spec:
|
|
//
|
|
// "Structures must have the same name, sequence of type names, and
|
|
// type definitions, and member names to be considered the same type.
|
|
// This rule applies recursively for nested or embedded types."
|
|
//
|
|
bool sameStructType(const TType& right) const
|
|
{
|
|
// Most commonly, they are both 0, or the same pointer to the same actual structure
|
|
if (structure == right.structure)
|
|
return true;
|
|
|
|
// Both being 0 was caught above, now they both have to be structures of the same number of elements
|
|
if (structure == 0 || right.structure == 0 ||
|
|
structure->size() != right.structure->size())
|
|
return false;
|
|
|
|
// Structure names have to match
|
|
if (*typeName != *right.typeName)
|
|
return false;
|
|
|
|
// Compare the names and types of all the members, which have to match
|
|
for (unsigned int i = 0; i < structure->size(); ++i) {
|
|
if ((*structure)[i].type->getFieldName() != (*right.structure)[i].type->getFieldName())
|
|
return false;
|
|
|
|
if (*(*structure)[i].type != *(*right.structure)[i].type)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// See if two types match, in all aspects except arrayness
|
|
bool sameElementType(const TType& right) const
|
|
{
|
|
return basicType == right.basicType && sameElementShape(right);
|
|
}
|
|
|
|
// See if two type's arrayness match
|
|
bool sameArrayness(const TType& right) const
|
|
{
|
|
return ((arraySizes == 0 && right.arraySizes == 0) ||
|
|
(arraySizes && right.arraySizes && arraySizes->sizes == right.arraySizes->sizes));
|
|
}
|
|
|
|
// See if two type's elements match in all ways except basic type
|
|
bool sameElementShape(const TType& right) const
|
|
{
|
|
return sampler == right.sampler &&
|
|
vectorSize == right.vectorSize &&
|
|
matrixCols == right.matrixCols &&
|
|
matrixRows == right.matrixRows &&
|
|
sameStructType(right);
|
|
}
|
|
|
|
// See if two types match in all ways (just the actual type, not qualification)
|
|
bool operator==(const TType& right) const
|
|
{
|
|
return sameElementType(right) && sameArrayness(right);
|
|
}
|
|
|
|
bool operator!=(const TType& right) const
|
|
{
|
|
return ! operator==(right);
|
|
}
|
|
|
|
protected:
|
|
// Require consumer to pick between deep copy and shallow copy.
|
|
TType(const TType& type);
|
|
TType& operator=(const TType& type);
|
|
|
|
void buildMangledName(TString&);
|
|
int getStructSize() const;
|
|
|
|
TBasicType basicType : 8;
|
|
int vectorSize : 4;
|
|
int matrixCols : 4;
|
|
int matrixRows : 4;
|
|
TSampler sampler;
|
|
TQualifier qualifier;
|
|
|
|
TArraySizes* arraySizes;
|
|
|
|
TTypeList* structure; // 0 unless this is a struct
|
|
mutable int structureSize; // a cache, updated on first access
|
|
TString *fieldName; // for structure field names
|
|
TString *typeName; // for structure type name
|
|
};
|
|
|
|
} // end namespace glslang
|
|
|
|
#endif // _TYPES_INCLUDED_
|