Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Johannes van Waveren 2016-10-21 17:21:46 +09:00
commit 2f4c832d47
484 changed files with 101726 additions and 19867 deletions

View file

@ -10,10 +10,12 @@ set(SOURCES
MachineIndependent/glslang.y
MachineIndependent/glslang_tab.cpp
MachineIndependent/Constant.cpp
MachineIndependent/iomapper.cpp
MachineIndependent/InfoSink.cpp
MachineIndependent/Initialize.cpp
MachineIndependent/IntermTraverse.cpp
MachineIndependent/Intermediate.cpp
MachineIndependent/ParseContextBase.cpp
MachineIndependent/ParseHelper.cpp
MachineIndependent/PoolAlloc.cpp
MachineIndependent/RemoveTree.cpp
@ -54,6 +56,8 @@ set(HEADERS
MachineIndependent/glslang_tab.cpp.h
MachineIndependent/gl_types.h
MachineIndependent/Initialize.h
MachineIndependent/iomapper.h
MachineIndependent/LiveTraverser.h
MachineIndependent/localintermediate.h
MachineIndependent/ParseHelper.h
MachineIndependent/reflection.h

View file

@ -46,7 +46,7 @@ class TGenericLinker : public TLinker {
public:
TGenericLinker(EShExecutable e, int dOptions) : TLinker(e, infoSink), debugOptions(dOptions) { }
bool link(TCompilerList&, TUniformMap*) { return true; }
void getAttributeBindings(ShBindingTable const **) const { }
void getAttributeBindings(ShBindingTable const **) const { }
TInfoSink infoSink;
int debugOptions;
};

View file

@ -46,6 +46,9 @@ enum TBasicType {
EbtVoid,
EbtFloat,
EbtDouble,
#ifdef AMD_EXTENSIONS
EbtFloat16,
#endif
EbtInt,
EbtUint,
EbtInt64,
@ -55,6 +58,10 @@ enum TBasicType {
EbtSampler,
EbtStruct,
EbtBlock,
// HLSL types that live only temporarily.
EbtString,
EbtNumTypes
};
@ -186,6 +193,20 @@ enum TBuiltInVariable {
EbvSamplePosition,
EbvSampleMask,
EbvHelperInvocation,
#ifdef AMD_EXTENSIONS
EbvBaryCoordNoPersp,
EbvBaryCoordNoPerspCentroid,
EbvBaryCoordNoPerspSample,
EbvBaryCoordSmooth,
EbvBaryCoordSmoothCentroid,
EbvBaryCoordSmoothSample,
EbvBaryCoordPullModel,
#endif
// HLSL built-ins that live only temporarily, until they get remapped
// to one of the above.
EbvFragDepthGreater,
EbvFragDepthLesser,
EbvLast
};
@ -286,6 +307,15 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v)
case EbvSamplePosition: return "SamplePosition";
case EbvSampleMask: return "SampleMaskIn";
case EbvHelperInvocation: return "HelperInvocation";
#ifdef AMD_EXTENSIONS
case EbvBaryCoordNoPersp: return "BaryCoordNoPersp";
case EbvBaryCoordNoPerspCentroid: return "BaryCoordNoPerspCentroid";
case EbvBaryCoordNoPerspSample: return "BaryCoordNoPerspSample";
case EbvBaryCoordSmooth: return "BaryCoordSmooth";
case EbvBaryCoordSmoothCentroid: return "BaryCoordSmoothCentroid";
case EbvBaryCoordSmoothSample: return "BaryCoordSmoothSample";
case EbvBaryCoordPullModel: return "BaryCoordPullModel";
#endif
default: return "unknown built-in variable";
}
}

View file

@ -68,6 +68,10 @@ inline long long int strtoll (const char* str, char** endptr, int base)
{
return _strtoi64(str, endptr, base);
}
inline unsigned long long int strtoull (const char* str, char** endptr, int base)
{
return _strtoui64(str, endptr, base);
}
inline long long int atoll (const char* str)
{
return strtoll(str, NULL, 10);
@ -93,8 +97,8 @@ inline long long int atoll (const char* str)
#include <list>
#include <algorithm>
#include <string>
#include <stdio.h>
#include <assert.h>
#include <cstdio>
#include <cassert>
#include "PoolAlloc.h"
@ -103,11 +107,11 @@ inline long long int atoll (const char* str)
//
#define POOL_ALLOCATOR_NEW_DELETE(A) \
void* operator new(size_t s) { return (A).allocate(s); } \
void* operator new(size_t, void *_Where) { return (_Where); } \
void* operator new(size_t, void *_Where) { return (_Where); } \
void operator delete(void*) { } \
void operator delete(void *, void *) { } \
void* operator new[](size_t s) { return (A).allocate(s); } \
void* operator new[](size_t, void *_Where) { return (_Where); } \
void* operator new[](size_t, void *_Where) { return (_Where); } \
void operator delete[](void*) { } \
void operator delete[](void *, void *) { }
@ -201,20 +205,25 @@ template <class T> T Max(const T a, const T b) { return a > b ? a : b; }
//
// Create a TString object from an integer.
//
#if defined _MSC_VER || defined MINGW_HAS_SECURE_API
inline const TString String(const int i, const int base = 10)
{
char text[16]; // 32 bit ints are at most 10 digits in base 10
_itoa_s(i, text, sizeof(text), base);
return text;
}
#else
inline const TString String(const int i, const int /*base*/ = 10)
{
char text[16]; // 32 bit ints are at most 10 digits in base 10
#if defined _MSC_VER || defined MINGW_HAS_SECURE_API
_itoa_s(i, text, sizeof(text), base);
#else
// we assume base 10 for all cases
snprintf(text, sizeof(text), "%d", i);
#endif
// we assume base 10 for all cases
snprintf(text, sizeof(text), "%d", i);
return text;
}
#endif
struct TSourceLoc {
void init() { name = nullptr; string = 0; line = 0; column = 0; }
// Returns the name if it exists. Otherwise, returns the string number.

View file

@ -36,7 +36,7 @@
#define _INFOSINK_INCLUDED_
#include "../Include/Common.h"
#include <math.h>
#include <cmath>
namespace glslang {
@ -74,7 +74,6 @@ public:
TInfoSinkBase& operator<<(const char* s) { append(s); return *this; }
TInfoSinkBase& operator<<(int n) { append(String(n)); return *this; }
TInfoSinkBase& operator<<(unsigned int n) { append(String(n)); return *this; }
TInfoSinkBase& operator<<(long unsigned int n) { append(String(n)); return *this; }
TInfoSinkBase& operator<<(float n) { const int size = 40; char buf[size];
snprintf(buf, size, (fabs(n) > 1e-8 && fabs(n) < 1e8) || n == 0.0f ? "%f" : "%g", n);
append(buf);

View file

@ -61,13 +61,13 @@
// class as the allocator (second) template argument.
//
#include <stddef.h>
#include <string.h>
#include <cstddef>
#include <cstring>
#include <vector>
namespace glslang {
// If we are using guard blocks, we must track each indivual
// If we are using guard blocks, we must track each individual
// allocation. If we aren't using guard blocks, these
// never get instantiated, so won't have any impact.
//
@ -297,10 +297,10 @@ public:
pointer allocate(size_type n, const void*) {
return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
void deallocate(void*, size_type) { }
void deallocate(void*, size_type) { }
void deallocate(pointer, size_type) { }
pointer _Charalloc(size_t n) {
pointer _Charalloc(size_t n) {
return reinterpret_cast<pointer>(getAllocator().allocate(n)); }
void construct(pointer p, const T& val) { new ((void *)p) T(val); }

View file

@ -123,8 +123,8 @@ public:
haveReturnableObjectCode(false),
appAttributeBindings(0),
fixedAttributeBindings(0),
excludedAttributes(0),
excludedCount(0),
excludedAttributes(0),
excludedCount(0),
uniformBindings(0) { }
virtual TLinker* getAsLinker() { return this; }
virtual ~TLinker() { }
@ -132,8 +132,8 @@ public:
virtual bool link(THandleList&) { return false; }
virtual void setAppAttributeBindings(const ShBindingTable* t) { appAttributeBindings = t; }
virtual void setFixedAttributeBindings(const ShBindingTable* t) { fixedAttributeBindings = t; }
virtual void getAttributeBindings(ShBindingTable const **t) const = 0;
virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; }
virtual void getAttributeBindings(ShBindingTable const **t) const = 0;
virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; }
virtual ShBindingTable* getUniformBindings() const { return uniformBindings; }
virtual const void* getObjectCode() const { return 0; } // a real compiler would be returning object code here
virtual TInfoSink& getInfoSink() { return infoSink; }
@ -145,8 +145,8 @@ protected:
const ShBindingTable* appAttributeBindings;
const ShBindingTable* fixedAttributeBindings;
const int* excludedAttributes;
int excludedCount;
const int* excludedAttributes;
int excludedCount;
ShBindingTable* uniformBindings; // created by the linker
};

View file

@ -78,12 +78,16 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler
bool sampler : 1; // true means a pure sampler, other fields should be clear()
bool external : 1; // GL_OES_EGL_image_external
unsigned int vectorSize : 3; // return vector size. TODO: support arbitrary types.
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; }
bool isShadow() const { return shadow; }
bool isArrayed() const { return arrayed; }
bool isMultiSample() const { return ms; }
void clear()
{
@ -96,6 +100,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
combined = false;
sampler = false;
external = false;
vectorSize = 4;
}
// make a combined sampler and texture
@ -161,7 +166,8 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
image == right.image &&
combined == right.combined &&
sampler == right.sampler &&
external == right.external;
external == right.external &&
vectorSize == right.vectorSize;
}
bool operator!=(const TSampler& right) const
@ -182,8 +188,6 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
case EbtFloat: break;
case EbtInt: s.append("i"); break;
case EbtUint: s.append("u"); break;
case EbtInt64: s.append("i64"); break;
case EbtUint64: s.append("u64"); break;
default: break; // some compilers want this
}
if (image) {
@ -403,6 +407,9 @@ public:
smooth = false;
flat = false;
nopersp = false;
#ifdef AMD_EXTENSIONS
explicitInterp = false;
#endif
patch = false;
sample = false;
coherent = false;
@ -436,6 +443,9 @@ public:
bool smooth : 1;
bool flat : 1;
bool nopersp : 1;
#ifdef AMD_EXTENSIONS
bool explicitInterp : 1;
#endif
bool patch : 1;
bool sample : 1;
bool coherent : 1;
@ -451,7 +461,11 @@ public:
}
bool isInterpolation() const
{
#ifdef AMD_EXTENSIONS
return flat || smooth || nopersp || explicitInterp;
#else
return flat || smooth || nopersp;
#endif
}
bool isAuxiliary() const
{
@ -610,8 +624,8 @@ public:
unsigned int layoutSet : 7;
static const unsigned int layoutSetEnd = 0x3F;
unsigned int layoutBinding : 8;
static const unsigned int layoutBindingEnd = 0xFF;
unsigned int layoutBinding : 16;
static const unsigned int layoutBindingEnd = 0xFFFF;
unsigned int layoutIndex : 8;
static const unsigned int layoutIndexEnd = 0xFF;
@ -1062,7 +1076,7 @@ public:
qualifier.clear();
qualifier.storage = q;
qualifier.precision = p;
assert(p >= 0 && p <= EpqHigh);
assert(p >= EpqNone && p <= EpqHigh);
}
// for turning a TPublicType into a TType, using a shallow copy
explicit TType(const TPublicType& p) :
@ -1080,6 +1094,15 @@ public:
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
}
// for construction of sampler types
TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) :
basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
sampler(sampler)
{
qualifier.clear();
qualifier.storage = q;
}
// to efficiently make a dereferenced type
// without ever duplicating the outer structure that will be thrown away
// and using only shallow copy
@ -1182,7 +1205,7 @@ public:
typeName = NewPoolTString(copyOf.typeName->c_str());
}
TType* clone()
TType* clone() const
{
TType *newType = new TType();
newType->deepCopy(*this);
@ -1255,7 +1278,11 @@ public:
virtual bool isImplicitlySizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage != EvqBuffer; }
virtual bool isRuntimeSizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage == EvqBuffer; }
virtual bool isStruct() const { return structure != nullptr; }
#ifdef AMD_EXTENSIONS
virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
#else
virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble; }
#endif
virtual bool isOpaque() const { return basicType == EbtSampler || basicType == EbtAtomicUint; }
@ -1337,6 +1364,9 @@ public:
case EbtVoid:
case EbtFloat:
case EbtDouble:
#ifdef AMD_EXTENSIONS
case EbtFloat16:
#endif
case EbtInt:
case EbtUint:
case EbtInt64:
@ -1429,6 +1459,9 @@ public:
case EbtVoid: return "void";
case EbtFloat: return "float";
case EbtDouble: return "double";
#ifdef AMD_EXTENSIONS
case EbtFloat16: return "float16_t";
#endif
case EbtInt: return "int";
case EbtUint: return "uint";
case EbtInt64: return "int64_t";
@ -1507,6 +1540,10 @@ public:
p += snprintf(p, end - p, "flat ");
if (qualifier.nopersp)
p += snprintf(p, end - p, "noperspective ");
#ifdef AMD_EXTENSIONS
if (qualifier.explicitInterp)
p += snprintf(p, end - p, "__explicitInterpAMD ");
#endif
if (qualifier.patch)
p += snprintf(p, end - p, "patch ");
if (qualifier.sample)
@ -1707,13 +1744,13 @@ protected:
// functionality is added.
// HLSL does have a 1-component vectors, so this will be true to disambiguate
// from a scalar.
TSampler sampler;
TQualifier qualifier;
TArraySizes* arraySizes; // nullptr unless an array; can be shared across types
TTypeList* structure; // nullptr unless this is a struct; can be shared across types
TString *fieldName; // for structure field names
TString *typeName; // for structure type name
TSampler sampler;
};
} // end namespace glslang

View file

