Update glslang.

This commit is contained in:
Alex Szpakowski
2017-12-17 21:05:40 -04:00
parent 640e8f0d2e
commit 54c09c910a
63 changed files with 3788 additions and 2646 deletions
+22 -12
View File
@@ -38,13 +38,17 @@
#include "InitializeDll.h"
#include "../glslang/Include/InitializeGlobals.h"
#include "../glslang/Public/ShaderLang.h"
#include "../glslang/Include/PoolAlloc.h"
namespace glslang {
OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
// Per-process initialization.
// Needs to be called at least once before parsing, etc. is done.
// Will also do thread initialization for the calling thread; other
// threads will need to do that explicitly.
bool InitProcess()
{
glslang::GetGlobalLock();
@@ -85,7 +89,9 @@ bool InitProcess()
return true;
}
// Per-thread scoped initialization.
// Must be called at least once by each new thread sharing the
// symbol tables, etc., needed to parse.
bool InitThread()
{
//
@@ -99,17 +105,21 @@ bool InitThread()
if (OS_GetTLSValue(ThreadInitializeIndex) != 0)
return true;
InitializeMemoryPools();
if (! OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) {
assert(0 && "InitThread(): Unable to set init flag.");
return false;
}
glslang::SetThreadPoolAllocator(nullptr);
return true;
}
// Not necessary to call this: InitThread() is reentrant, and the need
// to do per thread tear down has been removed.
//
// This is kept, with memory management removed, to satisfy any exiting
// calls to it that rely on it.
bool DetachThread()
{
bool success = true;
@@ -125,14 +135,18 @@ bool DetachThread()
assert(0 && "DetachThread(): Unable to clear init flag.");
success = false;
}
FreeGlobalPools();
}
return success;
}
// Not necessary to call this: InitProcess() is reentrant.
//
// This is kept, with memory management removed, to satisfy any exiting
// calls to it that rely on it.
//
// Users of glslang should call shFinalize() or glslang::FinalizeProcess() for
// process-scoped memory tear down.
bool DetachProcess()
{
bool success = true;
@@ -140,12 +154,8 @@ bool DetachProcess()
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
return true;
ShFinalize();
success = DetachThread();
FreePoolIndex();
OS_FreeTLSIndex(ThreadInitializeIndex);
ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+2 -2
View File
@@ -40,8 +40,8 @@ namespace glslang {
bool InitProcess();
bool InitThread();
bool DetachThread();
bool DetachProcess();
bool DetachThread(); // not called from standalone, perhaps other tools rely on parts of it
bool DetachProcess(); // not called from standalone, perhaps other tools rely on parts of it
} // end namespace glslang
View File
View File
+6 -1
View File
@@ -193,10 +193,12 @@ enum TBuiltInVariable {
EbvFragColor,
EbvFragData,
EbvFragDepth,
EbvFragStencilRef,
EbvSampleId,
EbvSamplePosition,
EbvSampleMask,
EbvHelperInvocation,
#ifdef AMD_EXTENSIONS
EbvBaryCoordNoPersp,
EbvBaryCoordNoPerspCentroid,
@@ -216,13 +218,13 @@ enum TBuiltInVariable {
EbvSecondaryViewportMaskNV,
EbvPositionPerViewNV,
EbvViewportMaskPerViewNV,
EbvFragFullyCoveredNV,
#endif
// HLSL built-ins that live only temporarily, until they get remapped
// to one of the above.
EbvFragDepthGreater,
EbvFragDepthLesser,
EbvStencilRef,
EbvGsOutputStream,
EbvOutputPatch,
EbvInputPatch,
@@ -329,10 +331,12 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v)
case EbvFragColor: return "FragColor";
case EbvFragData: return "FragData";
case EbvFragDepth: return "FragDepth";
case EbvFragStencilRef: return "FragStencilRef";
case EbvSampleId: return "SampleId";
case EbvSamplePosition: return "SamplePosition";
case EbvSampleMask: return "SampleMaskIn";
case EbvHelperInvocation: return "HelperInvocation";
#ifdef AMD_EXTENSIONS
case EbvBaryCoordNoPersp: return "BaryCoordNoPersp";
case EbvBaryCoordNoPerspCentroid: return "BaryCoordNoPerspCentroid";
@@ -352,6 +356,7 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v)
case EbvSecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
case EbvPositionPerViewNV: return "PositionPerViewNV";
case EbvViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
case EbvFragFullyCoveredNV: return "FragFullyCoveredNV";
#endif
default: return "unknown built-in variable";
}
+10 -2
View File
@@ -63,7 +63,7 @@ std::string to_string(const T& val) {
}
#endif
#if defined(_MSC_VER) && _MSC_VER < 1700
#if defined(_MSC_VER) && _MSC_VER < 1800
inline long long int strtoll (const char* str, char** endptr, int base)
{
return _strtoi64(str, endptr, base);
@@ -78,6 +78,10 @@ inline long long int atoll (const char* str)
}
#endif
#if defined(_MSC_VER)
#define strdup _strdup
#endif
/* windows only pragma */
#ifdef _MSC_VER
#pragma warning(disable : 4786) // Don't warn about too long identifiers
@@ -222,6 +226,7 @@ inline const TString String(const int i, const int /*base*/ = 10)
struct TSourceLoc {
void init() { name = nullptr; string = 0; line = 0; column = 0; }
void init(int stringNum) { init(); string = stringNum; }
// Returns the name if it exists. Otherwise, returns the string number.
std::string getStringNameOrNum(bool quoteStringName = true) const
{
@@ -235,7 +240,10 @@ struct TSourceLoc {
int column;
};
typedef TMap<TString, TString> TPragmaTable;
class TPragmaTable : public TMap<TString, TString> {
public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
};
const int MaxTokenLength = 1024;
View File
View File
-3
View File
@@ -37,10 +37,7 @@
namespace glslang {
void InitializeMemoryPools();
void FreeGlobalPools();
bool InitializePoolIndex();
void FreePoolIndex();
} // end namespace glslang
+1 -8
View File
@@ -250,15 +250,8 @@ private:
// different times. But a simple use is to have a global pop
// with everyone using the same global allocator.
//
typedef TPoolAllocator* PoolAllocatorPointer;
extern TPoolAllocator& GetThreadPoolAllocator();
struct TThreadMemoryPools
{
TPoolAllocator* threadPoolAllocator;
};
void SetThreadPoolAllocator(TPoolAllocator& poolAllocator);
void SetThreadPoolAllocator(TPoolAllocator* poolAllocator);
//
// This STL compatible allocator is intended to be used as the allocator
View File
+5 -2
View File
@@ -56,11 +56,14 @@ class TUniformMap;
//
class TShHandleBase {
public:
TShHandleBase() { }
virtual ~TShHandleBase() { }
TShHandleBase() { pool = new glslang::TPoolAllocator; }
virtual ~TShHandleBase() { delete pool; }
virtual TCompiler* getAsCompiler() { return 0; }
virtual TLinker* getAsLinker() { return 0; }
virtual TUniformMap* getAsUniformMap() { return 0; }
virtual glslang::TPoolAllocator* getPool() const { return pool; }
private:
glslang::TPoolAllocator* pool;
};
//
+68 -59
View File
@@ -80,7 +80,19 @@ 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.
unsigned int vectorSize : 3; // vector return type size.
// Some languages support structures as sample results. Storing the whole structure in the
// TSampler is too large, so there is an index to a separate table.
static const unsigned structReturnIndexBits = 4; // number of index bits to use.
static const unsigned structReturnSlots = (1<<structReturnIndexBits)-1; // number of valid values
static const unsigned noReturnStruct = structReturnSlots; // value if no return struct type.
// Index into a language specific table of texture return structures.
unsigned int structReturnIndex : structReturnIndexBits;
// Encapsulate getting members' vector sizes packed into the vectorSize bitfield.
unsigned int getVectorSize() const { return vectorSize; }
bool isImage() const { return image && dim != EsdSubpass; }
bool isSubpass() const { return dim == EsdSubpass; }
@@ -90,6 +102,7 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool isShadow() const { return shadow; }
bool isArrayed() const { return arrayed; }
bool isMultiSample() const { return ms; }
bool hasReturnStruct() const { return structReturnIndex != noReturnStruct; }
void clear()
{
@@ -102,6 +115,9 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
combined = false;
sampler = false;
external = false;
structReturnIndex = noReturnStruct;
// by default, returns a single vec4;
vectorSize = 4;
}
@@ -160,16 +176,17 @@ struct TSampler { // misnomer now; includes images, textures without sampler,
bool operator==(const TSampler& right) const
{
return type == right.type &&
dim == right.dim &&
arrayed == right.arrayed &&
shadow == right.shadow &&
ms == right.ms &&
image == right.image &&
combined == right.combined &&
sampler == right.sampler &&
external == right.external &&
vectorSize == right.vectorSize;
return type == right.type &&
dim == right.dim &&
arrayed == right.arrayed &&
shadow == right.shadow &&
ms == right.ms &&
image == right.image &&
combined == right.combined &&
sampler == right.sampler &&
external == right.external &&
vectorSize == right.vectorSize &&
structReturnIndex == right.structReturnIndex;
}
bool operator!=(const TSampler& right) const
@@ -633,15 +650,19 @@ public:
layoutXfbOffset = layoutXfbOffsetEnd;
}
bool hasLayout() const
bool hasNonXfbLayout() const
{
return hasUniformLayout() ||
hasAnyLocation() ||
hasStream() ||
hasXfb() ||
hasFormat() ||
layoutPushConstant;
}
bool hasLayout() const
{
return hasNonXfbLayout() ||
hasXfb();
}
TLayoutMatrix layoutMatrix : 3;
TLayoutPacking layoutPacking : 4;
int layoutOffset;
@@ -968,8 +989,10 @@ struct TShaderQualifiers {
int localSize[3]; // compute shader
int localSizeSpecId[3]; // compute shader specialization id for gl_WorkGroupSize
bool earlyFragmentTests; // fragment input
bool postDepthCoverage; // fragment input
TLayoutDepth layoutDepth;
bool blendEquation; // true if any blend equation was specified
int numViews; // multiview extenstions
#ifdef NV_EXTENSIONS
bool layoutOverrideCoverage; // true if layout override_coverage set
@@ -992,8 +1015,10 @@ struct TShaderQualifiers {
localSizeSpecId[1] = TQualifier::layoutNotSet;
localSizeSpecId[2] = TQualifier::layoutNotSet;
earlyFragmentTests = false;
postDepthCoverage = false;
layoutDepth = EldNone;
blendEquation = false;
numViews = TQualifier::layoutNotSet;
#ifdef NV_EXTENSIONS
layoutOverrideCoverage = false;
#endif
@@ -1029,10 +1054,14 @@ struct TShaderQualifiers {
}
if (src.earlyFragmentTests)
earlyFragmentTests = true;
if (src.postDepthCoverage)
postDepthCoverage = true;
if (src.layoutDepth)
layoutDepth = src.layoutDepth;
if (src.blendEquation)
blendEquation = src.blendEquation;
if (src.numViews != TQualifier::layoutNotSet)
numViews = src.numViews;
#ifdef NV_EXTENSIONS
if (src.layoutOverrideCoverage)
layoutOverrideCoverage = src.layoutOverrideCoverage;
@@ -1127,6 +1156,7 @@ public:
sampler.clear();
qualifier.clear();
qualifier.storage = q;
assert(!(isMatrix() && vectorSize != 0)); // prevent vectorSize != 0 on matrices
}
// for explicit precision qualifier
TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
@@ -1139,6 +1169,7 @@ public:
qualifier.storage = q;
qualifier.precision = p;
assert(p >= EpqNone && p <= EpqHigh);
assert(!(isMatrix() && vectorSize != 0)); // prevent vectorSize != 0 on matrices
}
// for turning a TPublicType into a TType, using a shallow copy
explicit TType(const TPublicType& p) :
@@ -1338,53 +1369,31 @@ public:
#else
virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble; }
#endif
virtual bool isIntegerDomain() const
{
switch (basicType) {
case EbtInt:
case EbtUint:
case EbtInt64:
case EbtUint64:
#ifdef AMD_EXTENSIONS
case EbtInt16:
case EbtUint16:
#endif
case EbtAtomicUint:
return true;
default:
break;
}
return false;
}
virtual bool isOpaque() const { return basicType == EbtSampler || basicType == EbtAtomicUint; }
virtual bool isBuiltIn() const { return getQualifier().builtIn != EbvNone; }
// "Image" is a superset of "Subpass"
virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); }
virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
virtual bool isBuiltInInterstageIO(EShLanguage language) const
{
return isPerVertexAndBuiltIn(language) || isLooseAndBuiltIn(language);
}
// Return true if this is an interstage IO builtin
virtual bool isPerVertexAndBuiltIn(EShLanguage language) const
{
if (language == EShLangFragment)
return false;
// Any non-fragment stage
switch (getQualifier().builtIn) {
case EbvPosition:
case EbvPointSize:
case EbvClipDistance:
case EbvCullDistance:
#ifdef NV_EXTENSIONS
case EbvLayer:
case EbvViewportMaskNV:
case EbvSecondaryPositionNV:
case EbvSecondaryViewportMaskNV:
case EbvPositionPerViewNV:
case EbvViewportMaskPerViewNV:
#endif
return true;
default:
return false;
}
}
// Return true if this is a loose builtin
virtual bool isLooseAndBuiltIn(EShLanguage language) const
{
if (getQualifier().builtIn == EbvNone)
return false;
return !isPerVertexAndBuiltIn(language);
}
// return true if this type contains any subtype which satisfies the given predicate.
template <typename P>
bool contains(P predicate) const
@@ -1426,10 +1435,10 @@ public:
return contains([](const TType* t) { return t->isOpaque(); } );
}
// Recursively checks if the type contains an interstage IO builtin
virtual bool containsBuiltInInterstageIO(EShLanguage language) const
// Recursively checks if the type contains a built-in variable
virtual bool containsBuiltIn() const
{
return contains([language](const TType* t) { return t->isBuiltInInterstageIO(language); } );
return contains([](const TType* t) { return t->isBuiltIn(); } );
}
virtual bool containsNonOpaque() const
@@ -1451,9 +1460,9 @@ public:
case EbtUint16:
#endif
case EbtBool:
return true;
return true;
default:
return false;
return false;
}
};
+9
View File
@@ -264,6 +264,15 @@ struct TArraySizes {
return false;
}
bool clearInnerImplicit()
{
for (int d = 1; d < sizes.size(); ++d) {
if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize)
setDimSize(d, 1);
}
return false;
}
bool isInnerSpecialization() const
{
for (int d = 1; d < sizes.size(); ++d) {
+86 -11
View File
@@ -417,9 +417,18 @@ enum TOperator {
EOpAtomicExchange,
EOpAtomicCompSwap,
EOpAtomicCounterIncrement,
EOpAtomicCounterDecrement,
EOpAtomicCounterIncrement, // results in pre-increment value
EOpAtomicCounterDecrement, // results in post-decrement value
EOpAtomicCounter,
EOpAtomicCounterAdd,
EOpAtomicCounterSubtract,
EOpAtomicCounterMin,
EOpAtomicCounterMax,
EOpAtomicCounterAnd,
EOpAtomicCounterOr,
EOpAtomicCounterXor,
EOpAtomicCounterExchange,
EOpAtomicCounterCompSwap,
EOpAny,
EOpAll,
@@ -584,6 +593,10 @@ enum TOperator {
EOpImageQuerySamples,
EOpImageLoad,
EOpImageStore,
#ifdef AMD_EXTENSIONS
EOpImageLoadLod,
EOpImageStoreLod,
#endif
EOpImageAtomicAdd,
EOpImageAtomicMin,
EOpImageAtomicMax,
@@ -596,6 +609,9 @@ enum TOperator {
EOpSubpassLoad,
EOpSubpassLoadMS,
EOpSparseImageLoad,
#ifdef AMD_EXTENSIONS
EOpSparseImageLoadLod,
#endif
EOpImageGuardEnd,
@@ -637,6 +653,8 @@ enum TOperator {
EOpTextureGatherLod,
EOpTextureGatherLodOffset,
EOpTextureGatherLodOffsets,
EOpFragmentMaskFetch,
EOpFragmentFetch,
#endif
EOpSparseTextureGuardBegin,
@@ -704,7 +722,8 @@ enum TOperator {
EOpInterlockedOr, // ...
EOpInterlockedXor, // ...
EOpAllMemoryBarrierWithGroupSync, // memory barriers without non-hlsl AST equivalents
EOpGroupMemoryBarrierWithGroupSync, // ...
EOpDeviceMemoryBarrier, // ...
EOpDeviceMemoryBarrierWithGroupSync, // ...
EOpWorkgroupMemoryBarrier, // ...
EOpWorkgroupMemoryBarrierWithGroupSync, // ...
EOpEvaluateAttributeSnapped, // InterpolateAtOffset with int position on 16x16 grid
@@ -772,6 +791,7 @@ class TIntermBranch;
class TIntermTyped;
class TIntermMethod;
class TIntermSymbol;
class TIntermLoop;
} // end namespace glslang
@@ -799,6 +819,7 @@ public:
virtual glslang::TIntermMethod* getAsMethodNode() { return 0; }
virtual glslang::TIntermSymbol* getAsSymbolNode() { return 0; }
virtual glslang::TIntermBranch* getAsBranchNode() { return 0; }
virtual glslang::TIntermLoop* getAsLoopNode() { return 0; }
virtual const glslang::TIntermTyped* getAsTyped() const { return 0; }
virtual const glslang::TIntermOperator* getAsOperator() const { return 0; }
@@ -811,6 +832,7 @@ public:
virtual const glslang::TIntermMethod* getAsMethodNode() const { return 0; }
virtual const glslang::TIntermSymbol* getAsSymbolNode() const { return 0; }
virtual const glslang::TIntermBranch* getAsBranchNode() const { return 0; }
virtual const glslang::TIntermLoop* getAsLoopNode() const { return 0; }
virtual ~TIntermNode() { }
protected:
@@ -854,6 +876,8 @@ public:
virtual bool isVector() const { return type.isVector(); }
virtual bool isScalar() const { return type.isScalar(); }
virtual bool isStruct() const { return type.isStruct(); }
virtual bool isFloatingDomain() const { return type.isFloatingDomain(); }
virtual bool isIntegerDomain() const { return type.isIntegerDomain(); }
TString getCompleteString() const { return type.getCompleteString(); }
protected:
@@ -861,6 +885,15 @@ protected:
TType type;
};
//
// Selection control hints
//
enum TSelectionControl {
ESelectionControlNone,
ESelectionControlFlatten,
ESelectionControlDontFlatten,
};
//
// Loop control hints
//
@@ -883,6 +916,8 @@ public:
control(ELoopControlNone)
{ }
virtual TIntermLoop* getAsLoopNode() { return this; }
virtual const TIntermLoop* getAsLoopNode() const { return this; }
virtual void traverse(TIntermTraverser*);
TIntermNode* getBody() const { return body; }
TIntermTyped* getTest() const { return test; }
@@ -945,7 +980,11 @@ public:
// per process threadPoolAllocator, then it causes increased memory usage per compile
// it is essential to use "symbol = sym" to assign to symbol
TIntermSymbol(int i, const TString& n, const TType& t)
: TIntermTyped(t), id(i), constSubtree(nullptr)
: TIntermTyped(t), id(i),
#ifdef ENABLE_HLSL
flattenSubset(-1),
#endif
constSubtree(nullptr)
{ name = n; }
virtual int getId() const { return id; }
virtual const TString& getName() const { return name; }
@@ -956,9 +995,20 @@ public:
const TConstUnionArray& getConstArray() const { return constArray; }
void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
TIntermTyped* getConstSubtree() const { return constSubtree; }
#ifdef ENABLE_HLSL
void setFlattenSubset(int subset) { flattenSubset = subset; }
int getFlattenSubset() const { return flattenSubset; } // -1 means full object
#endif
// This is meant for cases where a node has already been constructed, and
// later on, it becomes necessary to switch to a different symbol.
virtual void switchId(int newId) { id = newId; }
protected:
int id; // the unique id of the symbol this node represents
#ifdef ENABLE_HLSL
int flattenSubset; // how deeply the flattened object rooted at id has been dereferenced
#endif
TString name; // the name of the symbol this node represents
TConstUnionArray constArray; // if the symbol is a front-end compile-time constant, this is its value
TIntermTyped* constSubtree;
@@ -996,6 +1046,9 @@ struct TCrackedTextureOp {
bool grad;
bool subpass;
bool lodClamp;
#ifdef AMD_EXTENSIONS
bool fragMask;
#endif
};
//
@@ -1043,6 +1096,9 @@ public:
cracked.grad = false;
cracked.subpass = false;
cracked.lodClamp = false;
#ifdef AMD_EXTENSIONS
cracked.fragMask = false;
#endif
switch (op) {
case EOpImageQuerySize:
@@ -1169,6 +1225,19 @@ public:
cracked.offsets = true;
cracked.lod = true;
break;
case EOpImageLoadLod:
case EOpImageStoreLod:
case EOpSparseImageLoadLod:
cracked.lod = true;
break;
case EOpFragmentMaskFetch:
cracked.subpass = sampler.dim == EsdSubpass;
cracked.fragMask = true;
break;
case EOpFragmentFetch:
cracked.subpass = sampler.dim == EsdSubpass;
cracked.fragMask = true;
break;
#endif
case EOpSubpassLoad:
case EOpSubpassLoadMS:
@@ -1229,14 +1298,14 @@ protected:
};
typedef TVector<TIntermNode*> TIntermSequence;
typedef TVector<int> TQualifierList;
typedef TVector<TStorageQualifier> TQualifierList;
//
// Nodes that operate on an arbitrary sized set of children.
//
class TIntermAggregate : public TIntermOperator {
public:
TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(0) { }
TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(0) { }
TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(nullptr) { }
TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(nullptr) { }
~TIntermAggregate() { delete pragmaTable; }
virtual TIntermAggregate* getAsAggregate() { return this; }
virtual const TIntermAggregate* getAsAggregate() const { return this; }
@@ -1254,7 +1323,7 @@ public:
void setDebug(bool d) { debug = d; }
bool getOptimize() const { return optimize; }
bool getDebug() const { return debug; }
void addToPragmaTable(const TPragmaTable& pTable);
void setPragmaTable(const TPragmaTable& pTable);
const TPragmaTable& getPragmaTable() const { return *pragmaTable; }
protected:
TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
@@ -1274,19 +1343,22 @@ protected:
class TIntermSelection : public TIntermTyped {
public:
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
virtual void traverse(TIntermTraverser*);
virtual TIntermTyped* getCondition() const { return condition; }
virtual TIntermNode* getTrueBlock() const { return trueBlock; }
virtual TIntermNode* getFalseBlock() const { return falseBlock; }
virtual TIntermSelection* getAsSelectionNode() { return this; }
virtual const TIntermSelection* getAsSelectionNode() const { return this; }
void setSelectionControl(TSelectionControl c) { control = c; }
TSelectionControl getSelectionControl() const { return control; }
protected:
TIntermTyped* condition;
TIntermNode* trueBlock;
TIntermNode* falseBlock;
TSelectionControl control; // selection control hint
};
//
@@ -1297,15 +1369,18 @@ protected:
//
class TIntermSwitch : public TIntermNode {
public:
TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b) { }
TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b), control(ESelectionControlNone) { }
virtual void traverse(TIntermTraverser*);
virtual TIntermNode* getCondition() const { return condition; }
virtual TIntermAggregate* getBody() const { return body; }
virtual TIntermSwitch* getAsSwitchNode() { return this; }
virtual const TIntermSwitch* getAsSwitchNode() const { return this; }
void setSelectionControl(TSelectionControl c) { control = c; }
TSelectionControl getSelectionControl() const { return control; }
protected:
TIntermTyped* condition;
TIntermAggregate* body;
TSelectionControl control; // selection control hint
};
enum TVisit
View File
+26 -2
View File
@@ -38,6 +38,7 @@
#include <cmath>
#include <cfloat>
#include <cstdlib>
#include <climits>
namespace {
@@ -263,8 +264,31 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right
for (int i = 0; i < newComps; i++) {
if (rightUnionArray[i] == 0)
newConstArray[i] = leftUnionArray[i];
else
newConstArray[i] = leftUnionArray[i] % rightUnionArray[i];
else {
switch (getType().getBasicType()) {
case EbtInt:
if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == INT_MIN) {
newConstArray[i].setIConst(0);
break;
} else goto modulo_default;
case EbtInt64:
if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == LLONG_MIN) {
newConstArray[i].setI64Const(0);
break;
} else goto modulo_default;
#ifdef AMD_EXTENSIONS
case EbtInt16:
if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == SHRT_MIN) {
newConstArray[i].setIConst(0);
break;
} else goto modulo_default;
#endif
default:
modulo_default:
newConstArray[i] = leftUnionArray[i] % rightUnionArray[i];
}
}
}
break;
View File
+320 -49
View File
@@ -1,7 +1,7 @@
//
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
// Copyright (C) 2012-2016 LunarG, Inc.
// Copyright (C) 2015-2016 Google, Inc.
// Copyright (C) 2015-2017 Google, Inc.
//
// All rights reserved.
//
@@ -923,6 +923,32 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"\n");
}
#ifdef NV_EXTENSIONS
if (profile != EEsProfile && version >= 440) {
commonBuiltins.append(
"uint64_t atomicMin(coherent volatile inout uint64_t, uint64_t);"
" int64_t atomicMin(coherent volatile inout int64_t, int64_t);"
"uint64_t atomicMax(coherent volatile inout uint64_t, uint64_t);"
" int64_t atomicMax(coherent volatile inout int64_t, int64_t);"
"uint64_t atomicAnd(coherent volatile inout uint64_t, uint64_t);"
" int64_t atomicAnd(coherent volatile inout int64_t, int64_t);"
"uint64_t atomicOr (coherent volatile inout uint64_t, uint64_t);"
" int64_t atomicOr (coherent volatile inout int64_t, int64_t);"
"uint64_t atomicXor(coherent volatile inout uint64_t, uint64_t);"
" int64_t atomicXor(coherent volatile inout int64_t, int64_t);"
" int64_t atomicAdd(coherent volatile inout int64_t, int64_t);"
" int64_t atomicExchange(coherent volatile inout int64_t, int64_t);"
" int64_t atomicCompSwap(coherent volatile inout int64_t, int64_t, int64_t);"
"\n");
}
#endif
if ((profile == EEsProfile && version >= 310) ||
(profile != EEsProfile && version >= 450)) {
commonBuiltins.append(
@@ -1330,15 +1356,33 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
if (profile == EEsProfile) {
if (spvVersion.spv == 0) {
if (version < 300) {
commonBuiltins.append(
"vec4 texture2D(samplerExternalOES, vec2 coord);" // GL_OES_EGL_image_external
"vec4 texture2DProj(samplerExternalOES, vec3);" // GL_OES_EGL_image_external
"vec4 texture2DProj(samplerExternalOES, vec4);" // GL_OES_EGL_image_external
"\n");
} else {
commonBuiltins.append(
"highp ivec2 textureSize(samplerExternalOES, int lod);" // GL_OES_EGL_image_external_essl3
"vec4 texture(samplerExternalOES, vec2);" // GL_OES_EGL_image_external_essl3
"vec4 texture(samplerExternalOES, vec2, float bias);" // GL_OES_EGL_image_external_essl3
"vec4 textureProj(samplerExternalOES, vec3);" // GL_OES_EGL_image_external_essl3
"vec4 textureProj(samplerExternalOES, vec3, float bias);" // GL_OES_EGL_image_external_essl3
"vec4 textureProj(samplerExternalOES, vec4);" // GL_OES_EGL_image_external_essl3
"vec4 textureProj(samplerExternalOES, vec4, float bias);" // GL_OES_EGL_image_external_essl3
"vec4 texelFetch(samplerExternalOES, ivec2, int lod);" // GL_OES_EGL_image_external_essl3
"\n");
}
commonBuiltins.append(
"vec4 texture2D(samplerExternalOES, vec2 coord);" // GL_OES_EGL_image_external, caught by keyword check
"vec4 texture2DProj(samplerExternalOES, vec3);" // GL_OES_EGL_image_external, caught by keyword check
"vec4 texture2DProj(samplerExternalOES, vec4);" // GL_OES_EGL_image_external, caught by keyword check
"vec4 texture2DGradEXT(sampler2D, vec2, vec2, vec2);" // GL_EXT_shader_texture_lod
"vec4 texture2DProjGradEXT(sampler2D, vec3, vec2, vec2);" // GL_EXT_shader_texture_lod
"vec4 texture2DProjGradEXT(sampler2D, vec4, vec2, vec2);" // GL_EXT_shader_texture_lod
"vec4 textureCubeGradEXT(samplerCube, vec3, vec3, vec3);" // GL_EXT_shader_texture_lod
"float shadow2DEXT(sampler2DShadow, vec3);" // GL_EXT_shadow_samplers
"float shadow2DProjEXT(sampler2DShadow, vec4);" // GL_EXT_shadow_samplers
"\n");
}
}
@@ -1346,7 +1390,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
//
// Noise functions.
//
if (profile != EEsProfile) {
if (spvVersion.spv == 0 && profile != EEsProfile) {
commonBuiltins.append(
"float noise1(float x);"
"float noise1(vec2 x);"
@@ -1378,9 +1422,23 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
if ((profile != EEsProfile && version >= 300) ||
(profile == EEsProfile && version >= 310)) {
commonBuiltins.append(
"uint atomicCounterIncrement(atomic_uint x);"
"uint atomicCounterDecrement(atomic_uint x);"
"uint atomicCounter(atomic_uint x);"
"uint atomicCounterIncrement(atomic_uint);"
"uint atomicCounterDecrement(atomic_uint);"
"uint atomicCounter(atomic_uint);"
"\n");
}
if (profile != EEsProfile && version >= 460) {
commonBuiltins.append(
"uint atomicCounterAdd(atomic_uint, uint);"
"uint atomicCounterSubtract(atomic_uint, uint);"
"uint atomicCounterMin(atomic_uint, uint);"
"uint atomicCounterMax(atomic_uint, uint);"
"uint atomicCounterAnd(atomic_uint, uint);"
"uint atomicCounterOr(atomic_uint, uint);"
"uint atomicCounterXor(atomic_uint, uint);"
"uint atomicCounterExchange(atomic_uint, uint);"
"uint atomicCounterCompSwap(atomic_uint, uint, uint);"
"\n");
}
@@ -1565,7 +1623,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"\n");
}
// GL_ARB_shader_group_vote
// GL_ARB_shader_group_vote
if (profile != EEsProfile && version >= 430) {
commonBuiltins.append(
"bool anyInvocationARB(bool);"
@@ -1575,6 +1633,15 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"\n");
}
if (profile != EEsProfile && version >= 460) {
commonBuiltins.append(
"bool anyInvocation(bool);"
"bool allInvocations(bool);"
"bool allInvocationsEqual(bool);"
"\n");
}
#ifdef AMD_EXTENSIONS
// GL_AMD_shader_ballot
if (profile != EEsProfile && version >= 450) {
@@ -2263,7 +2330,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
if (profile != EEsProfile && version >= 450) {
commonBuiltins.append(
"float cubeFaceIndexAMD(vec3);"
"vec2 cubeFaceCoordAMD(vec3);"
"vec2 cubeFaceCoordAMD(vec3);"
"uint64_t timeAMD();"
"\n");
@@ -2767,6 +2834,29 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"\n");
}
// GL_AMD_shader_fragment_mask
if (profile != EEsProfile && version >= 450) {
commonBuiltins.append(
"uint fragmentMaskFetchAMD(sampler2DMS, ivec2);"
"uint fragmentMaskFetchAMD(isampler2DMS, ivec2);"
"uint fragmentMaskFetchAMD(usampler2DMS, ivec2);"
"uint fragmentMaskFetchAMD(sampler2DMSArray, ivec3);"
"uint fragmentMaskFetchAMD(isampler2DMSArray, ivec3);"
"uint fragmentMaskFetchAMD(usampler2DMSArray, ivec3);"
"vec4 fragmentFetchAMD(sampler2DMS, ivec2, uint);"
"ivec4 fragmentFetchAMD(isampler2DMS, ivec2, uint);"
"uvec4 fragmentFetchAMD(usampler2DMS, ivec2, uint);"
"vec4 fragmentFetchAMD(sampler2DMSArray, ivec3, uint);"
"ivec4 fragmentFetchAMD(isampler2DMSArray, ivec3, uint);"
"uvec4 fragmentFetchAMD(usampler2DMSArray, ivec3, uint);"
"\n");
}
#endif
//============================================================================
@@ -3115,6 +3205,20 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"\n");
}
// GL_AMD_shader_fragment_mask
if (profile != EEsProfile && version >= 450 && spvVersion.vulkan >= 100) {
stageBuiltins[EShLangFragment].append(
"uint fragmentMaskFetchAMD(subpassInputMS);"
"uint fragmentMaskFetchAMD(isubpassInputMS);"
"uint fragmentMaskFetchAMD(usubpassInputMS);"
"vec4 fragmentFetchAMD(subpassInputMS, uint);"
"ivec4 fragmentFetchAMD(isubpassInputMS, uint);"
"uvec4 fragmentFetchAMD(usubpassInputMS, uint);"
"\n");
}
#endif
//============================================================================
@@ -3414,12 +3518,23 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"in int gl_DrawIDARB;"
);
}
if (version >= 410) {
stageBuiltins[EShLangVertex].append(
"out int gl_ViewportIndex;"
"out int gl_Layer;"
);
}
if (version >= 460) {
stageBuiltins[EShLangVertex].append(
"in int gl_BaseVertex;"
"in int gl_BaseInstance;"
"in int gl_DrawID;"
);
}
#ifdef NV_EXTENSIONS
if (version >= 450)
stageBuiltins[EShLangVertex].append(
"out int gl_ViewportIndex;"
"out int gl_Layer;"
"out int gl_ViewportMask[];" // GL_NV_viewport_array2
"out int gl_SecondaryViewportMaskNV[];" // GL_NV_stereo_view_rendering
"out vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering
@@ -3469,6 +3584,12 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"\n");
}
if (version >= 300 /* both ES and non-ES */) {
stageBuiltins[EShLangVertex].append(
"in highp uint gl_ViewID_OVR;" // GL_OVR_multiview, GL_OVR_multiview2
"\n");
}
//============================================================================
//
@@ -3530,6 +3651,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"out int gl_PrimitiveID;"
"out int gl_Layer;");
if (version >= 150)
stageBuiltins[EShLangGeometry].append(
"out int gl_ViewportIndex;"
);
if (profile == ECompatibilityProfile && version < 400)
stageBuiltins[EShLangGeometry].append(
"out vec4 gl_ClipVertex;"
@@ -3539,11 +3665,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
stageBuiltins[EShLangGeometry].append(
"in int gl_InvocationID;"
);
// GL_ARB_viewport_array
if (version >= 150)
stageBuiltins[EShLangGeometry].append(
"out int gl_ViewportIndex;"
);
#ifdef NV_EXTENSIONS
if (version >= 450)
@@ -3620,8 +3741,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
stageBuiltins[EShLangTessControl].append(
"float gl_CullDistance[];"
#ifdef NV_EXTENSIONS
"int gl_ViewportIndex;"
"int gl_Layer;"
"int gl_ViewportMask[];" // GL_NV_viewport_array2
"vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering
"int gl_SecondaryViewportMaskNV[];" // GL_NV_stereo_view_rendering
@@ -3635,6 +3754,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"patch out float gl_TessLevelOuter[4];"
"patch out float gl_TessLevelInner[2];"
"\n");
if (version >= 410)
stageBuiltins[EShLangTessControl].append(
"out int gl_ViewportIndex;"
"out int gl_Layer;"
"\n");
} else {
// Note: "in gl_PerVertex {...} gl_in[gl_MaxPatchVertices];" is declared in initialize() below,
// as it depends on the resource sizing of gl_MaxPatchVertices.
@@ -3706,11 +3832,15 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"};"
"\n");
if (version >= 410)
stageBuiltins[EShLangTessEvaluation].append(
"out int gl_ViewportIndex;"
"out int gl_Layer;"
"\n");
#ifdef NV_EXTENSIONS
if (version >= 450)
stageBuiltins[EShLangTessEvaluation].append(
"out int gl_ViewportIndex;"
"out int gl_Layer;"
"out int gl_ViewportMask[];" // GL_NV_viewport_array2
"out vec4 gl_SecondaryPositionNV;" // GL_NV_stereo_view_rendering
"out int gl_SecondaryViewportMaskNV[];" // GL_NV_stereo_view_rendering
@@ -3765,6 +3895,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
stageBuiltins[EShLangFragment].append(
"vec2 gl_PointCoord;" // needs qualifier fixed later
);
if (version >= 140)
stageBuiltins[EShLangFragment].append(
"out int gl_FragStencilRefARB;"
);
if (IncludeLegacy(version, profile, spvVersion) || (! ForwardCompatibility && version < 420))
stageBuiltins[EShLangFragment].append(
"vec4 gl_FragColor;" // needs qualifier fixed later
@@ -3844,6 +3978,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"in vec3 gl_BaryCoordPullModelAMD;"
);
#endif
#ifdef NV_EXTENSIONS
if (version >= 430)
stageBuiltins[EShLangFragment].append(
"in bool gl_FragFullyCoveredNV;"
);
#endif
} else {
// ES profile
@@ -3913,6 +4054,12 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"\n");
}
if (version >= 300 /* both ES and non-ES */) {
stageBuiltins[EShLangFragment].append(
"flat in highp uint gl_ViewID_OVR;" // GL_OVR_multiview, GL_OVR_multiview2
"\n");
}
// printf("%s\n", commonBuiltins.c_str());
// printf("%s\n", stageBuiltins[EShLangFragment].c_str());
}
@@ -4204,6 +4351,43 @@ void TBuiltIns::addImageFunctions(TSampler sampler, const TString& typeName, int
}
}
}
#ifdef AMD_EXTENSIONS
if (sampler.dim == EsdRect || sampler.dim == EsdBuffer || sampler.shadow || sampler.ms)
return;
if (profile == EEsProfile || version < 450)
return;
TString imageLodParams = typeName;
if (dims == 1)
imageLodParams.append(", int");
else {
imageLodParams.append(", ivec");
imageLodParams.append(postfixes[dims]);
}
imageLodParams.append(", int");
commonBuiltins.append(prefixes[sampler.type]);
commonBuiltins.append("vec4 imageLoadLodAMD(readonly volatile coherent ");
commonBuiltins.append(imageLodParams);
commonBuiltins.append(");\n");
commonBuiltins.append("void imageStoreLodAMD(writeonly volatile coherent ");
commonBuiltins.append(imageLodParams);
commonBuiltins.append(", ");
commonBuiltins.append(prefixes[sampler.type]);
commonBuiltins.append("vec4);\n");
if (sampler.dim != Esd1D) {
commonBuiltins.append("int sparseImageLoadLodAMD(readonly volatile coherent ");
commonBuiltins.append(imageLodParams);
commonBuiltins.append(", out ");
commonBuiltins.append(prefixes[sampler.type]);
commonBuiltins.append("vec4");
commonBuiltins.append(");\n");
}
#endif
}
//
@@ -5212,16 +5396,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
switch(language) {
case EShLangVertex:
if (profile != EEsProfile) {
symbolTable.setVariableExtensions("gl_BaseVertexARB", 1, &E_GL_ARB_shader_draw_parameters);
symbolTable.setVariableExtensions("gl_BaseInstanceARB", 1, &E_GL_ARB_shader_draw_parameters);
symbolTable.setVariableExtensions("gl_DrawIDARB", 1, &E_GL_ARB_shader_draw_parameters);
BuiltInVariable("gl_BaseVertexARB", EbvBaseVertex, symbolTable);
BuiltInVariable("gl_BaseInstanceARB", EbvBaseInstance, symbolTable);
BuiltInVariable("gl_DrawIDARB", EbvDrawId, symbolTable);
}
if (profile != EEsProfile) {
if (version >= 440) {
symbolTable.setVariableExtensions("gl_BaseVertexARB", 1, &E_GL_ARB_shader_draw_parameters);
symbolTable.setVariableExtensions("gl_BaseInstanceARB", 1, &E_GL_ARB_shader_draw_parameters);
symbolTable.setVariableExtensions("gl_DrawIDARB", 1, &E_GL_ARB_shader_draw_parameters);
BuiltInVariable("gl_BaseVertexARB", EbvBaseVertex, symbolTable);
BuiltInVariable("gl_BaseInstanceARB", EbvBaseInstance, symbolTable);
BuiltInVariable("gl_DrawIDARB", EbvDrawId, symbolTable);
}
if (version >= 460) {
BuiltInVariable("gl_BaseVertex", EbvBaseVertex, symbolTable);
BuiltInVariable("gl_BaseInstance", EbvBaseInstance, symbolTable);
BuiltInVariable("gl_DrawID", EbvDrawId, symbolTable);
}
symbolTable.setVariableExtensions("gl_SubGroupSizeARB", 1, &E_GL_ARB_shader_ballot);
symbolTable.setVariableExtensions("gl_SubGroupInvocationARB", 1, &E_GL_ARB_shader_ballot);
symbolTable.setVariableExtensions("gl_SubGroupEqMaskARB", 1, &E_GL_ARB_shader_ballot);
@@ -5245,9 +5432,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
// Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan
SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable);
symbolTable.setFunctionExtensions("anyInvocationARB", 1, &E_GL_ARB_shader_group_vote);
symbolTable.setFunctionExtensions("allInvocationsARB", 1, &E_GL_ARB_shader_group_vote);
symbolTable.setFunctionExtensions("allInvocationsEqualARB", 1, &E_GL_ARB_shader_group_vote);
if (version >= 430) {
symbolTable.setFunctionExtensions("anyInvocationARB", 1, &E_GL_ARB_shader_group_vote);
symbolTable.setFunctionExtensions("allInvocationsARB", 1, &E_GL_ARB_shader_group_vote);
symbolTable.setFunctionExtensions("allInvocationsEqualARB", 1, &E_GL_ARB_shader_group_vote);
}
}
#ifdef AMD_EXTENSIONS
@@ -5288,6 +5477,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setFunctionExtensions("cubeFaceCoordAMD", 1, &E_GL_AMD_gcn_shader);
symbolTable.setFunctionExtensions("timeAMD", 1, &E_GL_AMD_gcn_shader);
}
if (profile != EEsProfile) {
symbolTable.setFunctionExtensions("fragmentMaskFetchAMD", 1, &E_GL_AMD_shader_fragment_mask);
symbolTable.setFunctionExtensions("fragmentFetchAMD", 1, &E_GL_AMD_shader_fragment_mask);
}
#endif
// Compatibility variables, vertex only
@@ -5312,13 +5506,14 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setFunctionExtensions("texture2DGradEXT", 1, &E_GL_EXT_shader_texture_lod);
symbolTable.setFunctionExtensions("texture2DProjGradEXT", 1, &E_GL_EXT_shader_texture_lod);
symbolTable.setFunctionExtensions("textureCubeGradEXT", 1, &E_GL_EXT_shader_texture_lod);
symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5);
if (version == 310)
symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5);
}
if (version >= 310)
if (version == 310)
symbolTable.setFunctionExtensions("fma", Num_AEP_gpu_shader5, AEP_gpu_shader5);
}
if (profile == EEsProfile) {
if (profile == EEsProfile && version < 320) {
symbolTable.setFunctionExtensions("imageAtomicAdd", 1, &E_GL_OES_shader_image_atomic);
symbolTable.setFunctionExtensions("imageAtomicMin", 1, &E_GL_OES_shader_image_atomic);
symbolTable.setFunctionExtensions("imageAtomicMax", 1, &E_GL_OES_shader_image_atomic);
@@ -5339,12 +5534,24 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
BuiltInVariable("gl_InstanceIndex", EbvInstanceIndex, symbolTable);
}
if (version >= 300 /* both ES and non-ES */) {
symbolTable.setVariableExtensions("gl_ViewID_OVR", Num_OVR_multiview_EXTs, OVR_multiview_EXTs);
BuiltInVariable("gl_ViewID_OVR", EbvViewIndex, symbolTable);
}
if (profile == EEsProfile) {
symbolTable.setFunctionExtensions("shadow2DEXT", 1, &E_GL_EXT_shadow_samplers);
symbolTable.setFunctionExtensions("shadow2DProjEXT", 1, &E_GL_EXT_shadow_samplers);
}
// Fall through
case EShLangTessControl:
if (profile == EEsProfile && version >= 310) {
symbolTable.setVariableExtensions("gl_BoundingBoxOES", Num_AEP_primitive_bounding_box, AEP_primitive_bounding_box);
BuiltInVariable("gl_BoundingBoxOES", EbvBoundingBox, symbolTable);
if (version < 320)
symbolTable.setVariableExtensions("gl_BoundingBoxOES", Num_AEP_primitive_bounding_box,
AEP_primitive_bounding_box);
}
// Fall through
@@ -5378,6 +5585,14 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setVariableExtensions("gl_Layer", Num_viewportEXTs, viewportEXTs);
symbolTable.setVariableExtensions("gl_ViewportIndex", Num_viewportEXTs, viewportEXTs);
}
#else
if (language != EShLangGeometry && version >= 410) {
symbolTable.setVariableExtensions("gl_Layer", 1, &E_GL_ARB_shader_viewport_layer_array);
symbolTable.setVariableExtensions("gl_ViewportIndex", 1, &E_GL_ARB_shader_viewport_layer_array);
}
#endif
#ifdef NV_EXTENSIONS
symbolTable.setVariableExtensions("gl_ViewportMask", 1, &E_GL_NV_viewport_array2);
symbolTable.setVariableExtensions("gl_SecondaryPositionNV", 1, &E_GL_NV_stereo_view_rendering);
symbolTable.setVariableExtensions("gl_SecondaryViewportMaskNV", 1, &E_GL_NV_stereo_view_rendering);
@@ -5394,8 +5609,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
BuiltInVariable("gl_in", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
BuiltInVariable("gl_in", "gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable);
}
BuiltInVariable("gl_out", "gl_Layer", EbvLayer, symbolTable);
BuiltInVariable("gl_out", "gl_ViewportIndex", EbvViewportIndex, symbolTable);
BuiltInVariable("gl_out", "gl_ViewportMask", EbvViewportMaskNV, symbolTable);
BuiltInVariable("gl_out", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
@@ -5480,13 +5693,18 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
BuiltInVariable("gl_CullDistance", EbvCullDistance, symbolTable);
BuiltInVariable("gl_PrimitiveID", EbvPrimitiveId, symbolTable);
if (profile != EEsProfile && version >= 140) {
symbolTable.setVariableExtensions("gl_FragStencilRefARB", 1, &E_GL_ARB_shader_stencil_export);
BuiltInVariable("gl_FragStencilRefARB", EbvFragStencilRef, symbolTable);
}
if ((profile != EEsProfile && version >= 400) ||
(profile == EEsProfile && version >= 310)) {
BuiltInVariable("gl_SampleID", EbvSampleId, symbolTable);
BuiltInVariable("gl_SamplePosition", EbvSamplePosition, symbolTable);
BuiltInVariable("gl_SampleMaskIn", EbvSampleMask, symbolTable);
BuiltInVariable("gl_SampleMask", EbvSampleMask, symbolTable);
if (profile == EEsProfile) {
if (profile == EEsProfile && version < 320) {
symbolTable.setVariableExtensions("gl_SampleID", 1, &E_GL_OES_sample_variables);
symbolTable.setVariableExtensions("gl_SamplePosition", 1, &E_GL_OES_sample_variables);
symbolTable.setVariableExtensions("gl_SampleMaskIn", 1, &E_GL_OES_sample_variables);
@@ -5520,14 +5738,15 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setFunctionExtensions("texture2DGradEXT", 1, &E_GL_EXT_shader_texture_lod);
symbolTable.setFunctionExtensions("texture2DProjGradEXT", 1, &E_GL_EXT_shader_texture_lod);
symbolTable.setFunctionExtensions("textureCubeGradEXT", 1, &E_GL_EXT_shader_texture_lod);
symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5);
if (version < 320)
symbolTable.setFunctionExtensions("textureGatherOffsets", Num_AEP_gpu_shader5, AEP_gpu_shader5);
}
if (version == 100) {
symbolTable.setFunctionExtensions("dFdx", 1, &E_GL_OES_standard_derivatives);
symbolTable.setFunctionExtensions("dFdy", 1, &E_GL_OES_standard_derivatives);
symbolTable.setFunctionExtensions("fwidth", 1, &E_GL_OES_standard_derivatives);
}
if (version >= 310) {
if (version == 310) {
symbolTable.setFunctionExtensions("fma", Num_AEP_gpu_shader5, AEP_gpu_shader5);
symbolTable.setFunctionExtensions("interpolateAtCentroid", 1, &E_GL_OES_shader_multisample_interpolation);
symbolTable.setFunctionExtensions("interpolateAtSample", 1, &E_GL_OES_shader_multisample_interpolation);
@@ -5673,16 +5892,30 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setFunctionExtensions("sparseTextureGatherLodOffsetAMD", 1, &E_GL_AMD_texture_gather_bias_lod);
symbolTable.setFunctionExtensions("sparseTextureGatherLodOffsetsAMD", 1, &E_GL_AMD_texture_gather_bias_lod);
}
// E_GL_AMD_shader_image_load_store_lod
if (profile != EEsProfile) {
symbolTable.setFunctionExtensions("imageLoadLodAMD", 1, &E_GL_AMD_shader_image_load_store_lod);
symbolTable.setFunctionExtensions("imageStoreLodAMD", 1, &E_GL_AMD_shader_image_load_store_lod);
symbolTable.setFunctionExtensions("sparseImageLoadLodAMD", 1, &E_GL_AMD_shader_image_load_store_lod);
}
#endif
#ifdef NV_EXTENSIONS
if (profile != EEsProfile && version >= 430) {
symbolTable.setVariableExtensions("gl_FragFullyCoveredNV", 1, &E_GL_NV_conservative_raster_underestimation);
BuiltInVariable("gl_FragFullyCoveredNV", EbvFragFullyCoveredNV, symbolTable);
}
#endif
symbolTable.setVariableExtensions("gl_FragDepthEXT", 1, &E_GL_EXT_frag_depth);
if (profile == EEsProfile) {
if (profile == EEsProfile && version < 320) {
symbolTable.setVariableExtensions("gl_PrimitiveID", Num_AEP_geometry_shader, AEP_geometry_shader);
symbolTable.setVariableExtensions("gl_Layer", Num_AEP_geometry_shader, AEP_geometry_shader);
}
if (profile == EEsProfile) {
if (profile == EEsProfile && version < 320) {
symbolTable.setFunctionExtensions("imageAtomicAdd", 1, &E_GL_OES_shader_image_atomic);
symbolTable.setFunctionExtensions("imageAtomicMin", 1, &E_GL_OES_shader_image_atomic);
symbolTable.setFunctionExtensions("imageAtomicMax", 1, &E_GL_OES_shader_image_atomic);
@@ -5697,6 +5930,15 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable);
symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview);
BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable);
if (version >= 300 /* both ES and non-ES */) {
symbolTable.setVariableExtensions("gl_ViewID_OVR", Num_OVR_multiview_EXTs, OVR_multiview_EXTs);
BuiltInVariable("gl_ViewID_OVR", EbvViewIndex, symbolTable);
}
if (profile == EEsProfile) {
symbolTable.setFunctionExtensions("shadow2DEXT", 1, &E_GL_EXT_shadow_samplers);
symbolTable.setFunctionExtensions("shadow2DProjEXT", 1, &E_GL_EXT_shadow_samplers);
}
break;
case EShLangCompute:
@@ -5898,6 +6140,18 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.relateToOperator("atomicCounterDecrement", EOpAtomicCounterDecrement);
symbolTable.relateToOperator("atomicCounter", EOpAtomicCounter);
if (profile != EEsProfile && version >= 460) {
symbolTable.relateToOperator("atomicCounterAdd", EOpAtomicCounterAdd);
symbolTable.relateToOperator("atomicCounterSubtract", EOpAtomicCounterSubtract);
symbolTable.relateToOperator("atomicCounterMin", EOpAtomicCounterMin);
symbolTable.relateToOperator("atomicCounterMax", EOpAtomicCounterMax);
symbolTable.relateToOperator("atomicCounterAnd", EOpAtomicCounterAnd);
symbolTable.relateToOperator("atomicCounterOr", EOpAtomicCounterOr);
symbolTable.relateToOperator("atomicCounterXor", EOpAtomicCounterXor);
symbolTable.relateToOperator("atomicCounterExchange", EOpAtomicCounterExchange);
symbolTable.relateToOperator("atomicCounterCompSwap", EOpAtomicCounterCompSwap);
}
symbolTable.relateToOperator("fma", EOpFma);
symbolTable.relateToOperator("frexp", EOpFrexp);
symbolTable.relateToOperator("ldexp", EOpLdexp);
@@ -6049,10 +6303,16 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.relateToOperator("readInvocationARB", EOpReadInvocation);
symbolTable.relateToOperator("readFirstInvocationARB", EOpReadFirstInvocation);
symbolTable.relateToOperator("anyInvocationARB", EOpAnyInvocation);
symbolTable.relateToOperator("allInvocationsARB", EOpAllInvocations);
symbolTable.relateToOperator("allInvocationsEqualARB", EOpAllInvocationsEqual);
if (version >= 430) {
symbolTable.relateToOperator("anyInvocationARB", EOpAnyInvocation);
symbolTable.relateToOperator("allInvocationsARB", EOpAllInvocations);
symbolTable.relateToOperator("allInvocationsEqualARB", EOpAllInvocationsEqual);
}
if (version >= 460) {
symbolTable.relateToOperator("anyInvocation", EOpAnyInvocation);
symbolTable.relateToOperator("allInvocations", EOpAllInvocations);
symbolTable.relateToOperator("allInvocationsEqual", EOpAllInvocationsEqual);
}
#ifdef AMD_EXTENSIONS
symbolTable.relateToOperator("minInvocationsAMD", EOpMinInvocations);
symbolTable.relateToOperator("maxInvocationsAMD", EOpMaxInvocations);
@@ -6091,8 +6351,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.relateToOperator("sparseTextureGatherLodAMD", EOpSparseTextureGatherLod);
symbolTable.relateToOperator("sparseTextureGatherLodOffsetAMD", EOpSparseTextureGatherLodOffset);
symbolTable.relateToOperator("sparseTextureGatherLodOffsetsAMD", EOpSparseTextureGatherLodOffsets);
symbolTable.relateToOperator("imageLoadLodAMD", EOpImageLoadLod);
symbolTable.relateToOperator("imageStoreLodAMD", EOpImageStoreLod);
symbolTable.relateToOperator("sparseImageLoadLodAMD", EOpSparseImageLoadLod);
symbolTable.relateToOperator("fragmentMaskFetchAMD", EOpFragmentMaskFetch);
symbolTable.relateToOperator("fragmentFetchAMD", EOpFragmentFetch);
#endif
}
if (profile == EEsProfile) {
symbolTable.relateToOperator("shadow2DEXT", EOpTexture);
symbolTable.relateToOperator("shadow2DProjEXT", EOpTextureProj);
}
}
switch(language) {
View File
View File
+63 -16
View File
@@ -1043,6 +1043,32 @@ TIntermTyped* TIntermediate::addShapeConversion(const TType& type, TIntermTyped*
// The new node that handles the conversion
TOperator constructorOp = mapTypeToConstructorOp(type);
// HLSL has custom semantics for scalar->mat shape conversions.
if (source == EShSourceHlsl) {
if (node->getType().isScalarOrVec1() && type.isMatrix()) {
// HLSL semantics: the scalar (or vec1) is replicated to every component of the matrix. Left to its
// own devices, the constructor from a scalar would populate the diagonal. This forces replication
// to every matrix element.
// Note that if the node is complex (e.g, a function call), we don't want to duplicate it here
// repeatedly, so we copy it to a temp, then use the temp.
const int matSize = type.getMatrixRows() * type.getMatrixCols();
TIntermAggregate* rhsAggregate = new TIntermAggregate();
const bool isSimple = (node->getAsSymbolNode() != nullptr) || (node->getAsConstantUnion() != nullptr);
if (!isSimple) {
assert(0); // TODO: use node replicator service when available.
}
for (int x=0; x<matSize; ++x)
rhsAggregate->getSequence().push_back(node);
return setAggregateOperator(rhsAggregate, constructorOp, type, node->getLoc());
}
}
// scalar -> vector or vec1 -> vector or
// vector -> scalar or
// bigger vector -> smaller vector
@@ -1588,7 +1614,7 @@ TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
//
// Returns the selection node created.
//
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc, TSelectionControl control)
{
//
// Don't prune the false path for compile-time constants; it's needed
@@ -1597,6 +1623,7 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair no
TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
node->setLoc(loc);
node->setSelectionControl(control);
return node;
}
@@ -1639,12 +1666,12 @@ TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type,
//
// Returns the selection node created, or nullptr if one could not be.
//
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc)
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc, TSelectionControl control)
{
// If it's void, go to the if-then-else selection()
if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
TIntermNodePair pair = { trueBlock, falseBlock };
return addSelection(cond, pair, loc);
return addSelection(cond, pair, loc, control);
}
//
@@ -2447,6 +2474,11 @@ bool TIntermediate::promoteBinary(TIntermBinary& node)
return false;
node.setLeft(left);
node.setRight(right);
// Update the original base assumption on result type..
node.setType(left->getType());
node.getWritableType().getQualifier().clear();
break;
default:
@@ -3143,10 +3175,10 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC
node->getLoc());
}
void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
void TIntermAggregate::setPragmaTable(const TPragmaTable& pTable)
{
assert(!pragmaTable);
pragmaTable = new TPragmaTable();
assert(pragmaTable == nullptr);
pragmaTable = new TPragmaTable;
*pragmaTable = pTable;
}
@@ -3160,6 +3192,11 @@ bool TIntermediate::specConstantPropagates(const TIntermTyped& node1, const TInt
}
struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser {
void visitSymbol(TIntermSymbol* symbol) override {
if (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isTexture()) {
symbol->getWritableType().getSampler().combined = true;
}
}
bool visitAggregate(TVisit, TIntermAggregate* ag) override {
using namespace std;
TIntermSequence& seq = ag->getSequence();
@@ -3173,17 +3210,11 @@ struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser {
});
seq.erase(newEnd, seq.end());
// replace constructors with sampler/textures
// update textures into sampled textures
for_each(seq.begin(), seq.end(), [](TIntermNode*& node) {
TIntermSymbol* symbol = node->getAsSymbolNode();
if (!symbol) {
TIntermAggregate *constructor = node->getAsAggregate();
if (constructor && constructor->getOp() == EOpConstructTextureSampler) {
if (!constructor->getSequence().empty())
node = constructor->getSequence()[0];
}
} else if (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isTexture()) {
symbol->getWritableType().getSampler().combined = true;
TIntermAggregate *constructor = node->getAsAggregate();
if (constructor && constructor->getOp() == EOpConstructTextureSampler) {
if (!constructor->getSequence().empty())
node = constructor->getSequence()[0];
}
});
return true;
@@ -3196,4 +3227,20 @@ void TIntermediate::performTextureUpgradeAndSamplerRemovalTransformation(TInterm
root->traverse(&transform);
}
const char* TIntermediate::getResourceName(TResourceType res)
{
switch (res) {
case EResSampler: return "shift-sampler-binding";
case EResTexture: return "shift-texture-binding";
case EResImage: return "shift-image-binding";
case EResUbo: return "shift-UBO-binding";
case EResSsbo: return "shift-ssbo-binding";
case EResUav: return "shift-uav-binding";
default:
assert(0); // internal error: should only be called with valid resource types.
return nullptr;
}
}
} // end namespace glslang
View File
+29
View File
@@ -234,6 +234,31 @@ void TParseContextBase::trackLinkage(TSymbol& symbol)
linkageSymbols.push_back(&symbol);
}
// Ensure index is in bounds, correct if necessary.
// Give an error if not.
void TParseContextBase::checkIndex(const TSourceLoc& loc, const TType& type, int& index)
{
if (index < 0) {
error(loc, "", "[", "index out of range '%d'", index);
index = 0;
} else if (type.isArray()) {
if (type.isExplicitlySizedArray() && index >= type.getOuterArraySize()) {
error(loc, "", "[", "array index out of range '%d'", index);
index = type.getOuterArraySize() - 1;
}
} else if (type.isVector()) {
if (index >= type.getVectorSize()) {
error(loc, "", "[", "vector index out of range '%d'", index);
index = type.getVectorSize() - 1;
}
} else if (type.isMatrix()) {
if (index >= type.getMatrixCols()) {
error(loc, "", "[", "matrix index out of range '%d'", index);
index = type.getMatrixCols() - 1;
}
}
}
// 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 already sharing it (non-shallow type),
@@ -544,6 +569,10 @@ void TParseContextBase::growGlobalUniformBlock(const TSourceLoc& loc, TType& mem
firstNewMember = 0;
}
// Update with binding and set
globalUniformBlock->getWritableType().getQualifier().layoutBinding = globalUniformBinding;
globalUniformBlock->getWritableType().getQualifier().layoutSet = globalUniformSet;
// Add the requested member as a member to the global block.
TType* type = new TType;
type->shallowCopy(memberType);
+166 -93
View File
@@ -49,8 +49,10 @@ namespace glslang {
TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins,
int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) :
TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages,
const TString* entryPoint) :
TParseContextBase(symbolTable, interm, parsingBuiltins, version, profile, spvVersion, language,
infoSink, forwardCompatible, messages, entryPoint),
inMain(false),
blockName(nullptr),
limits(resources.limits),
@@ -87,6 +89,9 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b
if (language == EShLangGeometry)
globalOutputDefaults.layoutStream = 0;
if (entryPoint != nullptr && entryPoint->size() > 0 && *entryPoint != "main")
infoSink.info.message(EPrefixError, "Source entry point must be \"main\"");
}
TParseContext::~TParseContext()
@@ -121,11 +126,6 @@ void TParseContext::setPrecisionDefaults()
sampler.set(EbtFloat, Esd2D);
sampler.external = true;
defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
} else {
// Non-ES profile
// All default to highp.
for (int type = 0; type < maxSamplerIndex; ++type)
defaultSamplerPrecision[type] = EpqHigh;
}
// If we are parsing built-in computational variables/functions, it is meaningful to record
@@ -141,6 +141,13 @@ void TParseContext::setPrecisionDefaults()
defaultPrecision[EbtUint] = EpqHigh;
defaultPrecision[EbtFloat] = EpqHigh;
}
if (profile != EEsProfile) {
// Non-ES profile
// All sampler precisions default to highp.
for (int type = 0; type < maxSamplerIndex; ++type)
defaultSamplerPrecision[type] = EpqHigh;
}
}
defaultPrecision[EbtSampler] = EpqLow;
@@ -382,7 +389,8 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
if (base->getQualifier().storage == EvqBuffer)
requireProfile(base->getLoc(), ~EEsProfile, "variable indexing buffer block array");
else if (base->getQualifier().storage == EvqUniform)
profileRequires(base->getLoc(), EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "variable indexing uniform block array");
profileRequires(base->getLoc(), EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5,
"variable indexing uniform block array");
else {
// input/output blocks either don't exist or can be variable indexed
}
@@ -391,7 +399,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
else if (base->getBasicType() == EbtSampler && version >= 130) {
const char* explanation = "variable indexing sampler array";
requireProfile(base->getLoc(), EEsProfile | ECoreProfile | ECompatibilityProfile, explanation);
profileRequires(base->getLoc(), EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, explanation);
profileRequires(base->getLoc(), EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, explanation);
profileRequires(base->getLoc(), ECoreProfile | ECompatibilityProfile, 400, nullptr, explanation);
}
@@ -423,29 +431,6 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
return result;
}
void TParseContext::checkIndex(const TSourceLoc& loc, const TType& type, int& index)
{
if (index < 0) {
error(loc, "", "[", "index out of range '%d'", index);
index = 0;
} else if (type.isArray()) {
if (type.isExplicitlySizedArray() && index >= type.getOuterArraySize()) {
error(loc, "", "[", "array index out of range '%d'", index);
index = type.getOuterArraySize() - 1;
}
} else if (type.isVector()) {
if (index >= type.getVectorSize()) {
error(loc, "", "[", "vector index out of range '%d'", index);
index = type.getVectorSize() - 1;
}
} else if (type.isMatrix()) {
if (index >= type.getMatrixCols()) {
error(loc, "", "[", "matrix index out of range '%d'", index);
index = type.getMatrixCols() - 1;
}
}
}
// for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms
void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* base, TIntermTyped* index)
{
@@ -680,7 +665,8 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
// leaving swizzles and struct/block dereferences.
TIntermTyped* result = base;
if (base->isVector() || base->isScalar()) {
if ((base->isVector() || base->isScalar()) &&
(base->isFloatingDomain() || base->isIntegerDomain() || base->getBasicType() == EbtBool)) {
if (base->isScalar()) {
const char* dotFeature = "scalar swizzle";
requireProfile(loc, ~EEsProfile, dotFeature);
@@ -1142,7 +1128,13 @@ void TParseContext::computeBuiltinPrecisions(TIntermTyped& node, const TFunction
operationPrecision = std::max(operationPrecision, function[arg].type->getQualifier().precision);
}
// compute the result precision
#ifdef AMD_EXTENSIONS
if (agg->isSampling() ||
agg->getOp() == EOpImageLoad || agg->getOp() == EOpImageStore ||
agg->getOp() == EOpImageLoadLod || agg->getOp() == EOpImageStoreLod)
#else
if (agg->isSampling() || agg->getOp() == EOpImageLoad || agg->getOp() == EOpImageStore)
#endif
resultPrecision = sequence[0]->getAsTyped()->getQualifier().precision;
else if (function.getType().getBasicType() != EbtBool)
resultPrecision = function.getType().getQualifier().precision == EpqNone ?
@@ -1385,8 +1377,9 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
unaryArg = callNode.getAsUnaryNode()->getOperand();
arg0 = unaryArg;
}
const TIntermSequence& aggArgs = *argp; // only valid when unaryArg is nullptr
TString featureString;
const char* feature = nullptr;
switch (callNode.getOp()) {
case EOpTextureGather:
case EOpTextureGatherOffset:
@@ -1395,8 +1388,8 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
// Figure out which variants are allowed by what extensions,
// and what arguments must be constant for which situations.
TString featureString = fnCandidate.getName() + "(...)";
const char* feature = featureString.c_str();
featureString = fnCandidate.getName() + "(...)";
feature = featureString.c_str();
profileRequires(loc, EEsProfile, 310, nullptr, feature);
int compArg = -1; // track which argument, if any, is the constant component argument
switch (callNode.getOp()) {
@@ -1416,8 +1409,9 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature);
else
profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument");
if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
profileRequires(loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5,
"non-constant offset argument");
if (! fnCandidate[0].type->getSampler().shadow)
compArg = 3;
break;
@@ -1426,7 +1420,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
if (! fnCandidate[0].type->getSampler().shadow)
compArg = 3;
// check for constant offsets
if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
if (! (*argp)[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion())
error(loc, "must be a compile-time constant:", feature, "offsets argument");
break;
default:
@@ -1434,8 +1428,8 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
}
if (compArg > 0 && compArg < fnCandidate.getParamCount()) {
if (aggArgs[compArg]->getAsConstantUnion()) {
int value = aggArgs[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
if ((*argp)[compArg]->getAsConstantUnion()) {
int value = (*argp)[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst();
if (value < 0 || value > 3)
error(loc, "must be 0, 1, 2, or 3:", feature, "component argument");
} else
@@ -1451,8 +1445,8 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
bias = fnCandidate.getParamCount() > 4;
if (bias) {
TString biasFeatureString = fnCandidate.getName() + "with bias argument";
const char* feature = biasFeatureString.c_str();
featureString = fnCandidate.getName() + "with bias argument";
feature = featureString.c_str();
profileRequires(loc, ~EEsProfile, 450, nullptr, feature);
requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature);
}
@@ -1474,8 +1468,8 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
bias = fnCandidate.getParamCount() > 5;
if (bias) {
TString featureString = fnCandidate.getName() + "with bias argument";
const char* feature = featureString.c_str();
featureString = fnCandidate.getName() + "with bias argument";
feature = featureString.c_str();
profileRequires(loc, ~EEsProfile, 450, nullptr, feature);
requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature);
}
@@ -1517,12 +1511,12 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
}
if (arg > 0) {
if (! aggArgs[arg]->getAsConstantUnion())
if (! (*argp)[arg]->getAsConstantUnion())
error(loc, "argument must be compile-time constant", "texel offset", "");
else {
const TType& type = aggArgs[arg]->getAsTyped()->getType();
const TType& type = (*argp)[arg]->getAsTyped()->getType();
for (int c = 0; c < type.getVectorSize(); ++c) {
int offset = aggArgs[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
int offset = (*argp)[arg]->getAsConstantUnion()->getConstArray()[c].getIConst();
if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset)
error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]");
}
@@ -1562,6 +1556,23 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
break;
}
#ifdef NV_EXTENSIONS
case EOpAtomicAdd:
case EOpAtomicMin:
case EOpAtomicMax:
case EOpAtomicAnd:
case EOpAtomicOr:
case EOpAtomicXor:
case EOpAtomicExchange:
case EOpAtomicCompSwap:
{
if (arg0->getType().getBasicType() == EbtInt64 || arg0->getType().getBasicType() == EbtUint64)
requireExtensions(loc, 1, &E_GL_NV_shader_atomic_int64, fnCandidate.getName().c_str());
break;
}
#endif
case EOpInterpolateAtCentroid:
case EOpInterpolateAtSample:
case EOpInterpolateAtOffset:
@@ -1631,7 +1642,8 @@ void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fn
profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature);
int offsetArg = fnCandidate[0].type->getSampler().shadow ? 3 : 2;
if (! callNode.getSequence()[offsetArg]->getAsConstantUnion())
profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument");
profileRequires(loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5,
"non-constant offset argument");
if (! fnCandidate[0].type->getSampler().shadow)
compArg = 3;
} else if (fnCandidate.getName().compare("textureGatherOffsets") == 0) {
@@ -2448,6 +2460,16 @@ void TParseContext::boolCheck(const TSourceLoc& loc, const TPublicType& pType)
void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const TString& identifier, TIntermTyped* /*initializer*/)
{
// Check that the appropriate extension is enabled if external sampler is used.
// There are two extensions. The correct one must be used based on GLSL version.
if (type.getBasicType() == EbtSampler && type.getSampler().external) {
if (version < 300) {
requireExtensions(loc, 1, &E_GL_OES_EGL_image_external, "samplerExternalOES");
} else {
requireExtensions(loc, 1, &E_GL_OES_EGL_image_external_essl3, "samplerExternalOES");
}
}
if (type.getQualifier().storage == EvqUniform)
return;
@@ -2472,16 +2494,22 @@ void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, co
error(loc, "atomic_uints can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
}
void TParseContext::transparentCheck(const TSourceLoc& loc, const TType& type, const TString& /*identifier*/)
void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
{
if (parsingBuiltins)
return;
// Vulkan doesn't allow transparent uniforms outside of blocks
if (spvVersion.vulkan == 0 || type.getQualifier().storage != EvqUniform)
if (type.getQualifier().storage != EvqUniform)
return;
if (type.containsNonOpaque())
vulkanRemoved(loc, "non-opaque uniforms outside a block");
if (type.containsNonOpaque()) {
// Vulkan doesn't allow transparent uniforms outside of blocks
if (spvVersion.vulkan > 0)
vulkanRemoved(loc, "non-opaque uniforms outside a block");
// OpenGL wants locations on these (unless they are getting automapped)
if (spvVersion.openGl > 0 && !type.getQualifier().hasLocation() && !intermediate.getAutoMapLocations())
error(loc, "non-opaque uniform variables need a layout(location=L)", identifier.c_str(), "");
}
}
//
@@ -2534,7 +2562,7 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
// now, knowing it is a shader in/out, do all the in/out semantic checks
if (publicType.basicType == EbtBool) {
if (publicType.basicType == EbtBool && !parsingBuiltins) {
error(loc, "cannot be bool", GetStorageQualifierString(qualifier.storage), "");
return;
}
@@ -2976,7 +3004,7 @@ void TParseContext::structArrayCheck(const TSourceLoc& /*loc*/, const TType& typ
}
}
void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qualifier, const TArraySizes* arraySizes, bool initializer, bool lastMember)
void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qualifier, TArraySizes* arraySizes, bool initializer, bool lastMember)
{
assert(arraySizes);
@@ -2989,8 +3017,10 @@ void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qua
return;
// No environment allows any non-outer-dimension to be implicitly sized
if (arraySizes->isInnerImplicit())
if (arraySizes->isInnerImplicit()) {
error(loc, "only outermost dimension of an array of arrays can be implicitly sized", "[]", "");
arraySizes->clearInnerImplicit();
}
if (arraySizes->isInnerSpecialization())
error(loc, "only outermost dimension of an array of arrays can be a specialization constant", "[]", "");
@@ -3010,19 +3040,22 @@ void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qua
switch (language) {
case EShLangGeometry:
if (qualifier.storage == EvqVaryingIn)
if (extensionsTurnedOn(Num_AEP_geometry_shader, AEP_geometry_shader))
if ((profile == EEsProfile && version >= 320) ||
extensionsTurnedOn(Num_AEP_geometry_shader, AEP_geometry_shader))
return;
break;
case EShLangTessControl:
if ( qualifier.storage == EvqVaryingIn ||
(qualifier.storage == EvqVaryingOut && ! qualifier.patch))
if (extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
if ((profile == EEsProfile && version >= 320) ||
extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
return;
break;
case EShLangTessEvaluation:
if ((qualifier.storage == EvqVaryingIn && ! qualifier.patch) ||
qualifier.storage == EvqVaryingOut)
if (extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
if ((profile == EEsProfile && version >= 320) ||
extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
return;
break;
default:
@@ -3261,7 +3294,8 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
return nullptr;
bool nonEsRedecls = (profile != EEsProfile && (version >= 130 || identifier == "gl_TexCoord"));
bool esRedecls = (profile == EEsProfile && extensionsTurnedOn(Num_AEP_shader_io_blocks, AEP_shader_io_blocks));
bool esRedecls = (profile == EEsProfile &&
(version >= 320 || extensionsTurnedOn(Num_AEP_shader_io_blocks, AEP_shader_io_blocks)));
if (! esRedecls && ! nonEsRedecls)
return nullptr;
@@ -3400,7 +3434,7 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes)
{
const char* feature = "built-in block redeclaration";
profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature);
if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment") {
@@ -3446,17 +3480,24 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
return;
}
// Fix XFB stuff up, it applies to the order of the redeclaration, not
// the order of the original members.
if (currentBlockQualifier.storage == EvqVaryingOut && globalOutputDefaults.hasXfbBuffer()) {
currentBlockQualifier.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer;
fixBlockXfbOffsets(currentBlockQualifier, newTypeList);
}
// Edit and error check the container against the redeclaration
// - remove unused members
// - ensure remaining qualifiers/types match
TType& type = block->getWritableType();
#ifdef NV_EXTENSIONS
// if gl_PerVertex is redeclared for the purpose of passing through "gl_Position"
// for passthrough purpose, the redclared block should have the same qualifers as
// for passthrough purpose, the redeclared block should have the same qualifers as
// the current one
if (currentBlockQualifier.layoutPassthrough)
{
if (currentBlockQualifier.layoutPassthrough) {
type.getQualifier().layoutPassthrough = currentBlockQualifier.layoutPassthrough;
type.getQualifier().storage = currentBlockQualifier.storage;
type.getQualifier().layoutStream = currentBlockQualifier.layoutStream;
@@ -3497,10 +3538,12 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
arrayLimitCheck(loc, member->type->getFieldName(), newType.getOuterArraySize());
if (newType.getQualifier().isMemory())
error(memberLoc, "cannot add memory qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
if (newType.getQualifier().hasLayout())
error(memberLoc, "cannot add layout to redeclared block member", member->type->getFieldName().c_str(), "");
if (newType.getQualifier().hasNonXfbLayout())
error(memberLoc, "cannot add non-XFB layout to redeclared block member", member->type->getFieldName().c_str(), "");
if (newType.getQualifier().patch)
error(memberLoc, "cannot add patch to redeclared block member", member->type->getFieldName().c_str(), "");
if (newType.getQualifier().hasXfbBuffer() && newType.getQualifier().layoutXfbBuffer != currentBlockQualifier.layoutXfbBuffer)
error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_buffer", "");
oldType.getQualifier().centroid = newType.getQualifier().centroid;
oldType.getQualifier().sample = newType.getQualifier().sample;
oldType.getQualifier().invariant = newType.getQualifier().invariant;
@@ -3508,15 +3551,9 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
oldType.getQualifier().smooth = newType.getQualifier().smooth;
oldType.getQualifier().flat = newType.getQualifier().flat;
oldType.getQualifier().nopersp = newType.getQualifier().nopersp;
#ifdef NV_EXTENSIONS
if (member->type->getFieldName() == "gl_Layer") {
if (!newType.getQualifier().layoutViewportRelative && newType.getQualifier().layoutSecondaryViewportRelativeOffset == -2048)
error(loc, "redeclaration only allowed for viewport_relative or secondary_view_offset layout", "redeclaration", member->type->getFieldName().c_str());
oldType.getQualifier().layoutViewportRelative = newType.getQualifier().layoutViewportRelative;
oldType.getQualifier().layoutSecondaryViewportRelativeOffset = newType.getQualifier().layoutSecondaryViewportRelativeOffset;
}
#endif
oldType.getQualifier().layoutXfbOffset = newType.getQualifier().layoutXfbOffset;
if (oldType.getQualifier().layoutXfbOffset != TQualifier::layoutXfbBufferEnd)
type.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer;
if (oldType.isImplicitlySizedArray() && newType.isExplicitlySizedArray())
oldType.changeOuterArraySize(newType.getOuterArraySize());
@@ -4014,6 +4051,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
publicType.shaderQualifiers.earlyFragmentTests = true;
return;
}
if (id == "post_depth_coverage") {
requireExtensions(loc, Num_post_depth_coverageEXTs, post_depth_coverageEXTs, "post depth coverage");
if (extensionTurnedOn(E_GL_ARB_post_depth_coverage)) {
publicType.shaderQualifiers.earlyFragmentTests = true;
}
publicType.shaderQualifiers.postDepthCoverage = true;
return;
}
for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth+1)) {
if (id == TQualifier::getLayoutDepthString(depth)) {
requireProfile(loc, ECoreProfile | ECompatibilityProfile, "depth layout qualifier");
@@ -4026,7 +4071,8 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
bool found = false;
for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
if (id == TQualifier::getBlendEquationString(be)) {
requireExtensions(loc, 1, &E_GL_KHR_blend_equation_advanced, "blend equation");
profileRequires(loc, EEsProfile, 320, E_GL_KHR_blend_equation_advanced, "blend equation");
profileRequires(loc, ~EEsProfile, 0, E_GL_KHR_blend_equation_advanced, "blend equation");
intermediate.addBlendEquation(be);
publicType.shaderQualifiers.blendEquation = true;
found = true;
@@ -4205,6 +4251,11 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
}
return;
}
if (id == "num_views") {
requireExtensions(loc, Num_OVR_multiview_EXTs, OVR_multiview_EXTs, "num_views");
publicType.shaderQualifiers.numViews = value;
return;
}
#if NV_EXTENSIONS
if (language == EShLangVertex ||
@@ -4425,8 +4476,8 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb
switch (qualifier.storage) {
case EvqVaryingIn:
case EvqVaryingOut:
if (type.getBasicType() != EbtBlock ||
(!(*type.getStruct())[0].type->getQualifier().hasLocation() &&
if (type.getBasicType() != EbtBlock ||
(!(*type.getStruct())[0].type->getQualifier().hasLocation() &&
(*type.getStruct())[0].type->getQualifier().builtIn == EbvNone))
error(loc, "SPIR-V requires location for user input/output", "location", "");
break;
@@ -4518,6 +4569,8 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
break;
case EvqUniform:
case EvqBuffer:
if (type.getBasicType() == EbtBlock)
error(loc, "cannot apply to uniform or buffer block", "location", "");
break;
default:
error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", "");
@@ -4578,7 +4631,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
} else
lastBinding += type.getCumulativeArraySize();
}
if (lastBinding >= resources.maxCombinedTextureImageUnits)
if (spvVersion.vulkan == 0 && lastBinding >= resources.maxCombinedTextureImageUnits)
error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : "");
}
if (type.getBasicType() == EbtAtomicUint) {
@@ -4777,8 +4830,24 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua
if (shaderQualifiers.geometry != ElgNone)
error(loc, message, TQualifier::getGeometryString(shaderQualifiers.geometry), "");
if (shaderQualifiers.spacing != EvsNone)
error(loc, message, TQualifier::getVertexSpacingString(shaderQualifiers.spacing), "");
if (shaderQualifiers.order != EvoNone)
error(loc, message, TQualifier::getVertexOrderString(shaderQualifiers.order), "");
if (shaderQualifiers.pointMode)
error(loc, message, "point_mode", "");
if (shaderQualifiers.invocations != TQualifier::layoutNotSet)
error(loc, message, "invocations", "");
if (shaderQualifiers.earlyFragmentTests)
error(loc, message, "early_fragment_tests", "");
if (shaderQualifiers.postDepthCoverage)
error(loc, message, "post_depth_coverage", "");
for (int i = 0; i < 3; ++i) {
if (shaderQualifiers.localSize[i] > 1)
error(loc, message, "local_size", "");
if (shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet)
error(loc, message, "local_size id", "");
}
if (shaderQualifiers.vertices != TQualifier::layoutNotSet) {
if (language == EShLangGeometry)
error(loc, message, "max_vertices", "");
@@ -4787,15 +4856,10 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua
else
assert(0);
}
for (int i = 0; i < 3; ++i) {
if (shaderQualifiers.localSize[i] > 1)
error(loc, message, "local_size", "");
if (shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet)
error(loc, message, "local_size id", "");
}
if (shaderQualifiers.blendEquation)
error(loc, message, "blend equation", "");
// TBD: correctness: are any of these missing? pixelCenterInteger, originUpperLeft, spacing, order, pointmode, earlyfragment, depth
if (shaderQualifiers.numViews != TQualifier::layoutNotSet)
error(loc, message, "num_views", "");
}
// Correct and/or advance an object's offset layout qualifier.
@@ -4816,7 +4880,7 @@ void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol)
// Check for overlap
int numOffsets = 4;
if (symbol.getType().isArray()) {
if (symbol.getType().isExplicitlySizedArray())
if (symbol.getType().isExplicitlySizedArray() && ! symbol.getType().getArraySizes()->isInnerImplicit())
numOffsets *= symbol.getType().getCumulativeArraySize();
else {
// "It is a compile-time error to declare an unsized array of atomic_uint."
@@ -5083,7 +5147,7 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
samplerCheck(loc, type, identifier, initializer);
atomicUintCheck(loc, type, identifier);
transparentCheck(loc, type, identifier);
transparentOpaqueCheck(loc, type, identifier);
if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
@@ -5425,6 +5489,9 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const
// Test for the correctness of the parameters passed to various constructor functions
// and also convert them to the right data type, if allowed and required.
//
// 'node' is what to construct from.
// 'type' is what type to construct.
//
// Returns nullptr for an error or the constructed node (aggregate or typed) for no error.
//
TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* node, const TType& type)
@@ -5454,7 +5521,7 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
bool singleArg;
if (aggrNode) {
if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
if (aggrNode->getOp() != EOpNull)
singleArg = true;
else
singleArg = false;
@@ -5774,7 +5841,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
case EvqVaryingOut:
requireProfile(memberLoc, ECoreProfile | ECompatibilityProfile | EEsProfile, feature);
profileRequires(memberLoc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
profileRequires(memberLoc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
profileRequires(memberLoc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
memberWithLocation = true;
break;
default:
@@ -5898,14 +5965,14 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q
// "Compute shaders do not permit user-defined input variables..."
requireStage(loc, (EShLanguageMask)(EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask|EShLangFragmentMask), "input block");
if (language == EShLangFragment)
profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "fragment input block");
profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "fragment input block");
break;
case EvqVaryingOut:
profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "output block");
requireStage(loc, (EShLanguageMask)(EShLangVertexMask|EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask), "output block");
// ES 310 can have a block before shader_io is turned on, so skip this test for built-ins
if (language == EShLangVertex && ! parsingBuiltins)
profileRequires(loc, EEsProfile, 0, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "vertex output block");
profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "vertex output block");
break;
default:
error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), "");
@@ -6271,6 +6338,12 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
else
error(loc, "can only apply to 'in'", "early_fragment_tests", "");
}
if (publicType.shaderQualifiers.postDepthCoverage) {
if (publicType.qualifier.storage == EvqVaryingIn)
intermediate.setPostDepthCoverage();
else
error(loc, "can only apply to 'in'", "post_coverage_coverage", "");
}
if (publicType.shaderQualifiers.blendEquation) {
if (publicType.qualifier.storage != EvqVaryingOut)
error(loc, "can only apply to 'out'", "blend equation", "");
+32 -11
View File
@@ -74,16 +74,23 @@ class TParseContextBase : public TParseVersions {
public:
TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins, int version,
EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages)
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages,
const TString* entryPoint = nullptr)
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
scopeMangler("::"),
symbolTable(symbolTable),
statementNestingLevel(0), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0),
postEntryPointReturn(false),
contextPragma(true, false),
limits(resources.limits),
parsingBuiltins(parsingBuiltins), scanContext(nullptr), ppContext(nullptr),
globalUniformBlock(nullptr)
{ }
limits(resources.limits),
globalUniformBlock(nullptr),
globalUniformBinding(TQualifier::layoutBindingEnd),
globalUniformSet(TQualifier::layoutSetEnd)
{
if (entryPoint != nullptr)
sourceEntryPointName = *entryPoint;
}
virtual ~TParseContextBase() { }
virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
@@ -97,6 +104,8 @@ public:
virtual void setLimits(const TBuiltInResource&) = 0;
void checkIndex(const TSourceLoc&, const TType&, int& index);
EShLanguage getLanguage() const { return language; }
void setScanContext(TScanContext* c) { scanContext = c; }
TScanContext* getScanContext() const { return scanContext; }
@@ -140,10 +149,19 @@ public:
// Manage the global uniform block (default uniforms in GLSL, $Global in HLSL)
virtual void growGlobalUniformBlock(const TSourceLoc&, TType&, const TString& memberName, TTypeList* typeList = nullptr);
// Potentially rename shader entry point function
void renameShaderFunction(TString*& name) const
{
// Replace the entry point name given in the shader with the real entry point name,
// if there is a substitution.
if (name != nullptr && *name == sourceEntryPointName && intermediate.getEntryPointName().size() > 0)
name = NewPoolTString(intermediate.getEntryPointName().c_str());
}
virtual bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
virtual void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
const char* const scopeMangler = "::";
const char* const scopeMangler;
// Basic parsing state, easily accessible to the grammar
@@ -172,6 +190,7 @@ protected:
TPpContext* ppContext;
TBuiltInResource resources;
TLimits& limits;
TString sourceEntryPointName;
// These, if set, will be called when a line, pragma ... is preprocessed.
// They will be called with any parameters to the original directive.
@@ -191,8 +210,10 @@ protected:
TSwizzleSelectors<TVectorSelector>&);
// 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
TVariable* globalUniformBlock; // the actual block, inserted into the symbol table
unsigned int globalUniformBinding; // the block's binding number
unsigned int globalUniformSet; // the block's set number
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() const { return ""; }
virtual void setUniformBlockDefaults(TType&) const { }
@@ -248,7 +269,8 @@ protected:
class TParseContext : public TParseContextBase {
public:
TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, const SpvVersion& spvVersion, EShLanguage, TInfoSink&,
bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
bool forwardCompatible = false, EShMessages messages = EShMsgDefault,
const TString* entryPoint = nullptr);
virtual ~TParseContext();
bool obeyPrecisionQualifiers() const { return precisionManager.respectingPrecisionQualifiers(); };
@@ -267,7 +289,6 @@ public:
void handlePragma(const TSourceLoc&, const TVector<TString>&) override;
TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string);
TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
void checkIndex(const TSourceLoc&, const TType&, int& index);
void handleIndexLimits(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
void makeEditable(TSymbol*&) override;
@@ -317,7 +338,7 @@ public:
bool arrayError(const TSourceLoc&, const TType&);
void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&);
void structArrayCheck(const TSourceLoc&, const TType& structure);
void arraySizesCheck(const TSourceLoc&, const TQualifier&, const TArraySizes*, bool initializer, bool lastMember);
void arraySizesCheck(const TSourceLoc&, const TQualifier&, TArraySizes*, bool initializer, bool lastMember);
void arrayOfArrayVersionCheck(const TSourceLoc&);
void arrayDimCheck(const TSourceLoc&, const TArraySizes* sizes1, const TArraySizes* sizes2);
void arrayDimCheck(const TSourceLoc&, const TType*, const TArraySizes*);
@@ -327,7 +348,7 @@ public:
void boolCheck(const TSourceLoc&, const TPublicType&);
void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier, TIntermTyped* initializer);
void atomicUintCheck(const TSourceLoc&, const TType&, const TString& identifier);
void transparentCheck(const TSourceLoc&, const TType&, const TString& identifier);
void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier);
void globalQualifierFixCheck(const TSourceLoc&, TQualifier&);
void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&);
bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
+16 -46
View File
@@ -40,35 +40,22 @@
namespace glslang {
// Process-wide TLS index
OS_TLSIndex PoolIndex;
void InitializeMemoryPools()
// Return the thread-specific current pool.
TPoolAllocator& GetThreadPoolAllocator()
{
TThreadMemoryPools* pools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
if (pools)
return;
TPoolAllocator *threadPoolAllocator = new TPoolAllocator();
TThreadMemoryPools* threadData = new TThreadMemoryPools();
threadData->threadPoolAllocator = threadPoolAllocator;
OS_SetTLSValue(PoolIndex, threadData);
return *static_cast<TPoolAllocator*>(OS_GetTLSValue(PoolIndex));
}
void FreeGlobalPools()
// Set the thread-specific current pool.
void SetThreadPoolAllocator(TPoolAllocator* poolAllocator)
{
// Release the allocated memory for this thread.
TThreadMemoryPools* globalPools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
if (! globalPools)
return;
GetThreadPoolAllocator().popAll();
delete &GetThreadPoolAllocator();
delete globalPools;
OS_SetTLSValue(PoolIndex, poolAllocator);
}
// Process-wide set up of the TLS pool storage.
bool InitializePoolIndex()
{
// Allocate a TLS index.
@@ -78,26 +65,6 @@ bool InitializePoolIndex()
return true;
}
void FreePoolIndex()
{
// Release the TLS index.
OS_FreeTLSIndex(PoolIndex);
}
TPoolAllocator& GetThreadPoolAllocator()
{
TThreadMemoryPools* threadData = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
return *threadData->threadPoolAllocator;
}
void SetThreadPoolAllocator(TPoolAllocator& poolAllocator)
{
TThreadMemoryPools* threadData = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
threadData->threadPoolAllocator = &poolAllocator;
}
//
// Implement the functionality of the TPoolAllocator class, which
// is documented in PoolAlloc.h.
@@ -234,13 +201,16 @@ void TPoolAllocator::pop()
currentPageOffset = stack.back().offset;
while (inUseList != page) {
// invoke destructor to free allocation list
inUseList->~tHeader();
tHeader* nextInUse = inUseList->nextPage;
if (inUseList->pageCount > 1)
size_t pageCount = inUseList->pageCount;
// This technically ends the lifetime of the header as C++ object,
// but we will still control the memory and reuse it.
inUseList->~tHeader(); // currently, just a debug allocation checker
if (pageCount > 1) {
delete [] reinterpret_cast<char*>(inUseList);
else {
} else {
inUseList->nextPage = freeList;
freeList = inUseList;
}
View File
View File
+26 -12
View File
@@ -864,14 +864,17 @@ int TScanContext::tokenizeIdentifier()
case PATCH:
if (parseContext.symbolTable.atBuiltInLevel() ||
(parseContext.profile == EEsProfile && parseContext.extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader)) ||
(parseContext.profile == EEsProfile &&
(parseContext.version >= 320 ||
parseContext.extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))) ||
(parseContext.profile != EEsProfile && parseContext.extensionTurnedOn(E_GL_ARB_tessellation_shader)))
return keyword;
return es30ReservedFromGLSL(400);
case SAMPLE:
if (parseContext.extensionsTurnedOn(1, &E_GL_OES_shader_multisample_interpolation))
if ((parseContext.profile == EEsProfile && parseContext.version >= 320) ||
parseContext.extensionsTurnedOn(1, &E_GL_OES_shader_multisample_interpolation))
return keyword;
return es30ReservedFromGLSL(400);
@@ -925,7 +928,8 @@ int TScanContext::tokenizeIdentifier()
case IIMAGEBUFFER:
case UIMAGEBUFFER:
afterType = true;
if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
if ((parseContext.profile == EEsProfile && parseContext.version >= 320) ||
parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
return keyword;
return firstGenerationImage(false);
@@ -948,7 +952,8 @@ int TScanContext::tokenizeIdentifier()
case IIMAGECUBEARRAY:
case UIMAGECUBEARRAY:
afterType = true;
if (parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array))
if ((parseContext.profile == EEsProfile && parseContext.version >= 320) ||
parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array))
return keyword;
return secondGenerationImage();
@@ -1030,7 +1035,8 @@ int TScanContext::tokenizeIdentifier()
case ISAMPLERCUBEARRAY:
case USAMPLERCUBEARRAY:
afterType = true;
if (parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array))
if ((parseContext.profile == EEsProfile && parseContext.version >= 320) ||
parseContext.extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array))
return keyword;
if (parseContext.profile == EEsProfile || (parseContext.version < 400 && ! parseContext.extensionTurnedOn(E_GL_ARB_texture_cube_map_array)))
reservedWord();
@@ -1066,14 +1072,16 @@ int TScanContext::tokenizeIdentifier()
case SAMPLERBUFFER:
afterType = true;
if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
if ((parseContext.profile == EEsProfile && parseContext.version >= 320) ||
parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
return keyword;
return es30ReservedFromGLSL(130);
case ISAMPLERBUFFER:
case USAMPLERBUFFER:
afterType = true;
if (parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
if ((parseContext.profile == EEsProfile && parseContext.version >= 320) ||
parseContext.extensionsTurnedOn(Num_AEP_texture_buffer, AEP_texture_buffer))
return keyword;
return es30ReservedFromGLSL(140);
@@ -1089,7 +1097,8 @@ int TScanContext::tokenizeIdentifier()
case ISAMPLER2DMSARRAY:
case USAMPLER2DMSARRAY:
afterType = true;
if (parseContext.extensionsTurnedOn(1, &E_GL_OES_texture_storage_multisample_2d_array))
if ((parseContext.profile == EEsProfile && parseContext.version >= 320) ||
parseContext.extensionsTurnedOn(1, &E_GL_OES_texture_storage_multisample_2d_array))
return keyword;
return es30ReservedFromGLSL(150);
@@ -1110,8 +1119,10 @@ int TScanContext::tokenizeIdentifier()
case SAMPLER2DSHADOW:
afterType = true;
if (parseContext.profile == EEsProfile && parseContext.version < 300)
reservedWord();
if (parseContext.profile == EEsProfile && parseContext.version < 300) {
if (!parseContext.extensionTurnedOn(E_GL_EXT_shadow_samplers))
reservedWord();
}
return keyword;
case SAMPLER1DARRAY:
@@ -1160,7 +1171,9 @@ int TScanContext::tokenizeIdentifier()
case SAMPLEREXTERNALOES:
afterType = true;
if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionTurnedOn(E_GL_OES_EGL_image_external))
if (parseContext.symbolTable.atBuiltInLevel() ||
parseContext.extensionTurnedOn(E_GL_OES_EGL_image_external) ||
parseContext.extensionTurnedOn(E_GL_OES_EGL_image_external_essl3))
return keyword;
return identifierOrType();
@@ -1245,7 +1258,8 @@ int TScanContext::tokenizeIdentifier()
return keyword;
case PRECISE:
if ((parseContext.profile == EEsProfile && parseContext.extensionsTurnedOn(Num_AEP_gpu_shader5, AEP_gpu_shader5)) ||
if ((parseContext.profile == EEsProfile &&
(parseContext.version >= 320 || parseContext.extensionsTurnedOn(Num_AEP_gpu_shader5, AEP_gpu_shader5))) ||
(parseContext.profile != EEsProfile && parseContext.version >= 400))
return keyword;
if (parseContext.profile == EEsProfile && parseContext.version == 310) {
+8 -9
View File
@@ -51,25 +51,24 @@ const int EndOfInput = -1;
//
class TInputScanner {
public:
TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0, bool single = false) :
TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr,
int b = 0, int f = 0, bool single = false) :
numSources(n),
sources(reinterpret_cast<const unsigned char* const *>(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters
lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single), endOfFileReached(false)
// up to this point, common usage is "char*", but now we need positive 8-bit characters
sources(reinterpret_cast<const unsigned char* const *>(s)),
lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single),
endOfFileReached(false)
{
loc = new TSourceLoc[numSources];
for (int i = 0; i < numSources; ++i) {
loc[i].init();
loc[i].init(i - stringBias);
}
if (names != nullptr) {
for (int i = 0; i < numSources; ++i)
loc[i].name = names[i];
}
loc[currentSource].string = -stringBias;
loc[currentSource].line = 1;
loc[currentSource].column = 0;
logicalSourceLoc.string = 0;
logicalSourceLoc.line = 1;
logicalSourceLoc.column = 0;
logicalSourceLoc.init(1);
logicalSourceLoc.name = loc[0].name;
}
View File
+241 -94
View File
@@ -1,7 +1,7 @@
//
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
// Copyright (C) 2013-2016 LunarG, Inc.
// Copyright (C) 2015-2016 Google, Inc.
// Copyright (C) 2015-2017 Google, Inc.
//
// All rights reserved.
//
@@ -69,6 +69,10 @@
namespace { // anonymous namespace for file-local functions and symbols
// Total number of successful initializers of glslang: a refcount
// Shared global; access should be protected by a global mutex/critical section.
int NumberOfClients = 0;
using namespace glslang;
// Create a language specific version of parseables.
@@ -91,18 +95,16 @@ TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate&
int version, EProfile profile, EShSource source,
EShLanguage language, TInfoSink& infoSink,
SpvVersion spvVersion, bool forwardCompatible, EShMessages messages,
bool parsingBuiltIns, const std::string sourceEntryPointName = "")
bool parsingBuiltIns, std::string sourceEntryPointName = "")
{
#ifndef ENABLE_HLSL
(void)sourceEntryPointName; // Unused argument.
#endif
switch (source) {
case EShSourceGlsl:
intermediate.setEntryPointName("main");
case EShSourceGlsl: {
if (sourceEntryPointName.size() == 0)
intermediate.setEntryPointName("main");
TString entryPoint = sourceEntryPointName.c_str();
return new TParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
language, infoSink, forwardCompatible, messages);
language, infoSink, forwardCompatible, messages, &entryPoint);
}
#ifdef ENABLE_HLSL
case EShSourceHlsl:
return new HlslParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
@@ -116,7 +118,7 @@ TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate&
// Local mapping functions for making arrays of symbol tables....
const int VersionCount = 15; // index range in MapVersionToIndex
const int VersionCount = 17; // index range in MapVersionToIndex
int MapVersionToIndex(int version)
{
@@ -138,7 +140,10 @@ int MapVersionToIndex(int version)
case 440: index = 12; break;
case 310: index = 13; break;
case 450: index = 14; break;
default: break;
case 500: index = 0; break; // HLSL
case 320: index = 15; break;
case 460: index = 16; break;
default: assert(0); break;
}
assert(index < VersionCount);
@@ -216,7 +221,7 @@ enum EPrecisionClass {
TSymbolTable* CommonSymbolTable[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EPcCount] = {};
TSymbolTable* SharedSymbolTables[VersionCount][SpvVersionCount][ProfileCount][SourceCount][EShLangCount] = {};
TPoolAllocator* PerProcessGPA = 0;
TPoolAllocator* PerProcessGPA = nullptr;
//
// Parse and add to the given symbol table the content of the given shader string.
@@ -360,7 +365,7 @@ bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& inf
// pool allocator intact, so:
// - Switch to a new pool for parsing the built-ins
// - Do the parsing, which builds the symbol table, using the new pool
// - Switch to the process-global pool to save a copy the resulting symbol table
// - Switch to the process-global pool to save a copy of the resulting symbol table
// - Free up the new pool used to parse the built-ins
// - Switch back to the original thread's pool
//
@@ -387,8 +392,8 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
// Switch to a new pool
TPoolAllocator& previousAllocator = GetThreadPoolAllocator();
TPoolAllocator* builtInPoolAllocator = new TPoolAllocator();
SetThreadPoolAllocator(*builtInPoolAllocator);
TPoolAllocator* builtInPoolAllocator = new TPoolAllocator;
SetThreadPoolAllocator(builtInPoolAllocator);
// Dynamically allocate the local symbol tables so we can control when they are deallocated WRT when the pool is popped.
TSymbolTable* commonTable[EPcCount];
@@ -402,7 +407,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
InitializeSymbolTables(infoSink, commonTable, stageTables, version, profile, spvVersion, source);
// Switch to the process-global pool
SetThreadPoolAllocator(*PerProcessGPA);
SetThreadPoolAllocator(PerProcessGPA);
// 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) {
@@ -429,7 +434,7 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
delete stageTables[stage];
delete builtInPoolAllocator;
SetThreadPoolAllocator(previousAllocator);
SetThreadPoolAllocator(&previousAllocator);
glslang::ReleaseGlobalLock();
}
@@ -447,7 +452,7 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
return correct;
}
// Get a good version...
// Get a version...
if (version == 0) {
version = defaultVersion;
// infoSink.info.message(EPrefixWarning, "#version: statement missing; use #version on first line of shader");
@@ -455,9 +460,9 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
// Get a good profile...
if (profile == ENoProfile) {
if (version == 300 || version == 310) {
if (version == 300 || version == 310 || version == 320) {
correct = false;
infoSink.info.message(EPrefixError, "#version: versions 300 and 310 require specifying the 'es' profile");
infoSink.info.message(EPrefixError, "#version: versions 300, 310, and 320 require specifying the 'es' profile");
profile = EEsProfile;
} else if (version == 100)
profile = EEsProfile;
@@ -474,16 +479,16 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
profile = EEsProfile;
else
profile = ENoProfile;
} else if (version == 300 || version == 310) {
} else if (version == 300 || version == 310 || version == 320) {
if (profile != EEsProfile) {
correct = false;
infoSink.info.message(EPrefixError, "#version: versions 300 and 310 support only the es profile");
infoSink.info.message(EPrefixError, "#version: versions 300, 310, and 320 support only the es profile");
}
profile = EEsProfile;
} else {
if (profile == EEsProfile) {
correct = false;
infoSink.info.message(EPrefixError, "#version: only version 300 and 310 support the es profile");
infoSink.info.message(EPrefixError, "#version: only version 300, 310, and 320 support the es profile");
if (version >= FirstProfileVersion)
profile = ECoreProfile;
else
@@ -493,6 +498,42 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
}
}
// Fix version...
switch (version) {
// ES versions
case 100: break;
case 300: break;
case 310: break;
case 320: break;
// desktop versions
case 110: break;
case 120: break;
case 130: break;
case 140: break;
case 150: break;
case 330: break;
case 400: break;
case 410: break;
case 420: break;
case 430: break;
case 440: break;
case 450: break;
case 460: break;
// unknown version
default:
correct = false;
infoSink.info.message(EPrefixError, "version not supported");
if (profile == EEsProfile)
version = 310;
else {
version = 450;
profile = ECoreProfile;
}
break;
}
// Correct for stage type...
switch (stage) {
case EShLangGeometry:
@@ -569,6 +610,89 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo
return correct;
}
// There are multiple paths in for setting environment stuff.
// TEnvironment takes precedence, for what it sets, so sort all this out.
// Ideally, the internal code could be made to use TEnvironment, but for
// now, translate it to the historically used parameters.
void TranslateEnvironment(const TEnvironment* environment, EShMessages& messages, EShSource& source,
EShLanguage& stage, SpvVersion& spvVersion)
{
// Set up environmental defaults, first ignoring 'environment'.
if (messages & EShMsgSpvRules)
spvVersion.spv = 0x00010000;
if (messages & EShMsgVulkanRules) {
spvVersion.vulkan = 100;
spvVersion.vulkanGlsl = 100;
} else if (spvVersion.spv != 0)
spvVersion.openGl = 100;
// Now, override, based on any content set in 'environment'.
// 'environment' must be cleared to ESh*None settings when items
// are not being set.
if (environment != nullptr) {
// input language
if (environment->input.languageFamily != EShSourceNone) {
stage = environment->input.stage;
switch (environment->input.dialect) {
case EShClientNone:
break;
case EShClientVulkan:
spvVersion.vulkanGlsl = environment->input.dialectVersion;
break;
case EShClientOpenGL:
spvVersion.openGl = environment->input.dialectVersion;
break;
}
switch (environment->input.languageFamily) {
case EShSourceNone:
break;
case EShSourceGlsl:
source = EShSourceGlsl;
messages = static_cast<EShMessages>(messages & ~EShMsgReadHlsl);
break;
case EShSourceHlsl:
source = EShSourceHlsl;
messages = static_cast<EShMessages>(messages | EShMsgReadHlsl);
break;
}
}
// client
switch (environment->client.client) {
case EShClientVulkan:
spvVersion.vulkan = environment->client.version;
break;
default:
break;
}
// generated code
switch (environment->target.language) {
case EshTargetSpv:
spvVersion.spv = environment->target.version;
break;
default:
break;
}
}
}
// Most processes are recorded when set in the intermediate representation,
// These are the few that are not.
void RecordProcesses(TIntermediate& intermediate, EShMessages messages, const std::string& sourceEntryPointName)
{
if ((messages & EShMsgRelaxedErrors) != 0)
intermediate.addProcess("relaxed-errors");
if ((messages & EShMsgSuppressWarnings) != 0)
intermediate.addProcess("suppress-warnings");
if ((messages & EShMsgKeepUncalled) != 0)
intermediate.addProcess("keep-uncalled");
if (sourceEntryPointName.size() > 0) {
intermediate.addProcess("source-entrypoint");
intermediate.addProcessArgument(sourceEntryPointName);
}
}
// This is the common setup and cleanup code for PreprocessDeferred and
// CompileDeferred.
// It takes any callable with a signature of
@@ -588,7 +712,7 @@ bool ProcessDeferred(
const char* customPreamble,
const EShOptimizationLevel optLevel,
const TBuiltInResource* resources,
int defaultVersion, // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan
int defaultVersion, // use 100 for ES environment, 110 for desktop; this is the GLSL version, not SPIR-V or Vulkan
EProfile defaultProfile,
// set version/profile to defaultVersion/defaultProfile regardless of the #version
// directive in the source code
@@ -599,12 +723,9 @@ bool ProcessDeferred(
ProcessingContext& processingContext,
bool requireNonempty,
TShader::Includer& includer,
const std::string sourceEntryPointName = ""
)
const std::string sourceEntryPointName = "",
const TEnvironment* environment = nullptr) // optional way of fully setting all versions, overriding the above
{
if (! InitThread())
return false;
// This must be undone (.pop()) by the caller, after it finishes consuming the created tree.
GetThreadPoolAllocator().push();
@@ -628,7 +749,7 @@ bool ProcessDeferred(
const char** names = new const char*[numTotal];
for (int s = 0; s < numStrings; ++s) {
strings[s + numPre] = shaderStrings[s];
if (inputLengths == 0 || inputLengths[s] < 0)
if (inputLengths == nullptr || inputLengths[s] < 0)
lengths[s + numPre] = strlen(shaderStrings[s]);
else
lengths[s + numPre] = inputLengths[s];
@@ -641,16 +762,25 @@ bool ProcessDeferred(
names[s + numPre] = nullptr;
}
// Get all the stages, languages, clients, and other environment
// stuff sorted out.
EShSource source = (messages & EShMsgReadHlsl) != 0 ? EShSourceHlsl : EShSourceGlsl;
SpvVersion spvVersion;
EShLanguage stage = compiler->getLanguage();
TranslateEnvironment(environment, messages, source, stage, spvVersion);
// First, without using the preprocessor or parser, find the #version, so we know what
// symbol tables, processing rules, etc. to set up. This does not need the extra strings
// outlined above, just the user shader.
glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]); // no preamble
// outlined above, just the user shader, after the system and user preambles.
glslang::TInputScanner userInput(numStrings, &strings[numPre], &lengths[numPre]);
int version = 0;
EProfile profile = ENoProfile;
bool versionNotFirstToken = false;
bool versionNotFirst = (messages & EShMsgReadHlsl) ? true : userInput.scanVersion(version, profile, versionNotFirstToken);
bool versionNotFirst = (source == EShSourceHlsl)
? true
: userInput.scanVersion(version, profile, versionNotFirstToken);
bool versionNotFound = version == 0;
if (forceDefaultVersionAndProfile && (messages & EShMsgReadHlsl) == 0) {
if (forceDefaultVersionAndProfile && source == EShSourceGlsl) {
if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound &&
(version != defaultVersion || profile != defaultProfile)) {
compiler->infoSink.info << "Warning, (version, profile) forced to be ("
@@ -667,15 +797,9 @@ bool ProcessDeferred(
version = defaultVersion;
profile = defaultProfile;
}
SpvVersion spvVersion;
if (messages & EShMsgSpvRules)
spvVersion.spv = 0x00010000; // TODO: eventually have this come from the outside
EShSource source = (messages & EShMsgReadHlsl) ? EShSourceHlsl : EShSourceGlsl;
if (messages & EShMsgVulkanRules)
spvVersion.vulkan = 100; // TODO: eventually have this come from the outside
else if (spvVersion.spv != 0)
spvVersion.openGl = 100; // TODO: eventually have this come from the outside
bool goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, source, version, profile, spvVersion);
bool goodVersion = DeduceVersionProfile(compiler->infoSink, stage,
versionNotFirst, defaultVersion, source, version, profile, spvVersion);
bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst));
bool warnVersionNotFirst = false;
if (! versionWillBeError && versionNotFirstToken) {
@@ -689,14 +813,15 @@ bool ProcessDeferred(
intermediate.setVersion(version);
intermediate.setProfile(profile);
intermediate.setSpv(spvVersion);
RecordProcesses(intermediate, messages, sourceEntryPointName);
if (spvVersion.vulkan >= 100)
intermediate.setOriginUpperLeft();
if ((messages & EShMsgHlslOffsets) || (messages & EShMsgReadHlsl))
if ((messages & EShMsgHlslOffsets) || source == EShSourceHlsl)
intermediate.setHlslOffsets();
if (messages & EShMsgDebugInfo) {
intermediate.setSourceFile(names[numPre]);
for (int s = 0; s < numStrings; ++s)
intermediate.addSourceText(strings[numPre]);
intermediate.addSourceText(strings[numPre + s]);
}
SetupBuiltinSymbolTable(version, profile, spvVersion, source);
@@ -704,7 +829,7 @@ bool ProcessDeferred(
[MapSpvVersionToIndex(spvVersion)]
[MapProfileToIndex(profile)]
[MapSourceToIndex(source)]
[compiler->getLanguage()];
[stage];
// Dynamically allocate the symbol table so we can control when it is deallocated WRT the pool.
TSymbolTable* symbolTableMemory = new TSymbolTable;
@@ -715,7 +840,7 @@ bool ProcessDeferred(
// Add built-in symbols that are potentially context dependent;
// they get popped again further down.
if (! AddContextSpecificSymbols(resources, compiler->infoSink, symbolTable, version, profile, spvVersion,
compiler->getLanguage(), source))
stage, source))
return false;
//
@@ -723,14 +848,14 @@ bool ProcessDeferred(
//
TParseContextBase* parseContext = CreateParseContext(symbolTable, intermediate, version, profile, source,
compiler->getLanguage(), compiler->infoSink,
stage, compiler->infoSink,
spvVersion, forwardCompatible, messages, false, sourceEntryPointName);
TPpContext ppContext(*parseContext, names[numPre]? names[numPre]: "", includer);
TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer);
// only GLSL (bison triggered, really) needs an externally set scan context
glslang::TScanContext scanContext(*parseContext);
if ((messages & EShMsgReadHlsl) == 0)
if (source == EShSourceGlsl)
parseContext->setScanContext(&scanContext);
parseContext->setPpContext(&ppContext);
@@ -1049,14 +1174,15 @@ bool CompileDeferred(
EShMessages messages, // warnings/errors/AST; things to print out
TIntermediate& intermediate,// returned tree, etc.
TShader::Includer& includer,
const std::string sourceEntryPointName = "")
const std::string sourceEntryPointName = "",
TEnvironment* environment = nullptr)
{
DoFullParse parser;
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
preamble, optLevel, resources, defaultVersion,
defaultProfile, forceDefaultVersionAndProfile,
forwardCompatible, messages, intermediate, parser,
true, includer, sourceEntryPointName);
true, includer, sourceEntryPointName, environment);
}
} // end anonymous namespace for local functions
@@ -1071,7 +1197,11 @@ int ShInitialize()
if (! InitProcess())
return 0;
if (! PerProcessGPA)
glslang::GetGlobalLock();
++NumberOfClients;
glslang::ReleaseGlobalLock();
if (PerProcessGPA == nullptr)
PerProcessGPA = new TPoolAllocator();
glslang::TScanContext::fillInKeywordMap();
@@ -1137,6 +1267,14 @@ void ShDestruct(ShHandle handle)
//
int __fastcall ShFinalize()
{
glslang::GetGlobalLock();
--NumberOfClients;
assert(NumberOfClients >= 0);
bool finalize = NumberOfClients == 0;
glslang::ReleaseGlobalLock();
if (! finalize)
return 1;
for (int version = 0; version < VersionCount; ++version) {
for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) {
for (int p = 0; p < ProfileCount; ++p) {
@@ -1163,10 +1301,9 @@ int __fastcall ShFinalize()
}
}
if (PerProcessGPA) {
PerProcessGPA->popAll();
if (PerProcessGPA != nullptr) {
delete PerProcessGPA;
PerProcessGPA = 0;
PerProcessGPA = nullptr;
}
glslang::TScanContext::deleteKeywordMap();
@@ -1207,6 +1344,8 @@ int ShCompile(
if (compiler == 0)
return 0;
SetThreadPoolAllocator(compiler->getPool());
compiler->infoSink.info.erase();
compiler->infoSink.debug.erase();
@@ -1264,6 +1403,8 @@ int ShLinkExt(
TShHandleBase* base = reinterpret_cast<TShHandleBase*>(linkHandle);
TLinker* linker = static_cast<TLinker*>(base->getAsLinker());
SetThreadPoolAllocator(linker->getPool());
if (linker == 0)
return 0;
@@ -1298,9 +1439,6 @@ void ShSetEncryptionMethod(ShHandle handle)
//
const char* ShGetInfoLog(const ShHandle handle)
{
if (!InitThread())
return 0;
if (handle == 0)
return 0;
@@ -1324,9 +1462,6 @@ const char* ShGetInfoLog(const ShHandle handle)
//
const void* ShGetExecutable(const ShHandle handle)
{
if (!InitThread())
return 0;
if (handle == 0)
return 0;
@@ -1349,9 +1484,6 @@ const void* ShGetExecutable(const ShHandle handle)
//
int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table)
{
if (!InitThread())
return 0;
if (handle == 0)
return 0;
@@ -1371,9 +1503,6 @@ int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* t
//
int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table)
{
if (!InitThread())
return 0;
if (handle == 0)
return 0;
@@ -1392,9 +1521,6 @@ int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* tab
//
int ShExcludeAttributes(const ShHandle handle, int *attributes, int count)
{
if (!InitThread())
return 0;
if (handle == 0)
return 0;
@@ -1416,9 +1542,6 @@ int ShExcludeAttributes(const ShHandle handle, int *attributes, int count)
//
int ShGetUniformLocation(const ShHandle handle, const char* name)
{
if (!InitThread())
return 0;
if (handle == 0)
return -1;
@@ -1447,12 +1570,12 @@ namespace glslang {
const char* GetEsslVersionString()
{
return "OpenGL ES GLSL 3.00 glslang LunarG Khronos." GLSLANG_REVISION " " GLSLANG_DATE;
return "OpenGL ES GLSL 3.20 glslang Khronos." GLSLANG_REVISION " " GLSLANG_DATE;
}
const char* GetGlslVersionString()
{
return "4.20 glslang LunarG Khronos." GLSLANG_REVISION " " GLSLANG_DATE;
return "4.60 glslang Khronos." GLSLANG_REVISION " " GLSLANG_DATE;
}
int GetKhronosToolId()
@@ -1477,11 +1600,18 @@ public:
};
TShader::TShader(EShLanguage s)
: pool(0), stage(s), lengths(nullptr), stringNames(nullptr), preamble("")
: stage(s), lengths(nullptr), stringNames(nullptr), preamble("")
{
pool = new TPoolAllocator;
infoSink = new TInfoSink;
compiler = new TDeferredCompiler(stage, *infoSink);
intermediate = new TIntermediate(s);
// clear environment (avoid constructors in them for use in a C interface)
environment.input.languageFamily = EShSourceNone;
environment.input.dialect = EShClientNone;
environment.client.client = EShClientNone;
environment.target.language = EShTargetNone;
}
TShader::~TShader()
@@ -1525,24 +1655,41 @@ void TShader::setSourceEntryPoint(const char* name)
sourceEntryPointName = name;
}
void TShader::addProcesses(const std::vector<std::string>& p)
{
intermediate->addProcesses(p);
}
// Set binding base for given resource type
void TShader::setShiftBinding(TResourceType res, unsigned int base) {
intermediate->setShiftBinding(res, base);
}
// Set binding base for given resource type for a given binding set.
void TShader::setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set) {
intermediate->setShiftBindingForSet(res, base, set);
}
// Set binding base for sampler types
void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShiftSamplerBinding(base); }
void TShader::setShiftSamplerBinding(unsigned int base) { setShiftBinding(EResSampler, base); }
// Set binding base for texture types (SRV)
void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); }
void TShader::setShiftTextureBinding(unsigned int base) { setShiftBinding(EResTexture, base); }
// Set binding base for image types
void TShader::setShiftImageBinding(unsigned int base) { intermediate->setShiftImageBinding(base); }
void TShader::setShiftImageBinding(unsigned int base) { setShiftBinding(EResImage, base); }
// Set binding base for uniform buffer objects (CBV)
void TShader::setShiftUboBinding(unsigned int base) { intermediate->setShiftUboBinding(base); }
void TShader::setShiftUboBinding(unsigned int base) { setShiftBinding(EResUbo, base); }
// Synonym for setShiftUboBinding, to match HLSL language.
void TShader::setShiftCbufferBinding(unsigned int base) { intermediate->setShiftUboBinding(base); }
void TShader::setShiftCbufferBinding(unsigned int base) { setShiftBinding(EResUbo, base); }
// Set binding base for UAV (unordered access view)
void TShader::setShiftUavBinding(unsigned int base) { intermediate->setShiftUavBinding(base); }
void TShader::setShiftUavBinding(unsigned int base) { setShiftBinding(EResUav, base); }
// Set binding base for SSBOs
void TShader::setShiftSsboBinding(unsigned int base) { intermediate->setShiftSsboBinding(base); }
void TShader::setShiftSsboBinding(unsigned int base) { setShiftBinding(EResSsbo, base); }
// Enables binding automapping using TIoMapper
void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); }
// Enables position.Y output negation in vertex shader
void TShader::setInvertY(bool invert) { intermediate->setInvertY(invert); }
// Fragile: currently within one stage: simple auto-assignment of location
void TShader::setAutoMapLocations(bool map) { intermediate->setAutoMapLocations(map); }
void TShader::setAutoMapLocations(bool map) { intermediate->setAutoMapLocations(map); }
// See comment above TDefaultHlslIoMapper in iomapper.cpp:
void TShader::setHlslIoMapping(bool hlslIoMap) { intermediate->setHlslIoMapping(hlslIoMap); }
void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); }
@@ -1560,16 +1707,16 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion
{
if (! InitThread())
return false;
SetThreadPoolAllocator(pool);
pool = new TPoolAllocator();
SetThreadPoolAllocator(*pool);
if (! preamble)
preamble = "";
return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
preamble, EShOptNone, builtInResources, defaultVersion,
defaultProfile, forceDefaultVersionAndProfile,
forwardCompatible, messages, *intermediate, includer, sourceEntryPointName);
forwardCompatible, messages, *intermediate, includer, sourceEntryPointName,
&environment);
}
// Fill in a string with the result of preprocessing ShaderStrings
@@ -1583,9 +1730,8 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources,
{
if (! InitThread())
return false;
SetThreadPoolAllocator(pool);
pool = new TPoolAllocator();
SetThreadPoolAllocator(*pool);
if (! preamble)
preamble = "";
@@ -1605,8 +1751,9 @@ const char* TShader::getInfoDebugLog()
return infoSink->debug.c_str();
}
TProgram::TProgram() : pool(0), reflection(0), ioMapper(nullptr), linked(false)
TProgram::TProgram() : reflection(0), ioMapper(nullptr), linked(false)
{
pool = new TPoolAllocator;
infoSink = new TInfoSink;
for (int s = 0; s < EShLangCount; ++s) {
intermediate[s] = 0;
@@ -1641,8 +1788,7 @@ bool TProgram::link(EShMessages messages)
bool error = false;
pool = new TPoolAllocator();
SetThreadPoolAllocator(*pool);
SetThreadPoolAllocator(pool);
for (int s = 0; s < EShLangCount; ++s) {
if (! linkStage((EShLanguage)s, messages))
@@ -1758,6 +1904,7 @@ const char* TProgram::getUniformName(int index) const { return reflection
const char* TProgram::getUniformBlockName(int index) const { return reflection->getUniformBlock(index).name.c_str(); }
int TProgram::getUniformBlockSize(int index) const { return reflection->getUniformBlock(index).size; }
int TProgram::getUniformIndex(const char* name) const { return reflection->getIndex(name); }
int TProgram::getUniformBinding(int index) const { return reflection->getUniform(index).getBinding(); }
int TProgram::getUniformBlockIndex(int index) const { return reflection->getUniform(index).index; }
int TProgram::getUniformBlockCounterIndex(int index) const { return reflection->getUniformBlock(index).counterIndex; }
int TProgram::getUniformType(int index) const { return reflection->getUniform(index).glDefineType; }
+14 -5
View File
@@ -104,11 +104,20 @@ void TType::buildMangledName(TString& mangledName) const
default: break; // some compilers want this
}
switch (sampler.vectorSize) {
case 1: mangledName += "1"; break;
case 2: mangledName += "2"; break;
case 3: mangledName += "3"; break;
case 4: break; // default to prior name mangle behavior
if (sampler.hasReturnStruct()) {
// Name mangle for sampler return struct uses struct table index.
mangledName += "-tx-struct";
char text[16]; // plenty enough space for the small integers.
snprintf(text, sizeof(text), "%d-", sampler.structReturnIndex);
mangledName += text;
} else {
switch (sampler.getVectorSize()) {
case 1: mangledName += "1"; break;
case 2: mangledName += "2"; break;
case 3: mangledName += "3"; break;
case 4: break; // default to prior name mangle behavior
}
}
if (sampler.ms)
View File
+34 -6
View File
@@ -154,9 +154,10 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_OES_standard_derivatives] = EBhDisable;
extensionBehavior[E_GL_EXT_frag_depth] = EBhDisable;
extensionBehavior[E_GL_OES_EGL_image_external] = EBhDisable;
extensionBehavior[E_GL_OES_EGL_image_external_essl3] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_texture_lod] = EBhDisable;
extensionBehavior[E_GL_EXT_texture_array] = EBhDisable;
extensionBehavior[E_GL_EXT_shadow_samplers] = EBhDisable;
extensionBehavior[E_GL_ARB_texture_rectangle] = EBhDisable;
extensionBehavior[E_GL_3DL_array_objects] = EBhDisable;
extensionBehavior[E_GL_ARB_shading_language_420pack] = EBhDisable;
@@ -180,10 +181,14 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_ARB_shader_ballot] = EBhDisable;
extensionBehavior[E_GL_ARB_sparse_texture2] = EBhDisable;
extensionBehavior[E_GL_ARB_sparse_texture_clamp] = EBhDisable;
extensionBehavior[E_GL_ARB_shader_stencil_export] = EBhDisable;
// extensionBehavior[E_GL_ARB_cull_distance] = EBhDisable; // present for 4.5, but need extension control over block members
extensionBehavior[E_GL_ARB_post_depth_coverage] = EBhDisable;
extensionBehavior[E_GL_ARB_shader_viewport_layer_array] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_image_load_formatted] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_image_load_formatted] = EBhDisable;
extensionBehavior[E_GL_EXT_post_depth_coverage] = EBhDisable;
// #line and #include
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
@@ -197,15 +202,18 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_AMD_gpu_shader_half_float] = EBhDisable;
extensionBehavior[E_GL_AMD_texture_gather_bias_lod] = EBhDisable;
extensionBehavior[E_GL_AMD_gpu_shader_int16] = EBhDisable;
extensionBehavior[E_GL_AMD_shader_image_load_store_lod] = EBhDisable;
extensionBehavior[E_GL_AMD_shader_fragment_mask] = EBhDisable;
#endif
#ifdef NV_EXTENSIONS
extensionBehavior[E_GL_NV_sample_mask_override_coverage] = EBhDisable;
extensionBehavior[E_SPV_NV_geometry_shader_passthrough] = EBhDisable;
extensionBehavior[E_GL_ARB_shader_viewport_layer_array] = EBhDisable;
extensionBehavior[E_GL_NV_viewport_array2] = EBhDisable;
extensionBehavior[E_GL_NV_stereo_view_rendering] = EBhDisable;
extensionBehavior[E_GL_NVX_multiview_per_view_attributes] = EBhDisable;
extensionBehavior[E_GL_NV_shader_atomic_int64] = EBhDisable;
extensionBehavior[E_GL_NV_conservative_raster_underestimation] = EBhDisable;
#endif
// AEP
@@ -239,6 +247,10 @@ void TParseVersions::initializeExtensionBehavior()
// EXT extensions
extensionBehavior[E_GL_EXT_device_group] = EBhDisable;
extensionBehavior[E_GL_EXT_multiview] = EBhDisable;
// OVR extensions
extensionBehavior[E_GL_OVR_multiview] = EBhDisable;
extensionBehavior[E_GL_OVR_multiview2] = EBhDisable;
}
// Get code that is not part of a shared symbol table, is specific to this shader,
@@ -254,7 +266,9 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_OES_standard_derivatives 1\n"
"#define GL_EXT_frag_depth 1\n"
"#define GL_OES_EGL_image_external 1\n"
"#define GL_OES_EGL_image_external_essl3 1\n"
"#define GL_EXT_shader_texture_lod 1\n"
"#define GL_EXT_shadow_samplers 1\n"
// AEP
"#define GL_ANDROID_extension_pack_es31a 1\n"
@@ -311,9 +325,12 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_ARB_shader_ballot 1\n"
"#define GL_ARB_sparse_texture2 1\n"
"#define GL_ARB_sparse_texture_clamp 1\n"
"#define GL_ARB_shader_stencil_export 1\n"
// "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members
"#define GL_ARB_post_depth_coverage 1\n"
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
"#define GL_EXT_shader_image_load_formatted 1\n"
"#define GL_EXT_post_depth_coverage 1\n"
#ifdef AMD_EXTENSIONS
"#define GL_AMD_shader_ballot 1\n"
@@ -323,12 +340,16 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_AMD_gpu_shader_half_float 1\n"
"#define GL_AMD_texture_gather_bias_lod 1\n"
"#define GL_AMD_gpu_shader_int16 1\n"
"#define GL_AMD_shader_image_load_store_lod 1\n"
"#define GL_AMD_shader_fragment_mask 1\n"
#endif
#ifdef NV_EXTENSIONS
"#define GL_NV_sample_mask_override_coverage 1\n"
"#define GL_NV_geometry_shader_passthrough 1\n"
"#define GL_NV_viewport_array2 1\n"
"#define GL_NV_shader_atomic_int64 1\n"
"#define GL_NV_conservative_raster_underestimation 1\n"
#endif
;
@@ -343,12 +364,19 @@ void TParseVersions::getPreamble(std::string& preamble)
if ((profile != EEsProfile && version >= 140) ||
(profile == EEsProfile && version >= 310)) {
preamble +=
preamble +=
"#define GL_EXT_device_group 1\n"
"#define GL_EXT_multiview 1\n"
;
}
if (version >= 300 /* both ES and non-ES */) {
preamble +=
"#define GL_OVR_multiview 1\n"
"#define GL_OVR_multiview2 1\n"
;
}
// #line and #include
preamble +=
"#define GL_GOOGLE_cpp_style_line_directive 1\n"
@@ -358,9 +386,9 @@ void TParseVersions::getPreamble(std::string& preamble)
// #define VULKAN XXXX
const int numberBufSize = 12;
char numberBuf[numberBufSize];
if (spvVersion.vulkan > 0) {
if (spvVersion.vulkanGlsl > 0) {
preamble += "#define VULKAN ";
snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkan);
snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkanGlsl);
preamble += numberBuf;
preamble += "\n";
}
+33 -7
View File
@@ -72,14 +72,19 @@ inline const char* ProfileName(EProfile profile)
}
//
// SPIR-V has versions for multiple things; tie them together.
// 0 means a target or rule set is not enabled.
// What source rules, validation rules, target language, etc. are needed
// desired for SPIR-V?
//
// 0 means a target or rule set is not enabled (ignore rules from that entity).
// Non-0 means to apply semantic rules arising from that version of its rule set.
// The union of all requested rule sets will be applied.
//
struct SpvVersion {
SpvVersion() : spv(0), vulkan(0), openGl(0) {}
unsigned int spv; // the version of the targeted SPIR-V, as defined by SPIR-V in word 1 of the SPIR-V binary header
int vulkan; // the version of semantics for Vulkan; e.g., for GLSL from KHR_vulkan_glsl "#define VULKAN"
int openGl; // the version of semantics for OpenGL; e.g., for GLSL from KHR_vulkan_glsl "#define GL_SPIRV"
SpvVersion() : spv(0), vulkanGlsl(0), vulkan(0), openGl(0) {}
unsigned int spv; // the version of SPIR-V to target, as defined by "word 1" of the SPIR-V binary header
int vulkanGlsl; // the version of GLSL semantics for Vulkan, from GL_KHR_vulkan_glsl, for "#define VULKAN XXX"
int vulkan; // the version of Vulkan, for which SPIR-V execution environment rules to use (100 means 1.0)
int openGl; // the version of GLSL semantics for OpenGL, from GL_ARB_gl_spirv, for "#define GL_SPIRV XXX"
};
//
@@ -102,7 +107,9 @@ const char* const E_GL_OES_texture_3D = "GL_OES_texture_3D";
const char* const E_GL_OES_standard_derivatives = "GL_OES_standard_derivatives";
const char* const E_GL_EXT_frag_depth = "GL_EXT_frag_depth";
const char* const E_GL_OES_EGL_image_external = "GL_OES_EGL_image_external";
const char* const E_GL_OES_EGL_image_external_essl3 = "GL_OES_EGL_image_external_essl3";
const char* const E_GL_EXT_shader_texture_lod = "GL_EXT_shader_texture_lod";
const char* const E_GL_EXT_shadow_samplers = "GL_EXT_shadow_samplers";
const char* const E_GL_EXT_texture_array = "GL_EXT_texture_array";
const char* const E_GL_ARB_texture_rectangle = "GL_ARB_texture_rectangle";
@@ -128,7 +135,10 @@ const char* const E_GL_ARB_gpu_shader_int64 = "GL_ARB_gpu_shader_int
const char* const E_GL_ARB_shader_ballot = "GL_ARB_shader_ballot";
const char* const E_GL_ARB_sparse_texture2 = "GL_ARB_sparse_texture2";
const char* const E_GL_ARB_sparse_texture_clamp = "GL_ARB_sparse_texture_clamp";
const char* const E_GL_ARB_shader_stencil_export = "GL_ARB_shader_stencil_export";
// const char* const E_GL_ARB_cull_distance = "GL_ARB_cull_distance"; // present for 4.5, but need extension control over block members
const char* const E_GL_ARB_post_depth_coverage = "GL_ARB_post_depth_coverage";
const char* const E_GL_ARB_shader_viewport_layer_array = "GL_ARB_shader_viewport_layer_array";
const char* const E_GL_EXT_shader_non_constant_global_initializers = "GL_EXT_shader_non_constant_global_initializers";
const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_load_formatted";
@@ -136,6 +146,19 @@ const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_lo
// EXT extensions
const char* const E_GL_EXT_device_group = "GL_EXT_device_group";
const char* const E_GL_EXT_multiview = "GL_EXT_multiview";
const char* const E_GL_EXT_post_depth_coverage = "GL_EXT_post_depth_coverage";
// Arrays of extensions for the above viewportEXTs duplications
const char* const post_depth_coverageEXTs[] = { E_GL_ARB_post_depth_coverage, E_GL_EXT_post_depth_coverage };
const int Num_post_depth_coverageEXTs = sizeof(post_depth_coverageEXTs) / sizeof(post_depth_coverageEXTs[0]);
// OVR extensions
const char* const E_GL_OVR_multiview = "GL_OVR_multiview";
const char* const E_GL_OVR_multiview2 = "GL_OVR_multiview2";
const char* const OVR_multiview_EXTs[] = { E_GL_OVR_multiview, E_GL_OVR_multiview2 };
const int Num_OVR_multiview_EXTs = sizeof(OVR_multiview_EXTs) / sizeof(OVR_multiview_EXTs[0]);
// #line and #include
const char* const E_GL_GOOGLE_cpp_style_line_directive = "GL_GOOGLE_cpp_style_line_directive";
@@ -149,16 +172,19 @@ const char* const E_GL_AMD_gcn_shader = "GL_AMD_gcn_sh
const char* const E_GL_AMD_gpu_shader_half_float = "GL_AMD_gpu_shader_half_float";
const char* const E_GL_AMD_texture_gather_bias_lod = "GL_AMD_texture_gather_bias_lod";
const char* const E_GL_AMD_gpu_shader_int16 = "GL_AMD_gpu_shader_int16";
const char* const E_GL_AMD_shader_image_load_store_lod = "GL_AMD_shader_image_load_store_lod";
const char* const E_GL_AMD_shader_fragment_mask = "GL_AMD_shader_fragment_mask";
#endif
#ifdef NV_EXTENSIONS
const char* const E_GL_NV_sample_mask_override_coverage = "GL_NV_sample_mask_override_coverage";
const char* const E_SPV_NV_geometry_shader_passthrough = "GL_NV_geometry_shader_passthrough";
const char* const E_GL_ARB_shader_viewport_layer_array = "GL_ARB_shader_viewport_layer_array";
const char* const E_GL_NV_viewport_array2 = "GL_NV_viewport_array2";
const char* const E_GL_NV_stereo_view_rendering = "GL_NV_stereo_view_rendering";
const char* const E_GL_NVX_multiview_per_view_attributes = "GL_NVX_multiview_per_view_attributes";
const char* const E_GL_NV_shader_atomic_int64 = "GL_NV_shader_atomic_int64";
const char* const E_GL_NV_conservative_raster_underestimation = "GL_NV_conservative_raster_underestimation";
// Arrays of extensions for the above viewportEXTs duplications
View File
+2011 -2010
View File
File diff suppressed because it is too large Load Diff
+3 -5
View File
@@ -1,8 +1,8 @@
/* A Bison parser, made by GNU Bison 3.0.4. */
/* A Bison parser, made by GNU Bison 3.0. */
/* 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-2013 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
@@ -345,7 +345,7 @@ extern int yydebug;
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE YYSTYPE;
union YYSTYPE
{
#line 68 "MachineIndependent/glslang.y" /* yacc.c:1909 */
@@ -384,8 +384,6 @@ union YYSTYPE
#line 386 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
+32 -4
View File
@@ -196,6 +196,7 @@ bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
case EOpLogicalOr: out.debug << "logical-or"; break;
case EOpLogicalXor: out.debug << "logical-xor"; break;
case EOpLogicalAnd: out.debug << "logical-and"; break;
default: out.debug << "<unknown op>";
}
@@ -431,10 +432,13 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpMaxInvocationsExclusiveScanNonUniform: out.debug << "maxInvocationsExclusiveScanNonUniform"; break;
case EOpAddInvocationsExclusiveScanNonUniform: out.debug << "addInvocationsExclusiveScanNonUniform"; break;
case EOpMbcnt: out.debug << "mbcnt"; break;
case EOpMbcnt: out.debug << "mbcnt"; break;
case EOpCubeFaceIndex: out.debug << "cubeFaceIndex"; break;
case EOpCubeFaceCoord: out.debug << "cubeFaceCoord"; break;
case EOpCubeFaceIndex: out.debug << "cubeFaceIndex"; break;
case EOpCubeFaceCoord: out.debug << "cubeFaceCoord"; break;
case EOpFragmentMaskFetch: out.debug << "fragmentMaskFetchAMD"; break;
case EOpFragmentFetch: out.debug << "fragmentFetchAMD"; break;
case EOpConvBoolToFloat16: out.debug << "Convert bool to float16"; break;
case EOpConvIntToFloat16: out.debug << "Convert int to float16"; break;
@@ -488,6 +492,9 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
case EOpConvUint16ToUint64: out.debug << "Convert uint16 to uint64"; break;
#endif
case EOpSubpassLoad: out.debug << "subpassLoad"; break;
case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break;
default: out.debug.message(EPrefixError, "Bad unary op");
}
@@ -682,6 +689,16 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpAtomicExchange: out.debug << "AtomicExchange"; break;
case EOpAtomicCompSwap: out.debug << "AtomicCompSwap"; break;
case EOpAtomicCounterAdd: out.debug << "AtomicCounterAdd"; break;
case EOpAtomicCounterSubtract: out.debug << "AtomicCounterSubtract"; break;
case EOpAtomicCounterMin: out.debug << "AtomicCounterMin"; break;
case EOpAtomicCounterMax: out.debug << "AtomicCounterMax"; break;
case EOpAtomicCounterAnd: out.debug << "AtomicCounterAnd"; break;
case EOpAtomicCounterOr: out.debug << "AtomicCounterOr"; break;
case EOpAtomicCounterXor: out.debug << "AtomicCounterXor"; break;
case EOpAtomicCounterExchange: out.debug << "AtomicCounterExchange"; break;
case EOpAtomicCounterCompSwap: out.debug << "AtomicCounterCompSwap"; break;
case EOpImageQuerySize: out.debug << "imageQuerySize"; break;
case EOpImageQuerySamples: out.debug << "imageQuerySamples"; break;
case EOpImageLoad: out.debug << "imageLoad"; break;
@@ -694,6 +711,10 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpImageAtomicXor: out.debug << "imageAtomicXor"; break;
case EOpImageAtomicExchange: out.debug << "imageAtomicExchange"; break;
case EOpImageAtomicCompSwap: out.debug << "imageAtomicCompSwap"; break;
#ifdef AMD_EXTENSIONS
case EOpImageLoadLod: out.debug << "imageLoadLod"; break;
case EOpImageStoreLod: out.debug << "imageStoreLod"; break;
#endif
case EOpTextureQuerySize: out.debug << "textureSize"; break;
case EOpTextureQueryLod: out.debug << "textureQueryLod"; break;
@@ -746,6 +767,7 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpSparseTextureGatherLod: out.debug << "sparseTextureGatherLod"; break;
case EOpSparseTextureGatherLodOffset: out.debug << "sparseTextureGatherLodOffset"; break;
case EOpSparseTextureGatherLodOffsets: out.debug << "sparseTextureGatherLodOffsets"; break;
case EOpSparseImageLoadLod: out.debug << "sparseImageLoadLod"; break;
#endif
case EOpAddCarry: out.debug << "addCarry"; break;
@@ -769,10 +791,14 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
case EOpGenMul: out.debug << "mul"; break;
case EOpAllMemoryBarrierWithGroupSync: out.debug << "AllMemoryBarrierWithGroupSync"; break;
case EOpGroupMemoryBarrierWithGroupSync: out.debug << "GroupMemoryBarrierWithGroupSync"; break;
case EOpDeviceMemoryBarrier: out.debug << "DeviceMemoryBarrier"; break;
case EOpDeviceMemoryBarrierWithGroupSync: out.debug << "DeviceMemoryBarrierWithGroupSync"; break;
case EOpWorkgroupMemoryBarrier: out.debug << "WorkgroupMemoryBarrier"; break;
case EOpWorkgroupMemoryBarrierWithGroupSync: out.debug << "WorkgroupMemoryBarrierWithGroupSync"; break;
case EOpSubpassLoad: out.debug << "subpassLoad"; break;
case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break;
default: out.debug.message(EPrefixError, "Bad aggregation op");
}
@@ -1085,6 +1111,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
infoSink.debug << "gl_FragCoord origin is upper left\n";
if (earlyFragmentTests)
infoSink.debug << "using early_fragment_tests\n";
if (postDepthCoverage)
infoSink.debug << "using post_depth_coverage\n";
if (depthLayout != EldNone)
infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n";
if (blendEquations != 0) {
+117 -64
View File
@@ -253,10 +253,14 @@ struct TResolverUniformAdaptor
ent.newBinding = -1;
ent.newSet = -1;
ent.newIndex = -1;
const bool isValid = resolver.validateBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
const bool isValid = resolver.validateBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(),
ent.live);
if (isValid) {
ent.newBinding = resolver.resolveBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
ent.newBinding = resolver.resolveBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(),
ent.live);
ent.newSet = resolver.resolveSet(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
ent.newLocation = resolver.resolveUniformLocation(stage, ent.symbol->getName().c_str(),
ent.symbol->getType(), ent.live);
if (ent.newBinding != -1) {
if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
@@ -347,15 +351,21 @@ private:
// Base class for shared TIoMapResolver services, used by several derivations.
struct TDefaultIoResolverBase : public glslang::TIoMapResolver
{
int baseSamplerBinding;
int baseTextureBinding;
int baseImageBinding;
int baseUboBinding;
int baseSsboBinding;
int baseUavBinding;
std::vector<std::string> baseResourceSetBinding;
bool doAutoBindingMapping;
bool doAutoLocationMapping;
TDefaultIoResolverBase(const TIntermediate &intermediate) :
intermediate(intermediate),
nextUniformLocation(0)
{ }
int getBaseBinding(TResourceType res, unsigned int set) const {
return selectBaseBinding(intermediate.getShiftBinding(res),
intermediate.getShiftBindingForSet(res, set));
}
const std::vector<std::string>& getResourceSetBinding() const { return intermediate.getResourceSetBinding(); }
bool doAutoBindingMapping() const { return intermediate.getAutoMapBindings(); }
bool doAutoLocationMapping() const { return intermediate.getAutoMapLocations(); }
typedef std::vector<int> TSlotSet;
typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
TSlotSetMap slots;
@@ -404,18 +414,56 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver
{
if (type.getQualifier().hasSet())
return type.getQualifier().layoutSet;
// If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN)
if (getResourceSetBinding().size() == 1)
return atoi(getResourceSetBinding()[0].c_str());
return 0;
}
int resolveUniformLocation(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override
{
// kick out of not doing this
if (!doAutoLocationMapping())
return -1;
// no locations added if already present, a built-in variable, a block, or an opaque
if (type.getQualifier().hasLocation() || type.isBuiltIn() ||
type.getBasicType() == EbtBlock || type.containsOpaque())
return -1;
// no locations on blocks of built-in variables
if (type.isStruct()) {
if (type.getStruct()->size() < 1)
return -1;
if ((*type.getStruct())[0].type->isBuiltIn())
return -1;
}
return nextUniformLocation++;
}
bool validateInOut(EShLanguage /*stage*/, const char* /*name*/, const TType& /*type*/, bool /*is_live*/) override
{
return true;
}
int resolveInOutLocation(EShLanguage /*stage*/, const char* /*name*/, const TType& type, bool /*is_live*/) override
{
if (!doAutoLocationMapping || type.getQualifier().hasLocation())
// kick out of not doing this
if (!doAutoLocationMapping())
return -1;
// no locations added if already present, or a built-in variable
if (type.getQualifier().hasLocation() || type.isBuiltIn())
return -1;
// no locations on blocks of built-in variables
if (type.isStruct()) {
if (type.getStruct()->size() < 1)
return -1;
if ((*type.getStruct())[0].type->isBuiltIn())
return -1;
}
// Placeholder.
// TODO: It would be nice to flesh this out using
// intermediate->computeTypeLocationSize(type), or functions that call it like
@@ -436,9 +484,20 @@ struct TDefaultIoResolverBase : public glslang::TIoMapResolver
void notifyBinding(EShLanguage, const char* /*name*/, const TType&, bool /*is_live*/) override {}
void notifyInOut(EShLanguage, const char* /*name*/, const TType&, bool /*is_live*/) override {}
void endNotifications() override {}
void endNotifications(EShLanguage) override {}
void beginNotifications(EShLanguage) override {}
void beginResolve(EShLanguage) override {}
void endResolve(EShLanguage) override {}
protected:
const TIntermediate &intermediate;
int nextUniformLocation;
// Return descriptor set specific base if there is one, and the generic base otherwise.
int selectBaseBinding(int base, int descriptorSetBase) const {
return descriptorSetBase != -1 ? descriptorSetBase : base;
}
static int getLayoutSet(const glslang::TType& type) {
if (type.getQualifier().hasSet())
return type.getQualifier().layoutSet;
@@ -451,7 +510,8 @@ protected:
}
static bool isTextureType(const glslang::TType& type) {
return type.getBasicType() == glslang::EbtSampler && type.getSampler().isTexture();
return (type.getBasicType() == glslang::EbtSampler &&
(type.getSampler().isTexture() || type.getSampler().isSubpass()));
}
static bool isUboType(const glslang::TType& type) {
@@ -471,6 +531,8 @@ protected:
*/
struct TDefaultIoResolver : public TDefaultIoResolverBase
{
TDefaultIoResolver(const TIntermediate &intermediate) : TDefaultIoResolverBase(intermediate) { }
bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& /*type*/, bool /*is_live*/) override
{
return true;
@@ -482,37 +544,37 @@ struct TDefaultIoResolver : public TDefaultIoResolverBase
if (type.getQualifier().hasBinding()) {
if (isImageType(type))
return reserveSlot(set, baseImageBinding + type.getQualifier().layoutBinding);
return reserveSlot(set, getBaseBinding(EResImage, set) + type.getQualifier().layoutBinding);
if (isTextureType(type))
return reserveSlot(set, baseTextureBinding + type.getQualifier().layoutBinding);
return reserveSlot(set, getBaseBinding(EResTexture, set) + type.getQualifier().layoutBinding);
if (isSsboType(type))
return reserveSlot(set, baseSsboBinding + type.getQualifier().layoutBinding);
return reserveSlot(set, getBaseBinding(EResSsbo, set) + type.getQualifier().layoutBinding);
if (isSamplerType(type))
return reserveSlot(set, baseSamplerBinding + type.getQualifier().layoutBinding);
return reserveSlot(set, getBaseBinding(EResSampler, set) + type.getQualifier().layoutBinding);
if (isUboType(type))
return reserveSlot(set, baseUboBinding + type.getQualifier().layoutBinding);
} else if (is_live && doAutoBindingMapping) {
return reserveSlot(set, getBaseBinding(EResUbo, set) + type.getQualifier().layoutBinding);
} else if (is_live && doAutoBindingMapping()) {
// find free slot, the caller did make sure it passes all vars with binding
// first and now all are passed that do not have a binding and needs one
if (isImageType(type))
return getFreeSlot(set, baseImageBinding);
return getFreeSlot(set, getBaseBinding(EResImage, set));
if (isTextureType(type))
return getFreeSlot(set, baseTextureBinding);
return getFreeSlot(set, getBaseBinding(EResTexture, set));
if (isSsboType(type))
return getFreeSlot(set, baseSsboBinding);
return getFreeSlot(set, getBaseBinding(EResSsbo, set));
if (isSamplerType(type))
return getFreeSlot(set, baseSamplerBinding);
return getFreeSlot(set, getBaseBinding(EResSampler, set));
if (isUboType(type))
return getFreeSlot(set, baseUboBinding);
return getFreeSlot(set, getBaseBinding(EResUbo, set));
}
return -1;
@@ -573,6 +635,8 @@ b for constant buffer views (CBV)
********************************************************************************/
struct TDefaultHlslIoResolver : public TDefaultIoResolverBase
{
TDefaultHlslIoResolver(const TIntermediate &intermediate) : TDefaultIoResolverBase(intermediate) { }
bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& /*type*/, bool /*is_live*/) override
{
return true;
@@ -584,31 +648,31 @@ struct TDefaultHlslIoResolver : public TDefaultIoResolverBase
if (type.getQualifier().hasBinding()) {
if (isUavType(type))
return reserveSlot(set, baseUavBinding + type.getQualifier().layoutBinding);
return reserveSlot(set, getBaseBinding(EResUav, set) + type.getQualifier().layoutBinding);
if (isSrvType(type))
return reserveSlot(set, baseTextureBinding + type.getQualifier().layoutBinding);
return reserveSlot(set, getBaseBinding(EResTexture, set) + type.getQualifier().layoutBinding);
if (isSamplerType(type))
return reserveSlot(set, baseSamplerBinding + type.getQualifier().layoutBinding);
return reserveSlot(set, getBaseBinding(EResSampler, set) + type.getQualifier().layoutBinding);
if (isUboType(type))
return reserveSlot(set, baseUboBinding + type.getQualifier().layoutBinding);
} else if (is_live && doAutoBindingMapping) {
return reserveSlot(set, getBaseBinding(EResUbo, set) + type.getQualifier().layoutBinding);
} else if (is_live && doAutoBindingMapping()) {
// find free slot, the caller did make sure it passes all vars with binding
// first and now all are passed that do not have a binding and needs one
if (isUavType(type))
return getFreeSlot(set, baseUavBinding);
return getFreeSlot(set, getBaseBinding(EResUav, set));
if (isSrvType(type))
return getFreeSlot(set, baseTextureBinding);
return getFreeSlot(set, getBaseBinding(EResTexture, set));
if (isSamplerType(type))
return getFreeSlot(set, baseSamplerBinding);
return getFreeSlot(set, getBaseBinding(EResSampler, set));
if (isUboType(type))
return getFreeSlot(set, baseUboBinding);
return getFreeSlot(set, getBaseBinding(EResUbo, set));
}
return -1;
@@ -637,17 +701,17 @@ protected:
// Returns false if the input is too malformed to do this.
bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSink &infoSink, TIoMapResolver *resolver)
{
// Trivial return if there is nothing to do.
if (intermediate.getShiftSamplerBinding() == 0 &&
intermediate.getShiftTextureBinding() == 0 &&
intermediate.getShiftImageBinding() == 0 &&
intermediate.getShiftUboBinding() == 0 &&
intermediate.getShiftSsboBinding() == 0 &&
intermediate.getShiftUavBinding() == 0 &&
intermediate.getResourceSetBinding().empty() &&
intermediate.getAutoMapBindings() == false &&
intermediate.getAutoMapLocations() == false &&
resolver == nullptr)
bool somethingToDo = !intermediate.getResourceSetBinding().empty() ||
intermediate.getAutoMapBindings() ||
intermediate.getAutoMapLocations();
for (int res = 0; res < EResCount; ++res) {
somethingToDo = somethingToDo ||
(intermediate.getShiftBinding(TResourceType(res)) != 0) ||
intermediate.hasShiftBindingForSet(TResourceType(res));
}
if (!somethingToDo && resolver == nullptr)
return true;
if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
@@ -658,29 +722,15 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSi
return false;
// if no resolver is provided, use the default resolver with the given shifts and auto map settings
TDefaultIoResolver defaultResolver;
TDefaultHlslIoResolver defaultHlslResolver;
TDefaultIoResolver defaultResolver(intermediate);
TDefaultHlslIoResolver defaultHlslResolver(intermediate);
if (resolver == nullptr) {
TDefaultIoResolverBase* resolverBase;
// TODO: use a passed in IO mapper for this
if (intermediate.usingHlslIoMapping())
resolverBase = &defaultHlslResolver;
resolver = &defaultHlslResolver;
else
resolverBase = &defaultResolver;
resolverBase->baseSamplerBinding = intermediate.getShiftSamplerBinding();
resolverBase->baseTextureBinding = intermediate.getShiftTextureBinding();
resolverBase->baseImageBinding = intermediate.getShiftImageBinding();
resolverBase->baseUboBinding = intermediate.getShiftUboBinding();
resolverBase->baseSsboBinding = intermediate.getShiftSsboBinding();
resolverBase->baseUavBinding = intermediate.getShiftUavBinding();
resolverBase->baseResourceSetBinding = intermediate.getResourceSetBinding();
resolverBase->doAutoBindingMapping = intermediate.getAutoMapBindings();
resolverBase->doAutoLocationMapping = intermediate.getAutoMapLocations();
resolver = resolverBase;
resolver = &defaultResolver;
}
TVarLiveMap inVarMap, outVarMap, uniformVarMap;
@@ -704,13 +754,16 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSi
TNotifyUniformAdaptor uniformNotify(stage, *resolver);
TResolverUniformAdaptor uniformResolve(stage, *resolver, infoSink, hadError, intermediate);
TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError, intermediate);
resolver->beginNotifications(stage);
std::for_each(inVarMap.begin(), inVarMap.end(), inOutNotify);
std::for_each(outVarMap.begin(), outVarMap.end(), inOutNotify);
std::for_each(uniformVarMap.begin(), uniformVarMap.end(), uniformNotify);
resolver->endNotifications();
resolver->endNotifications(stage);
resolver->beginResolve(stage);
std::for_each(inVarMap.begin(), inVarMap.end(), inOutResolve);
std::for_each(outVarMap.begin(), outVarMap.end(), inOutResolve);
std::for_each(uniformVarMap.begin(), uniformVarMap.end(), uniformResolve);
resolver->endResolve(stage);
if (!hadError) {
// sort by id again, so we can use lower bound to find entries
View File
View File
+10 -2
View File
@@ -101,6 +101,9 @@ void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit)
if (! earlyFragmentTests)
earlyFragmentTests = unit.earlyFragmentTests;
if (!postDepthCoverage)
postDepthCoverage = unit.postDepthCoverage;
if (depthLayout == EldNone)
depthLayout = unit.depthLayout;
else if (depthLayout != unit.depthLayout)
@@ -459,9 +462,9 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
error(infoSink, "At least one shader must specify an output layout(vertices=...)");
break;
case EShLangTessEvaluation:
if (inputPrimitive == ElgNone)
error(infoSink, "At least one shader must specify an input layout primitive");
if (source == EShSourceGlsl) {
if (inputPrimitive == ElgNone)
error(infoSink, "At least one shader must specify an input layout primitive");
if (vertexSpacing == EvsNone)
vertexSpacing = EvsEqual;
if (vertexOrder == EvoNone)
@@ -485,6 +488,11 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
error(infoSink, "At least one shader must specify a layout(max_vertices = value)");
break;
case EShLangFragment:
// for GL_ARB_post_depth_coverage, EarlyFragmentTest is set automatically in
// ParseHelper.cpp. So if we reach here, this must be GL_EXT_post_depth_coverage
// requiring explicit early_fragment_tests
if (getPostDepthCoverage() && !getEarlyFragmentTests())
error(infoSink, "post_depth_coverage requires early_fragment_tests");
break;
case EShLangCompute:
break;
+211 -46
View File
@@ -42,6 +42,7 @@
#include <algorithm>
#include <set>
#include <array>
class TInfoSink;
@@ -150,6 +151,54 @@ struct TXfbBuffer {
bool containsDouble;
};
// Track a set of strings describing how the module was processed.
// Using the form:
// process arg0 arg1 arg2 ...
// process arg0 arg1 arg2 ...
// where everything is textual, and there can be zero or more arguments
class TProcesses {
public:
TProcesses() {}
~TProcesses() {}
void addProcess(const char* process)
{
processes.push_back(process);
}
void addProcess(const std::string& process)
{
processes.push_back(process);
}
void addArgument(int arg)
{
processes.back().append(" ");
std::string argString = std::to_string(arg);
processes.back().append(argString);
}
void addArgument(const char* arg)
{
processes.back().append(" ");
processes.back().append(arg);
}
void addArgument(const std::string& arg)
{
processes.back().append(" ");
processes.back().append(arg);
}
void addIfNonZero(const char* process, int value)
{
if (value != 0) {
addProcess(process);
addArgument(value);
}
}
const std::vector<std::string>& getProcesses() const { return processes; }
private:
std::vector<std::string> processes;
};
class TSymbolTable;
class TSymbol;
class TVariable;
@@ -160,30 +209,29 @@ class TVariable;
class TIntermediate {
public:
explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
implicitThisName("@this"),
language(l), source(EShSourceNone), profile(p), version(v), treeRoot(0),
numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false),
invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone),
invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet),
inputPrimitive(ElgNone), outputPrimitive(ElgNone),
pixelCenterInteger(false), originUpperLeft(false),
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), depthReplacing(false), blendEquations(0),
xfbMode(false), multiStream(false),
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false),
postDepthCoverage(false), depthLayout(EldNone), depthReplacing(false),
blendEquations(0), xfbMode(false), multiStream(false),
#ifdef NV_EXTENSIONS
layoutOverrideCoverage(false),
geoPassthroughEXT(false),
#endif
shiftSamplerBinding(0),
shiftTextureBinding(0),
shiftImageBinding(0),
shiftUboBinding(0),
shiftSsboBinding(0),
shiftUavBinding(0),
autoMapBindings(false),
autoMapLocations(false),
invertY(false),
flattenUniformArrays(false),
useUnknownFormat(false),
hlslOffsets(false),
useStorageBuffer(false),
hlslIoMapping(false),
textureSamplerTransformMode(EShTexSampTransKeep)
textureSamplerTransformMode(EShTexSampTransKeep),
needToLegalize(false)
{
localSize[0] = 1;
localSize[1] = 1;
@@ -192,6 +240,8 @@ public:
localSizeSpecId[1] = TQualifier::layoutNotSet;
localSizeSpecId[2] = TQualifier::layoutNotSet;
xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
shiftBinding.fill(0);
}
void setLimits(const TBuiltInResource& r) { resources = r; }
@@ -201,46 +251,140 @@ public:
void setSource(EShSource s) { source = s; }
EShSource getSource() const { return source; }
void setEntryPointName(const char* ep) { entryPointName = ep; }
void setEntryPointName(const char* ep)
{
entryPointName = ep;
processes.addProcess("entry-point");
processes.addArgument(entryPointName);
}
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 setShiftImageBinding(unsigned int shift) { shiftImageBinding = shift; }
unsigned int getShiftImageBinding() const { return shiftImageBinding; }
void setShiftUboBinding(unsigned int shift) { shiftUboBinding = shift; }
unsigned int getShiftUboBinding() const { return shiftUboBinding; }
void setShiftSsboBinding(unsigned int shift) { shiftSsboBinding = shift; }
unsigned int getShiftSsboBinding() const { return shiftSsboBinding; }
void setShiftUavBinding(unsigned int shift) { shiftUavBinding = shift; }
unsigned int getShiftUavBinding() const { return shiftUavBinding; }
void setResourceSetBinding(const std::vector<std::string>& shift) { resourceSetBinding = shift; }
void setShiftBinding(TResourceType res, unsigned int shift)
{
shiftBinding[res] = shift;
const char* name = getResourceName(res);
if (name != nullptr)
processes.addIfNonZero(name, shift);
}
unsigned int getShiftBinding(TResourceType res) const { return shiftBinding[res]; }
void setShiftBindingForSet(TResourceType res, unsigned int shift, unsigned int set)
{
if (shift == 0) // ignore if there's no shift: it's a no-op.
return;
shiftBindingForSet[res][set] = shift;
const char* name = getResourceName(res);
if (name != nullptr) {
processes.addProcess(name);
processes.addArgument(shift);
processes.addArgument(set);
}
}
int getShiftBindingForSet(TResourceType res, unsigned int set) const
{
const auto shift = shiftBindingForSet[res].find(set);
return shift == shiftBindingForSet[res].end() ? -1 : shift->second;
}
bool hasShiftBindingForSet(TResourceType res) const { return !shiftBindingForSet[res].empty(); }
void setResourceSetBinding(const std::vector<std::string>& shift)
{
resourceSetBinding = shift;
if (shift.size() > 0) {
processes.addProcess("resource-set-binding");
for (int s = 0; s < (int)shift.size(); ++s)
processes.addArgument(shift[s]);
}
}
const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
void setAutoMapBindings(bool map) { autoMapBindings = map; }
bool getAutoMapBindings() const { return autoMapBindings; }
void setAutoMapLocations(bool map) { autoMapLocations = map; }
bool getAutoMapLocations() const { return autoMapLocations; }
void setFlattenUniformArrays(bool flatten) { flattenUniformArrays = flatten; }
bool getFlattenUniformArrays() const { return flattenUniformArrays; }
void setNoStorageFormat(bool b) { useUnknownFormat = b; }
bool getNoStorageFormat() const { return useUnknownFormat; }
void setHlslOffsets() { hlslOffsets = true; }
void setAutoMapBindings(bool map)
{
autoMapBindings = map;
if (autoMapBindings)
processes.addProcess("auto-map-bindings");
}
bool getAutoMapBindings() const { return autoMapBindings; }
void setAutoMapLocations(bool map)
{
autoMapLocations = map;
if (autoMapLocations)
processes.addProcess("auto-map-locations");
}
bool getAutoMapLocations() const { return autoMapLocations; }
void setInvertY(bool invert)
{
invertY = invert;
if (invertY)
processes.addProcess("invert-y");
}
bool getInvertY() const { return invertY; }
void setFlattenUniformArrays(bool flatten)
{
flattenUniformArrays = flatten;
if (flattenUniformArrays)
processes.addProcess("flatten-uniform-arrays");
}
bool getFlattenUniformArrays() const { return flattenUniformArrays; }
void setNoStorageFormat(bool b)
{
useUnknownFormat = b;
if (useUnknownFormat)
processes.addProcess("no-storage-format");
}
bool getNoStorageFormat() const { return useUnknownFormat; }
void setHlslOffsets()
{
hlslOffsets = true;
if (hlslOffsets)
processes.addProcess("hlsl-offsets");
}
bool usingHlslOFfsets() const { return hlslOffsets; }
void setUseStorageBuffer() { useStorageBuffer = true; }
void setUseStorageBuffer()
{
useStorageBuffer = true;
processes.addProcess("use-storage-buffer");
}
bool usingStorageBuffer() const { return useStorageBuffer; }
void setHlslIoMapping(bool b) { hlslIoMapping = b; }
bool usingHlslIoMapping() { return hlslIoMapping; }
void setHlslIoMapping(bool b)
{
hlslIoMapping = b;
if (hlslIoMapping)
processes.addProcess("hlsl-iomap");
}
bool usingHlslIoMapping() { return hlslIoMapping; }
void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
void setVersion(int v) { version = v; }
int getVersion() const { return version; }
void setProfile(EProfile p) { profile = p; }
EProfile getProfile() const { return profile; }
void setSpv(const SpvVersion& s) { spvVersion = s; }
void setSpv(const SpvVersion& s)
{
spvVersion = s;
// client processes
if (spvVersion.vulkan > 0)
processes.addProcess("client vulkan100");
if (spvVersion.openGl > 0)
processes.addProcess("client opengl100");
// target-environment processes
if (spvVersion.vulkan == 100)
processes.addProcess("target-env vulkan1.0");
else if (spvVersion.vulkan > 0)
processes.addProcess("target-env vulkanUnknown");
if (spvVersion.openGl > 0)
processes.addProcess("target-env opengl");
}
const SpvVersion& getSpv() const { return spvVersion; }
EShLanguage getStage() const { return language; }
void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
@@ -276,8 +420,8 @@ public:
TIntermAggregate* makeAggregate(const TSourceLoc&);
TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
bool areAllChildConst(TIntermAggregate* aggrNode);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
@@ -403,6 +547,8 @@ public:
bool getPixelCenterInteger() const { return pixelCenterInteger; }
void setEarlyFragmentTests() { earlyFragmentTests = true; }
bool getEarlyFragmentTests() const { return earlyFragmentTests; }
void setPostDepthCoverage() { postDepthCoverage = true; }
bool getPostDepthCoverage() const { return postDepthCoverage; }
bool setDepth(TLayoutDepth d)
{
if (depthLayout != EldNone)
@@ -437,6 +583,7 @@ public:
xfbBuffers[buffer].stride = stride;
return true;
}
unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
int addXfbBufferOffset(const TType&);
unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
static int getBaseAlignmentScalar(const TType&, int& size);
@@ -460,8 +607,18 @@ public:
const std::string& getSourceFile() const { return sourceFile; }
void addSourceText(const char* text) { sourceText = sourceText + text; }
const std::string& getSourceText() const { return sourceText; }
void addProcesses(const std::vector<std::string>& p) {
for (int i = 0; i < (int)p.size(); ++i)
processes.addProcess(p[i]);
}
void addProcess(const std::string& process) { processes.addProcess(process); }
void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
const char* const implicitThisName = "@this";
void setNeedsLegalization() { needToLegalize = true; }
bool needsLegalization() const { return needToLegalize; }
const char* const implicitThisName;
protected:
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
@@ -485,6 +642,7 @@ protected:
void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&);
void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root);
static const char* getResourceName(TResourceType);
const EShLanguage language; // stage, known at construction time
EShSource source; // source language, known a bit later
@@ -513,6 +671,7 @@ protected:
int localSize[3];
int localSizeSpecId[3];
bool earlyFragmentTests;
bool postDepthCoverage;
TLayoutDepth depthLayout;
bool depthReplacing;
int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift
@@ -524,15 +683,16 @@ protected:
bool geoPassthroughEXT;
#endif
unsigned int shiftSamplerBinding;
unsigned int shiftTextureBinding;
unsigned int shiftImageBinding;
unsigned int shiftUboBinding;
unsigned int shiftSsboBinding;
unsigned int shiftUavBinding;
// Base shift values
std::array<unsigned int, EResCount> shiftBinding;
// Per-descriptor-set shift values
std::array<std::map<int, int>, EResCount> shiftBindingForSet;
std::vector<std::string> resourceSetBinding;
bool autoMapBindings;
bool autoMapLocations;
bool invertY;
bool flattenUniformArrays;
bool useUnknownFormat;
bool hlslOffsets;
@@ -555,6 +715,11 @@ protected:
std::string sourceFile;
std::string sourceText;
// for OpModuleProcessed, or equivalent
TProcesses processes;
bool needToLegalize;
private:
void operator=(TIntermediate&); // prevent assignments
};
View File
+33 -21
View File
@@ -84,6 +84,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <climits>
#include "PpContext.h"
#include "PpTokens.h"
@@ -241,15 +242,20 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
int nextAtom = atomStrings.getAtom(ppToken->name);
if (nextAtom == PpAtomIf || nextAtom == PpAtomIfdef || nextAtom == PpAtomIfndef) {
depth++;
ifdepth++;
elsetracker++;
if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) {
parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if/#ifdef/#ifndef", "");
return EndOfInput;
} else {
ifdepth++;
elsetracker++;
}
} else if (nextAtom == PpAtomEndif) {
token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
elseSeen[elsetracker] = false;
--elsetracker;
if (depth == 0) {
// found the #endif we are looking for
if (ifdepth)
if (ifdepth > 0)
--ifdepth;
break;
}
@@ -266,7 +272,7 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
/* we decrement ifdepth here, because CPPif will increment
* it and we really want to leave it alone */
if (ifdepth) {
if (ifdepth > 0) {
--ifdepth;
elseSeen[elsetracker] = false;
--elsetracker;
@@ -345,8 +351,8 @@ namespace {
int op_add(int a, int b) { return a + b; }
int op_sub(int a, int b) { return a - b; }
int op_mul(int a, int b) { return a * b; }
int op_div(int a, int b) { return a / b; }
int op_mod(int a, int b) { return a % b; }
int op_div(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a / b; }
int op_mod(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a % b; }
int op_pos(int a) { return a; }
int op_neg(int a) { return -a; }
int op_cmpl(int a) { return ~a; }
@@ -536,11 +542,12 @@ int TPpContext::evalToToken(int token, bool shortCircuit, int& res, bool& err, T
int TPpContext::CPPif(TPpToken* ppToken)
{
int token = scanToken(ppToken);
elsetracker++;
ifdepth++;
if (ifdepth > maxIfNesting) {
if (ifdepth >= maxIfNesting || elsetracker >= maxIfNesting) {
parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#if", "");
return 0;
return EndOfInput;
} else {
elsetracker++;
ifdepth++;
}
int res = 0;
bool err = false;
@@ -556,11 +563,14 @@ int TPpContext::CPPif(TPpToken* ppToken)
int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
{
int token = scanToken(ppToken);
if (++ifdepth > maxIfNesting) {
if (ifdepth > maxIfNesting || elsetracker > maxIfNesting) {
parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
return 0;
return EndOfInput;
} else {
elsetracker++;
ifdepth++;
}
elsetracker++;
if (token != PpAtomIdentifier) {
if (defined)
parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifdef", "");
@@ -886,16 +896,16 @@ int TPpContext::readCPPline(TPpToken* ppToken)
token = CPPdefine(ppToken);
break;
case PpAtomElse:
if (elsetracker[elseSeen])
if (elseSeen[elsetracker])
parseContext.ppError(ppToken->loc, "#else after #else", "#else", "");
elsetracker[elseSeen] = true;
if (! ifdepth)
elseSeen[elsetracker] = true;
if (ifdepth == 0)
parseContext.ppError(ppToken->loc, "mismatched statements", "#else", "");
token = extraTokenCheck(PpAtomElse, ppToken, scanToken(ppToken));
token = CPPelse(0, ppToken);
break;
case PpAtomElif:
if (! ifdepth)
if (ifdepth == 0)
parseContext.ppError(ppToken->loc, "mismatched statements", "#elif", "");
if (elseSeen[elsetracker])
parseContext.ppError(ppToken->loc, "#elif after #else", "#elif", "");
@@ -906,7 +916,7 @@ int TPpContext::readCPPline(TPpToken* ppToken)
token = CPPelse(0, ppToken);
break;
case PpAtomEndif:
if (! ifdepth)
if (ifdepth == 0)
parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
else {
elseSeen[elsetracker] = false;
@@ -1068,6 +1078,10 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken)
pasting = true;
}
// HLSL does expand macros before concatenation
if (pasting && pp->parseContext.isReadingHLSL())
pasting = false;
// TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding
if (token == PpAtomIdentifier) {
int i;
@@ -1143,7 +1157,6 @@ int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOka
}
MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom);
int token;
int depth = 0;
// no recursive expansions
@@ -1165,13 +1178,12 @@ int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOka
TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error
in->mac = macro;
if (macro->args.size() > 0 || macro->emptyArgs) {
token = scanToken(ppToken);
int token = scanToken(ppToken);
if (newLineOkay) {
while (token == '\n')
token = scanToken(ppToken);
}
if (token != '(') {
parseContext.ppError(loc, "expected '(' following", "macro expansion", atomStrings.getString(macroAtom));
UngetToken(token, ppToken);
delete in;
return 0;
+1 -1
View File
@@ -309,7 +309,7 @@ protected:
bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); }
bool isMacroInput() { return inputStack.size() > 0 && inputStack.back()->isMacroInput(); }
static const int maxIfNesting = 64;
static const int maxIfNesting = 65;
int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor)
bool elseSeen[maxIfNesting]; // Keep a track of whether an else has been seen at a particular depth
+6 -3
View File
@@ -128,7 +128,7 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
ch = getChar();
// 1.#INF or -1.#INF
if (ch == '#') {
if (parseContext.intermediate.getSource() == EShSourceHlsl && ch == '#') {
if ((len < 2) ||
(len == 2 && ppToken->name[0] != '1') ||
(len == 3 && ppToken->name[1] != '1' && !(ppToken->name[0] == '-' || ppToken->name[0] == '+')) ||
@@ -420,7 +420,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
ival = 0;
do {
if (ival <= 0x0fffffffu || (enableInt64 && ival <= 0x0fffffffffffffffull)) {
if (len < MaxTokenLength && (ival <= 0x0fffffffu || (enableInt64 && ival <= 0x0fffffffffffffffull))) {
ppToken->name[len++] = (char)ch;
if (ch >= '0' && ch <= '9') {
ii = ch - '0';
@@ -433,7 +433,10 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
ival = (ival << 4) | ii;
} else {
if (! AlreadyComplained) {
pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
if(len < MaxTokenLength)
pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too big", "", "");
else
pp->parseContext.ppError(ppToken->loc, "hexadecimal literal too long", "", "");
AlreadyComplained = 1;
}
ival = 0xffffffffffffffffull;
+22 -12
View File
@@ -131,8 +131,11 @@ public:
for (int m = 0; m <= index; ++m) {
// modify just the children's view of matrix layout, if there is one for this member
TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, dummyStride, type.getQualifier().layoutPacking == ElpStd140,
subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : type.getQualifier().layoutMatrix == ElmRowMajor);
int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, dummyStride,
type.getQualifier().layoutPacking == ElpStd140,
subMatrixLayout != ElmNone
? subMatrixLayout == ElmRowMajor
: type.getQualifier().layoutMatrix == ElmRowMajor);
RoundToPow2(offset, memberAlignment);
if (m < index)
offset += memberSize;
@@ -151,7 +154,8 @@ public:
int lastMemberSize;
int dummyStride;
intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, blockType.getQualifier().layoutPacking == ElpStd140,
intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
blockType.getQualifier().layoutPacking == ElpStd140,
blockType.getQualifier().layoutMatrix == ElmRowMajor);
return lastOffset + lastMemberSize;
@@ -167,7 +171,7 @@ public:
void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize)
{
// process the part of the derefence chain that was explicit in the shader
// process the part of the dereference chain that was explicit in the shader
TString name = baseName;
const TType* terminalType = &baseType;
for (; deref != derefs.end(); ++deref) {
@@ -177,7 +181,7 @@ public:
switch (visitNode->getOp()) {
case EOpIndexIndirect:
// Visit all the indices of this array, and for each one add on the remaining dereferencing
for (int i = 0; i < visitNode->getLeft()->getType().getOuterArraySize(); ++i) {
for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) {
TString newBaseName = name;
if (baseType.getBasicType() != EbtBlock)
newBaseName.append(TString("[") + String(i) + "]");
@@ -212,7 +216,7 @@ public:
if (terminalType->isArray()) {
// Visit all the indices of this array, and for each one,
// fully explode the remaining aggregate to dereference
for (int i = 0; i < terminalType->getOuterArraySize(); ++i) {
for (int i = 0; i < std::max(terminalType->getOuterArraySize(), 1); ++i) {
TString newBaseName = name;
newBaseName.append(TString("[") + String(i) + "]");
TType derefType(*terminalType, 0);
@@ -235,7 +239,7 @@ public:
}
// Finally, add a full string to the reflection database, and update the array size if necessary.
// If the derefenced entity to record is an array, compute the size and update the maximum size.
// If the dereferenced entity to record is an array, compute the size and update the maximum size.
// there might not be a final array dereference, it could have been copied as an array object
if (arraySize == 0)
@@ -244,7 +248,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, *terminalType, offset, mapToGlType(*terminalType),
reflection.indexToUniform.push_back(TObjectReflection(name, *terminalType, offset,
mapToGlType(*terminalType),
arraySize, blockIndex));
} else if (arraySize > 1) {
int& reflectedArraySize = reflection.indexToUniform[it->second].size;
@@ -417,7 +422,8 @@ public:
case Esd2D:
switch ((int)sampler.ms) {
case false: return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D;
case true: return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_INT_SAMPLER_2D_MULTISAMPLE;
case true: return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY
: GL_INT_SAMPLER_2D_MULTISAMPLE;
}
case Esd3D:
return GL_INT_SAMPLER_3D;
@@ -435,7 +441,8 @@ public:
case Esd2D:
switch ((int)sampler.ms) {
case false: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D;
case true: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
case true: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY
: GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
}
case Esd3D:
return GL_UNSIGNED_INT_SAMPLER_3D;
@@ -495,7 +502,8 @@ public:
case Esd2D:
switch ((int)sampler.ms) {
case false: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D;
case true: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE;
case true: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY
: GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE;
}
case Esd3D:
return GL_UNSIGNED_INT_IMAGE_3D;
@@ -725,7 +733,9 @@ void TReflection::buildCounterIndices()
// Returns false if the input is too malformed to do this.
bool TReflection::addStage(EShLanguage stage, const TIntermediate& intermediate)
{
if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
if (intermediate.getTreeRoot() == nullptr ||
intermediate.getNumEntryPoints() != 1 ||
intermediate.isRecursive())
return false;
buildAttributeReflection(stage, intermediate);
+10 -11
View File
@@ -59,7 +59,15 @@ public:
name(pName), offset(pOffset),
glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1), type(pType.clone()) { }
void dump() const {
const TType* const getType() const { return type; }
int getBinding() const
{
if (type == nullptr || !type->getQualifier().hasBinding())
return -1;
return type->getQualifier().layoutBinding;
}
void dump() const
{
printf("%s: offset %d, type %x, size %d, index %d, binding %d",
name.c_str(), offset, glDefineType, size, index, getBinding() );
@@ -68,8 +76,7 @@ public:
printf("\n");
}
const TType* const getType() const { return type; }
static TObjectReflection badReflection() { return TObjectReflection(); }
TString name;
int offset;
@@ -78,15 +85,7 @@ public:
int index;
int counterIndex;
static TObjectReflection badReflection() { return TObjectReflection(); }
protected:
int getBinding() const {
if (type == nullptr || type->getQualifier().layoutBinding == TQualifier::layoutBindingEnd)
return -1;
return type->getQualifier().layoutBinding;
}
TObjectReflection() : offset(-1), glDefineType(-1), size(-1), index(-1), type(nullptr) { }
const TType* type;
+13
View File
@@ -43,6 +43,9 @@
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <cstdio>
#include <sys/time.h>
#include <sys/resource.h>
namespace glslang {
@@ -184,8 +187,18 @@ void ReleaseGlobalLock()
pthread_mutex_unlock(&gMutex);
}
// #define DUMP_COUNTERS
void OS_DumpMemoryCounters()
{
#ifdef DUMP_COUNTERS
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) == 0)
printf("Working set size: %ld\n", usage.ru_maxrss * 1024);
#else
printf("Recompile with DUMP_COUNTERS defined to see counters.\n");
#endif
}
} // end namespace glslang
View File
View File
View File
+102 -17
View File
@@ -68,15 +68,14 @@
#endif
//
// Driver must call this first, once, before doing any other
// compiler/linker operations.
// Call before doing any other compiler/linker operations.
//
// (Call once per process, not once per thread.)
//
SH_IMPORT_EXPORT int ShInitialize();
//
// Driver should call this at process shutdown.
// Call this at process shutdown to clean up memory.
//
SH_IMPORT_EXPORT int __fastcall ShFinalize();
@@ -110,7 +109,44 @@ typedef enum {
EShSourceNone,
EShSourceGlsl,
EShSourceHlsl,
} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead
} EShSource; // if EShLanguage were EShStage, this could be EShLanguage instead
typedef enum {
EShClientNone,
EShClientVulkan,
EShClientOpenGL,
} EShClient;
typedef enum {
EShTargetNone,
EshTargetSpv,
} EShTargetLanguage;
struct TInputLanguage {
EShSource languageFamily; // redundant information with other input, this one overrides when not EShSourceNone
EShLanguage stage; // redundant information with other input, this one overrides when not EShSourceNone
EShClient dialect;
int dialectVersion; // version of client's language definition, not the client (when not EShClientNone)
};
struct TClient {
EShClient client;
int version; // version of client itself (not the client's input dialect)
};
struct TTarget {
EShTargetLanguage language;
unsigned int version; // the version to target, if SPIR-V, defined by "word 1" of the SPIR-V binary header
};
// All source/client/target versions and settings.
// Can override previous methods of setting, when items are set here.
// Expected to grow, as more are added, rather than growing parameter lists.
struct TEnvironment {
TInputLanguage input; // definition of the input language
TClient client; // what client is the overall compilation being done for?
TTarget target; // what to generate
};
const char* StageName(EShLanguage);
@@ -253,7 +289,7 @@ SH_IMPORT_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char*
// Deferred-Lowering C++ Interface
// -----------------------------------
//
// Below is a new alternate C++ interface that might potentially replace the above
// Below is a new alternate C++ interface, which deprecates the above
// opaque handle-based interface.
//
// The below is further designed to handle multiple compilation units per stage, where
@@ -287,6 +323,17 @@ bool InitializeProcess();
// Call once per process to tear down everything
void FinalizeProcess();
// Resource type for IO resolver
enum TResourceType {
EResSampler,
EResTexture,
EResImage,
EResUbo,
EResSsbo,
EResUav,
EResCount
};
// Make one TShader per shader that you will link into a program. Then provide
// the shader through setStrings() or setStringsWithLengths(), then call parse(),
// then query the info logs.
@@ -309,21 +356,46 @@ public:
void setPreamble(const char* s) { preamble = s; }
void setEntryPoint(const char* entryPoint);
void setSourceEntryPoint(const char* sourceEntryPointName);
void setShiftSamplerBinding(unsigned int base);
void setShiftTextureBinding(unsigned int base);
void setShiftImageBinding(unsigned int base);
void setShiftUboBinding(unsigned int base);
void setShiftUavBinding(unsigned int base);
void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding
void setShiftSsboBinding(unsigned int base);
void addProcesses(const std::vector<std::string>&);
// IO resolver binding data: see comments in ShaderLang.cpp
void setShiftBinding(TResourceType res, unsigned int base);
void setShiftSamplerBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftTextureBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftImageBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftUboBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftUavBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftCbufferBinding(unsigned int base); // synonym for setShiftUboBinding
void setShiftSsboBinding(unsigned int base); // DEPRECATED: use setShiftBinding
void setShiftBindingForSet(TResourceType res, unsigned int base, unsigned int set);
void setResourceSetBinding(const std::vector<std::string>& base);
void setAutoMapBindings(bool map);
void setAutoMapLocations(bool map);
void setInvertY(bool invert);
void setHlslIoMapping(bool hlslIoMap);
void setFlattenUniformArrays(bool flatten);
void setNoStorageFormat(bool useUnknownFormat);
void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode);
// For setting up the environment (initialized in the constructor):
void setEnvInput(EShSource lang, EShLanguage envStage, EShClient client, int version)
{
environment.input.languageFamily = lang;
environment.input.stage = envStage;
environment.input.dialect = client;
environment.input.dialectVersion = version;
}
void setEnvClient(EShClient client, int version)
{
environment.client.client = client;
environment.client.version = version;
}
void setEnvTarget(EShTargetLanguage lang, unsigned int version)
{
environment.target.language = lang;
environment.target.version = version;
}
// Interface to #include handlers.
//
// To support #include, a client of Glslang does the following:
@@ -436,8 +508,8 @@ public:
const char* getInfoLog();
const char* getInfoDebugLog();
EShLanguage getStage() const { return stage; }
TIntermediate* getIntermediate() const { return intermediate; }
protected:
TPoolAllocator* pool;
@@ -463,6 +535,8 @@ protected:
// a function in the source string can be renamed FROM this TO the name given in setEntryPoint.
std::string sourceEntryPointName;
TEnvironment environment;
friend class TProgram;
private:
@@ -474,9 +548,10 @@ class TIoMapper;
// Allows to customize the binding layout after linking.
// All used uniform variables will invoke at least validateBinding.
// If validateBinding returned true then the other resolveBinding
// and resolveSet are invoked to resolve the binding and descriptor
// set index respectively.
// If validateBinding returned true then the other resolveBinding,
// resolveSet, and resolveLocation are invoked to resolve the binding
// and descriptor set index respectively.
//
// Invocations happen in a particular order:
// 1) all shader inputs
// 2) all shader outputs
@@ -508,6 +583,9 @@ public:
// Should return a value >= 0 if the current set should be overridden.
// Return -1 if the current set (including no set) should be kept.
virtual int resolveSet(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
// Should return a value >= 0 if the current location should be overridden.
// Return -1 if the current location (including no location) should be kept.
virtual int resolveUniformLocation(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
// Should return true if the resulting/current setup would be okay.
// Basic idea is to do aliasing checks and reject invalid semantic names.
virtual bool validateInOut(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
@@ -525,7 +603,13 @@ public:
// Notification of a in or out variable
virtual void notifyInOut(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
// Called by mapIO when it has finished the notify pass
virtual void endNotifications() = 0;
virtual void endNotifications(EShLanguage stage) = 0;
// Called by mapIO when it starts its notify pass for the given stage
virtual void beginNotifications(EShLanguage stage) = 0;
// Called by mipIO when it starts its resolve pass for the given stage
virtual void beginResolve(EShLanguage stage) = 0;
// Called by mapIO when it has finished the resolve pass
virtual void endResolve(EShLanguage stage) = 0;
};
// Make one TProgram per set of shaders that will get linked together. Add all
@@ -555,6 +639,7 @@ public:
const char* getUniformBlockName(int blockIndex) const; // can be used for glGetActiveUniformBlockName()
int getUniformBlockSize(int blockIndex) const; // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
int getUniformIndex(const char* name) const; // can be used for glGetUniformIndices()
int getUniformBinding(int index) const; // returns the binding number
int getUniformBlockIndex(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
int getUniformBlockCounterIndex(int index) const; // returns block index of associated counter.
int getUniformType(int index) const; // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)