@ -57,6 +57,8 @@
namespace glslang {
class TIntermediate;
//
// Operators used by the high-level (parse tree) representation.
//
@ -124,6 +126,22 @@ enum TOperator {
EOpConvFloatToUint64,
EOpConvDoubleToUint64,
EOpConvInt64ToUint64,
#ifdef AMD_EXTENSIONS
EOpConvBoolToFloat16,
EOpConvIntToFloat16,
EOpConvUintToFloat16,
EOpConvFloatToFloat16,
EOpConvDoubleToFloat16,
EOpConvInt64ToFloat16,
EOpConvUint64ToFloat16,
EOpConvFloat16ToBool,
EOpConvFloat16ToInt,
EOpConvFloat16ToUint,
EOpConvFloat16ToFloat,
EOpConvFloat16ToDouble,
EOpConvFloat16ToInt64,
EOpConvFloat16ToUint64,
#endif
//
// binary operations
@ -241,6 +259,10 @@ enum TOperator {
EOpUnpackInt2x32,
EOpPackUint2x32,
EOpUnpackUint2x32,
#ifdef AMD_EXTENSIONS
EOpPackFloat2x16,
EOpUnpackFloat2x16,
#endif
EOpLength,
EOpDistance,
@ -251,6 +273,12 @@ enum TOperator {
EOpReflect,
EOpRefract,
#ifdef AMD_EXTENSIONS
EOpMin3,
EOpMax3,
EOpMid3,
#endif
EOpDPdx, // Fragment only
EOpDPdy, // Fragment only
EOpFwidth, // Fragment only
@ -265,6 +293,10 @@ enum TOperator {
EOpInterpolateAtSample, // Fragment only
EOpInterpolateAtOffset, // Fragment only
#ifdef AMD_EXTENSIONS
EOpInterpolateAtVertex,
#endif
EOpMatrixTimesMatrix,
EOpOuterProduct,
EOpDeterminant,
@ -296,6 +328,23 @@ enum TOperator {
EOpAllInvocations,
EOpAllInvocationsEqual,
#ifdef AMD_EXTENSIONS
EOpMinInvocations,
EOpMaxInvocations,
EOpAddInvocations,
EOpMinInvocationsNonUniform,
EOpMaxInvocationsNonUniform,
EOpAddInvocationsNonUniform,
EOpSwizzleInvocations,
EOpSwizzleInvocationsMasked,
EOpWriteInvocation,
EOpMbcnt,
EOpCubeFaceIndex,
EOpCubeFaceCoord,
EOpTime,
#endif
EOpAtomicAdd,
EOpAtomicMin,
EOpAtomicMax,
@ -374,6 +423,21 @@ enum TOperator {
EOpConstructDMat4x2,
EOpConstructDMat4x3,
EOpConstructDMat4x4,
#ifdef AMD_EXTENSIONS
EOpConstructFloat16,
EOpConstructF16Vec2,
EOpConstructF16Vec3,
EOpConstructF16Vec4,
EOpConstructF16Mat2x2,
EOpConstructF16Mat2x3,
EOpConstructF16Mat2x4,
EOpConstructF16Mat3x2,
EOpConstructF16Mat3x3,
EOpConstructF16Mat3x4,
EOpConstructF16Mat4x2,
EOpConstructF16Mat4x3,
EOpConstructF16Mat4x4,
#endif
EOpConstructStruct,
EOpConstructTextureSampler,
EOpConstructGuardEnd,
@ -439,6 +503,9 @@ enum TOperator {
EOpTextureQueryLod,
EOpTextureQueryLevels,
EOpTextureQuerySamples,
EOpSamplingGuardBegin,
EOpTexture,
EOpTextureProj,
EOpTextureLod,
@ -481,7 +548,7 @@ enum TOperator {
EOpSparseTextureGradOffsetClamp,
EOpSparseTextureGuardEnd,
EOpSamplingGuardEnd,
EOpTextureGuardEnd,
//
@ -530,6 +597,30 @@ enum TOperator {
EOpLit, // HLSL lighting coefficient vector
EOpTextureBias, // HLSL texture bias: will be lowered to EOpTexture
EOpAsDouble, // slightly different from EOpUint64BitsToDouble
EOpMethodSample, // Texture object methods. These are translated to existing
EOpMethodSampleBias, // AST methods, and exist to represent HLSL semantics until that
EOpMethodSampleCmp, // translation is performed. See HlslParseContext::decomposeSampleMethods().
EOpMethodSampleCmpLevelZero, // ...
EOpMethodSampleGrad, // ...
EOpMethodSampleLevel, // ...
EOpMethodLoad, // ...
EOpMethodGetDimensions, // ...
EOpMethodGetSamplePosition, // ...
EOpMethodGather, // ...
EOpMethodCalculateLevelOfDetail, // ...
EOpMethodCalculateLevelOfDetailUnclamped, // ...
// SM5 texture methods
EOpMethodGatherRed, // These are covered under the above EOpMethodSample comment about
EOpMethodGatherGreen, // translation to existing AST opcodes. They exist temporarily
EOpMethodGatherBlue, // because HLSL arguments are slightly different.
EOpMethodGatherAlpha, // ...
EOpMethodGatherCmp, // ...
EOpMethodGatherCmpRed, // ...
EOpMethodGatherCmpGreen, // ...
EOpMethodGatherCmpBlue, // ...
EOpMethodGatherCmpAlpha, // ...
};
class TIntermTraverser;
@ -761,14 +852,30 @@ public:
virtual TIntermOperator* getAsOperator() { return this; }
virtual const TIntermOperator* getAsOperator() const { return this; }
TOperator getOp() const { return op; }
virtual bool promote() { return true; }
void setOp(TOperator newOp) { op = newOp; }
bool modifiesState() const;
bool isConstructor() const;
bool isTexture() const { return op > EOpTextureGuardBegin && op < EOpTextureGuardEnd; }
bool isImage() const { return op > EOpImageGuardBegin && op < EOpImageGuardEnd; }
bool isTexture() const { return op > EOpTextureGuardBegin && op < EOpTextureGuardEnd; }
bool isSampling() const { return op > EOpSamplingGuardBegin && op < EOpSamplingGuardEnd; }
bool isImage() const { return op > EOpImageGuardBegin && op < EOpImageGuardEnd; }
bool isSparseTexture() const { return op > EOpSparseTextureGuardBegin && op < EOpSparseTextureGuardEnd; }
bool isSparseImage() const { return op == EOpSparseImageLoad; }
void setOperationPrecision(TPrecisionQualifier p) { operationPrecision = p; }
TPrecisionQualifier getOperationPrecision() const { return operationPrecision != EpqNone ?
operationPrecision :
type.getQualifier().precision; }
TString getCompleteString() const
{
TString cs = type.getCompleteString();
if (getOperationPrecision() != type.getQualifier().precision) {
cs += ", operation at ";
cs += GetPrecisionQualifierString(getOperationPrecision());
}
return cs;
}
// Crack the op into the individual dimensions of texturing operation.
void crackTexture(TSampler sampler, TCrackedTextureOp& cracked) const
{
@ -900,9 +1007,15 @@ public:
}
protected:
TIntermOperator(TOperator o) : TIntermTyped(EbtFloat), op(o) {}
TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
TIntermOperator(TOperator o) : TIntermTyped(EbtFloat), op(o), operationPrecision(EpqNone) {}
TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o), operationPrecision(EpqNone) {}
TOperator op;
// The result precision is in the inherited TType, and is usually meant to be both
// the operation precision and the result precision. However, some more complex things,
// like built-in function calls, distinguish between the two, in which case non-EqpNone
// 'operationPrecision' overrides the result precision as far as operation precision
// is concerned.
TPrecisionQualifier operationPrecision;
};
//
@ -918,7 +1031,6 @@ public:
virtual TIntermTyped* getRight() const { return right; }
virtual TIntermBinary* getAsBinaryNode() { return this; }
virtual const TIntermBinary* getAsBinaryNode() const { return this; }
virtual bool promote();
virtual void updatePrecision();
protected:
TIntermTyped* left;
@ -938,7 +1050,6 @@ public:
virtual const TIntermTyped* getOperand() const { return operand; }
virtual TIntermUnary* getAsUnaryNode() { return this; }
virtual const TIntermUnary* getAsUnaryNode() const { return this; }
virtual bool promote();
virtual void updatePrecision();
protected:
TIntermTyped* operand;

View file

@ -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.947"
#define GLSLANG_DATE "15-Feb-2016"
#define GLSLANG_REVISION "Overload400-PrecQual.1603"
#define GLSLANG_DATE "16-Oct-2016"

View file

@ -176,6 +176,9 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right
switch (getType().getBasicType()) {
case EbtDouble:
case EbtFloat:
#ifdef AMD_EXTENSIONS
case EbtFloat16:
#endif
newConstArray[i].setDConst(leftUnionArray[i].getDConst() / rightUnionArray[i].getDConst());
break;
@ -450,6 +453,9 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
case EOpNegative:
switch (getType().getBasicType()) {
case EbtDouble:
#ifdef AMD_EXTENSIONS
case EbtFloat16:
#endif
case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break;
case EbtInt: newConstArray[i].setIConst(-unionArray[i].getIConst()); break;
case EbtUint: newConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst()))); break;
@ -688,6 +694,9 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
// Second, do the actual folding
bool isFloatingPoint = children[0]->getAsTyped()->getBasicType() == EbtFloat ||
#ifdef AMD_EXTENSIONS
children[0]->getAsTyped()->getBasicType() == EbtFloat16 ||
#endif
children[0]->getAsTyped()->getBasicType() == EbtDouble;
bool isSigned = children[0]->getAsTyped()->getBasicType() == EbtInt ||
children[0]->getAsTyped()->getBasicType() == EbtInt64;

View file

@ -34,15 +34,19 @@
#include "../Include/InfoSink.h"
#include <string.h>
#include <cstring>
namespace glslang {
void TInfoSinkBase::append(const char* s)
void TInfoSinkBase::append(const char* s)
{
if (outputStream & EString) {
checkMem(strlen(s));
sink.append(s);
if (s == nullptr)
sink.append("(null)");
else {
checkMem(strlen(s));
sink.append(s);
}
}
//#ifdef _WIN32
@ -54,10 +58,10 @@ void TInfoSinkBase::append(const char* s)
fprintf(stdout, "%s", s);
}
void TInfoSinkBase::append(int count, char c)
void TInfoSinkBase::append(int count, char c)
{
if (outputStream & EString) {
checkMem(count);
checkMem(count);
sink.append(count, c);
}
@ -74,10 +78,10 @@ void TInfoSinkBase::append(int count, char c)
fprintf(stdout, "%c", c);
}
void TInfoSinkBase::append(const TPersistString& t)
void TInfoSinkBase::append(const TPersistString& t)
{
if (outputStream & EString) {
checkMem(t.size());
checkMem(t.size());
sink.append(t);
}
@ -93,7 +97,7 @@ void TInfoSinkBase::append(const TPersistString& t)
void TInfoSinkBase::append(const TString& t)
{
if (outputStream & EString) {
checkMem(t.size());
checkMem(t.size());
sink.append(t.c_str());
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
//
//Copyright (C) 2016 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.
//
#include "../Include/Common.h"
#include "reflection.h"
#include "localintermediate.h"
#include "gl_types.h"
#include <list>
#include <unordered_set>
namespace glslang {
//
// The traverser: mostly pass through, except
// - processing function-call nodes to push live functions onto the stack of functions to process
// - processing selection nodes to trim semantically dead code
//
// This is in the glslang namespace directly so it can be a friend of TReflection.
// This can be derived from to implement reflection database traversers or
// binding mappers: anything that wants to traverse the live subset of the tree.
//
class TLiveTraverser : public TIntermTraverser {
public:
TLiveTraverser(const TIntermediate& i, bool traverseAll = false,
bool preVisit = true, bool inVisit = false, bool postVisit = false) :
TIntermTraverser(preVisit, inVisit, postVisit),
intermediate(i), traverseAll(traverseAll)
{ }
//
// Given a function name, find its subroot in the tree, and push it onto the stack of
// functions left to process.
//
void pushFunction(const TString& name)
{
TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence();
for (unsigned int f = 0; f < globals.size(); ++f) {
TIntermAggregate* candidate = globals[f]->getAsAggregate();
if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) {
functions.push_back(candidate);
break;
}
}
}
typedef std::list<TIntermAggregate*> TFunctionStack;
TFunctionStack functions;
protected:
// To catch which function calls are not dead, and hence which functions must be visited.
virtual bool visitAggregate(TVisit, TIntermAggregate* node)
{
if (!traverseAll)
if (node->getOp() == EOpFunctionCall)
addFunctionCall(node);
return true; // traverse this subtree
}
// To prune semantically dead paths.
virtual bool visitSelection(TVisit /* visit */, TIntermSelection* node)
{
if (traverseAll)
return true; // traverse all code
TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion();
if (constant) {
// cull the path that is dead
if (constant->getConstArray()[0].getBConst() == true && node->getTrueBlock())
node->getTrueBlock()->traverse(this);
if (constant->getConstArray()[0].getBConst() == false && node->getFalseBlock())
node->getFalseBlock()->traverse(this);
return false; // don't traverse any more, we did it all above
} else
return true; // traverse the whole subtree
}
// Track live functions as well as uniforms, so that we don't visit dead functions
// and only visit each function once.
void addFunctionCall(TIntermAggregate* call)
{
// // just use the map to ensure we process each function at most once
if (liveFunctions.find(call->getName()) == liveFunctions.end()) {
liveFunctions.insert(call->getName());
pushFunction(call->getName());
}
}
const TIntermediate& intermediate;
typedef std::unordered_set<TString> TLiveFunctions;
TLiveFunctions liveFunctions;
bool traverseAll;
private:
// prevent copy & copy construct
TLiveTraverser(TLiveTraverser&);
TLiveTraverser& operator=(TLiveTraverser&);
};
} // namespace glslang

View file

@ -0,0 +1,451 @@
//
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
//Copyright (C) 2016 Google, 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.
//
// Implement the TParseContextBase class.
#include <cstdarg>
#include "ParseHelper.h"
extern int yyparse(glslang::TParseContext*);
namespace glslang {
//
// Used to output syntax, parsing, and semantic errors.
//
void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReason,
const char* szToken,
const char* szExtraInfoFormat,
TPrefixType prefix, va_list args)
{
const int maxSize = MaxTokenLength + 200;
char szExtraInfo[maxSize];
safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args);
infoSink.info.prefix(prefix);
infoSink.info.location(loc);
infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n";
if (prefix == EPrefixError) {
++numErrors;
}
}
void C_DECL TParseContextBase::error(const TSourceLoc& loc, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...)
{
if (messages & EShMsgOnlyPreprocessor)
return;
va_list args;
va_start(args, szExtraInfoFormat);
outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args);
va_end(args);
if ((messages & EShMsgCascadingErrors) == 0)
currentScanner->setEndOfInput();
}
void C_DECL TParseContextBase::warn(const TSourceLoc& loc, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...)
{
if (suppressWarnings())
return;
va_list args;
va_start(args, szExtraInfoFormat);
outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args);
va_end(args);
}
void C_DECL TParseContextBase::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...)
{
va_list args;
va_start(args, szExtraInfoFormat);
outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args);
va_end(args);
if ((messages & EShMsgCascadingErrors) == 0)
currentScanner->setEndOfInput();
}
void C_DECL TParseContextBase::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...)
{
va_list args;
va_start(args, szExtraInfoFormat);
outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args);
va_end(args);
}
//
// Both test and if necessary, spit out an error, to see if the node is really
// an l-value that can be operated on this way.
//
// Returns true if there was an error.
//
bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
{
TIntermBinary* binaryNode = node->getAsBinaryNode();
if (binaryNode) {
switch(binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect: // fall through
case EOpIndexDirectStruct: // fall through
case EOpVectorSwizzle:
return lValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
error(loc, " l-value required", op, "", "");
return true;
}
const char* symbol = nullptr;
TIntermSymbol* symNode = node->getAsSymbolNode();
if (symNode != nullptr)
symbol = symNode->getName().c_str();
const char* message = nullptr;
switch (node->getQualifier().storage) {
case EvqConst: message = "can't modify a const"; break;
case EvqConstReadOnly: message = "can't modify a const"; break;
case EvqUniform: message = "can't modify a uniform"; break;
case EvqBuffer:
if (node->getQualifier().readonly)
message = "can't modify a readonly buffer";
break;
default:
//
// Type that can't be written to?
//
switch (node->getBasicType()) {
case EbtSampler:
message = "can't modify a sampler";
break;
case EbtAtomicUint:
message = "can't modify an atomic_uint";
break;
case EbtVoid:
message = "can't modify void";
break;
default:
break;
}
}
if (message == nullptr && binaryNode == nullptr && symNode == nullptr) {
error(loc, " l-value required", op, "", "");
return true;
}
//
// Everything else is okay, no error.
//
if (message == nullptr)
return false;
//
// If we get here, we have an error and a message.
//
if (symNode)
error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message);
else
error(loc, " l-value required", op, "(%s)", message);
return true;
}
// Test for and give an error if the node can't be read from.
void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node)
{
if (! node)
return;
TIntermBinary* binaryNode = node->getAsBinaryNode();
if (binaryNode) {
switch(binaryNode->getOp()) {
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectStruct:
case EOpVectorSwizzle:
rValueErrorCheck(loc, op, binaryNode->getLeft());
default:
break;
}
return;
}
TIntermSymbol* symNode = node->getAsSymbolNode();
if (symNode && symNode->getQualifier().writeonly)
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
}
// Make a shared symbol have a non-shared version that can be edited by the current
// compile, such that editing its type will not change the shared version and will
// effect all nodes sharing it.
void TParseContextBase::makeEditable(TSymbol*& symbol)
{
// copyUp() does a deep copy of the type.
symbol = symbolTable.copyUp(symbol);
// Save it in the AST for linker use.
intermediate.addSymbolLinkageNode(linkage, *symbol);
}
// Return a writable version of the variable 'name'.
//
// Return nullptr if 'name' is not found. This should mean
// something is seriously wrong (e.g., compiler asking self for
// built-in that doesn't exist).
TVariable* TParseContextBase::getEditableVariable(const char* name)
{
bool builtIn;
TSymbol* symbol = symbolTable.find(name, &builtIn);
assert(symbol != nullptr);
if (symbol == nullptr)
return nullptr;
if (builtIn)
makeEditable(symbol);
return symbol->getAsVariable();
}
// Select the best matching function for 'call' from 'candidateList'.
//
// Assumptions
//
// There is no exact match, so a selection algorithm needs to run. That is, the
// language-specific handler should check for exact match first, to
// decide what to do, before calling this selector.
//
// Input
//
// * list of candidate signatures to select from
// * the call
// * a predicate function convertible(from, to) that says whether or not type
// 'from' can implicitly convert to type 'to' (it includes the case of what
// the calling language would consider a matching type with no conversion
// needed)
// * a predicate function better(from1, from2, to1, to2) that says whether or
// not a conversion from <-> to2 is considered better than a conversion
// from <-> to1 (both in and out directions need testing, as declared by the
// formal parameter)
//
// Output
//
// * best matching candidate (or none, if no viable candidates found)
// * whether there was a tie for the best match (ambiguous overload selection,
// caller's choice for how to report)
//
const TFunction* TParseContextBase::selectFunction(
const TVector<const TFunction*> candidateList,
const TFunction& call,
std::function<bool(const TType& from, const TType& to)> convertible,
std::function<bool(const TType& from, const TType& to1, const TType& to2)> better,
/* output */ bool& tie)
{
//
// Operation
//
// 1. Prune the input list of candidates down to a list of viable candidates,
// where each viable candidate has
//
// * at least as many parameters as there are calling arguments, with any
// remaining parameters being optional or having default values
// * each parameter is true under convertible(A, B), where A is the calling
// type for in and B is the formal type, and in addition, for out B is the
// calling type and A is the formal type
//
// 2. If there are no viable candidates, return with no match.
//
// 3. If there is only one viable candidate, it is the best match.
//
// 4. If there are multiple viable candidates, select the first viable candidate
// as the incumbent. Compare the incumbent to the next viable candidate, and if
// that candidate is better (bullets below), make it the incumbent. Repeat, with
// a linear walk through the viable candidate list. The final incumbent will be
// returned as the best match. A viable candidate is better than the incumbent if
//
// * it has a function argument with a better(...) conversion than the incumbent,
// for all directions needed by in and out
// * the incumbent has no argument with a better(...) conversion then the
// candidate, for either in or out (as needed)
//
// 5. Check for ambiguity by comparing the best match against all other viable
// candidates. If any other viable candidate has a function argument with a
// better(...) conversion than the best candidate (for either in or out
// directions), return that there was a tie for best.
//
tie = false;
// 1. prune to viable...
TVector<const TFunction*> viableCandidates;
for (auto it = candidateList.begin(); it != candidateList.end(); ++it) {
const TFunction& candidate = *(*it);
// to even be a potential match, number of arguments has to match
if (call.getParamCount() != candidate.getParamCount())
continue;
// see if arguments are convertible
bool viable = true;
for (int param = 0; param < candidate.getParamCount(); ++param) {
if (candidate[param].type->getQualifier().isParamInput()) {
if (! convertible(*call[param].type, *candidate[param].type)) {
viable = false;
break;
}
}
if (candidate[param].type->getQualifier().isParamOutput()) {
if (! convertible(*candidate[param].type, *call[param].type)) {
viable = false;
break;
}
}
}
if (viable)
viableCandidates.push_back(&candidate);
}
// 2. none viable...
if (viableCandidates.size() == 0)
return nullptr;
// 3. only one viable...
if (viableCandidates.size() == 1)
return viableCandidates.front();
// 4. find best...
auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
// is call -> can2 better than call -> can1 for any parameter
bool hasBetterParam = false;
for (int param = 0; param < call.getParamCount(); ++param) {
if (better(*call[param].type, *can1[param].type, *can2[param].type)) {
hasBetterParam = true;
break;
}
}
return hasBetterParam;
};
const TFunction* incumbent = viableCandidates.front();
for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) {
const TFunction& candidate = *(*it);
if (betterParam(*incumbent, candidate) && ! betterParam(candidate, *incumbent))
incumbent = &candidate;
}
// 5. ambiguity...
for (auto it = viableCandidates.begin(); it != viableCandidates.end(); ++it) {
if (incumbent == *it)
continue;
const TFunction& candidate = *(*it);
if (betterParam(*incumbent, candidate))
tie = true;
}
return incumbent;
}
//
// Make the passed-in variable information become a member of the
// global uniform block. If this doesn't exist yet, make it.
//
void TParseContextBase::growGlobalUniformBlock(TSourceLoc& loc, TType& memberType, TString& memberName)
{
// make the global block, if not yet made
if (globalUniformBlock == nullptr) {
TString& blockName = *NewPoolTString(getGlobalUniformBlockName());
TQualifier blockQualifier;
blockQualifier.clear();
blockQualifier.storage = EvqUniform;
TType blockType(new TTypeList, blockName, blockQualifier);
TString* instanceName = NewPoolTString("");
globalUniformBlock = new TVariable(instanceName, blockType, true);
firstNewMember = 0;
}
// add the requested member as a member to the block
TType* type = new TType;
type->shallowCopy(memberType);
type->setFieldName(memberName);
TTypeLoc typeLoc = {type, loc};
globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc);
}
//
// Insert into the symbol table the global uniform block created in
// growGlobalUniformBlock(). The variables added as members won't be
// found unless this is done.
//
bool TParseContextBase::insertGlobalUniformBlock()
{
if (globalUniformBlock == nullptr)
return true;
int numMembers = (int)globalUniformBlock->getType().getStruct()->size();
bool inserted = false;
if (firstNewMember == 0) {
// This is the first request; we need a normal symbol table insert
inserted = symbolTable.insert(*globalUniformBlock);
if (inserted)
intermediate.addSymbolLinkageNode(linkage, *globalUniformBlock);
} else if (firstNewMember <= numMembers) {
// This is a follow-on request; we need to amend the first insert
inserted = symbolTable.amend(*globalUniformBlock, firstNewMember);
}
if (inserted) {
finalizeGlobalUniformBlockLayout(*globalUniformBlock);
firstNewMember = numMembers;
}
return inserted;
}
} // end namespace glslang

File diff suppressed because it is too large Load diff

View file

@ -77,12 +77,22 @@ public:
EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages)
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
symbolTable(symbolTable), tokensBeforeEOF(false),
linkage(nullptr), scanContext(nullptr), ppContext(nullptr) { }
symbolTable(symbolTable),
linkage(nullptr), scanContext(nullptr), ppContext(nullptr),
globalUniformBlock(nullptr) { }
virtual ~TParseContextBase() { }
virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
virtual void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
virtual void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
virtual void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
virtual void setLimits(const TBuiltInResource&) = 0;
EShLanguage getLanguage() const { return language; }
TIntermAggregate*& getLinkage() { return linkage; }
void setScanContext(TScanContext* c) { scanContext = c; }
@ -125,7 +135,16 @@ public:
}
TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile
bool tokensBeforeEOF;
// Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
// TODO: This could perhaps get its own object, but the current design doesn't work
// yet when new uniform variables are declared between function definitions, so
// this is pending getting a fully functional design.
virtual void growGlobalUniformBlock(TSourceLoc&, TType&, TString& memberName);
virtual bool insertGlobalUniformBlock();
virtual bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
virtual void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
protected:
TParseContextBase(TParseContextBase&);
@ -142,6 +161,58 @@ protected:
std::function<void(int, int, const char*)> versionCallback;
std::function<void(int, const char*, const char*)> extensionCallback;
std::function<void(int, const char*)> errorCallback;
// see implementation for detail
const TFunction* selectFunction(const TVector<const TFunction*>, const TFunction&,
std::function<bool(const TType&, const TType&)>,
std::function<bool(const TType&, const TType&, const TType&)>,
/* output */ bool& tie);
// Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
TVariable* globalUniformBlock; // the actual block, inserted into the symbol table
int firstNewMember; // the index of the first member not yet inserted into the symbol table
// override this to set the language-specific name
virtual const char* getGlobalUniformBlockName() { return ""; }
virtual void finalizeGlobalUniformBlockLayout(TVariable&) { }
virtual void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, TPrefixType prefix,
va_list args);
virtual void makeEditable(TSymbol*&);
virtual TVariable* getEditableVariable(const char* name);
};
//
// Manage the state for when to respect precision qualifiers and when to warn about
// the defaults being different than might be expected.
//
class TPrecisionManager {
public:
TPrecisionManager() : obey(false), warn(false), explicitIntDefault(false), explicitFloatDefault(false){ }
virtual ~TPrecisionManager() {}
void respectPrecisionQualifiers() { obey = true; }
bool respectingPrecisionQualifiers() const { return obey; }
bool shouldWarnAboutDefaults() const { return warn; }
void defaultWarningGiven() { warn = false; }
void warnAboutDefaults() { warn = true; }
void explicitIntDefaultSeen()
{
explicitIntDefault = true;
if (explicitFloatDefault)
warn = false;
}
void explicitFloatDefaultSeen()
{
explicitFloatDefault = true;
if (explicitIntDefault)
warn = false;
}
protected:
bool obey; // respect precision qualifiers
bool warn; // need to give a warning about the defaults
bool explicitIntDefault; // user set the default for int/uint
bool explicitFloatDefault; // user set the default for float
};
//
@ -155,19 +226,13 @@ public:
bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
virtual ~TParseContext();
bool obeyPrecisionQualifiers() const { return precisionManager.respectingPrecisionQualifiers(); };
void setPrecisionDefaults();
void setLimits(const TBuiltInResource&);
bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false);
void parserError(const char* s); // for bison's yyerror
void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, ...);
void reservedErrorCheck(const TSourceLoc&, const TString&);
void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op);
bool lineContinuationCheck(const TSourceLoc&, bool endOfComment);
@ -181,7 +246,6 @@ 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);
@ -197,6 +261,8 @@ public:
TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
TIntermTyped* handleBuiltInFunctionCall(TSourceLoc, TIntermNode& arguments, const TFunction& function);
void computeBuiltinPrecisions(TIntermTyped&, const TFunction&);
TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
void checkLocation(const TSourceLoc&, TOperator);
TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
@ -204,15 +270,19 @@ public:
TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const;
void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&);
void nonOpBuiltInCheck(const TSourceLoc&, const TFunction&, TIntermAggregate&);
void userFunctionCallCheck(const TSourceLoc&, TIntermAggregate&);
void samplerConstructorLocationCheck(const TSourceLoc&, const char* token, TIntermNode*);
TFunction* handleConstructorCall(const TSourceLoc&, const TPublicType&);
void handlePrecisionQualifier(const TSourceLoc&, TQualifier&, TPrecisionQualifier);
void checkPrecisionQualifier(const TSourceLoc&, TPrecisionQualifier);
bool parseVectorFields(const TSourceLoc&, const TString&, int vecSize, TVectorFields&);
void assignError(const TSourceLoc&, const char* op, TString left, TString right);
void unaryOpError(const TSourceLoc&, const char* op, TString operand);
void binaryOpError(const TSourceLoc&, const char* op, TString left, TString right);
void variableCheck(TIntermTyped*& nodePtr);
bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override;
void constantValueCheck(TIntermTyped* node, const char* token);
void integerCheck(const TIntermTyped* node, const char* token);
void globalCheck(const TSourceLoc&, const char* token);
@ -276,7 +346,7 @@ public:
const TFunction* findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
void declareTypeDefaults(const TSourceLoc&, const TPublicType&);
TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0);
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&, TOperator);
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&);
TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
@ -302,11 +372,7 @@ protected:
void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer);
TOperator mapTypeToConstructorOp(const TType&) const;
void finalErrorCheck();
void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken,
const char* szExtraInfoFormat, TPrefixType prefix,
va_list args);
public:
//
@ -338,7 +404,7 @@ protected:
const bool parsingBuiltins; // true if parsing built-in symbols/functions
static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2 * 2 * 2)); // see computeSamplerTypeIndex()
TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
bool afterEOF;
TPrecisionManager precisionManager;
TQualifier globalBufferDefaults;
TQualifier globalUniformDefaults;
TQualifier globalInputDefaults;

View file

@ -53,7 +53,7 @@ void InitializeMemoryPools()
TThreadMemoryPools* threadData = new TThreadMemoryPools();
threadData->threadPoolAllocator = threadPoolAllocator;
OS_SetTLSValue(PoolIndex, threadData);
}
@ -63,7 +63,7 @@ void FreeGlobalPools()
TThreadMemoryPools* globalPools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
if (! globalPools)
return;
GetThreadPoolAllocator().popAll();
delete &GetThreadPoolAllocator();
delete globalPools;
@ -149,12 +149,12 @@ TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
TPoolAllocator::~TPoolAllocator()
{
while (inUseList) {
tHeader* next = inUseList->nextPage;
while (inUseList) {
tHeader* next = inUseList->nextPage;
inUseList->~tHeader();
delete [] reinterpret_cast<char*>(inUseList);
inUseList = next;
}
inUseList = next;
}
//
// Always delete the free list memory - it can't be being

View file

@ -38,7 +38,7 @@
// GLSL scanning, leveraging the scanning done by the preprocessor.
//
#include <string.h>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
@ -55,7 +55,7 @@
// Required to avoid missing prototype warnings for some compilers
int yylex(YYSTYPE*, glslang::TParseContext&);
namespace glslang {
// read past any white space
@ -463,6 +463,25 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["u64vec3"] = U64VEC3;
(*KeywordMap)["u64vec4"] = U64VEC4;
#ifdef AMD_EXTENSIONS
(*KeywordMap)["float16_t"] = FLOAT16_T;
(*KeywordMap)["f16vec2"] = F16VEC2;
(*KeywordMap)["f16vec3"] = F16VEC3;
(*KeywordMap)["f16vec4"] = F16VEC4;
(*KeywordMap)["f16mat2"] = F16MAT2;
(*KeywordMap)["f16mat3"] = F16MAT3;
(*KeywordMap)["f16mat4"] = F16MAT4;
(*KeywordMap)["f16mat2x2"] = F16MAT2X2;
(*KeywordMap)["f16mat2x3"] = F16MAT2X3;
(*KeywordMap)["f16mat2x4"] = F16MAT2X4;
(*KeywordMap)["f16mat3x2"] = F16MAT3X2;
(*KeywordMap)["f16mat3x3"] = F16MAT3X3;
(*KeywordMap)["f16mat3x4"] = F16MAT3X4;
(*KeywordMap)["f16mat4x2"] = F16MAT4X2;
(*KeywordMap)["f16mat4x3"] = F16MAT4X3;
(*KeywordMap)["f16mat4x4"] = F16MAT4X4;
#endif
(*KeywordMap)["sampler2D"] = SAMPLER2D;
(*KeywordMap)["samplerCube"] = SAMPLERCUBE;
(*KeywordMap)["samplerCubeArray"] = SAMPLERCUBEARRAY;
@ -553,6 +572,9 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["noperspective"] = NOPERSPECTIVE;
(*KeywordMap)["smooth"] = SMOOTH;
(*KeywordMap)["flat"] = FLAT;
#ifdef AMD_EXTENSIONS
(*KeywordMap)["__explicitInterpAMD"] = __EXPLICITINTERPAMD;
#endif
(*KeywordMap)["centroid"] = CENTROID;
(*KeywordMap)["precise"] = PRECISE;
(*KeywordMap)["invariant"] = INVARIANT;
@ -561,7 +583,7 @@ void TScanContext::fillInKeywordMap()
(*KeywordMap)["superp"] = SUPERP;
ReservedSet = new std::unordered_set<const char*, str_hash, str_eq>;
ReservedSet->insert("common");
ReservedSet->insert("partition");
ReservedSet->insert("active");
@ -609,13 +631,15 @@ void TScanContext::deleteKeywordMap()
ReservedSet = nullptr;
}
// Called by yylex to get the next token.
// Returning 0 implies end of input.
int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
{
do {
parserToken = &token;
TPpToken ppToken;
tokenText = pp->tokenize(&ppToken);
if (tokenText == nullptr)
if (tokenText == nullptr || tokenText[0] == 0)
return 0;
loc = ppToken.loc;
@ -675,13 +699,16 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
case PpAtomDecrement: return DEC_OP;
case PpAtomIncrement: return INC_OP;
case PpAtomConstInt: parserToken->sType.lex.i = ppToken.ival; return INTCONSTANT;
case PpAtomConstUint: parserToken->sType.lex.i = ppToken.ival; return UINTCONSTANT;
case PpAtomConstInt64: parserToken->sType.lex.i64 = ppToken.i64val; return INT64CONSTANT;
case PpAtomConstUint64: parserToken->sType.lex.i64 = ppToken.i64val; return UINT64CONSTANT;
case PpAtomConstFloat: parserToken->sType.lex.d = ppToken.dval; return FLOATCONSTANT;
case PpAtomConstDouble: parserToken->sType.lex.d = ppToken.dval; return DOUBLECONSTANT;
#ifdef AMD_EXTENSIONS
case PpAtomConstFloat16: parserToken->sType.lex.d = ppToken.dval; return FLOAT16CONSTANT;
#endif
case PpAtomIdentifier:
{
int token = tokenizeIdentifier();
@ -847,7 +874,7 @@ int TScanContext::tokenizeIdentifier()
case MAT3X4:
case MAT4X2:
case MAT4X3:
case MAT4X4:
case MAT4X4:
return matNxM();
case DMAT2:
@ -933,10 +960,38 @@ int TScanContext::tokenizeIdentifier()
case U64VEC2:
case U64VEC3:
case U64VEC4:
if (parseContext.profile != EEsProfile && parseContext.version >= 450)
afterType = true;
if (parseContext.symbolTable.atBuiltInLevel() ||
(parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_int64) &&
parseContext.profile != EEsProfile && parseContext.version >= 450))
return keyword;
return identifierOrType();
#ifdef AMD_EXTENSIONS
case FLOAT16_T:
case F16VEC2:
case F16VEC3:
case F16VEC4:
case F16MAT2:
case F16MAT3:
case F16MAT4:
case F16MAT2X2:
case F16MAT2X3:
case F16MAT2X4:
case F16MAT3X2:
case F16MAT3X3:
case F16MAT3X4:
case F16MAT4X2:
case F16MAT4X3:
case F16MAT4X4:
afterType = true;
if (parseContext.symbolTable.atBuiltInLevel() ||
(parseContext.extensionTurnedOn(E_GL_AMD_gpu_shader_half_float) &&
parseContext.profile != EEsProfile && parseContext.version >= 450))
return keyword;
return identifierOrType();
#endif
case SAMPLERCUBEARRAY:
case SAMPLERCUBEARRAYSHADOW:
case ISAMPLERCUBEARRAY:
@ -973,7 +1028,7 @@ int TScanContext::tokenizeIdentifier()
case USAMPLER2DARRAY:
afterType = true;
return nonreservedKeyword(300, 130);
case ISAMPLER2DRECT:
case USAMPLER2DRECT:
afterType = true;
@ -991,7 +1046,7 @@ int TScanContext::tokenizeIdentifier()
if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
return keyword;
return es30ReservedFromGLSL(140);
case SAMPLER2DMS:
case ISAMPLER2DMS:
case USAMPLER2DMS:
@ -1110,13 +1165,21 @@ int TScanContext::tokenizeIdentifier()
case NOPERSPECTIVE:
return es30ReservedFromGLSL(130);
case SMOOTH:
if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
(parseContext.profile != EEsProfile && parseContext.version < 130))
return identifierOrType();
return keyword;
#ifdef AMD_EXTENSIONS
case __EXPLICITINTERPAMD:
if (parseContext.profile != EEsProfile && parseContext.version >= 450 &&
parseContext.extensionTurnedOn(E_GL_AMD_shader_explicit_vertex_parameter))
return keyword;
return identifierOrType();
#endif
case FLAT:
if (parseContext.profile == EEsProfile && parseContext.version < 300)
reservedWord();
@ -1161,7 +1224,7 @@ int TScanContext::tokenizeIdentifier()
bool reserved = parseContext.profile == EEsProfile || parseContext.version >= 130;
return identifierOrReserved(reserved);
}
default:
parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
return 0;

View file

@ -204,6 +204,8 @@ public:
currentSource = numSources;
}
bool atEndOfInput() const { return endOfFileReached; }
const TSourceLoc& getSourceLoc() const
{
if (singleLogical) {

View file

@ -41,7 +41,7 @@
// This is the platform independent interface between an OGL driver
// and the shading language compiler/linker.
//
#include <string.h>
#include <cstring>
#include <iostream>
#include <sstream>
#include <memory>
@ -51,6 +51,7 @@
#include "../../hlsl/hlslParseables.h"
#include "Scan.h"
#include "ScanContext.h"
#include "../../hlsl/hlslScanContext.h"
#include "../Include/ShHandle.h"
#include "../../OGLCompilersDLL/InitializeDll.h"
@ -60,6 +61,7 @@
#define SH_EXPORTING
#include "../Public/ShaderLang.h"
#include "reflection.h"
#include "iomapper.h"
#include "Initialize.h"
namespace { // anonymous namespace for file-local functions and symbols
@ -146,6 +148,23 @@ int MapProfileToIndex(EProfile profile)
return index;
}
const int SourceCount = 2;
int MapSourceToIndex(EShSource source)
{
int index = 0;
switch (source) {
case EShSourceGlsl: index = 0; break;
case EShSourceHlsl: index = 1; break;
default: break;
}
assert(index < SourceCount);
return index;
}
// only one of these needed for non-ES; ES needs 2 for different precision defaults of built-ins
enum EPrecisionClass {
EPcGeneral,
@ -161,8 +180,8 @@ enum EPrecisionClass {
// Each has a different set of built-ins, and we want to preserve that from
// compile to compile.
//
TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][EPcCount] = {};
TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][EShLangCount] = {};
TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {};
TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {};
TPoolAllocator* PerProcessGPA = 0;
@ -305,7 +324,8 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
int versionIndex = MapVersionToIndex(version);
int spvVersionIndex = MapSpvVersionToIndex(spvVersion);
int profileIndex = MapProfileToIndex(profile);
if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][EPcGeneral]) {
int sourceIndex = MapSourceToIndex(source);
if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) {
glslang::ReleaseGlobalLock();
return;
@ -333,18 +353,18 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
// Copy the local symbol tables from the new pool to the global tables using the process-global pool
for (int precClass = 0; precClass < EPcCount; ++precClass) {
if (! commonTable[precClass]->isEmpty()) {
CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][precClass] = new TSymbolTable;
CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][precClass]->copyTable(*commonTable[precClass]);
CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][precClass]->readOnly();
CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass] = new TSymbolTable;
CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->copyTable(*commonTable[precClass]);
CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][precClass]->readOnly();
}
}
for (int stage = 0; stage < EShLangCount; ++stage) {
if (! stageTables[stage]->isEmpty()) {
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][stage] = new TSymbolTable;
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][stage]->adoptLevels(*CommonSymbolTable
[versionIndex][spvVersionIndex][profileIndex][CommonIndex(profile, (EShLanguage)stage)]);
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][stage]->copyTable(*stageTables[stage]);
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][stage]->readOnly();
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage] = new TSymbolTable;
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->adoptLevels(*CommonSymbolTable
[versionIndex][spvVersionIndex][profileIndex][sourceIndex][CommonIndex(profile, (EShLanguage)stage)]);
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->copyTable(*stageTables[stage]);
SharedSymbolTables[versionIndex][spvVersionIndex][profileIndex][sourceIndex][stage]->readOnly();
}
}
@ -656,6 +676,7 @@ bool ProcessDeferred(
TSymbolTable* cachedTable = SharedSymbolTables[MapVersionToIndex(version)]
[MapSpvVersionToIndex(spvVersion)]
[MapProfileToIndex(profile)]
[MapSourceToIndex(source)]
[compiler->getLanguage()];
// Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
@ -676,10 +697,9 @@ bool ProcessDeferred(
TParseContextBase* parseContext;
if (source == EShSourceHlsl) {
parseContext = new HlslParseContext(symbolTable, intermediate, false, version, profile, spvVersion,
compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
}
else {
intermediate.setEntryPoint("main");
compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
} else {
intermediate.setEntryPointName("main");
parseContext = new TParseContext(symbolTable, intermediate, false, version, profile, spvVersion,
compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
}
@ -1030,6 +1050,7 @@ int ShInitialize()
PerProcessGPA = new TPoolAllocator();
glslang::TScanContext::fillInKeywordMap();
glslang::HlslScanContext::fillInKeywordMap();
return 1;
}
@ -1092,9 +1113,11 @@ int __fastcall ShFinalize()
for (int version = 0; version < VersionCount; ++version) {
for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
for (int p = 0; p < ProfileCount; ++p) {
for (int lang = 0; lang < EShLangCount; ++lang) {
delete SharedSymbolTables[version][spvVersion][p][lang];
SharedSymbolTables[version][spvVersion][p][lang] = 0;
for (int source = 0; source < SourceCount; ++source) {
for (int stage = 0; stage < EShLangCount; ++stage) {
delete SharedSymbolTables[version][spvVersion][p][source][stage];
SharedSymbolTables[version][spvVersion][p][source][stage] = 0;
}
}
}
}
@ -1103,9 +1126,11 @@ int __fastcall ShFinalize()
for (int version = 0; version < VersionCount; ++version) {
for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
for (int p = 0; p < ProfileCount; ++p) {
for (int pc = 0; pc < EPcCount; ++pc) {
delete CommonSymbolTable[version][spvVersion][p][pc];
CommonSymbolTable[version][spvVersion][p][pc] = 0;
for (int source = 0; source < SourceCount; ++source) {
for (int pc = 0; pc < EPcCount; ++pc) {
delete CommonSymbolTable[version][spvVersion][p][source][pc];
CommonSymbolTable[version][spvVersion][p][source][pc] = 0;
}
}
}
}
@ -1118,6 +1143,7 @@ int __fastcall ShFinalize()
}
glslang::TScanContext::deleteKeywordMap();
glslang::HlslScanContext::deleteKeywordMap();
return 1;
}
@ -1463,9 +1489,16 @@ void TShader::setStringsWithLengthsAndNames(
void TShader::setEntryPoint(const char* entryPoint)
{
intermediate->setEntryPoint(entryPoint);
intermediate->setEntryPointName(entryPoint);
}
void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShiftSamplerBinding(base); }
void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); }
void TShader::setShiftUboBinding(unsigned int base) { intermediate->setShiftUboBinding(base); }
void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); }
void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); }
void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); }
//
// Turn the shader strings into a parse tree in the TIntermediate.
//
@ -1526,7 +1559,7 @@ const char* TShader::getInfoDebugLog()
return infoSink->debug.c_str();
}
TProgram::TProgram() : pool(0), reflection(0), linked(false)
TProgram::TProgram() : pool(0), reflection(0), ioMapper(nullptr), linked(false)
{
infoSink = new TInfoSink;
for (int s = 0; s < EShLangCount; ++s) {
@ -1662,20 +1695,42 @@ bool TProgram::buildReflection()
return true;
}
int TProgram::getNumLiveUniformVariables() { return reflection->getNumUniforms(); }
int TProgram::getNumLiveUniformBlocks() { return reflection->getNumUniformBlocks(); }
const char* TProgram::getUniformName(int index) { return reflection->getUniform(index).name.c_str(); }
const char* TProgram::getUniformBlockName(int index) { return reflection->getUniformBlock(index).name.c_str(); }
int TProgram::getUniformBlockSize(int index) { return reflection->getUniformBlock(index).size; }
int TProgram::getUniformIndex(const char* name) { return reflection->getIndex(name); }
int TProgram::getUniformBlockIndex(int index) { return reflection->getUniform(index).index; }
int TProgram::getUniformType(int index) { return reflection->getUniform(index).glDefineType; }
int TProgram::getUniformBufferOffset(int index) { return reflection->getUniform(index).offset; }
int TProgram::getUniformArraySize(int index) { return reflection->getUniform(index).size; }
int TProgram::getNumLiveAttributes() { return reflection->getNumAttributes(); }
const char* TProgram::getAttributeName(int index) { return reflection->getAttribute(index).name.c_str(); }
int TProgram::getAttributeType(int index) { return reflection->getAttribute(index).glDefineType; }
int TProgram::getNumLiveUniformVariables() const { return reflection->getNumUniforms(); }
int TProgram::getNumLiveUniformBlocks() const { return reflection->getNumUniformBlocks(); }
const char* TProgram::getUniformName(int index) const { return reflection->getUniform(index).name.c_str(); }
const char* TProgram::getUniformBlockName(int index) const { return reflection->getUniformBlock(index).name.c_str(); }
int TProgram::getUniformBlockSize(int index) const { return reflection->getUniformBlock(index).size; }
int TProgram::getUniformIndex(const char* name) const { return reflection->getIndex(name); }
int TProgram::getUniformBlockIndex(int index) const { return reflection->getUniform(index).index; }
int TProgram::getUniformType(int index) const { return reflection->getUniform(index).glDefineType; }
int TProgram::getUniformBufferOffset(int index) const { return reflection->getUniform(index).offset; }
int TProgram::getUniformArraySize(int index) const { return reflection->getUniform(index).size; }
int TProgram::getNumLiveAttributes() const { return reflection->getNumAttributes(); }
const char* TProgram::getAttributeName(int index) const { return reflection->getAttribute(index).name.c_str(); }
int TProgram::getAttributeType(int index) const { return reflection->getAttribute(index).glDefineType; }
const TType* TProgram::getUniformTType(int index) const { return reflection->getUniform(index).getType(); }
const TType* TProgram::getUniformBlockTType(int index) const { return reflection->getUniformBlock(index).getType(); }
void TProgram::dumpReflection() { reflection->dump(); }
//
// I/O mapping implementation.
//
bool TProgram::mapIO()
{
if (! linked || ioMapper)
return false;
ioMapper = new TIoMapper;
for (int s = 0; s < EShLangCount; ++s) {
if (intermediate[s]) {
if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink))
return false;
}
}
return true;
}
} // end namespace glslang

View file

@ -35,7 +35,7 @@
//
//
// Symbol table for parsing. Most functionaliy and main ideas
// Symbol table for parsing. Most functionality and main ideas
// are documented in the header file.
//
@ -60,6 +60,9 @@ void TType::buildMangledName(TString& mangledName)
switch (basicType) {
case EbtFloat: mangledName += 'f'; break;
case EbtDouble: mangledName += 'd'; break;
#ifdef AMD_EXTENSIONS
case EbtFloat16: mangledName += "f16"; break;
#endif
case EbtInt: mangledName += 'i'; break;
case EbtUint: mangledName += 'u'; break;
case EbtInt64: mangledName += "i64"; break;
@ -250,7 +253,7 @@ TSymbol::TSymbol(const TSymbol& copyOf)
}
TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
{
{
type.deepCopy(copyOf.type);
userType = copyOf.userType;
numExtensions = 0;
@ -276,7 +279,7 @@ TVariable* TVariable::clone() const
}
TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
{
{
for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) {
TParameter param;
parameters.push_back(param);

View file

@ -147,7 +147,8 @@ public:
TVariable(const TString *name, const TType& t, bool uT = false )
: TSymbol(name),
userType(uT),
constSubtree(nullptr) { type.shallowCopy(t); }
constSubtree(nullptr),
anonId(-1) { type.shallowCopy(t); }
virtual TVariable* clone() const;
virtual ~TVariable() { }
@ -161,6 +162,8 @@ public:
virtual void setConstArray(const TConstUnionArray& array) { constArray = array; }
virtual void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
virtual TIntermTyped* getConstSubtree() const { return constSubtree; }
virtual void setAnonId(int i) { anonId = i; }
virtual int getAnonId() const { return anonId; }
virtual void dump(TInfoSink &infoSink) const;
@ -178,6 +181,7 @@ protected:
// constant, or neither, but never both.
TConstUnionArray constArray; // for compile-time constant value
TIntermTyped* constSubtree; // for specialization constant computation
int anonId; // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
};
//
@ -305,27 +309,16 @@ public:
//
// returning true means symbol was added to the table with no semantic errors
//
tInsertResult result;
const TString& name = symbol.getName();
if (name == "") {
symbol.getAsVariable()->setAnonId(anonId++);
// An empty name means an anonymous container, exposing its members to the external scope.
// Give it a name and insert its members in the symbol table, pointing to the container.
char buf[20];
snprintf(buf, 20, "%s%d", AnonymousPrefix, anonId);
snprintf(buf, 20, "%s%d", AnonymousPrefix, symbol.getAsVariable()->getAnonId());
symbol.changeName(NewPoolTString(buf));
bool isOkay = true;
const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
for (unsigned int m = 0; m < types.size(); ++m) {
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), anonId);
result = level.insert(tLevelPair(member->getMangledName(), member));
if (! result.second)
isOkay = false;
}
++anonId;
return isOkay;
return insertAnonymousMembers(symbol, 0);
} else {
// Check for redefinition errors:
// - STL itself will tell us if there is a direct name collision, with name mangling, at this level
@ -340,14 +333,35 @@ public:
level.insert(tLevelPair(insertName, &symbol));
return true;
} else {
result = level.insert(tLevelPair(insertName, &symbol));
return result.second;
}
} else
return level.insert(tLevelPair(insertName, &symbol)).second;
}
}
// Add more members to an already inserted aggregate object
bool amend(TSymbol& symbol, int firstNewMember)
{
// See insert() for comments on basic explanation of insert.
// This operates similarly, but more simply.
// Only supporting amend of anonymous blocks so far.
if (IsAnonymous(symbol.getName()))
return insertAnonymousMembers(symbol, firstNewMember);
else
return false;
}
bool insertAnonymousMembers(TSymbol& symbol, int firstMember)
{
const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
for (unsigned int m = firstMember; m < types.size(); ++m) {
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), symbol.getAsVariable()->getAnonId());
if (! level.insert(tLevelPair(member->getMangledName(), member)).second)
return false;
}
return true;
}
TSymbol* find(const TString& name) const
{
tLevel::const_iterator it = level.find(name);
@ -357,7 +371,7 @@ public:
return (*it).second;
}
void findFunctionNameList(const TString& name, TVector<TFunction*>& list)
void findFunctionNameList(const TString& name, TVector<const TFunction*>& list)
{
size_t parenAt = name.find_first_of('(');
TString base(name, 0, parenAt + 1);
@ -546,6 +560,14 @@ public:
return table[currentLevel()]->insert(symbol, separateNameSpaces);
}
// Add more members to an already inserted aggregate object
bool amend(TSymbol& symbol, int firstNewMember)
{
// See insert() for comments on basic explanation of insert.
// This operates similarly, but more simply.
return table[currentLevel()]->amend(symbol, firstNewMember);
}
//
// To allocate an internal temporary, which will need to be uniquely
// identified by the consumer of the AST, but never need to
@ -624,7 +646,7 @@ public:
return false;
}
void findFunctionNameList(const TString& name, TVector<TFunction*>& list, bool& builtIn)
void findFunctionNameList(const TString& name, TVector<const TFunction*>& list, bool& builtIn)
{
// For user levels, return the set found in the first scope with a match
builtIn = false;

View file

@ -187,6 +187,14 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
extensionBehavior[E_GL_GOOGLE_include_directive] = EBhDisable;
#ifdef AMD_EXTENSIONS
extensionBehavior[E_GL_AMD_shader_ballot] = EBhDisable;
extensionBehavior[E_GL_AMD_shader_trinary_minmax] = EBhDisable;
extensionBehavior[E_GL_AMD_shader_explicit_vertex_parameter] = EBhDisable;
extensionBehavior[E_GL_AMD_gcn_shader] = EBhDisable;
extensionBehavior[E_GL_AMD_gpu_shader_half_float] = EBhDisable;
#endif
// AEP
extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisable;
extensionBehavior[E_GL_KHR_blend_equation_advanced] = EBhDisable;
@ -286,6 +294,14 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_ARB_sparse_texture_clamp 1\n"
// "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
#ifdef AMD_EXTENSIONS
"#define GL_AMD_shader_ballot 1\n"
"#define GL_AMD_shader_trinary_minmax 1\n"
"#define GL_AMD_shader_explicit_vertex_parameter 1\n"
"#define GL_AMD_gcn_shader 1\n"
"#define GL_AMD_gpu_shader_half_float 1\n"
#endif
;
}
@ -649,6 +665,19 @@ void TParseVersions::doubleCheck(const TSourceLoc& loc, const char* op)
profileRequires(loc, ECompatibilityProfile, 400, nullptr, op);
}
#ifdef AMD_EXTENSIONS
// Call for any operation needing GLSL float16 data-type support.
void TParseVersions::float16Check(const TSourceLoc& loc, const char* op, bool builtIn)
{
if (!builtIn) {
requireExtensions(loc, 1, &E_GL_AMD_gpu_shader_half_float, "shader half float");
requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
profileRequires(loc, ECoreProfile, 450, nullptr, op);
profileRequires(loc, ECompatibilityProfile, 450, nullptr, op);
}
}
#endif
// Call for any operation needing GLSL 64-bit integer data-type support.
void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool builtIn)
{

View file

@ -135,6 +135,14 @@ const char* const E_GL_EXT_shader_non_constant_global_initializers = "GL_EXT_sha
const char* const E_GL_GOOGLE_cpp_style_line_directive = "GL_GOOGLE_cpp_style_line_directive";
const char* const E_GL_GOOGLE_include_directive = "GL_GOOGLE_include_directive";
#ifdef AMD_EXTENSIONS
const char* const E_GL_AMD_shader_ballot = "GL_AMD_shader_ballot";
const char* const E_GL_AMD_shader_trinary_minmax = "GL_AMD_shader_trinary_minmax";
const char* const E_GL_AMD_shader_explicit_vertex_parameter = "GL_AMD_shader_explicit_vertex_parameter";
const char* const E_GL_AMD_gcn_shader = "GL_AMD_gcn_shader";
const char* const E_GL_AMD_gpu_shader_half_float = "GL_AMD_gpu_shader_half_float";
#endif
// AEP
const char* const E_GL_ANDROID_extension_pack_es31a = "GL_ANDROID_extension_pack_es31a";
const char* const E_GL_KHR_blend_equation_advanced = "GL_KHR_blend_equation_advanced";

View file

@ -76,6 +76,24 @@
#define GL_DOUBLE_MAT4x2 0x8F4D
#define GL_DOUBLE_MAT4x3 0x8F4E
#ifdef AMD_EXTENSIONS
// Those constants are borrowed from extension NV_gpu_shader5
#define GL_FLOAT16_NV 0x8FF8
#define GL_FLOAT16_VEC2_NV 0x8FF9
#define GL_FLOAT16_VEC3_NV 0x8FFA
#define GL_FLOAT16_VEC4_NV 0x8FFB
#define GL_FLOAT16_MAT2_AMD 0x91C5
#define GL_FLOAT16_MAT3_AMD 0x91C6
#define GL_FLOAT16_MAT4_AMD 0x91C7
#define GL_FLOAT16_MAT2x3_AMD 0x91C8
#define GL_FLOAT16_MAT2x4_AMD 0x91C9
#define GL_FLOAT16_MAT3x2_AMD 0x91CA
#define GL_FLOAT16_MAT3x4_AMD 0x91CB
#define GL_FLOAT16_MAT4x2_AMD 0x91CC
#define GL_FLOAT16_MAT4x3_AMD 0x91CD
#endif
#define GL_SAMPLER_1D 0x8B5D
#define GL_SAMPLER_2D 0x8B5E
#define GL_SAMPLER_3D 0x8B5F

View file

@ -119,14 +119,15 @@ extern int yylex(YYSTYPE*, TParseContext&);
%expect 1 // One shift reduce conflict because of if | else
%token <lex> ATTRIBUTE VARYING
%token <lex> CONST BOOL FLOAT DOUBLE INT UINT INT64_T UINT64_T
%token <lex> CONST BOOL FLOAT DOUBLE INT UINT INT64_T UINT64_T FLOAT16_T
%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT SUBROUTINE
%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 I64VEC2 I64VEC3 I64VEC4 UVEC2 UVEC3 UVEC4 U64VEC2 U64VEC3 U64VEC4 VEC2 VEC3 VEC4
%token <lex> MAT2 MAT3 MAT4 CENTROID IN OUT INOUT
%token <lex> UNIFORM PATCH SAMPLE BUFFER SHARED
%token <lex> COHERENT VOLATILE RESTRICT READONLY WRITEONLY
%token <lex> DVEC2 DVEC3 DVEC4 DMAT2 DMAT3 DMAT4
%token <lex> NOPERSPECTIVE FLAT SMOOTH LAYOUT
%token <lex> F16VEC2 F16VEC3 F16VEC4 F16MAT2 F16MAT3 F16MAT4
%token <lex> NOPERSPECTIVE FLAT SMOOTH LAYOUT __EXPLICITINTERPAMD
%token <lex> MAT2X2 MAT2X3 MAT2X4
%token <lex> MAT3X2 MAT3X3 MAT3X4
@ -134,6 +135,9 @@ extern int yylex(YYSTYPE*, TParseContext&);
%token <lex> DMAT2X2 DMAT2X3 DMAT2X4
%token <lex> DMAT3X2 DMAT3X3 DMAT3X4
%token <lex> DMAT4X2 DMAT4X3 DMAT4X4
%token <lex> F16MAT2X2 F16MAT2X3 F16MAT2X4
%token <lex> F16MAT3X2 F16MAT3X3 F16MAT3X4
%token <lex> F16MAT4X2 F16MAT4X3 F16MAT4X4
%token <lex> ATOMIC_UINT
// combined image/sampler
@ -182,7 +186,7 @@ extern int yylex(YYSTYPE*, TParseContext&);
%token <lex> STRUCT VOID WHILE
%token <lex> IDENTIFIER TYPE_NAME
%token <lex> FLOATCONSTANT DOUBLECONSTANT INTCONSTANT UINTCONSTANT INT64CONSTANT UINT64CONSTANT BOOLCONSTANT
%token <lex> FLOATCONSTANT DOUBLECONSTANT INTCONSTANT UINTCONSTANT INT64CONSTANT UINT64CONSTANT BOOLCONSTANT FLOAT16CONSTANT
%token <lex> LEFT_OP RIGHT_OP
%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
@ -274,6 +278,12 @@ primary_expression
parseContext.doubleCheck($1.loc, "double literal");
$$ = parseContext.intermediate.addConstantUnion($1.d, EbtDouble, $1.loc, true);
}
| FLOAT16CONSTANT {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float literal");
$$ = parseContext.intermediate.addConstantUnion($1.d, EbtFloat16, $1.loc, true);
#endif
}
| BOOLCONSTANT {
$$ = parseContext.intermediate.addConstantUnion($1.b, $1.loc, true);
}
@ -691,6 +701,7 @@ expression
$$ = $1;
}
| expression COMMA assignment_expression {
parseContext.samplerConstructorLocationCheck($2.loc, ",", $3);
$$ = parseContext.intermediate.addComma($1, $3, $2.loc);
if ($$ == 0) {
parseContext.binaryOpError($2.loc, ",", $1->getCompleteString(), $3->getCompleteString());
@ -1050,6 +1061,15 @@ interpolation_qualifier
$$.init($1.loc);
$$.qualifier.nopersp = true;
}
| __EXPLICITINTERPAMD {
#ifdef AMD_EXTENSIONS
parseContext.globalCheck($1.loc, "__explicitInterpAMD");
parseContext.profileRequires($1.loc, ECoreProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation");
parseContext.profileRequires($1.loc, ECompatibilityProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation");
$$.init($1.loc);
$$.qualifier.explicitInterp = true;
#endif
}
;
layout_qualifier
@ -1115,6 +1135,7 @@ single_type_qualifier
$$ = $1;
}
| precision_qualifier {
parseContext.checkPrecisionQualifier($1.loc, $1.qualifier.precision);
$$ = $1;
}
| interpolation_qualifier {
@ -1313,6 +1334,13 @@ type_specifier_nonarray
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtDouble;
}
| FLOAT16_T {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
#endif
}
| INT {
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtInt;
@ -1369,6 +1397,30 @@ type_specifier_nonarray
$$.basicType = EbtDouble;
$$.setVector(4);
}
| F16VEC2 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setVector(2);
#endif
}
| F16VEC3 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setVector(3);
#endif
}
| F16VEC4 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float vector", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setVector(4);
#endif
}
| BVEC2 {
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtBool;
@ -1585,6 +1637,102 @@ type_specifier_nonarray
$$.basicType = EbtDouble;
$$.setMatrix(4, 4);
}
| F16MAT2 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(2, 2);
#endif
}
| F16MAT3 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(3, 3);
#endif
}
| F16MAT4 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(4, 4);
#endif
}
| F16MAT2X2 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(2, 2);
#endif
}
| F16MAT2X3 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(2, 3);
#endif
}
| F16MAT2X4 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(2, 4);
#endif
}
| F16MAT3X2 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(3, 2);
#endif
}
| F16MAT3X3 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(3, 3);
#endif
}
| F16MAT3X4 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(3, 4);
#endif
}
| F16MAT4X2 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(4, 2);
#endif
}
| F16MAT4X3 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(4, 3);
#endif
}
| F16MAT4X4 {
#ifdef AMD_EXTENSIONS
parseContext.float16Check($1.loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel());
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
$$.basicType = EbtFloat16;
$$.setMatrix(4, 4);
#endif
}
| ATOMIC_UINT {
parseContext.vulkanRemoved($1.loc, "atomic counter types");
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
@ -2196,20 +2344,17 @@ precision_qualifier
: HIGH_PRECISION {
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "highp precision qualifier");
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
if (parseContext.profile == EEsProfile)
$$.qualifier.precision = EpqHigh;
parseContext.handlePrecisionQualifier($1.loc, $$.qualifier, EpqHigh);
}
| MEDIUM_PRECISION {
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "mediump precision qualifier");
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
if (parseContext.profile == EEsProfile)
$$.qualifier.precision = EpqMedium;
parseContext.handlePrecisionQualifier($1.loc, $$.qualifier, EpqMedium);
}
| LOW_PRECISION {
parseContext.profileRequires($1.loc, ENoProfile, 130, 0, "lowp precision qualifier");
$$.init($1.loc, parseContext.symbolTable.atGlobalLevel());
if (parseContext.profile == EEsProfile)
$$.qualifier.precision = EpqLow;
parseContext.handlePrecisionQualifier($1.loc, $$.qualifier, EpqLow);
}
;

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,19 @@
/* A Bison parser, made by GNU Bison 3.0.4. */
/* A Bison parser, made by GNU Bison 2.7. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@ -26,13 +26,13 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED
# define YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED
/* Debug traces. */
#ifndef YY_YY_GLSLANG_TAB_CPP_H_INCLUDED
# define YY_YY_GLSLANG_TAB_CPP_H_INCLUDED
/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 1
#endif
@ -40,287 +40,306 @@
extern int yydebug;
#endif
/* Token type. */
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
ATTRIBUTE = 258,
VARYING = 259,
CONST = 260,
BOOL = 261,
FLOAT = 262,
DOUBLE = 263,
INT = 264,
UINT = 265,
INT64_T = 266,
UINT64_T = 267,
BREAK = 268,
CONTINUE = 269,
DO = 270,
ELSE = 271,
FOR = 272,
IF = 273,
DISCARD = 274,
RETURN = 275,
SWITCH = 276,
CASE = 277,
DEFAULT = 278,
SUBROUTINE = 279,
BVEC2 = 280,
BVEC3 = 281,
BVEC4 = 282,
IVEC2 = 283,
IVEC3 = 284,
IVEC4 = 285,
I64VEC2 = 286,
I64VEC3 = 287,
I64VEC4 = 288,
UVEC2 = 289,
UVEC3 = 290,
UVEC4 = 291,
U64VEC2 = 292,
U64VEC3 = 293,
U64VEC4 = 294,
VEC2 = 295,
VEC3 = 296,
VEC4 = 297,
MAT2 = 298,
MAT3 = 299,
MAT4 = 300,
CENTROID = 301,
IN = 302,
OUT = 303,
INOUT = 304,
UNIFORM = 305,
PATCH = 306,
SAMPLE = 307,
BUFFER = 308,
SHARED = 309,
COHERENT = 310,
VOLATILE = 311,
RESTRICT = 312,
READONLY = 313,
WRITEONLY = 314,
DVEC2 = 315,
DVEC3 = 316,
DVEC4 = 317,
DMAT2 = 318,
DMAT3 = 319,
DMAT4 = 320,
NOPERSPECTIVE = 321,
FLAT = 322,
SMOOTH = 323,
LAYOUT = 324,
MAT2X2 = 325,
MAT2X3 = 326,
MAT2X4 = 327,
MAT3X2 = 328,
MAT3X3 = 329,
MAT3X4 = 330,
MAT4X2 = 331,
MAT4X3 = 332,
MAT4X4 = 333,
DMAT2X2 = 334,
DMAT2X3 = 335,
DMAT2X4 = 336,
DMAT3X2 = 337,
DMAT3X3 = 338,
DMAT3X4 = 339,
DMAT4X2 = 340,
DMAT4X3 = 341,
DMAT4X4 = 342,
ATOMIC_UINT = 343,
SAMPLER1D = 344,
SAMPLER2D = 345,
SAMPLER3D = 346,
SAMPLERCUBE = 347,
SAMPLER1DSHADOW = 348,
SAMPLER2DSHADOW = 349,
SAMPLERCUBESHADOW = 350,
SAMPLER1DARRAY = 351,
SAMPLER2DARRAY = 352,
SAMPLER1DARRAYSHADOW = 353,
SAMPLER2DARRAYSHADOW = 354,
ISAMPLER1D = 355,
ISAMPLER2D = 356,
ISAMPLER3D = 357,
ISAMPLERCUBE = 358,
ISAMPLER1DARRAY = 359,
ISAMPLER2DARRAY = 360,
USAMPLER1D = 361,
USAMPLER2D = 362,
USAMPLER3D = 363,
USAMPLERCUBE = 364,
USAMPLER1DARRAY = 365,
USAMPLER2DARRAY = 366,
SAMPLER2DRECT = 367,
SAMPLER2DRECTSHADOW = 368,
ISAMPLER2DRECT = 369,
USAMPLER2DRECT = 370,
SAMPLERBUFFER = 371,
ISAMPLERBUFFER = 372,
USAMPLERBUFFER = 373,
SAMPLERCUBEARRAY = 374,
SAMPLERCUBEARRAYSHADOW = 375,
ISAMPLERCUBEARRAY = 376,
USAMPLERCUBEARRAY = 377,
SAMPLER2DMS = 378,
ISAMPLER2DMS = 379,
USAMPLER2DMS = 380,
SAMPLER2DMSARRAY = 381,
ISAMPLER2DMSARRAY = 382,
USAMPLER2DMSARRAY = 383,
SAMPLEREXTERNALOES = 384,
SAMPLER = 385,
SAMPLERSHADOW = 386,
TEXTURE1D = 387,
TEXTURE2D = 388,
TEXTURE3D = 389,
TEXTURECUBE = 390,
TEXTURE1DARRAY = 391,
TEXTURE2DARRAY = 392,
ITEXTURE1D = 393,
ITEXTURE2D = 394,
ITEXTURE3D = 395,
ITEXTURECUBE = 396,
ITEXTURE1DARRAY = 397,
ITEXTURE2DARRAY = 398,
UTEXTURE1D = 399,
UTEXTURE2D = 400,
UTEXTURE3D = 401,
UTEXTURECUBE = 402,
UTEXTURE1DARRAY = 403,
UTEXTURE2DARRAY = 404,
TEXTURE2DRECT = 405,
ITEXTURE2DRECT = 406,
UTEXTURE2DRECT = 407,
TEXTUREBUFFER = 408,
ITEXTUREBUFFER = 409,
UTEXTUREBUFFER = 410,
TEXTURECUBEARRAY = 411,
ITEXTURECUBEARRAY = 412,
UTEXTURECUBEARRAY = 413,
TEXTURE2DMS = 414,
ITEXTURE2DMS = 415,
UTEXTURE2DMS = 416,
TEXTURE2DMSARRAY = 417,
ITEXTURE2DMSARRAY = 418,
UTEXTURE2DMSARRAY = 419,
SUBPASSINPUT = 420,
SUBPASSINPUTMS = 421,
ISUBPASSINPUT = 422,
ISUBPASSINPUTMS = 423,
USUBPASSINPUT = 424,
USUBPASSINPUTMS = 425,
IMAGE1D = 426,
IIMAGE1D = 427,
UIMAGE1D = 428,
IMAGE2D = 429,
IIMAGE2D = 430,
UIMAGE2D = 431,
IMAGE3D = 432,
IIMAGE3D = 433,
UIMAGE3D = 434,
IMAGE2DRECT = 435,
IIMAGE2DRECT = 436,
UIMAGE2DRECT = 437,
IMAGECUBE = 438,
IIMAGECUBE = 439,
UIMAGECUBE = 440,
IMAGEBUFFER = 441,
IIMAGEBUFFER = 442,
UIMAGEBUFFER = 443,
IMAGE1DARRAY = 444,
IIMAGE1DARRAY = 445,
UIMAGE1DARRAY = 446,
IMAGE2DARRAY = 447,
IIMAGE2DARRAY = 448,
UIMAGE2DARRAY = 449,
IMAGECUBEARRAY = 450,
IIMAGECUBEARRAY = 451,
UIMAGECUBEARRAY = 452,
IMAGE2DMS = 453,
IIMAGE2DMS = 454,
UIMAGE2DMS = 455,
IMAGE2DMSARRAY = 456,
IIMAGE2DMSARRAY = 457,
UIMAGE2DMSARRAY = 458,
STRUCT = 459,
VOID = 460,
WHILE = 461,
IDENTIFIER = 462,
TYPE_NAME = 463,
FLOATCONSTANT = 464,
DOUBLECONSTANT = 465,
INTCONSTANT = 466,
UINTCONSTANT = 467,
INT64CONSTANT = 468,
UINT64CONSTANT = 469,
BOOLCONSTANT = 470,
LEFT_OP = 471,
RIGHT_OP = 472,
INC_OP = 473,
DEC_OP = 474,
LE_OP = 475,
GE_OP = 476,
EQ_OP = 477,
NE_OP = 478,
AND_OP = 479,
OR_OP = 480,
XOR_OP = 481,
MUL_ASSIGN = 482,
DIV_ASSIGN = 483,
ADD_ASSIGN = 484,
MOD_ASSIGN = 485,
LEFT_ASSIGN = 486,
RIGHT_ASSIGN = 487,
AND_ASSIGN = 488,
XOR_ASSIGN = 489,
OR_ASSIGN = 490,
SUB_ASSIGN = 491,
LEFT_PAREN = 492,
RIGHT_PAREN = 493,
LEFT_BRACKET = 494,
RIGHT_BRACKET = 495,
LEFT_BRACE = 496,
RIGHT_BRACE = 497,
DOT = 498,
COMMA = 499,
COLON = 500,
EQUAL = 501,
SEMICOLON = 502,
BANG = 503,
DASH = 504,
TILDE = 505,
PLUS = 506,
STAR = 507,
SLASH = 508,
PERCENT = 509,
LEFT_ANGLE = 510,
RIGHT_ANGLE = 511,
VERTICAL_BAR = 512,
CARET = 513,
AMPERSAND = 514,
QUESTION = 515,
INVARIANT = 516,
PRECISE = 517,
HIGH_PRECISION = 518,
MEDIUM_PRECISION = 519,
LOW_PRECISION = 520,
PRECISION = 521,
PACKED = 522,
RESOURCE = 523,
SUPERP = 524
};
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
ATTRIBUTE = 258,
VARYING = 259,
CONST = 260,
BOOL = 261,
FLOAT = 262,
DOUBLE = 263,
INT = 264,
UINT = 265,
INT64_T = 266,
UINT64_T = 267,
FLOAT16_T = 268,
BREAK = 269,
CONTINUE = 270,
DO = 271,
ELSE = 272,
FOR = 273,
IF = 274,
DISCARD = 275,
RETURN = 276,
SWITCH = 277,
CASE = 278,
DEFAULT = 279,
SUBROUTINE = 280,
BVEC2 = 281,
BVEC3 = 282,
BVEC4 = 283,
IVEC2 = 284,
IVEC3 = 285,
IVEC4 = 286,
I64VEC2 = 287,
I64VEC3 = 288,
I64VEC4 = 289,
UVEC2 = 290,
UVEC3 = 291,
UVEC4 = 292,
U64VEC2 = 293,
U64VEC3 = 294,
U64VEC4 = 295,
VEC2 = 296,
VEC3 = 297,
VEC4 = 298,
MAT2 = 299,
MAT3 = 300,
MAT4 = 301,
CENTROID = 302,
IN = 303,
OUT = 304,
INOUT = 305,
UNIFORM = 306,
PATCH = 307,
SAMPLE = 308,
BUFFER = 309,
SHARED = 310,
COHERENT = 311,
VOLATILE = 312,
RESTRICT = 313,
READONLY = 314,
WRITEONLY = 315,
DVEC2 = 316,
DVEC3 = 317,
DVEC4 = 318,
DMAT2 = 319,
DMAT3 = 320,
DMAT4 = 321,
F16VEC2 = 322,
F16VEC3 = 323,
F16VEC4 = 324,
F16MAT2 = 325,
F16MAT3 = 326,
F16MAT4 = 327,
NOPERSPECTIVE = 328,
FLAT = 329,
SMOOTH = 330,
LAYOUT = 331,
__EXPLICITINTERPAMD = 332,
MAT2X2 = 333,
MAT2X3 = 334,
MAT2X4 = 335,
MAT3X2 = 336,
MAT3X3 = 337,
MAT3X4 = 338,
MAT4X2 = 339,
MAT4X3 = 340,
MAT4X4 = 341,
DMAT2X2 = 342,
DMAT2X3 = 343,
DMAT2X4 = 344,
DMAT3X2 = 345,
DMAT3X3 = 346,
DMAT3X4 = 347,
DMAT4X2 = 348,
DMAT4X3 = 349,
DMAT4X4 = 350,
F16MAT2X2 = 351,
F16MAT2X3 = 352,
F16MAT2X4 = 353,
F16MAT3X2 = 354,
F16MAT3X3 = 355,
F16MAT3X4 = 356,
F16MAT4X2 = 357,
F16MAT4X3 = 358,
F16MAT4X4 = 359,
ATOMIC_UINT = 360,
SAMPLER1D = 361,
SAMPLER2D = 362,
SAMPLER3D = 363,
SAMPLERCUBE = 364,
SAMPLER1DSHADOW = 365,
SAMPLER2DSHADOW = 366,
SAMPLERCUBESHADOW = 367,
SAMPLER1DARRAY = 368,
SAMPLER2DARRAY = 369,
SAMPLER1DARRAYSHADOW = 370,
SAMPLER2DARRAYSHADOW = 371,
ISAMPLER1D = 372,
ISAMPLER2D = 373,
ISAMPLER3D = 374,
ISAMPLERCUBE = 375,
ISAMPLER1DARRAY = 376,
ISAMPLER2DARRAY = 377,
USAMPLER1D = 378,
USAMPLER2D = 379,
USAMPLER3D = 380,
USAMPLERCUBE = 381,
USAMPLER1DARRAY = 382,
USAMPLER2DARRAY = 383,
SAMPLER2DRECT = 384,
SAMPLER2DRECTSHADOW = 385,
ISAMPLER2DRECT = 386,
USAMPLER2DRECT = 387,
SAMPLERBUFFER = 388,
ISAMPLERBUFFER = 389,
USAMPLERBUFFER = 390,
SAMPLERCUBEARRAY = 391,
SAMPLERCUBEARRAYSHADOW = 392,
ISAMPLERCUBEARRAY = 393,
USAMPLERCUBEARRAY = 394,
SAMPLER2DMS = 395,
ISAMPLER2DMS = 396,
USAMPLER2DMS = 397,
SAMPLER2DMSARRAY = 398,
ISAMPLER2DMSARRAY = 399,
USAMPLER2DMSARRAY = 400,
SAMPLEREXTERNALOES = 401,
SAMPLER = 402,
SAMPLERSHADOW = 403,
TEXTURE1D = 404,
TEXTURE2D = 405,
TEXTURE3D = 406,
TEXTURECUBE = 407,
TEXTURE1DARRAY = 408,
TEXTURE2DARRAY = 409,
ITEXTURE1D = 410,
ITEXTURE2D = 411,
ITEXTURE3D = 412,
ITEXTURECUBE = 413,
ITEXTURE1DARRAY = 414,
ITEXTURE2DARRAY = 415,
UTEXTURE1D = 416,
UTEXTURE2D = 417,
UTEXTURE3D = 418,
UTEXTURECUBE = 419,
UTEXTURE1DARRAY = 420,
UTEXTURE2DARRAY = 421,
TEXTURE2DRECT = 422,
ITEXTURE2DRECT = 423,
UTEXTURE2DRECT = 424,
TEXTUREBUFFER = 425,
ITEXTUREBUFFER = 426,
UTEXTUREBUFFER = 427,
TEXTURECUBEARRAY = 428,
ITEXTURECUBEARRAY = 429,
UTEXTURECUBEARRAY = 430,
TEXTURE2DMS = 431,
ITEXTURE2DMS = 432,
UTEXTURE2DMS = 433,
TEXTURE2DMSARRAY = 434,
ITEXTURE2DMSARRAY = 435,
UTEXTURE2DMSARRAY = 436,
SUBPASSINPUT = 437,
SUBPASSINPUTMS = 438,
ISUBPASSINPUT = 439,
ISUBPASSINPUTMS = 440,
USUBPASSINPUT = 441,
USUBPASSINPUTMS = 442,
IMAGE1D = 443,
IIMAGE1D = 444,
UIMAGE1D = 445,
IMAGE2D = 446,
IIMAGE2D = 447,
UIMAGE2D = 448,
IMAGE3D = 449,
IIMAGE3D = 450,
UIMAGE3D = 451,
IMAGE2DRECT = 452,
IIMAGE2DRECT = 453,
UIMAGE2DRECT = 454,
IMAGECUBE = 455,
IIMAGECUBE = 456,
UIMAGECUBE = 457,
IMAGEBUFFER = 458,
IIMAGEBUFFER = 459,
UIMAGEBUFFER = 460,
IMAGE1DARRAY = 461,
IIMAGE1DARRAY = 462,
UIMAGE1DARRAY = 463,
IMAGE2DARRAY = 464,
IIMAGE2DARRAY = 465,
UIMAGE2DARRAY = 466,
IMAGECUBEARRAY = 467,
IIMAGECUBEARRAY = 468,
UIMAGECUBEARRAY = 469,
IMAGE2DMS = 470,
IIMAGE2DMS = 471,
UIMAGE2DMS = 472,
IMAGE2DMSARRAY = 473,
IIMAGE2DMSARRAY = 474,
UIMAGE2DMSARRAY = 475,
STRUCT = 476,
VOID = 477,
WHILE = 478,
IDENTIFIER = 479,
TYPE_NAME = 480,
FLOATCONSTANT = 481,
DOUBLECONSTANT = 482,
INTCONSTANT = 483,
UINTCONSTANT = 484,
INT64CONSTANT = 485,
UINT64CONSTANT = 486,
BOOLCONSTANT = 487,
FLOAT16CONSTANT = 488,
LEFT_OP = 489,
RIGHT_OP = 490,
INC_OP = 491,
DEC_OP = 492,
LE_OP = 493,
GE_OP = 494,
EQ_OP = 495,
NE_OP = 496,
AND_OP = 497,
OR_OP = 498,
XOR_OP = 499,
MUL_ASSIGN = 500,
DIV_ASSIGN = 501,
ADD_ASSIGN = 502,
MOD_ASSIGN = 503,
LEFT_ASSIGN = 504,
RIGHT_ASSIGN = 505,
AND_ASSIGN = 506,
XOR_ASSIGN = 507,
OR_ASSIGN = 508,
SUB_ASSIGN = 509,
LEFT_PAREN = 510,
RIGHT_PAREN = 511,
LEFT_BRACKET = 512,
RIGHT_BRACKET = 513,
LEFT_BRACE = 514,
RIGHT_BRACE = 515,
DOT = 516,
COMMA = 517,
COLON = 518,
EQUAL = 519,
SEMICOLON = 520,
BANG = 521,
DASH = 522,
TILDE = 523,
PLUS = 524,
STAR = 525,
SLASH = 526,
PERCENT = 527,
LEFT_ANGLE = 528,
RIGHT_ANGLE = 529,
VERTICAL_BAR = 530,
CARET = 531,
AMPERSAND = 532,
QUESTION = 533,
INVARIANT = 534,
PRECISE = 535,
HIGH_PRECISION = 536,
MEDIUM_PRECISION = 537,
LOW_PRECISION = 538,
PRECISION = 539,
PACKED = 540,
RESOURCE = 541,
SUPERP = 542
};
#endif
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
#line 66 "MachineIndependent/glslang.y" /* yacc.c:1909 */
/* Line 2058 of yacc.c */
#line 66 "glslang.y"
struct {
glslang::TSourceLoc loc;
@ -354,16 +373,28 @@ union YYSTYPE
};
} interm;
#line 358 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
/* Line 2058 of yacc.c */
#line 379 "glslang_tab.cpp.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
#else
int yyparse ();
#endif
#else /* ! YYPARSE_PARAM */
#if defined __STDC__ || defined __cplusplus
int yyparse (glslang::TParseContext* pParseContext);
#else
int yyparse ();
#endif
#endif /* ! YYPARSE_PARAM */
#endif /* !YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED */
#endif /* !YY_YY_GLSLANG_TAB_CPP_H_INCLUDED */

View file

@ -38,11 +38,9 @@
#include "../Include/InfoSink.h"
#ifdef _MSC_VER
#include <float.h>
#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__
#include <cmath>
#include <cfloat>
#else
#include <math.h>
#include <cmath>
#endif
namespace {
@ -50,10 +48,8 @@ namespace {
bool is_positive_infinity(double x) {
#ifdef _MSC_VER
return _fpclass(x) == _FPCLASS_PINF;
#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__
return std::isinf(x) && (x >= 0);
#else
return isinf(x) && (x >= 0);
return std::isinf(x) && (x >= 0);
#endif
}
@ -308,6 +304,11 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpPackUint2x32: out.debug << "packUint2x32"; break;
case EOpUnpackUint2x32: out.debug << "unpackUint2x32"; break;
#ifdef AMD_EXTENSIONS
case EOpPackFloat2x16: out.debug << "packFloat2x16"; break;
case EOpUnpackFloat2x16: out.debug << "unpackFloat2x16"; break;
#endif
case EOpLength: out.debug << "length"; break;
case EOpNormalize: out.debug << "normalize"; break;
case EOpDPdx: out.debug << "dPdx"; break;
@ -355,6 +356,7 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpBallot: out.debug << "ballot"; break;
case EOpReadFirstInvocation: out.debug << "readFirstInvocation"; break;
case EOpAnyInvocation: out.debug << "anyInvocation"; break;
case EOpAllInvocations: out.debug << "allInvocations"; break;
case EOpAllInvocationsEqual: out.debug << "allInvocationsEqual"; break;
@ -365,6 +367,34 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpRcp: out.debug << "rcp"; break;
case EOpSaturate: out.debug << "saturate"; break;
#ifdef AMD_EXTENSIONS
case EOpMinInvocations: out.debug << "minInvocations"; break;
case EOpMaxInvocations: out.debug << "maxInvocations"; break;
case EOpAddInvocations: out.debug << "addInvocations"; break;
case EOpMinInvocationsNonUniform: out.debug << "minInvocationsNonUniform"; break;
case EOpMaxInvocationsNonUniform: out.debug << "maxInvocationsNonUniform"; break;
case EOpAddInvocationsNonUniform: out.debug << "addInvocationsNonUniform"; break;
case EOpMbcnt: out.debug << "mbcnt"; break;
case EOpCubeFaceIndex: out.debug << "cubeFaceIndex"; break;
case EOpCubeFaceCoord: out.debug << "cubeFaceCoord"; break;
case EOpConvBoolToFloat16: out.debug << "Convert bool to float16"; break;
case EOpConvIntToFloat16: out.debug << "Convert int to float16"; break;
case EOpConvUintToFloat16: out.debug << "Convert uint to float16"; break;
case EOpConvFloatToFloat16: out.debug << "Convert float to float16"; break;
case EOpConvDoubleToFloat16: out.debug << "Convert double to float16"; break;
case EOpConvInt64ToFloat16: out.debug << "Convert int64 to float16"; break;
case EOpConvUint64ToFloat16: out.debug << "Convert uint64 to float16"; break;
case EOpConvFloat16ToBool: out.debug << "Convert float16 to bool"; break;
case EOpConvFloat16ToInt: out.debug << "Convert float16 to int"; break;
case EOpConvFloat16ToUint: out.debug << "Convert float16 to uint"; break;
case EOpConvFloat16ToFloat: out.debug << "Convert float16 to float"; break;
case EOpConvFloat16ToDouble: out.debug << "Convert float16 to double"; break;
case EOpConvFloat16ToInt64: out.debug << "Convert float16 to int64"; break;
case EOpConvFloat16ToUint64: out.debug << "Convert float16 to uint64"; break;
#endif
default: out.debug.message(EPrefixError, "Bad unary op");
}
@ -437,6 +467,21 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpConstructDMat4x2: out.debug << "Construct dmat4x2"; break;
case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break;
case EOpConstructDMat4x4: out.debug << "Construct dmat4"; break;
#ifdef AMD_EXTENSIONS
case EOpConstructFloat16: out.debug << "Construct float16_t"; break;
case EOpConstructF16Vec2: out.debug << "Construct f16vec2"; break;
case EOpConstructF16Vec3: out.debug << "Construct f16vec3"; break;
case EOpConstructF16Vec4: out.debug << "Construct f16vec4"; break;
case EOpConstructF16Mat2x2: out.debug << "Construct f16mat2"; break;
case EOpConstructF16Mat2x3: out.debug << "Construct f16mat2x3"; break;
case EOpConstructF16Mat2x4: out.debug << "Construct f16mat2x4"; break;
case EOpConstructF16Mat3x2: out.debug << "Construct f16mat3x2"; break;
case EOpConstructF16Mat3x3: out.debug << "Construct f16mat3"; break;
case EOpConstructF16Mat3x4: out.debug << "Construct f16mat3x4"; break;
case EOpConstructF16Mat4x2: out.debug << "Construct f16mat4x2"; break;
case EOpConstructF16Mat4x3: out.debug << "Construct f16mat4x3"; break;
case EOpConstructF16Mat4x4: out.debug << "Construct f16mat4"; break;
#endif
case EOpConstructStruct: out.debug << "Construct structure"; break;
case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
@ -482,6 +527,18 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpReadInvocation: out.debug << "readInvocation"; break;
#ifdef AMD_EXTENSIONS
case EOpSwizzleInvocations: out.debug << "swizzleInvocations"; break;
case EOpSwizzleInvocationsMasked: out.debug << "swizzleInvocationsMasked"; break;
case EOpWriteInvocation: out.debug << "writeInvocation"; break;
case EOpMin3: out.debug << "min3"; break;
case EOpMax3: out.debug << "max3"; break;
case EOpMid3: out.debug << "mid3"; break;
case EOpTime: out.debug << "time"; break;
#endif
case EOpAtomicAdd: out.debug << "AtomicAdd"; break;
case EOpAtomicMin: out.debug << "AtomicMin"; break;
case EOpAtomicMax: out.debug << "AtomicMax"; break;
@ -539,6 +596,9 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpInterpolateAtSample: out.debug << "interpolateAtSample"; break;
case EOpInterpolateAtOffset: out.debug << "interpolateAtOffset"; break;
#ifdef AMD_EXTENSIONS
case EOpInterpolateAtVertex: out.debug << "interpolateAtVertex"; break;
#endif
case EOpSinCos: out.debug << "sincos"; break;
case EOpGenMul: out.debug << "mul"; break;
@ -611,6 +671,9 @@ static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const
break;
case EbtFloat:
case EbtDouble:
#ifdef AMD_EXTENSIONS
case EbtFloat16:
#endif
{
const double value = constUnion[i].getDConst();
// Print infinity in a portable way, for test stability.

View file

@ -0,0 +1,270 @@
//
//Copyright (C) 2016 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.
//
#include "../Include/Common.h"
#include "../Include/InfoSink.h"
#include "iomapper.h"
#include "LiveTraverser.h"
#include "localintermediate.h"
#include "gl_types.h"
#include <unordered_set>
#include <unordered_map>
//
// Map IO bindings.
//
// High-level algorithm for one stage:
//
// 1. Traverse all code (live+dead) to find the explicitly provided bindings.
//
// 2. Traverse (just) the live code to determine which non-provided bindings
// require auto-numbering. We do not auto-number dead ones.
//
// 3. Traverse all the code to apply the bindings:
// a. explicitly given bindings are offset according to their type
// b. implicit live bindings are auto-numbered into the holes, using
// any open binding slot.
// c. implicit dead bindings are left un-bound.
//
namespace glslang {
// Map of IDs to bindings
typedef std::unordered_map<unsigned int, int> TBindingMap;
typedef std::unordered_set<int> TUsedBindings;
// This traverses the AST to determine which bindings are used, and which are implicit
// (for subsequent auto-numbering)
class TBindingTraverser : public TLiveTraverser {
public:
TBindingTraverser(const TIntermediate& i, TBindingMap& bindingMap, TUsedBindings& usedBindings,
bool traverseDeadCode = false) :
TLiveTraverser(i, traverseDeadCode, true, true, false),
bindingMap(bindingMap),
usedBindings(usedBindings)
{ }
protected:
virtual void visitSymbol(TIntermSymbol* base) {
if (base->getQualifier().storage == EvqUniform)
addUniform(*base);
}
// Return the right binding base given the variable type.
int getBindingBase(const TType& type) {
if (type.getBasicType() == EbtSampler) {
const TSampler& sampler = type.getSampler();
if (sampler.isPureSampler())
return intermediate.getShiftSamplerBinding();
if (sampler.isTexture())
return intermediate.getShiftTextureBinding();
}
if (type.getQualifier().isUniformOrBuffer())
return intermediate.getShiftUboBinding();
return -1; // not a type with a binding
}
// Mark a given base symbol ID as being bound to 'binding'
void markBinding(const TIntermSymbol& base, int binding) {
bindingMap[base.getId()] = binding;
if (binding >= 0) {
// const TType& type = base.getType();
const unsigned int size = 1; // type.isArray() ? type.getCumulativeArraySize() : 1;
for (unsigned int offset=0; offset<size; ++offset)
usedBindings.insert(binding + offset);
}
}
// Mark the bindings that are given explicitly, and set ones that need
// implicit bindings to -1 for a subsequent pass. (Can't happen in this
// pass because explicit bindings in dead code reserve the location).
virtual void addUniform(TIntermSymbol& base)
{
// Skip ones we've already seen.
if (bindingMap.find(base.getId()) != bindingMap.end())
return;
const TType& type = base.getType();
const int bindingBase = getBindingBase(type);
// Return if it's not a type we bind
if (bindingBase == -1)
return;
if (type.getQualifier().hasBinding()) {
// It has a binding: keep that one.
markBinding(base, type.getQualifier().layoutBinding + bindingBase);
} else if (!traverseAll) {
// Mark it as something we need to dynamically create a binding for,
// only if we're walking just the live code. We don't auto-number
// in dead code.
markBinding(base, -1);
}
}
TBindingMap& bindingMap;
TUsedBindings& usedBindings;
};
// This traverses the AST and applies binding maps it's given.
class TIoMappingTraverser : public TBindingTraverser {
public:
TIoMappingTraverser(TIntermediate& i, TBindingMap& bindingMap, TUsedBindings& usedBindings,
TInfoSink& infoSink, bool traverseDeadCode) :
TBindingTraverser(i, bindingMap, usedBindings, traverseDeadCode),
infoSink(infoSink),
assignError(false)
{ }
bool success() const { return !assignError; }
protected:
unsigned checkBindingRange(const TIntermSymbol& base, unsigned binding)
{
if (binding >= TQualifier::layoutBindingEnd) {
TString err = "mapped binding out of range: ";
err += base.getName();
infoSink.info.message(EPrefixInternalError, err.c_str());
assignError = true;
return 0;
}
return binding;
}
void addUniform(TIntermSymbol& base) override
{
// Skip things we don't intend to bind.
if (bindingMap.find(base.getId()) == bindingMap.end())
return;
const int existingBinding = bindingMap[base.getId()];
// Apply existing binding, if we were given one or already made one up.
if (existingBinding != -1) {
base.getWritableType().getQualifier().layoutBinding = checkBindingRange(base, existingBinding);
return;
}
if (intermediate.getAutoMapBindings()) {
// Otherwise, find a free spot for it.
const int freeBinding = getFreeBinding(base.getType(), getBindingBase(base.getType()));
markBinding(base, freeBinding);
base.getWritableType().getQualifier().layoutBinding = checkBindingRange(base, freeBinding);
}
}
// Search for N free consecutive binding slots in [base, base+required).
// E.g, if we want to reserve consecutive bindings for flattened arrays.
bool hasNFreeSlots(int base, int required) {
for (int binding = base; binding < (base + required); ++binding)
if (usedBindings.find(binding) != usedBindings.end())
return false;
return true;
}
// Find a free binding spot
int getFreeBinding(const TType&, int nextBinding) {
while (!hasNFreeSlots(nextBinding, 1))
++nextBinding;
return nextBinding;
}
private:
bool assignError; // true if there was an error assigning the bindings
TInfoSink& infoSink;
};
// Map I/O variables to provided offsets, and make bindings for
// unbound but live variables.
//
// Returns false if the input is too malformed to do this.
bool TIoMapper::addStage(EShLanguage, TIntermediate& intermediate, TInfoSink& infoSink)
{
// Trivial return if there is nothing to do.
if (intermediate.getShiftSamplerBinding() == 0 &&
intermediate.getShiftTextureBinding() == 0 &&
intermediate.getShiftUboBinding() == 0 &&
intermediate.getAutoMapBindings() == false)
return true;
if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
return false;
TIntermNode* root = intermediate.getTreeRoot();
if (root == nullptr)
return false;
// The lifetime of this data spans several passes.
TBindingMap bindingMap;
TUsedBindings usedBindings;
TBindingTraverser it_binding_all(intermediate, bindingMap, usedBindings, true);
TBindingTraverser it_binding_live(intermediate, bindingMap, usedBindings, false);
TIoMappingTraverser it_iomap(intermediate, bindingMap, usedBindings, infoSink, true);
// Traverse all (live+dead) code to find explicit bindings, so we can avoid those.
root->traverse(&it_binding_all);
// Traverse just live code to find things that need implicit bindings.
it_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str());
while (! it_binding_live.functions.empty()) {
TIntermNode* function = it_binding_live.functions.back();
it_binding_live.functions.pop_back();
function->traverse(&it_binding_live);
}
// Bind everything that needs a binding and doesn't have one.
root->traverse(&it_iomap);
return it_iomap.success();
}
} // end namespace glslang

View file

@ -0,0 +1,63 @@
//
//Copyright (C) 2016 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 _IOMAPPER_INCLUDED
#define _IOMAPPER_INCLUDED
#include "../Public/ShaderLang.h"
//
// A reflection database and its interface, consistent with the OpenGL API reflection queries.
//
class TInfoSink;
namespace glslang {
class TIntermediate;
// I/O mapper
class TIoMapper {
public:
TIoMapper() {}
virtual ~TIoMapper() {}
// grow the reflection stage by stage
bool addStage(EShLanguage, TIntermediate&, TInfoSink&);
};
} // end namespace glslang
#endif // _IOMAPPER_INCLUDED

View file

@ -75,13 +75,13 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
if (source != unit.source)
error(infoSink, "can't link compilation units from different source languages");
if (source == EShSourceHlsl && unit.entryPoint.size() > 0) {
if (entryPoint.size() > 0)
if (source == EShSourceHlsl && unit.getNumEntryPoints() > 0) {
if (getNumEntryPoints() > 0)
error(infoSink, "can't handle multiple entry points per stage");
else
entryPoint = unit.entryPoint;
entryPointName = unit.entryPointName;
}
numMains += unit.numMains;
numEntryPoints += unit.numEntryPoints;
numErrors += unit.numErrors;
numPushConstants += unit.numPushConstants;
callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end());
@ -370,8 +370,8 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
//
void TIntermediate::finalCheck(TInfoSink& infoSink)
{
if (source == EShSourceGlsl && numMains < 1)
error(infoSink, "Missing entry point: Each stage requires one \"void main()\" entry point");
if (source == EShSourceGlsl && numEntryPoints < 1)
error(infoSink, "Missing entry point: Each stage requires one entry point");
if (numPushConstants > 1)
error(infoSink, "Only one push_constant block is allowed per stage");
@ -651,7 +651,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
int size;
if (qualifier.isUniformOrBuffer()) {
if (type.isArray())
if (type.isExplicitlySizedArray())
size = type.getCumulativeArraySize();
else
size = 1;
@ -664,30 +664,93 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
size = computeTypeLocationSize(type);
}
TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1);
TRange componentRange(0, 3);
if (qualifier.hasComponent()) {
componentRange.start = qualifier.layoutComponent;
componentRange.last = componentRange.start + type.getVectorSize() - 1;
}
TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.layoutIndex : 0);
// Locations, and components within locations.
//
// Almost always, dealing with components means a single location is involved.
// The exception is a dvec3. From the spec:
//
// "A dvec3 will consume all four components of the first location and components 0 and 1 of
// the second location. This leaves components 2 and 3 available for other component-qualified
// declarations."
//
// That means, without ever mentioning a component, a component range
// for a different location gets specified, if it's not a vertex shader input. (!)
// (A vertex shader input will show using only one location, even for a dvec3/4.)
//
// So, for the case of dvec3, we need two independent ioRanges.
// check for collisions, except for vertex inputs on desktop
if (! (profile != EEsProfile && language == EShLangVertex && qualifier.isPipeInput())) {
for (size_t r = 0; r < usedIo[set].size(); ++r) {
if (range.overlap(usedIo[set][r])) {
// there is a collision; pick one
return std::max(locationRange.start, usedIo[set][r].location.start);
} else if (locationRange.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) {
// aliased-type mismatch
typeCollision = true;
return std::max(locationRange.start, usedIo[set][r].location.start);
}
int collision = -1; // no collision
if (size == 2 && type.getBasicType() == EbtDouble && type.getVectorSize() == 3 &&
(qualifier.isPipeInput() || qualifier.isPipeOutput())) {
// Dealing with dvec3 in/out split across two locations.
// Need two io-ranges.
// The case where the dvec3 doesn't start at component 0 was previously caught as overflow.
// First range:
TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation);
TRange componentRange(0, 3);
TIoRange range(locationRange, componentRange, type.getBasicType(), 0);
// check for collisions
collision = checkLocationRange(set, range, type, typeCollision);
if (collision < 0) {
usedIo[set].push_back(range);
// Second range:
TRange locationRange2(qualifier.layoutLocation + 1, qualifier.layoutLocation + 1);
TRange componentRange2(0, 1);
TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0);
// check for collisions
collision = checkLocationRange(set, range2, type, typeCollision);
if (collision < 0)
usedIo[set].push_back(range2);
}
} else {
// Not a dvec3 in/out split across two locations, generic path.
// Need a single IO-range block.
TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1);
TRange componentRange(0, 3);
if (qualifier.hasComponent() || type.getVectorSize() > 0) {
int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1);
if (qualifier.hasComponent())
componentRange.start = qualifier.layoutComponent;
componentRange.last = componentRange.start + consumedComponents - 1;
}
// combine location and component ranges
TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.layoutIndex : 0);
// check for collisions, except for vertex inputs on desktop
if (! (profile != EEsProfile && language == EShLangVertex && qualifier.isPipeInput()))
collision = checkLocationRange(set, range, type, typeCollision);
if (collision < 0)
usedIo[set].push_back(range);
}
return collision;
}
// Compare a new (the passed in) 'range' against the existing set, and see
// if there are any collisions.
//
// Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value.
//
int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TType& type, bool& typeCollision)
{
for (size_t r = 0; r < usedIo[set].size(); ++r) {
if (range.overlap(usedIo[set][r])) {
// there is a collision; pick one
return std::max(range.location.start, usedIo[set][r].location.start);
} else if (range.location.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) {
// aliased-type mismatch
typeCollision = true;
return std::max(range.location.start, usedIo[set][r].location.start);
}
}
usedIo[set].push_back(range);
return -1; // no collision
}
@ -887,6 +950,9 @@ int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size)
case EbtInt64:
case EbtUint64:
case EbtDouble: size = 8; return 8;
#ifdef AMD_EXTENSIONS
case EbtFloat16: size = 2; return 2;
#endif
default: size = 4; return 4;
}
}
@ -940,7 +1006,7 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b
// components each, according to rule (4).
//
// 6. If the member is an array of S column-major matrices with C columns and
// R rows, the matrix is stored identically to a row of S  C column vectors
// R rows, the matrix is stored identically to a row of S X C column vectors
// with R components each, according to rule (4).
//
// 7. If the member is a row-major matrix with C columns and R rows, the matrix
@ -948,7 +1014,7 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, b
// according to rule (4).
//
// 8. If the member is an array of S row-major matrices with C columns and R
// rows, the matrix is stored identically to a row of S  R row vectors with C
// rows, the matrix is stored identically to a row of S X R row vectors with C
// components each, according to rule (4).
//
// 9. If the member is a structure, the base alignment of the structure is N , where

View file

@ -1,5 +1,6 @@
//
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
//Copyright (C) 2016 LunarG, Inc.
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
@ -47,6 +48,16 @@ class TInfoSink;
namespace glslang {
struct TVectorFields {
TVectorFields() { }
TVectorFields(int c0, int c1, int c2, int c3) : num(4)
{
offsets[0] = c0;
offsets[1] = c1;
offsets[2] = c2;
offsets[3] = c3;
}
int offsets[4];
int num;
};
@ -126,11 +137,17 @@ class TIntermediate {
public:
explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
source(EShSourceNone), language(l), profile(p), version(v), treeRoot(0),
numMains(0), numErrors(0), numPushConstants(0), recursive(false),
numEntryPoints(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),
multiStream(false), xfbMode(false)
multiStream(false), xfbMode(false),
shiftSamplerBinding(0),
shiftTextureBinding(0),
shiftUboBinding(0),
autoMapBindings(false),
flattenUniformArrays(false),
useUnknownFormat(false)
{
localSize[0] = 1;
localSize[1] = 1;
@ -148,8 +165,24 @@ public:
void setSource(EShSource s) { source = s; }
EShSource getSource() const { return source; }
void setEntryPoint(const char* ep) { entryPoint = ep; }
const std::string& getEntryPoint() const { return entryPoint; }
void setEntryPointName(const char* ep) { entryPointName = ep; }
void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
const std::string& getEntryPointName() const { return entryPointName; }
const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
void setShiftSamplerBinding(unsigned int shift) { shiftSamplerBinding = shift; }
unsigned int getShiftSamplerBinding() const { return shiftSamplerBinding; }
void setShiftTextureBinding(unsigned int shift) { shiftTextureBinding = shift; }
unsigned int getShiftTextureBinding() const { return shiftTextureBinding; }
void setShiftUboBinding(unsigned int shift) { shiftUboBinding = shift; }
unsigned int getShiftUboBinding() const { return shiftUboBinding; }
void setAutoMapBindings(bool map) { autoMapBindings = map; }
bool getAutoMapBindings() const { return autoMapBindings; }
void setFlattenUniformArrays(bool flatten) { flattenUniformArrays = flatten; }
bool getFlattenUniformArrays() const { return flattenUniformArrays; }
void setNoStorageFormat(bool b) { useUnknownFormat = b; }
bool getNoStorageFormat() const { return useUnknownFormat; }
void setVersion(int v) { version = v; }
int getVersion() const { return version; }
void setProfile(EProfile p) { profile = p; }
@ -162,8 +195,8 @@ public:
void setTreeRoot(TIntermNode* r) { treeRoot = r; }
TIntermNode* getTreeRoot() const { return treeRoot; }
void addMainCount() { ++numMains; }
int getNumMains() const { return numMains; }
void incrementEntryPointCount() { ++numEntryPoints; }
int getNumEntryPoints() const { return numEntryPoints; }
int getNumErrors() const { return numErrors; }
void addPushConstantCount() { ++numPushConstants; }
bool isRecursive() const { return recursive; }
@ -171,13 +204,16 @@ public:
TIntermSymbol* addSymbol(const TVariable&);
TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
TIntermSymbol* addSymbol(const TIntermSymbol&);
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
TIntermTyped* addShapeConversion(TOperator, const TType&, TIntermTyped*);
TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc);
TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
bool canImplicitlyPromote(TBasicType from, TBasicType to) const;
bool canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op = EOpNull) const;
TOperator mapTypeToConstructorOp(const TType&) const;
TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
TIntermAggregate* makeAggregate(TIntermNode* node);
@ -203,6 +239,16 @@ public:
TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&);
// Low level functions to add nodes (no conversions or other higher level transformations)
// If a type is provided, the node's type will be set to it.
TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc) const;
TIntermBinary* addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, const TType&) const;
TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc) const;
TIntermUnary* addUnaryNode(TOperator op, TIntermTyped* child, TSourceLoc, const TType&) const;
// Add conversion from node's type to given basic type.
TIntermTyped* convertToBasicType(TOperator op, TBasicType basicType, TIntermTyped* node) const;
// Constant folding (in Constant.cpp)
TIntermTyped* fold(TIntermAggregate* aggrNode);
TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
@ -318,6 +364,7 @@ public:
bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
int checkLocationRange(int set, const TIoRange& range, const TType&, bool& typeCollision);
int addUsedOffsets(int binding, int offset, int numOffsets);
bool addUsedConstantId(int id);
int computeTypeLocationSize(const TType&) const;
@ -346,17 +393,28 @@ protected:
bool userOutputUsed() const;
static int getBaseAlignmentScalar(const TType&, int& size);
bool isSpecializationOperation(const TIntermOperator&) const;
bool promote(TIntermOperator*);
bool promoteUnary(TIntermUnary&);
bool promoteBinary(TIntermBinary&);
const EShLanguage language; // stage, known at construction time
EShSource source; // source language, known a bit later
std::string entryPoint;
std::string entryPointName;
std::string entryPointMangledName;
unsigned int shiftSamplerBinding;
unsigned int shiftTextureBinding;
unsigned int shiftUboBinding;
bool autoMapBindings;
bool flattenUniformArrays;
bool useUnknownFormat;
EProfile profile;
int version;
SpvVersion spvVersion;
TIntermNode* treeRoot;
std::set<std::string> requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
TBuiltInResource resources;
int numMains;
int numEntryPoints;
int numErrors;
int numPushConstants;
bool recursive;

View file

@ -76,6 +76,9 @@ public:
virtual void updateExtensionBehavior(int line, const char* const extension, const char* behavior);
virtual void fullIntegerCheck(const TSourceLoc&, const char* op);
virtual void doubleCheck(const TSourceLoc&, const char* op);
#ifdef AMD_EXTENSIONS
virtual void float16Check(const TSourceLoc&, const char* op, bool builtIn = false);
#endif
virtual void int64Check(const TSourceLoc&, const char* op, bool builtIn = false);
virtual void spvRemoved(const TSourceLoc&, const char* op);
virtual void vulkanRemoved(const TSourceLoc&, const char* op);
@ -119,12 +122,12 @@ public:
TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree
protected:
TMap<TString, TExtensionBehavior> extensionBehavior; // for each extension string, what its current behavior is set to
EShMessages messages; // errors/warnings/rule-sets
int numErrors; // number of compile-time errors encountered
TInputScanner* currentScanner;
private:
TMap<TString, TExtensionBehavior> extensionBehavior; // for each extension string, what its current behavior is set to
explicit TParseVersions(const TParseVersions&);
TParseVersions& operator=(const TParseVersions&);
};

View file

@ -81,12 +81,10 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define _CRT_SECURE_NO_WARNINGS
#include <stdarg.h>
#include <stdio.h>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include "PpContext.h"
#include "PpTokens.h"
@ -192,7 +190,7 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
do {
int oldToken;
TPpToken oldPpToken;
TPpToken newPpToken;
TPpToken newPpToken;
oldToken = ReadToken(symb->mac.body, &oldPpToken);
newToken = ReadToken(mac.body, &newPpToken);
if (oldToken != newToken || oldPpToken != newPpToken) {
@ -250,7 +248,7 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
if (token != '#') {
while (token != '\n' && token != EndOfInput)
token = scanToken(ppToken);
if (token == EndOfInput)
return token;
@ -495,7 +493,7 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo
if (op < 0 || binop[op].precedence <= precedence)
break;
int leftSide = res;
// Setup short-circuiting, needed for ES, unless already in a short circuit.
// (Once in a short-circuit, can't turn off again, until that whole subexpression is done.
if (! shortCircuit) {
@ -707,6 +705,9 @@ int TPpContext::CPPerror(TPpToken* ppToken)
while (token != '\n' && token != EndOfInput) {
if (token == PpAtomConstInt || token == PpAtomConstUint ||
token == PpAtomConstInt64 || token == PpAtomConstUint64 ||
#ifdef AMD_EXTENSIONS
token == PpAtomConstFloat16 ||
#endif
token == PpAtomConstFloat || token == PpAtomConstDouble) {
message.append(ppToken->name);
} else if (token == PpAtomIdentifier || token == PpAtomConstString) {
@ -741,6 +742,9 @@ int TPpContext::CPPpragma(TPpToken* ppToken)
case PpAtomConstUint64:
case PpAtomConstFloat:
case PpAtomConstDouble:
#ifdef AMD_EXTENSIONS
case PpAtomConstFloat16:
#endif
tokens.push_back(ppToken->name);
break;
default:
@ -756,7 +760,7 @@ int TPpContext::CPPpragma(TPpToken* ppToken)
else
parseContext.handlePragma(loc, tokens);
return token;
return token;
}
// #version: This is just for error checking: the version and profile are decided before preprocessing starts
@ -980,7 +984,7 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken)
if (token == EndOfInput)
mac->busy = 0;
return token;
}
@ -1060,7 +1064,7 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
if (sym->mac.args) {
token = scanToken(ppToken);
if (newLineOkay) {
while (token == '\n')
while (token == '\n')
token = scanToken(ppToken);
}
if (token != '(') {

View file

@ -82,10 +82,9 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define _CRT_SECURE_NO_WARNINGS
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include "PpContext.h"
#include "PpTokens.h"
@ -98,6 +97,32 @@ const struct {
int val;
const char* str;
} tokens[] = {
{ PpAtomAdd, "+=" },
{ PpAtomSub, "-=" },
{ PpAtomMul, "*=" },
{ PpAtomDiv, "/=" },
{ PpAtomMod, "%=" },
{ PpAtomRight, ">>" },
{ PpAtomLeft, "<<" },
{ PpAtomAnd, "&&" },
{ PpAtomOr, "||" },
{ PpAtomXor, "^^" },
{ PpAtomRightAssign, ">>=" },
{ PpAtomLeftAssign, "<<=" },
{ PpAtomAndAssign, "&=" },
{ PpAtomOrAssign, "|=" },
{ PpAtomXorAssign, "^=" },
{ PpAtomEQ, "==" },
{ PpAtomNE, "!=" },
{ PpAtomGE, ">=" },
{ PpAtomLE, "<=" },
{ PpAtomDecrement, "--" },
{ PpAtomIncrement, "++" },
{ PpAtomDefine, "define" },
{ PpAtomDefined, "defined" },
{ PpAtomUndef, "undef" },
@ -121,8 +146,7 @@ const struct {
{ PpAtomFileMacro, "__FILE__" },
{ PpAtomVersionMacro, "__VERSION__" },
{ PpAtomInclude, "include" },
{ PpAtomInclude, "include" },
};
} // end anonymous namespace

View file

@ -76,8 +76,7 @@ TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <cstdlib>
#include "PpContext.h"

View file

@ -218,7 +218,7 @@ protected:
TParseContextBase& parseContext;
// Get the next token from *stack* of input sources, popping input sources
// that are out of tokens, down until an input sources is found that has a token.
// that are out of tokens, down until an input source is found that has a token.
// Return EndOfInput when there are no more tokens to be found by doing this.
int scanToken(TPpToken* ppToken)
{
@ -226,7 +226,7 @@ protected:
while (! inputStack.empty()) {
token = inputStack.back()->scan(ppToken);
if (token != EndOfInput)
if (token != EndOfInput || inputStack.empty())
break;
popInput();
}

View file

@ -76,10 +76,9 @@ TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\****************************************************************************/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include "PpContext.h"

View file

@ -81,10 +81,8 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define _CRT_SECURE_NO_WARNINGS
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdlib>
#include <cstring>
#include "PpContext.h"
#include "PpTokens.h"
@ -119,6 +117,10 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
int declen;
int str_len;
int isDouble = 0;
#ifdef AMD_EXTENSIONS
int isFloat16 = 0;
bool enableFloat16 = parseContext.version >= 450 && parseContext.extensionTurnedOn(E_GL_AMD_gpu_shader_half_float);
#endif
declen = 0;
@ -202,6 +204,28 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
len = 1,str_len=1;
}
}
#ifdef AMD_EXTENSIONS
} else if (enableFloat16 && (ch == 'h' || ch == 'H')) {
parseContext.float16Check(ppToken->loc, "half floating-point suffix");
if (!HasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
int ch2 = getChar();
if (ch2 != 'f' && ch2 != 'F') {
ungetChar();
ungetChar();
}
else {
if (len < MaxTokenLength) {
str[len++] = (char)ch;
str[len++] = (char)ch2;
isFloat16 = 1;
}
else {
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
len = 1, str_len = 1;
}
}
#endif
} else if (ch == 'f' || ch == 'F') {
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
if (! parseContext.relaxedErrors())
@ -224,6 +248,10 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
if (isDouble)
return PpAtomConstDouble;
#ifdef AMD_EXTENSIONS
else if (isFloat16)
return PpAtomConstFloat16;
#endif
else
return PpAtomConstFloat;
}
@ -298,7 +326,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
ppToken->name[len++] = (char)ch;
ch = getch();
if (ch == 'x' || ch == 'X') {
// must be hexidecimal
// must be hexadecimal
bool isUnsigned = false;
bool isInt64 = false;
@ -319,11 +347,11 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
} else if (ch >= 'a' && ch <= 'f') {
ii = ch - 'a' + 10;
} else
pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", "");
ival = (ival << 4) | ii;
} else {
if (! AlreadyComplained) {
pp->parseContext.ppError(ppToken->loc, "hexidecimal literal too big", "", "");
pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
AlreadyComplained = 1;
}
ival = 0xffffffffffffffffull;
@ -333,7 +361,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
(ch >= 'A' && ch <= 'F') ||
(ch >= 'a' && ch <= 'f'));
} else {
pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
pp->parseContext.ppError(ppToken->loc, "bad digit in hexadecimal literal", "", "");
}
if (ch == 'u' || ch == 'U') {
if (len < MaxTokenLength)
@ -405,7 +433,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
}
if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F')
return pp->lFloatConst(len, ch, ppToken);
// wasn't a float, so must be octal...
if (nonOctal)
pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", "");
@ -447,7 +475,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
break;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
// can't be hexidecimal or octal, is either decimal or floating point
// can't be hexadecimal or octal, is either decimal or floating point
do {
if (len < MaxTokenLength)
@ -698,14 +726,14 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
}
//
// The main functional entry-point into the preprocessor, which will
// The main functional entry point into the preprocessor, which will
// scan the source strings to figure out and return the next processing token.
//
// Return string pointer to next token.
// Return 0 when no more tokens.
//
const char* TPpContext::tokenize(TPpToken* ppToken)
{
{
int token = '\n';
for(;;) {
@ -746,10 +774,18 @@ const char* TPpContext::tokenize(TPpToken* ppToken)
case PpAtomConstInt64:
case PpAtomConstUint64:
case PpAtomConstDouble:
#ifdef AMD_EXTENSIONS
case PpAtomConstFloat16:
#endif
tokenString = ppToken->name;
break;
case PpAtomConstString:
parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", "");
if (parseContext.intermediate.getSource() == EShSourceHlsl) {
// HLSL allows string literals.
tokenString = ppToken->name;
} else {
parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", "");
}
break;
case '\'':
parseContext.ppError(ppToken->loc, "character literals not supported", "\'", "");
@ -759,12 +795,8 @@ const char* TPpContext::tokenize(TPpToken* ppToken)
break;
}
if (tokenString) {
if (tokenString[0] != 0)
parseContext.tokensBeforeEOF = 1;
if (tokenString)
return tokenString;
}
}
}

View file

@ -79,10 +79,9 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// symbols.c
//
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include "PpContext.h"

View file

@ -85,11 +85,10 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define snprintf sprintf_s
#endif
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include "PpContext.h"
#include "PpTokens.h"
@ -145,6 +144,9 @@ void TPpContext::RecordToken(TokenStream *pTok, int token, TPpToken* ppToken)
case PpAtomConstUint64:
case PpAtomConstFloat:
case PpAtomConstDouble:
#ifdef AMD_EXTENSIONS
case PpAtomConstFloat16:
#endif
str = ppToken->name;
while (*str) {
lAddByte(pTok, (unsigned char) *str);
@ -179,20 +181,26 @@ int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken)
if (ltoken > 127)
ltoken += 128;
switch (ltoken) {
case '#':
if (lReadByte(pTok) == '#') {
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
parseContext.error(ppToken->loc, "token pasting not implemented (internal error)", "##", "");
//return PpAtomPaste;
return ReadToken(pTok, ppToken);
} else
lUnreadByte(pTok);
case '#':
// Check for ##, unless the current # is the last character
if (pTok->current < pTok->data.size()) {
if (lReadByte(pTok) == '#') {
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
parseContext.error(ppToken->loc, "token pasting not implemented (internal error)", "##", "");
//return PpAtomPaste;
return ReadToken(pTok, ppToken);
} else
lUnreadByte(pTok);
}
break;
case PpAtomConstString:
case PpAtomIdentifier:
case PpAtomConstFloat:
case PpAtomConstDouble:
#ifdef AMD_EXTENSIONS
case PpAtomConstFloat16:
#endif
case PpAtomConstInt:
case PpAtomConstUint:
case PpAtomConstInt64:
@ -219,20 +227,30 @@ int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken)
break;
case PpAtomConstFloat:
case PpAtomConstDouble:
#ifdef AMD_EXTENSIONS
case PpAtomConstFloat16:
#endif
ppToken->dval = atof(ppToken->name);
break;
case PpAtomConstInt:
case PpAtomConstUint:
if (len > 0 && tokenText[0] == '0') {
if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
ppToken->ival = strtol(ppToken->name, 0, 16);
ppToken->ival = (int)strtol(ppToken->name, 0, 16);
else
ppToken->ival = strtol(ppToken->name, 0, 8);
ppToken->ival = (int)strtol(ppToken->name, 0, 8);
} else
ppToken->ival = atoi(ppToken->name);
break;
case PpAtomConstUint:
if (len > 0 && tokenText[0] == '0') {
if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
ppToken->ival = (int)strtoul(ppToken->name, 0, 16);
else
ppToken->ival = (int)strtoul(ppToken->name, 0, 8);
} else
ppToken->ival = (int)strtoul(ppToken->name, 0, 10);
break;
case PpAtomConstInt64:
case PpAtomConstUint64:
if (len > 0 && tokenText[0] == '0') {
if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
ppToken->i64val = strtoll(ppToken->name, nullptr, 16);
@ -241,6 +259,15 @@ int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken)
} else
ppToken->i64val = atoll(ppToken->name);
break;
case PpAtomConstUint64:
if (len > 0 && tokenText[0] == '0') {
if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
ppToken->i64val = (long long)strtoull(ppToken->name, nullptr, 16);
else
ppToken->i64val = (long long)strtoull(ppToken->name, nullptr, 8);
} else
ppToken->i64val = (long long)strtoull(ppToken->name, 0, 10);
break;
}
}

View file

@ -123,9 +123,12 @@ enum EFixedAtoms {
PpAtomConstUint64,
PpAtomConstFloat,
PpAtomConstDouble,
#ifdef AMD_EXTENSIONS
PpAtomConstFloat16,
#endif
PpAtomConstString,
// Indentifiers
// Identifiers
PpAtomIdentifier,
// preprocessor "keywords"

View file

@ -670,7 +670,7 @@ protected:
// Gets the struct dereference index that leads to 'precise' object.
ObjectAccessChain precise_accesschain_index_str =
getFrontElement(remained_accesschain_);
unsigned precise_accesschain_index = strtoul(precise_accesschain_index_str.c_str(), nullptr, 10);
unsigned precise_accesschain_index = (unsigned)strtoul(precise_accesschain_index_str.c_str(), nullptr, 10);
// Gets the node pointed by the access chain index extracted before.
glslang::TIntermTyped* potential_precise_node =
node->getSequence()[precise_accesschain_index]->getAsTyped();

View file

@ -1,5 +1,5 @@
//
//Copyright (C) 2013 LunarG, Inc.
//Copyright (C) 2013-2016 LunarG, Inc.
//
//All rights reserved.
//
@ -35,6 +35,7 @@
#include "../Include/Common.h"
#include "reflection.h"
#include "LiveTraverser.h"
#include "localintermediate.h"
#include "gl_types.h"
@ -48,7 +49,7 @@
//
// High-level algorithm for one stage:
//
// 1. Put main() on list of live functions.
// 1. Put the entry point on the list of live functions.
//
// 2. Traverse any live function, while skipping if-tests with a compile-time constant
// condition of false, and while adding any encountered function calls to the live
@ -59,40 +60,29 @@
// 3. Add any encountered uniform variables and blocks to the reflection database.
//
// Can be attempted with a failed link, but will return false if recursion had been detected, or
// there wasn't exactly one main.
// there wasn't exactly one entry point.
//
namespace glslang {
//
// The traverser: mostly pass through, except
// - processing function-call nodes to push live functions onto the stack of functions to process
// - processing binary nodes to see if they are dereferences of an aggregates to track
// - processing symbol nodes to see if they are non-aggregate objects to track
// - processing selection nodes to trim semantically dead code
//
// This ignores semantically dead code by using TLiveTraverser.
//
// This is in the glslang namespace directly so it can be a friend of TReflection.
//
class TLiveTraverser : public TIntermTraverser {
class TReflectionTraverser : public TLiveTraverser {
public:
TLiveTraverser(const TIntermediate& i, TReflection& r) : intermediate(i), reflection(r) { }
TReflectionTraverser(const TIntermediate& i, TReflection& r) :
TLiveTraverser(i), reflection(r) { }
virtual bool visitAggregate(TVisit, TIntermAggregate* node);
virtual bool visitBinary(TVisit, TIntermBinary* node);
virtual void visitSymbol(TIntermSymbol* base);
virtual bool visitSelection(TVisit, TIntermSelection* node);
// Track live funtions as well as uniforms, so that we don't visit dead functions
// and only visit each function once.
void addFunctionCall(TIntermAggregate* call)
{
// just use the map to ensure we process each function at most once
if (reflection.nameToIndex.find(call->getName()) == reflection.nameToIndex.end()) {
reflection.nameToIndex[call->getName()] = -1;
pushFunction(call->getName());
}
}
// Add a simple reference to a uniform variable to the uniform database, no dereference involved.
// However, no dereference doesn't mean simple... it could be a complex aggregate.
@ -119,7 +109,7 @@ public:
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
if (it == reflection.nameToIndex.end()) {
reflection.nameToIndex[name] = (int)reflection.indexToAttribute.size();
reflection.indexToAttribute.push_back(TObjectReflection(name, 0, mapToGlType(type), 0, 0));
reflection.indexToAttribute.push_back(TObjectReflection(name, type, 0, mapToGlType(type), 0, 0));
}
}
}
@ -255,7 +245,8 @@ public:
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
if (it == reflection.nameToIndex.end()) {
reflection.nameToIndex[name] = (int)reflection.indexToUniform.size();
reflection.indexToUniform.push_back(TObjectReflection(name, offset, mapToGlType(*terminalType), arraySize, blockIndex));
reflection.indexToUniform.push_back(TObjectReflection(name, *terminalType, offset, mapToGlType(*terminalType),
arraySize, blockIndex));
} else if (arraySize > 1) {
int& reflectedArraySize = reflection.indexToUniform[it->second].size;
reflectedArraySize = std::max(arraySize, reflectedArraySize);
@ -306,12 +297,18 @@ public:
if (block) {
offset = 0;
anonymous = IsAnonymous(base->getName());
const TString& blockName = base->getType().getTypeName();
if (base->getType().isArray()) {
TType derefType(base->getType(), 0);
assert(! anonymous);
for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
blockIndex = addBlockName(base->getType().getTypeName() + "[" + String(e) + "]", getBlockSize(base->getType()));
blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType,
getBlockSize(base->getType()));
} else
blockIndex = addBlockName(base->getType().getTypeName(), getBlockSize(base->getType()));
blockIndex = addBlockName(blockName, base->getType(), getBlockSize(base->getType()));
}
// Process the dereference chain, backward, accumulating the pieces for later forward traversal.
@ -344,35 +341,20 @@ public:
blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize);
}
int addBlockName(const TString& name, int size)
int addBlockName(const TString& name, const TType& type, int size)
{
int blockIndex;
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {
blockIndex = (int)reflection.indexToUniformBlock.size();
reflection.nameToIndex[name] = blockIndex;
reflection.indexToUniformBlock.push_back(TObjectReflection(name, -1, -1, size, -1));
reflection.indexToUniformBlock.push_back(TObjectReflection(name, type, -1, -1, size, -1));
} else
blockIndex = it->second;
return blockIndex;
}
//
// Given a function name, find its subroot in the tree, and push it onto the stack of
// functions left to process.
//
void pushFunction(const TString& name)
{
TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence();
for (unsigned int f = 0; f < globals.size(); ++f) {
TIntermAggregate* candidate = globals[f]->getAsAggregate();
if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) {
functions.push_back(candidate);
break;
}
}
}
// Are we at a level in a dereference chain at which individual active uniform queries are made?
bool isReflectionGranularity(const TType& type)
@ -554,6 +536,9 @@ public:
switch (type.getBasicType()) {
case EbtFloat: return GL_FLOAT_VEC2 + offset;
case EbtDouble: return GL_DOUBLE_VEC2 + offset;
#ifdef AMD_EXTENSIONS
case EbtFloat16: return GL_FLOAT16_VEC2_NV + offset;
#endif
case EbtInt: return GL_INT_VEC2 + offset;
case EbtUint: return GL_UNSIGNED_INT_VEC2 + offset;
case EbtInt64: return GL_INT64_ARB + offset;
@ -613,6 +598,32 @@ public:
default: return 0;
}
}
#ifdef AMD_EXTENSIONS
case EbtFloat16:
switch (type.getMatrixCols()) {
case 2:
switch (type.getMatrixRows()) {
case 2: return GL_FLOAT16_MAT2_AMD;
case 3: return GL_FLOAT16_MAT2x3_AMD;
case 4: return GL_FLOAT16_MAT2x4_AMD;
default: return 0;
}
case 3:
switch (type.getMatrixRows()) {
case 2: return GL_FLOAT16_MAT3x2_AMD;
case 3: return GL_FLOAT16_MAT3_AMD;
case 4: return GL_FLOAT16_MAT3x4_AMD;
default: return 0;
}
case 4:
switch (type.getMatrixRows()) {
case 2: return GL_FLOAT16_MAT4x2_AMD;
case 3: return GL_FLOAT16_MAT4x3_AMD;
case 4: return GL_FLOAT16_MAT4_AMD;
default: return 0;
}
}
#endif
default:
return 0;
}
@ -621,6 +632,9 @@ public:
switch (type.getBasicType()) {
case EbtFloat: return GL_FLOAT;
case EbtDouble: return GL_DOUBLE;
#ifdef AMD_EXTENSIONS
case EbtFloat16: return GL_FLOAT16_NV;
#endif
case EbtInt: return GL_INT;
case EbtUint: return GL_UNSIGNED_INT;
case EbtInt64: return GL_INT64_ARB;
@ -639,33 +653,21 @@ public:
return type.isArray() ? type.getOuterArraySize() : 1;
}
typedef std::list<TIntermAggregate*> TFunctionStack;
TFunctionStack functions;
const TIntermediate& intermediate;
TReflection& reflection;
std::set<const TIntermNode*> processedDerefs;
protected:
TLiveTraverser(TLiveTraverser&);
TLiveTraverser& operator=(TLiveTraverser&);
TReflectionTraverser(TReflectionTraverser&);
TReflectionTraverser& operator=(TReflectionTraverser&);
};
//
// Implement the traversal functions of interest.
//
// To catch which function calls are not dead, and hence which functions must be visited.
bool TLiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
{
if (node->getOp() == EOpFunctionCall)
addFunctionCall(node);
return true; // traverse this subtree
}
// To catch dereferenced aggregates that must be reflected.
// This catches them at the highest level possible in the tree.
bool TLiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
bool TReflectionTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
{
switch (node->getOp()) {
case EOpIndexDirect:
@ -683,7 +685,7 @@ bool TLiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
}
// To reflect non-dereferenced objects.
void TLiveTraverser::visitSymbol(TIntermSymbol* base)
void TReflectionTraverser::visitSymbol(TIntermSymbol* base)
{
if (base->getQualifier().storage == EvqUniform)
addUniform(*base);
@ -692,21 +694,6 @@ void TLiveTraverser::visitSymbol(TIntermSymbol* base)
addAttribute(*base);
}
// To prune semantically dead paths.
bool TLiveTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node)
{
TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion();
if (constant) {
// cull the path that is dead
if (constant->getConstArray()[0].getBConst() == true && node->getTrueBlock())
node->getTrueBlock()->traverse(this);
if (constant->getConstArray()[0].getBConst() == false && node->getFalseBlock())
node->getFalseBlock()->traverse(this);
return false; // don't traverse any more, we did it all above
} else
return true; // traverse the whole subtree
}
//
// Implement TReflection methods.
@ -717,13 +704,13 @@ bool TLiveTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node)
// Returns false if the input is too malformed to do this.
bool TReflection::addStage(EShLanguage, const TIntermediate& intermediate)
{
if (intermediate.getNumMains() != 1 || intermediate.isRecursive())
if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
return false;
TLiveTraverser it(intermediate, *this);
TReflectionTraverser it(intermediate, *this);
// put main() on functions to process
it.pushFunction("main(");
// put the entry point on the list of functions to process
it.pushFunction(intermediate.getEntryPointMangledName().c_str());
// process all the functions
while (! it.functions.empty()) {

View file

@ -1,5 +1,5 @@
//
//Copyright (C) 2013 LunarG, Inc.
//Copyright (C) 2013-2016 LunarG, Inc.
//
//All rights reserved.
//
@ -37,6 +37,7 @@
#define _REFLECTION_INCLUDED
#include "../Public/ShaderLang.h"
#include "../Include/Types.h"
#include <list>
#include <set>
@ -49,25 +50,46 @@ namespace glslang {
class TIntermediate;
class TIntermAggregate;
class TLiveTraverser;
class TReflectionTraverser;
// Data needed for just a single object at the granularity exchanged by the reflection API
class TObjectReflection {
public:
TObjectReflection(const TString& pName, int pOffset, int pGLDefineType, int pSize, int pIndex) :
name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex) { }
void dump() const { printf("%s: offset %d, type %x, size %d, index %d\n", name.c_str(), offset, glDefineType, size, index); }
TObjectReflection(const TString& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex) :
name(pName), type(pType.clone()),
offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex) { }
void dump() const {
printf("%s: offset %d, type %x, size %d, index %d, binding %d\n",
name.c_str(), offset, glDefineType, size, index, getBinding() );
}
const TType* const getType() const { return type; }
TString name;
int offset;
int glDefineType;
int size; // data size in bytes for a block, array size for a (non-block) object that's an array
int index;
static TObjectReflection badReflection() { return TObjectReflection(); }
protected:
int getBinding() const {
if (type == nullptr || type->getQualifier().layoutBinding == TQualifier::layoutBindingEnd)
return -1;
return type->getQualifier().layoutBinding;
}
TObjectReflection() : type(nullptr), offset(-1), glDefineType(-1), size(-1), index(-1) { }
const TType* type;
};
// The full reflection database
class TReflection {
public:
TReflection() : badReflection("__bad__", -1, -1, -1, -1) {}
TReflection() : badReflection(TObjectReflection::badReflection()) { }
virtual ~TReflection() {}
// grow the reflection stage by stage
@ -116,7 +138,7 @@ public:
void dump();
protected:
friend class glslang::TLiveTraverser;
friend class glslang::TReflectionTraverser;
// Need a TString hash: typedef std::unordered_map<TString, int> TNameToIndex;
typedef std::map<TString, int> TNameToIndex;

View file

@ -165,21 +165,39 @@ bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
return false;
}
// TODO: non-windows: if we need these on linux, flesh them out
void InitGlobalLock() { }
void GetGlobalLock() { }
void ReleaseGlobalLock() { }
namespace {
pthread_mutex_t gMutex;
}
void* OS_CreateThread(TThreadEntrypoint entry)
void InitGlobalLock()
{
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&gMutex, &mutexattr);
}
void GetGlobalLock()
{
pthread_mutex_lock(&gMutex);
}
void ReleaseGlobalLock()
{
pthread_mutex_unlock(&gMutex);
}
// TODO: non-windows: if we need these on linux, flesh them out
void* OS_CreateThread(TThreadEntrypoint /*entry*/)
{
return 0;
}
void OS_WaitForAllThreads(void* threads, int numThreads)
void OS_WaitForAllThreads(void* /*threads*/, int /*numThreads*/)
{
}
void OS_Sleep(int milliseconds)
void OS_Sleep(int /*milliseconds*/)
{
}

View file

@ -37,14 +37,14 @@
#define STRICT
#define VC_EXTRALEAN 1
#include <windows.h>
#include <assert.h>
#include <cassert>
#include <process.h>
#include <psapi.h>
#include <stdio.h>
#include <stdint.h>
#include <cstdio>
#include <cstdint>
//
// This file contains contains the Window-OS-specific functions
// This file contains the Window-OS-specific functions
//
#if !(defined(_WIN32) || defined(_WIN64))
@ -55,12 +55,12 @@ namespace glslang {
inline OS_TLSIndex ToGenericTLSIndex (DWORD handle)
{
return (OS_TLSIndex)((uintptr_t)handle + 1);
return (OS_TLSIndex)((uintptr_t)handle + 1);
}
inline DWORD ToNativeTLSIndex (OS_TLSIndex nIndex)
{
return (DWORD)((uintptr_t)nIndex - 1);
return (DWORD)((uintptr_t)nIndex - 1);
}
//
@ -68,46 +68,46 @@ inline DWORD ToNativeTLSIndex (OS_TLSIndex nIndex)
//
OS_TLSIndex OS_AllocTLSIndex()
{
DWORD dwIndex = TlsAlloc();
if (dwIndex == TLS_OUT_OF_INDEXES) {
assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
return OS_INVALID_TLS_INDEX;
}
DWORD dwIndex = TlsAlloc();
if (dwIndex == TLS_OUT_OF_INDEXES) {
assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
return OS_INVALID_TLS_INDEX;
}
return ToGenericTLSIndex(dwIndex);
return ToGenericTLSIndex(dwIndex);
}
bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
{
if (nIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
return false;
}
if (nIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
return false;
}
if (TlsSetValue(ToNativeTLSIndex(nIndex), lpvValue))
return true;
else
return false;
if (TlsSetValue(ToNativeTLSIndex(nIndex), lpvValue))
return true;
else
return false;
}
void* OS_GetTLSValue(OS_TLSIndex nIndex)
{
assert(nIndex != OS_INVALID_TLS_INDEX);
return TlsGetValue(ToNativeTLSIndex(nIndex));
assert(nIndex != OS_INVALID_TLS_INDEX);
return TlsGetValue(ToNativeTLSIndex(nIndex));
}
bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
{
if (nIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
return false;
}
if (nIndex == OS_INVALID_TLS_INDEX) {
assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
return false;
}
if (TlsFree(ToNativeTLSIndex(nIndex)))
return true;
else
return false;
if (TlsFree(ToNativeTLSIndex(nIndex)))
return true;
else
return false;
}
HANDLE GlobalLock;
@ -129,7 +129,7 @@ void ReleaseGlobalLock()
unsigned int __stdcall EnterGenericThread (void* entry)
{
return ((TThreadEntrypoint)entry)(0);
return ((TThreadEntrypoint)entry)(0);
}
void* OS_CreateThread(TThreadEntrypoint entry)

View file

@ -1,5 +1,7 @@
//
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
//Copyright (C) 2013-2016 LunarG, Inc.
//
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
@ -37,7 +39,7 @@
#include "../Include/ResourceLimits.h"
#include "../MachineIndependent/Versions.h"
#include <string.h>
#include <cstring>
#ifdef _WIN32
#define C_DECL __cdecl
@ -101,6 +103,8 @@ typedef enum {
namespace glslang {
class TType;
typedef enum {
EShSourceNone,
EShSourceGlsl,
@ -300,6 +304,12 @@ public:
const char* const* s, const int* l, const char* const* names, int n);
void setPreamble(const char* s) { preamble = s; }
void setEntryPoint(const char* entryPoint);
void setShiftSamplerBinding(unsigned int base);
void setShiftTextureBinding(unsigned int base);
void setShiftUboBinding(unsigned int base);
void setAutoMapBindings(bool map);
void setFlattenUniformArrays(bool flatten);
void setNoStorageFormat(bool useUnknownFormat);
// Interface to #include handlers.
//
@ -433,6 +443,7 @@ private:
};
class TReflection;
class TIoMapper;
// Make one TProgram per set of shaders that will get linked together. Add all
// the shaders that are to be linked together. After calling shader.parse()
@ -455,21 +466,27 @@ public:
// Reflection Interface
bool buildReflection(); // call first, to do liveness analysis, index mapping, etc.; returns false on failure
int getNumLiveUniformVariables(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
int getNumLiveUniformBlocks(); // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
const char* getUniformName(int index); // can be used for "name" part of glGetActiveUniform()
const char* getUniformBlockName(int blockIndex); // can be used for glGetActiveUniformBlockName()
int getUniformBlockSize(int blockIndex); // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
int getUniformIndex(const char* name); // can be used for glGetUniformIndices()
int getUniformBlockIndex(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
int getUniformType(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
int getUniformBufferOffset(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
int getUniformArraySize(int index); // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
int getNumLiveAttributes(); // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
const char *getAttributeName(int index); // can be used for glGetActiveAttrib()
int getAttributeType(int index); // can be used for glGetActiveAttrib()
int getNumLiveUniformVariables() const; // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
int getNumLiveUniformBlocks() const; // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
const char* getUniformName(int index) const; // can be used for "name" part of glGetActiveUniform()
const char* getUniformBlockName(int blockIndex) const; // can be used for glGetActiveUniformBlockName()
int getUniformBlockSize(int blockIndex) const; // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
int getUniformIndex(const char* name) const; // can be used for glGetUniformIndices()
int getUniformBlockIndex(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
int getUniformType(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
int getUniformBufferOffset(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
int getUniformArraySize(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
int getNumLiveAttributes() const; // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
const char *getAttributeName(int index) const; // can be used for glGetActiveAttrib()
int getAttributeType(int index) const; // can be used for glGetActiveAttrib()
const TType* getUniformTType(int index) const; // returns a TType*
const TType* getUniformBlockTType(int index) const; // returns a TType*
void dumpReflection();
// I/O mapping: apply base offsets and map live unbound variables
bool mapIO();
protected:
bool linkStage(EShLanguage, EShMessages);
@ -479,6 +496,7 @@ protected:
bool newedIntermediate[EShLangCount]; // track which intermediate were "new" versus reusing a singleton unit in a stage
TInfoSink* infoSink;
TReflection* reflection;
TIoMapper* ioMapper;
bool linked;
private: