summaryrefslogtreecommitdiffstats
path: root/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp')
-rw-r--r--thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp1392
1 files changed, 828 insertions, 564 deletions
diff --git a/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp b/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp
index 6a8d379b09..a2224e1609 100644
--- a/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp
+++ b/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp
@@ -2,7 +2,7 @@
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
// Copyright (C) 2012-2015 LunarG, Inc.
// Copyright (C) 2015-2018 Google, Inc.
-// Copyright (C) 2017 ARM Limited.
+// Copyright (C) 2017, 2019 ARM Limited.
//
// All rights reserved.
//
@@ -56,13 +56,16 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b
infoSink, forwardCompatible, messages, entryPoint),
inMain(false),
blockName(nullptr),
- limits(resources.limits),
+ limits(resources.limits)
+#ifndef GLSLANG_WEB
+ ,
atomicUintOffsets(nullptr), anyIndexLimits(false)
+#endif
{
// decide whether precision qualifiers should be ignored or respected
- if (profile == EEsProfile || spvVersion.vulkan > 0) {
+ if (isEsProfile() || spvVersion.vulkan > 0) {
precisionManager.respectPrecisionQualifiers();
- if (! parsingBuiltins && language == EShLangFragment && profile != EEsProfile && spvVersion.vulkan > 0)
+ if (! parsingBuiltins && language == EShLangFragment && !isEsProfile() && spvVersion.vulkan > 0)
precisionManager.warnAboutDefaults();
}
@@ -83,6 +86,7 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b
globalInputDefaults.clear();
globalOutputDefaults.clear();
+#ifndef GLSLANG_WEB
// "Shaders in the transform
// feedback capturing mode have an initial global default of
// layout(xfb_buffer = 0) out;"
@@ -94,6 +98,7 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b
if (language == EShLangGeometry)
globalOutputDefaults.layoutStream = 0;
+#endif
if (entryPoint != nullptr && entryPoint->size() > 0 && *entryPoint != "main")
infoSink.info.message(EPrefixError, "Source entry point must be \"main\"");
@@ -101,7 +106,9 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b
TParseContext::~TParseContext()
{
+#ifndef GLSLANG_WEB
delete [] atomicUintOffsets;
+#endif
}
// Set up all default precisions as needed by the current environment.
@@ -121,7 +128,7 @@ void TParseContext::setPrecisionDefaults()
// replace with real precision defaults for those that have them
if (obeyPrecisionQualifiers()) {
- if (profile == EEsProfile) {
+ if (isEsProfile()) {
// Most don't have defaults, a few default to lowp.
TSampler sampler;
sampler.set(EbtFloat, Esd2D);
@@ -129,7 +136,7 @@ void TParseContext::setPrecisionDefaults()
sampler.set(EbtFloat, EsdCube);
defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
sampler.set(EbtFloat, Esd2D);
- sampler.external = true;
+ sampler.setExternal(true);
defaultSamplerPrecision[computeSamplerTypeIndex(sampler)] = EpqLow;
}
@@ -138,7 +145,7 @@ void TParseContext::setPrecisionDefaults()
// is used to resolve the precision from the supplied arguments/operands instead.
// So, we don't actually want to replace EpqNone with a default precision for built-ins.
if (! parsingBuiltins) {
- if (profile == EEsProfile && language == EShLangFragment) {
+ if (isEsProfile() && language == EShLangFragment) {
defaultPrecision[EbtInt] = EpqMedium;
defaultPrecision[EbtUint] = EpqMedium;
} else {
@@ -147,7 +154,7 @@ void TParseContext::setPrecisionDefaults()
defaultPrecision[EbtFloat] = EpqHigh;
}
- if (profile != EEsProfile) {
+ if (!isEsProfile()) {
// Non-ES profile
// All sampler precisions default to highp.
for (int type = 0; type < maxSamplerIndex; ++type)
@@ -163,7 +170,9 @@ void TParseContext::setPrecisionDefaults()
void TParseContext::setLimits(const TBuiltInResource& r)
{
resources = r;
+ intermediate.setLimits(r);
+#ifndef GLSLANG_WEB
anyIndexLimits = ! limits.generalAttributeMatrixVectorIndexing ||
! limits.generalConstantMatrixVectorIndexing ||
! limits.generalSamplerIndexing ||
@@ -171,7 +180,6 @@ void TParseContext::setLimits(const TBuiltInResource& r)
! limits.generalVariableIndexing ||
! limits.generalVaryingIndexing;
- intermediate.setLimits(resources);
// "Each binding point tracks its own current default offset for
// inheritance of subsequent variables using the same binding. The initial state of compilation is that all
@@ -179,6 +187,7 @@ void TParseContext::setLimits(const TBuiltInResource& r)
atomicUintOffsets = new int[resources.maxAtomicCounterBindings];
for (int b = 0; b < resources.maxAtomicCounterBindings; ++b)
atomicUintOffsets[b] = 0;
+#endif
}
//
@@ -213,6 +222,7 @@ void TParseContext::parserError(const char* s)
void TParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>& tokens)
{
+#ifndef GLSLANG_WEB
if (pragmaCallback)
pragmaCallback(loc.line, tokens);
@@ -285,6 +295,7 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>&
warn(loc, "not implemented", "#pragma once", "");
} else if (tokens[0].compare("glslang_binary_double_output") == 0)
intermediate.setBinaryDoubleOutput();
+#endif
}
//
@@ -298,6 +309,7 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
if (symbol && symbol->getNumExtensions())
requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str());
+#ifndef GLSLANG_WEB
if (symbol && symbol->isReadOnly()) {
// All shared things containing an unsized array must be copied up
// on first use, so that all future references will share its array structure,
@@ -307,11 +319,17 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
// If this is a variable or a block, check it and all it contains, but if this
// is a member of an anonymous block, check the whole block, as the whole block
// will need to be copied up if it contains an unsized array.
- if (symbol->getType().containsUnsizedArray() ||
- (symbol->getAsAnonMember() &&
- symbol->getAsAnonMember()->getAnonContainer().getType().containsUnsizedArray()))
- makeEditable(symbol);
+ //
+ // This check is being done before the block-name check further down, so guard
+ // for that too.
+ if (!symbol->getType().isUnusableName()) {
+ if (symbol->getType().containsUnsizedArray() ||
+ (symbol->getAsAnonMember() &&
+ symbol->getAsAnonMember()->getAnonContainer().getType().containsUnsizedArray()))
+ makeEditable(symbol);
+ }
}
+#endif
const TVariable* variable;
const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr;
@@ -334,8 +352,7 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
// See if it was a variable.
variable = symbol ? symbol->getAsVariable() : nullptr;
if (variable) {
- if ((variable->getType().getBasicType() == EbtBlock ||
- variable->getType().getBasicType() == EbtStruct) && variable->getType().getStruct() == nullptr) {
+ if (variable->getType().isUnusableName()) {
error(loc, "cannot be used (maybe an instance name is needed)", string->c_str(), "");
variable = nullptr;
}
@@ -357,7 +374,7 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
if (variable->getType().getQualifier().isIo())
intermediate.addIoAccessed(*string);
- if (variable->getType().getBasicType() == EbtReference &&
+ if (variable->getType().isReference() &&
variable->getType().getQualifier().bufferReferenceNeedsVulkanMemoryModel()) {
intermediate.setUseVulkanMemoryModel();
}
@@ -378,7 +395,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
variableCheck(base);
if (! base->isArray() && ! base->isMatrix() && ! base->isVector() && ! base->getType().isCoopMat() &&
- base->getBasicType() != EbtReference) {
+ ! base->isReference()) {
if (base->getAsSymbolNode())
error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
else
@@ -389,7 +406,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
}
if (!base->isArray() && base->isVector()) {
- if (base->getType().containsBasicType(EbtFloat16))
+ if (base->getType().contains16BitFloat())
requireFloat16Arithmetic(loc, "[", "does not operate on types containing float16");
if (base->getType().contains16BitInt())
requireInt16Arithmetic(loc, "[", "does not operate on types containing (u)int16");
@@ -407,23 +424,24 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
// at least one of base and index is not a front-end constant variable...
TIntermTyped* result = nullptr;
- if (base->getBasicType() == EbtReference && ! base->isArray()) {
+#ifndef GLSLANG_WEB
+ if (base->isReference() && ! base->isArray()) {
requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference indexing");
result = intermediate.addBinaryMath(EOpAdd, base, index, loc);
result->setType(base->getType());
return result;
}
+ if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
+ handleIoResizeArrayAccess(loc, base);
+#endif
if (index->getQualifier().isFrontEndConstant())
checkIndex(loc, base->getType(), indexValue);
- if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
- handleIoResizeArrayAccess(loc, base);
-
if (index->getQualifier().isFrontEndConstant()) {
+#ifndef GLSLANG_WEB
if (base->getType().isUnsizedArray()) {
base->getWritableType().updateImplicitArraySize(indexValue + 1);
-#ifdef NV_EXTENSIONS
// For 2D per-view builtin arrays, update the inner dimension size in parent type
if (base->getQualifier().isPerView() && base->getQualifier().builtIn != EbvNone) {
TIntermBinary* binaryNode = base->getAsBinaryNode();
@@ -434,11 +452,12 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
arraySizes.setDimSize(1, std::max(arraySizes.getDimSize(1), indexValue + 1));
}
}
-#endif
} else
+#endif
checkIndex(loc, base->getType(), indexValue);
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
} else {
+#ifndef GLSLANG_WEB
if (base->getType().isUnsizedArray()) {
// we have a variable index into an unsized array, which is okay,
// depending on the situation
@@ -450,6 +469,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
}
base->getWritableType().setArrayVariablyIndexed();
}
+#endif
if (base->getBasicType() == EbtBlock) {
if (base->getQualifier().storage == EvqBuffer)
requireProfile(base->getLoc(), ~EEsProfile, "variable indexing buffer block array");
@@ -457,7 +477,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
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
+ // input/output blocks either don't exist or can't be variably indexed
}
} else if (language == EShLangFragment && base->getQualifier().isPipeOutput())
requireProfile(base->getLoc(), ~EEsProfile, "variable indexing fragment shader output array");
@@ -471,8 +491,8 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
result = intermediate.addIndex(EOpIndexIndirect, base, index, loc);
}
- // Insert valid dereferenced result
- TType newType(base->getType(), 0); // dereferenced type
+ // Insert valid dereferenced result type
+ TType newType(base->getType(), 0);
if (base->getType().getQualifier().isConstant() && index->getQualifier().isConstant()) {
newType.getQualifier().storage = EvqConst;
// If base or index is a specialization constant, the result should also be a specialization constant.
@@ -480,20 +500,27 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
newType.getQualifier().makeSpecConstant();
}
} else {
- newType.getQualifier().makePartialTemporary();
+ newType.getQualifier().storage = EvqTemporary;
+ newType.getQualifier().specConstant = false;
}
result->setType(newType);
+#ifndef GLSLANG_WEB
+ inheritMemoryQualifiers(base->getQualifier(), result->getWritableType().getQualifier());
+
// Propagate nonuniform
if (base->getQualifier().isNonUniform() || index->getQualifier().isNonUniform())
result->getWritableType().getQualifier().nonUniform = true;
if (anyIndexLimits)
handleIndexLimits(loc, base, index);
+#endif
return result;
}
+#ifndef GLSLANG_WEB
+
// 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)
{
@@ -530,14 +557,12 @@ bool TParseContext::isIoResizeArray(const TType& type) const
{
return type.isArray() &&
((language == EShLangGeometry && type.getQualifier().storage == EvqVaryingIn) ||
- (language == EShLangTessControl && type.getQualifier().storage == EvqVaryingOut && ! type.getQualifier().patch)
-#ifdef NV_EXTENSIONS
- ||
- (language == EShLangFragment && type.getQualifier().storage == EvqVaryingIn && type.getQualifier().pervertexNV) ||
- (language == EShLangMeshNV && type.getQualifier().storage == EvqVaryingOut && !type.getQualifier().perTaskNV)
-
-#endif
- );
+ (language == EShLangTessControl && type.getQualifier().storage == EvqVaryingOut &&
+ ! type.getQualifier().patch) ||
+ (language == EShLangFragment && type.getQualifier().storage == EvqVaryingIn &&
+ type.getQualifier().pervertexNV) ||
+ (language == EShLangMeshNV && type.getQualifier().storage == EvqVaryingOut &&
+ !type.getQualifier().perTaskNV));
}
// If an array is not isIoResizeArray() but is an io array, make sure it has the right size
@@ -566,11 +591,7 @@ void TParseContext::fixIoArraySize(const TSourceLoc& loc, TType& type)
void TParseContext::ioArrayCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
{
if (! type.isArray() && ! symbolTable.atBuiltInLevel()) {
- if (type.getQualifier().isArrayedIo(language)
-#ifdef NV_EXTENSIONS
- && !type.getQualifier().layoutPassthrough
-#endif
- )
+ if (type.getQualifier().isArrayedIo(language) && !type.getQualifier().layoutPassthrough)
error(loc, "type must be an array:", type.getStorageQualifierString(), identifier.c_str());
}
}
@@ -617,12 +638,7 @@ void TParseContext::checkIoArraysConsistency(const TSourceLoc &loc, bool tailOnl
// As I/O array sizes don't change, fetch requiredSize only once,
// except for mesh shaders which could have different I/O array sizes based on type qualifiers.
- if (firstIteration
-#ifdef NV_EXTENSIONS
- || (language == EShLangMeshNV)
-#endif
- )
- {
+ if (firstIteration || (language == EShLangMeshNV)) {
requiredSize = getIoArrayImplicitSize(type.getQualifier(), &featureString);
if (requiredSize == 0)
break;
@@ -647,14 +663,11 @@ int TParseContext::getIoArrayImplicitSize(const TQualifier &qualifier, TString *
else if (language == EShLangTessControl) {
expectedSize = maxVertices;
str = "vertices";
- }
-#ifdef NV_EXTENSIONS
- else if (language == EShLangFragment) {
+ } else if (language == EShLangFragment) {
// Number of vertices for Fragment shader is always three.
expectedSize = 3;
str = "vertices";
- }
- else if (language == EShLangMeshNV) {
+ } else if (language == EShLangMeshNV) {
unsigned int maxPrimitives =
intermediate.getPrimitives() != TQualifier::layoutNotSet ? intermediate.getPrimitives() : 0;
if (qualifier.builtIn == EbvPrimitiveIndicesNV) {
@@ -671,7 +684,6 @@ int TParseContext::getIoArrayImplicitSize(const TQualifier &qualifier, TString *
str = "max_vertices";
}
}
-#endif
if (featureString)
*featureString = str;
return expectedSize;
@@ -686,19 +698,19 @@ void TParseContext::checkIoArrayConsistency(const TSourceLoc& loc, int requiredS
error(loc, "inconsistent input primitive for array size of", feature, name.c_str());
else if (language == EShLangTessControl)
error(loc, "inconsistent output number of vertices for array size of", feature, name.c_str());
-#ifdef NV_EXTENSIONS
else if (language == EShLangFragment) {
if (type.getOuterArraySize() > requiredSize)
error(loc, " cannot be greater than 3 for pervertexNV", feature, name.c_str());
}
else if (language == EShLangMeshNV)
error(loc, "inconsistent output array size of", feature, name.c_str());
-#endif
else
assert(0);
}
}
+#endif // GLSLANG_WEB
+
// Handle seeing a binary node with a math operation.
// Returns nullptr if not semantically allowed.
TIntermTyped* TParseContext::handleBinaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right)
@@ -721,7 +733,7 @@ TIntermTyped* TParseContext::handleBinaryMath(const TSourceLoc& loc, const char*
break;
}
- if (((left->getType().containsBasicType(EbtFloat16) || right->getType().containsBasicType(EbtFloat16)) && !float16Arithmetic()) ||
+ if (((left->getType().contains16BitFloat() || right->getType().contains16BitFloat()) && !float16Arithmetic()) ||
((left->getType().contains16BitInt() || right->getType().contains16BitInt()) && !int16Arithmetic()) ||
((left->getType().contains8BitInt() || right->getType().contains8BitInt()) && !int8Arithmetic())) {
allowed = false;
@@ -743,14 +755,13 @@ TIntermTyped* TParseContext::handleUnaryMath(const TSourceLoc& loc, const char*
rValueErrorCheck(loc, str, childNode);
bool allowed = true;
- if ((childNode->getType().containsBasicType(EbtFloat16) && !float16Arithmetic()) ||
+ if ((childNode->getType().contains16BitFloat() && !float16Arithmetic()) ||
(childNode->getType().contains16BitInt() && !int16Arithmetic()) ||
(childNode->getType().contains8BitInt() && !int8Arithmetic())) {
allowed = false;
}
TIntermTyped* result = nullptr;
-
if (allowed)
result = intermediate.addUnaryMath(op, childNode, loc);
@@ -819,7 +830,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
TSwizzleSelectors<TVectorSelector> selectors;
parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
- if (base->isVector() && selectors.size() != 1 && base->getType().containsBasicType(EbtFloat16))
+ if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitFloat())
requireFloat16Arithmetic(loc, ".", "can't swizzle types containing float16");
if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitInt())
requireInt16Arithmetic(loc, ".", "can't swizzle types containing (u)int16");
@@ -854,12 +865,10 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
if (base->getType().getQualifier().isSpecConstant())
result->getWritableType().getQualifier().makeSpecConstant();
}
- } else if (base->getBasicType() == EbtStruct ||
- base->getBasicType() == EbtBlock ||
- base->getBasicType() == EbtReference) {
- const TTypeList* fields = base->getBasicType() == EbtReference ?
- base->getType().getReferentType()->getStruct() :
- base->getType().getStruct();
+ } else if (base->isStruct() || base->isReference()) {
+ const TTypeList* fields = base->isReference() ?
+ base->getType().getReferentType()->getStruct() :
+ base->getType().getStruct();
bool fieldFound = false;
int member;
for (member = 0; member < (int)fields->size(); ++member) {
@@ -879,14 +888,15 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
if ((*fields)[member].type->getQualifier().isIo())
intermediate.addIoAccessed(field);
}
+ inheritMemoryQualifiers(base->getQualifier(), result->getWritableType().getQualifier());
} else
error(loc, "no such field in structure", field.c_str(), "");
} else
error(loc, "does not apply to this type:", field.c_str(), base->getType().getCompleteString().c_str());
// Propagate noContraction up the dereference chain
- if (base->getQualifier().noContraction)
- result->getWritableType().getQualifier().noContraction = true;
+ if (base->getQualifier().isNoContraction())
+ result->getWritableType().getQualifier().setNoContraction();
// Propagate nonuniform
if (base->getQualifier().isNonUniform())
@@ -1126,7 +1136,7 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction
if (builtIn && fnCandidate->getNumExtensions())
requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str());
- if (builtIn && fnCandidate->getType().containsBasicType(EbtFloat16))
+ if (builtIn && fnCandidate->getType().contains16BitFloat())
requireFloat16Arithmetic(loc, "built-in function", "float16 types can only be in uniform block or buffer storage");
if (builtIn && fnCandidate->getType().contains16BitInt())
requireInt16Arithmetic(loc, "built-in function", "(u)int16 types can only be in uniform block or buffer storage");
@@ -1146,9 +1156,11 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction
if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped()))
error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", "");
}
- TQualifier& argQualifier = arg->getAsTyped()->getQualifier();
- if (argQualifier.isMemory()) {
+ const TType& argType = arg->getAsTyped()->getType();
+ const TQualifier& argQualifier = argType.getQualifier();
+ if (argQualifier.isMemory() && (argType.containsOpaque() || argType.isReference())) {
const char* message = "argument cannot drop memory qualifier when passed to formal parameter";
+#ifndef GLSLANG_WEB
if (argQualifier.volatil && ! formalQualifier.volatil)
error(arguments->getLoc(), message, "volatile", "");
if (argQualifier.coherent && ! (formalQualifier.devicecoherent || formalQualifier.coherent))
@@ -1165,18 +1177,19 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction
error(arguments->getLoc(), message, "readonly", "");
if (argQualifier.writeonly && ! formalQualifier.writeonly)
error(arguments->getLoc(), message, "writeonly", "");
- if (!builtIn && argQualifier.restrict && ! formalQualifier.restrict)
- error(arguments->getLoc(), message, "restrict", "");
+ // Don't check 'restrict', it is different than the rest:
+ // "...but only restrict can be taken away from a calling argument, by a formal parameter that
+ // lacks the restrict qualifier..."
+#endif
}
- if (!builtIn && argQualifier.layoutFormat != formalQualifier.layoutFormat) {
+ if (!builtIn && argQualifier.getFormat() != formalQualifier.getFormat()) {
// we have mismatched formats, which should only be allowed if writeonly
// and at least one format is unknown
- if (!formalQualifier.writeonly || (formalQualifier.layoutFormat != ElfNone &&
- argQualifier.layoutFormat != ElfNone))
+ if (!formalQualifier.isWriteOnly() || (formalQualifier.getFormat() != ElfNone &&
+ argQualifier.getFormat() != ElfNone))
error(arguments->getLoc(), "image formats must match", "format", "");
}
-
- if (builtIn && arg->getAsTyped()->getType().containsBasicType(EbtFloat16))
+ if (builtIn && arg->getAsTyped()->getType().contains16BitFloat())
requireFloat16Arithmetic(arguments->getLoc(), "built-in function", "float16 types can only be in uniform block or buffer storage");
if (builtIn && arg->getAsTyped()->getType().contains16BitInt())
requireInt16Arithmetic(arguments->getLoc(), "built-in function", "(u)int16 types can only be in uniform block or buffer storage");
@@ -1216,9 +1229,11 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction
intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName());
}
+#ifndef GLSLANG_WEB
if (builtIn)
nonOpBuiltInCheck(loc, *fnCandidate, *call);
else
+#endif
userFunctionCallCheck(loc, *call);
}
@@ -1347,13 +1362,9 @@ 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 ?
@@ -1374,7 +1385,9 @@ void TParseContext::computeBuiltinPrecisions(TIntermTyped& node, const TFunction
TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermTyped* value)
{
+#ifndef GLSLANG_WEB
storage16BitAssignmentCheck(loc, value->getType(), "return");
+#endif
functionReturnsValue = true;
if (currentFunctionType->getBasicType() == EbtVoid) {
@@ -1399,6 +1412,7 @@ TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermType
// See if the operation is being done in an illegal location.
void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op)
{
+#ifndef GLSLANG_WEB
switch (op) {
case EOpBarrier:
if (language == EShLangTessControl) {
@@ -1410,9 +1424,48 @@ void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op)
error(loc, "tessellation control barrier() cannot be placed after a return from main()", "", "");
}
break;
+ case EOpBeginInvocationInterlock:
+ if (language != EShLangFragment)
+ error(loc, "beginInvocationInterlockARB() must be in a fragment shader", "", "");
+ if (! inMain)
+ error(loc, "beginInvocationInterlockARB() must be in main()", "", "");
+ else if (postEntryPointReturn)
+ error(loc, "beginInvocationInterlockARB() cannot be placed after a return from main()", "", "");
+ if (controlFlowNestingLevel > 0)
+ error(loc, "beginInvocationInterlockARB() cannot be placed within flow control", "", "");
+
+ if (beginInvocationInterlockCount > 0)
+ error(loc, "beginInvocationInterlockARB() must only be called once", "", "");
+ if (endInvocationInterlockCount > 0)
+ error(loc, "beginInvocationInterlockARB() must be called before endInvocationInterlockARB()", "", "");
+
+ beginInvocationInterlockCount++;
+
+ // default to pixel_interlock_ordered
+ if (intermediate.getInterlockOrdering() == EioNone)
+ intermediate.setInterlockOrdering(EioPixelInterlockOrdered);
+ break;
+ case EOpEndInvocationInterlock:
+ if (language != EShLangFragment)
+ error(loc, "endInvocationInterlockARB() must be in a fragment shader", "", "");
+ if (! inMain)
+ error(loc, "endInvocationInterlockARB() must be in main()", "", "");
+ else if (postEntryPointReturn)
+ error(loc, "endInvocationInterlockARB() cannot be placed after a return from main()", "", "");
+ if (controlFlowNestingLevel > 0)
+ error(loc, "endInvocationInterlockARB() cannot be placed within flow control", "", "");
+
+ if (endInvocationInterlockCount > 0)
+ error(loc, "endInvocationInterlockARB() must only be called once", "", "");
+ if (beginInvocationInterlockCount == 0)
+ error(loc, "beginInvocationInterlockARB() must be called before endInvocationInterlockARB()", "", "");
+
+ endInvocationInterlockCount++;
+ break;
default:
break;
}
+#endif
}
// Finish processing object.length(). This started earlier in handleDotDereference(), where
@@ -1430,29 +1483,28 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction
const TType& type = intermNode->getAsTyped()->getType();
if (type.isArray()) {
if (type.isUnsizedArray()) {
+#ifndef GLSLANG_WEB
if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) {
// We could be between a layout declaration that gives a built-in io array implicit size and
// a user redeclaration of that array, meaning we have to substitute its implicit size here
// without actually redeclaring the array. (It is an error to use a member before the
// redeclaration, but not an error to use the array name itself.)
const TString& name = intermNode->getAsSymbolNode()->getName();
- if (name == "gl_in" || name == "gl_out"
-#ifdef NV_EXTENSIONS
- || name == "gl_MeshVerticesNV"
- || name == "gl_MeshPrimitivesNV"
-#endif
- )
- {
+ if (name == "gl_in" || name == "gl_out" || name == "gl_MeshVerticesNV" ||
+ name == "gl_MeshPrimitivesNV") {
length = getIoArrayImplicitSize(type.getQualifier());
}
}
+#endif
if (length == 0) {
+#ifndef GLSLANG_WEB
if (intermNode->getAsSymbolNode() && isIoResizeArray(type))
error(loc, "", function->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier");
else if (isRuntimeLength(*intermNode->getAsTyped())) {
// Create a unary op and let the back end handle it
return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt));
} else
+#endif
error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method");
}
} else if (type.getOuterArrayNode()) {
@@ -1485,6 +1537,7 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction
//
void TParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments) const
{
+#ifndef GLSLANG_WEB
TIntermAggregate* aggregate = arguments->getAsAggregate();
// Process each argument's conversion
@@ -1512,6 +1565,7 @@ void TParseContext::addInputArgumentConversions(const TFunction& function, TInte
}
}
}
+#endif
}
//
@@ -1523,6 +1577,9 @@ void TParseContext::addInputArgumentConversions(const TFunction& function, TInte
//
TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const
{
+#ifdef GLSLANG_WEB
+ return &intermNode;
+#else
TIntermSequence& arguments = intermNode.getSequence();
// Will there be any output conversions?
@@ -1590,6 +1647,7 @@ TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& funct
conversionTree = intermediate.setAggregateOperator(conversionTree, EOpComma, intermNode.getType(), intermNode.getLoc());
return conversionTree;
+#endif
}
void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction& fnCandidate, const TIntermOperator& callNode)
@@ -1602,6 +1660,7 @@ void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction&
const int gl_SemanticsAcquireRelease = 0x8;
const int gl_SemanticsMakeAvailable = 0x2000;
const int gl_SemanticsMakeVisible = 0x4000;
+ const int gl_SemanticsVolatile = 0x8000;
//const int gl_StorageSemanticsNone = 0x0;
const int gl_StorageSemanticsBuffer = 0x40;
@@ -1691,7 +1750,8 @@ void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction&
gl_SemanticsRelease |
gl_SemanticsAcquireRelease |
gl_SemanticsMakeAvailable |
- gl_SemanticsMakeVisible))) {
+ gl_SemanticsMakeVisible |
+ gl_SemanticsVolatile))) {
error(loc, "Invalid semantics value", fnCandidate.getName().c_str(), "");
}
if (((storageClassSemantics | storageClassSemantics2) & ~(gl_StorageSemanticsBuffer |
@@ -1743,10 +1803,18 @@ void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction&
error(loc, "gl_SemanticsMakeVisible requires gl_SemanticsAcquire or gl_SemanticsAcquireRelease",
fnCandidate.getName().c_str(), "");
}
-
+ if ((semantics & gl_SemanticsVolatile) &&
+ (callNode.getOp() == EOpMemoryBarrier || callNode.getOp() == EOpBarrier)) {
+ error(loc, "gl_SemanticsVolatile must not be used with memoryBarrier or controlBarrier",
+ fnCandidate.getName().c_str(), "");
+ }
+ if ((callNode.getOp() == EOpAtomicCompSwap || callNode.getOp() == EOpImageAtomicCompSwap) &&
+ ((semantics ^ semantics2) & gl_SemanticsVolatile)) {
+ error(loc, "semEqual and semUnequal must either both include gl_SemanticsVolatile or neither",
+ fnCandidate.getName().c_str(), "");
+ }
}
-
//
// Do additional checking of built-in function calls that is not caught
// by normal semantic checks on argument type, extension tagging, etc.
@@ -1774,6 +1842,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
TString featureString;
const char* feature = nullptr;
switch (callNode.getOp()) {
+#ifndef GLSLANG_WEB
case EOpTextureGather:
case EOpTextureGatherOffset:
case EOpTextureGatherOffsets:
@@ -1830,7 +1899,6 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
error(loc, "must be a compile-time constant:", feature, "component argument");
}
-#ifdef AMD_EXTENSIONS
bool bias = false;
if (callNode.getOp() == EOpTextureGather)
bias = fnCandidate.getParamCount() > 3;
@@ -1845,12 +1913,8 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
profileRequires(loc, ~EEsProfile, 450, nullptr, feature);
requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature);
}
-#endif
-
break;
}
-
-#ifdef AMD_EXTENSIONS
case EOpSparseTextureGather:
case EOpSparseTextureGatherOffset:
case EOpSparseTextureGatherOffsets:
@@ -1928,7 +1992,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
int arg = -1;
switch (callNode.getOp()) {
case EOpTextureOffset: arg = 2; break;
- case EOpTextureFetchOffset: arg = (arg0->getType().getSampler().dim != EsdRect) ? 3 : 2; break;
+ case EOpTextureFetchOffset: arg = (arg0->getType().getSampler().isRect()) ? 2 : 3; break;
case EOpTextureProjOffset: arg = 2; break;
case EOpTextureLodOffset: arg = 3; break;
case EOpTextureProjLodOffset: arg = 3; break;
@@ -1941,7 +2005,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
if (arg > 0) {
-#ifdef AMD_EXTENSIONS
+#ifndef GLSLANG_WEB
bool f16ShadowCompare = (*argp)[1]->getAsTyped()->getBasicType() == EbtFloat16 && arg0->getType().getSampler().shadow;
if (f16ShadowCompare)
++arg;
@@ -1961,7 +2025,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
break;
}
-#ifdef NV_EXTENSIONS
+#ifndef GLSLANG_WEB
case EOpTraceNV:
if (!(*argp)[10]->getAsConstantUnion())
error(loc, "argument must be compile-time constant", "payload number", "");
@@ -1970,7 +2034,6 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
if (!(*argp)[1]->getAsConstantUnion())
error(loc, "argument must be compile-time constant", "callable data number", "");
break;
-#endif
case EOpTextureQuerySamples:
case EOpImageQuerySamples:
@@ -1992,12 +2055,12 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
// Make sure the image types have the correct layout() format and correct argument types
const TType& imageType = arg0->getType();
if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) {
- if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui)
+ if (imageType.getQualifier().getFormat() != ElfR32i && imageType.getQualifier().getFormat() != ElfR32ui)
error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
} else {
if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0)
error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
- else if (imageType.getQualifier().layoutFormat != ElfR32f && profile == EEsProfile)
+ else if (imageType.getQualifier().getFormat() != ElfR32f && isEsProfile())
error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), "");
}
@@ -2025,13 +2088,9 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
requireExtensions(loc, 1, &E_GL_KHR_memory_scope_semantics, fnCandidate.getName().c_str());
memorySemanticsCheck(loc, fnCandidate, callNode);
} else if (arg0->getType().getBasicType() == EbtInt64 || arg0->getType().getBasicType() == EbtUint64) {
-#ifdef NV_EXTENSIONS
const char* const extensions[2] = { E_GL_NV_shader_atomic_int64,
E_GL_EXT_shader_atomic_int64 };
requireExtensions(loc, 2, extensions, fnCandidate.getName().c_str());
-#else
- requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_int64, fnCandidate.getName().c_str());
-#endif
}
break;
}
@@ -2039,9 +2098,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
case EOpInterpolateAtCentroid:
case EOpInterpolateAtSample:
case EOpInterpolateAtOffset:
-#ifdef AMD_EXTENSIONS
case EOpInterpolateAtVertex:
-#endif
// Make sure the first argument is an interpolant, or an array element of an interpolant
if (arg0->getType().getQualifier().storage != EvqVaryingIn) {
// It might still be an array element.
@@ -2051,13 +2108,12 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
//
// ES and desktop 4.3 and earlier: swizzles may not be used
// desktop 4.4 and later: swizzles may be used
- bool swizzleOkay = (profile != EEsProfile) && (version >= 440);
+ bool swizzleOkay = (!isEsProfile()) && (version >= 440);
const TIntermTyped* base = TIntermediate::findLValueBase(arg0, swizzleOkay);
if (base == nullptr || base->getType().getQualifier().storage != EvqVaryingIn)
error(loc, "first argument must be an interpolant, or interpolant-array element", fnCandidate.getName().c_str(), "");
}
-#ifdef AMD_EXTENSIONS
if (callNode.getOp() == EOpInterpolateAtVertex) {
if (!arg0->getType().getQualifier().isExplicitInterpolation())
error(loc, "argument must be qualified as __explicitInterpAMD in", "interpolant", "");
@@ -2071,8 +2127,6 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
}
}
}
-#endif
-
break;
case EOpEmitStreamVertex:
@@ -2103,9 +2157,12 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
break;
case EOpSubgroupBroadcast:
- // <id> must be an integral constant expression.
- if ((*argp)[1]->getAsConstantUnion() == nullptr)
- error(loc, "argument must be compile-time constant", "id", "");
+ case EOpSubgroupQuadBroadcast:
+ if (spvVersion.spv < EShTargetSpv_1_5) {
+ // <id> must be an integral constant expression.
+ if ((*argp)[1]->getAsConstantUnion() == nullptr)
+ error(loc, "argument must be compile-time constant", "id", "");
+ }
break;
case EOpBarrier:
@@ -2115,6 +2172,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
memorySemanticsCheck(loc, fnCandidate, callNode);
}
break;
+#endif
default:
break;
@@ -2132,7 +2190,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
const TSampler& sampler = fnCandidate[0].type->getSampler();
const bool isTexture = sampler.isTexture() && !sampler.isCombined();
- const bool isBuffer = sampler.dim == EsdBuffer;
+ const bool isBuffer = sampler.isBuffer();
const bool isFetch = callNode.getOp() == EOpTextureFetch || callNode.getOp() == EOpTextureFetchOffset;
if (isTexture && (!isBuffer || !isFetch))
@@ -2145,13 +2203,39 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
break;
}
- if (callNode.getOp() > EOpSubgroupGuardStart && callNode.getOp() < EOpSubgroupGuardStop) {
+ if (callNode.isSubgroup()) {
// these require SPIR-V 1.3
if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_3)
error(loc, "requires SPIR-V 1.3", "subgroup op", "");
+
+ // Check that if extended types are being used that the correct extensions are enabled.
+ if (arg0 != nullptr) {
+ const TType& type = arg0->getType();
+ switch (type.getBasicType()) {
+ default:
+ break;
+ case EbtInt8:
+ case EbtUint8:
+ requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int8, type.getCompleteString().c_str());
+ break;
+ case EbtInt16:
+ case EbtUint16:
+ requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int16, type.getCompleteString().c_str());
+ break;
+ case EbtInt64:
+ case EbtUint64:
+ requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int64, type.getCompleteString().c_str());
+ break;
+ case EbtFloat16:
+ requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_float16, type.getCompleteString().c_str());
+ break;
+ }
+ }
}
}
+#ifndef GLSLANG_WEB
+
extern bool PureOperatorBuiltins;
// Deprecated! Use PureOperatorBuiltins == true instead, in which case this
@@ -2267,17 +2351,19 @@ void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fn
if (fnCandidate.getName().compare(0, 11, "imageAtomic") == 0) {
const TType& imageType = callNode.getSequence()[0]->getAsTyped()->getType();
if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) {
- if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui)
+ if (imageType.getQualifier().getFormat() != ElfR32i && imageType.getQualifier().getFormat() != ElfR32ui)
error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), "");
} else {
if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0)
error(loc, "only supported on integer images", fnCandidate.getName().c_str(), "");
- else if (imageType.getQualifier().layoutFormat != ElfR32f && profile == EEsProfile)
+ else if (imageType.getQualifier().getFormat() != ElfR32f && isEsProfile())
error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), "");
}
}
}
+#endif
+
//
// Do any extra checking for a user function call.
//
@@ -2425,6 +2511,7 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
bool errorReturn = false;
switch(binaryNode->getOp()) {
+#ifndef GLSLANG_WEB
case EOpIndexDirect:
case EOpIndexIndirect:
// ... tessellation control shader ...
@@ -2440,10 +2527,8 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
error(loc, "tessellation-control per-vertex output l-value must be indexed with gl_InvocationID", "[]", "");
}
}
-
- break; // left node is checked by base class
- case EOpIndexDirectStruct:
break; // left node is checked by base class
+#endif
case EOpVectorSwizzle:
errorReturn = lValueErrorCheck(loc, op, binaryNode->getLeft());
if (!errorReturn) {
@@ -2475,8 +2560,7 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
}
}
- if (binaryNode && binaryNode->getOp() == EOpIndexDirectStruct &&
- binaryNode->getLeft()->getBasicType() == EbtReference)
+ if (binaryNode && binaryNode->getOp() == EOpIndexDirectStruct && binaryNode->getLeft()->isReference())
return false;
// Let the base class check errors
@@ -2499,7 +2583,7 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
case EvqFragDepth:
intermediate.setDepthReplacing();
// "In addition, it is an error to statically write to gl_FragDepth in the fragment shader."
- if (profile == EEsProfile && intermediate.getEarlyFragmentTests())
+ if (isEsProfile() && intermediate.getEarlyFragmentTests())
message = "can't modify gl_FragDepth if using early_fragment_tests";
break;
@@ -2536,12 +2620,10 @@ void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TInt
// Let the base class check errors
TParseContextBase::rValueErrorCheck(loc, op, node);
-#ifdef AMD_EXTENSIONS
TIntermSymbol* symNode = node->getAsSymbolNode();
- if (!(symNode && symNode->getQualifier().writeonly)) // base class checks
- if (symNode && symNode->getQualifier().explicitInterp)
+ if (!(symNode && symNode->getQualifier().isWriteOnly())) // base class checks
+ if (symNode && symNode->getQualifier().isExplicitInterpolation())
error(loc, "can't read from explicitly-interpolated object: ", op, symNode->getName().c_str());
-#endif
}
//
@@ -2587,14 +2669,14 @@ void TParseContext::reservedErrorCheck(const TSourceLoc& loc, const TString& ide
if (builtInName(identifier))
error(loc, "identifiers starting with \"gl_\" are reserved", identifier.c_str(), "");
- // "__" are not supposed to be an error. ES 310 (and desktop) added the clarification:
+ // "__" are not supposed to be an error. ES 300 (and desktop) added the clarification:
// "In addition, all identifiers containing two consecutive underscores (__) are
// reserved; using such a name does not itself result in an error, but may result
// in undefined behavior."
// however, before that, ES tests required an error.
if (identifier.find("__") != TString::npos) {
- if (profile == EEsProfile && version <= 300)
- error(loc, "identifiers containing consecutive underscores (\"__\") are reserved, and an error if version <= 300", identifier.c_str(), "");
+ if (isEsProfile() && version < 300)
+ error(loc, "identifiers containing consecutive underscores (\"__\") are reserved, and an error if version < 300", identifier.c_str(), "");
else
warn(loc, "identifiers containing consecutive underscores (\"__\") are reserved", identifier.c_str(), "");
}
@@ -2606,7 +2688,7 @@ void TParseContext::reservedErrorCheck(const TSourceLoc& loc, const TString& ide
//
void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* identifier, const char* op)
{
- // "__" are not supposed to be an error. ES 310 (and desktop) added the clarification:
+ // "__" are not supposed to be an error. ES 300 (and desktop) added the clarification:
// "All macro names containing two consecutive underscores ( __ ) are reserved;
// defining such a name does not itself result in an error, but may result in
// undefined behavior. All macro names prefixed with "GL_" ("GL" followed by a
@@ -2618,14 +2700,14 @@ void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* iden
else if (strncmp(identifier, "defined", 8) == 0)
ppError(loc, "\"defined\" can't be (un)defined:", op, identifier);
else if (strstr(identifier, "__") != 0) {
- if (profile == EEsProfile && version >= 300 &&
+ if (isEsProfile() && version >= 300 &&
(strcmp(identifier, "__LINE__") == 0 ||
strcmp(identifier, "__FILE__") == 0 ||
strcmp(identifier, "__VERSION__") == 0))
ppError(loc, "predefined names can't be (un)defined:", op, identifier);
else {
- if (profile == EEsProfile && version <= 300)
- ppError(loc, "names containing consecutive underscores are reserved, and an error if version <= 300:", op, identifier);
+ if (isEsProfile() && version < 300)
+ ppError(loc, "names containing consecutive underscores are reserved, and an error if version < 300:", op, identifier);
else
ppWarn(loc, "names containing consecutive underscores are reserved:", op, identifier);
}
@@ -2639,10 +2721,14 @@ void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* iden
//
bool TParseContext::lineContinuationCheck(const TSourceLoc& loc, bool endOfComment)
{
+#ifdef GLSLANG_WEB
+ return true;
+#endif
+
const char* message = "line continuation";
- bool lineContinuationAllowed = (profile == EEsProfile && version >= 300) ||
- (profile != EEsProfile && (version >= 420 || extensionTurnedOn(E_GL_ARB_shading_language_420pack)));
+ bool lineContinuationAllowed = (isEsProfile() && version >= 300) ||
+ (!isEsProfile() && (version >= 420 || extensionTurnedOn(E_GL_ARB_shading_language_420pack)));
if (endOfComment) {
if (lineContinuationAllowed)
@@ -2691,10 +2777,27 @@ bool TParseContext::builtInName(const TString& identifier)
//
bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, TFunction& function, TOperator op, TType& type)
{
- type.shallowCopy(function.getType());
+ // See if the constructor does not establish the main type, only requalifies
+ // it, in which case the type comes from the argument instead of from the
+ // constructor function.
+ switch (op) {
+#ifndef GLSLANG_WEB
+ case EOpConstructNonuniform:
+ if (node != nullptr && node->getAsTyped() != nullptr) {
+ type.shallowCopy(node->getAsTyped()->getType());
+ type.getQualifier().makeTemporary();
+ type.getQualifier().nonUniform = true;
+ }
+ break;
+#endif
+ default:
+ type.shallowCopy(function.getType());
+ break;
+ }
+ // See if it's a matrix
bool constructingMatrix = false;
- switch(op) {
+ switch (op) {
case EOpConstructTextureSampler:
return constructorTextureSamplerError(loc, function);
case EOpConstructMat2x2:
@@ -2706,6 +2809,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
case EOpConstructMat4x2:
case EOpConstructMat4x3:
case EOpConstructMat4x4:
+#ifndef GLSLANG_WEB
case EOpConstructDMat2x2:
case EOpConstructDMat2x3:
case EOpConstructDMat2x4:
@@ -2724,6 +2828,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
case EOpConstructF16Mat4x2:
case EOpConstructF16Mat4x3:
case EOpConstructF16Mat4x4:
+#endif
constructingMatrix = true;
break;
default:
@@ -2773,20 +2878,21 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
if (function[arg].type->isFloatingDomain())
floatArgument = true;
if (type.isStruct()) {
- if (function[arg].type->containsBasicType(EbtFloat16)) {
+ if (function[arg].type->contains16BitFloat()) {
requireFloat16Arithmetic(loc, "constructor", "can't construct structure containing 16-bit type");
}
- if (function[arg].type->containsBasicType(EbtUint16) ||
- function[arg].type->containsBasicType(EbtInt16)) {
+ if (function[arg].type->contains16BitInt()) {
requireInt16Arithmetic(loc, "constructor", "can't construct structure containing 16-bit type");
}
- if (function[arg].type->containsBasicType(EbtUint8) ||
- function[arg].type->containsBasicType(EbtInt8)) {
+ if (function[arg].type->contains8BitInt()) {
requireInt8Arithmetic(loc, "constructor", "can't construct structure containing 8-bit type");
}
}
}
+ if (op == EOpConstructNonuniform)
+ constType = false;
+#ifndef GLSLANG_WEB
switch (op) {
case EOpConstructFloat16:
case EOpConstructF16Vec2:
@@ -2826,6 +2932,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
default:
break;
}
+#endif
// inherit constness from children
if (constType) {
@@ -2834,17 +2941,24 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
if (specConstType) {
switch (op) {
case EOpConstructInt8:
- case EOpConstructUint8:
- case EOpConstructInt16:
- case EOpConstructUint16:
case EOpConstructInt:
case EOpConstructUint:
- case EOpConstructInt64:
- case EOpConstructUint64:
case EOpConstructBool:
case EOpConstructBVec2:
case EOpConstructBVec3:
case EOpConstructBVec4:
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructUVec2:
+ case EOpConstructUVec3:
+ case EOpConstructUVec4:
+#ifndef GLSLANG_WEB
+ case EOpConstructUint8:
+ case EOpConstructInt16:
+ case EOpConstructUint16:
+ case EOpConstructInt64:
+ case EOpConstructUint64:
case EOpConstructI8Vec2:
case EOpConstructI8Vec3:
case EOpConstructI8Vec4:
@@ -2857,18 +2971,13 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
case EOpConstructU16Vec2:
case EOpConstructU16Vec3:
case EOpConstructU16Vec4:
- case EOpConstructIVec2:
- case EOpConstructIVec3:
- case EOpConstructIVec4:
- case EOpConstructUVec2:
- case EOpConstructUVec3:
- case EOpConstructUVec4:
case EOpConstructI64Vec2:
case EOpConstructI64Vec3:
case EOpConstructI64Vec4:
case EOpConstructU64Vec2:
case EOpConstructU64Vec3:
case EOpConstructU64Vec4:
+#endif
// This was the list of valid ones, if they aren't converting from float
// and aren't making an array.
makeSpecConst = ! floatArgument && ! type.isArray();
@@ -2978,7 +3087,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
error(loc, "cannot convert a sampler", "constructor", "");
return true;
}
- if (op != EOpConstructStruct && typed->getBasicType() == EbtAtomicUint) {
+ if (op != EOpConstructStruct && typed->isAtomic()) {
error(loc, "cannot convert an atomic_uint", "constructor", "");
return true;
}
@@ -3024,7 +3133,7 @@ bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const
}
// simulate the first argument's impact on the result type, so it can be compared with the encapsulated operator!=()
TSampler texture = function.getType().getSampler();
- texture.combined = false;
+ texture.setCombined(false);
texture.shadow = false;
if (texture != function[0].type->getSampler()) {
error(loc, "sampler-constructor first argument must match type and dimensionality of constructor type", token, "");
@@ -3076,14 +3185,14 @@ void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const
{
// 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 (type.getBasicType() == EbtSampler && type.getSampler().isExternal()) {
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.getSampler().yuv) {
+ if (type.getSampler().isYuv()) {
requireExtensions(loc, 1, &E_GL_EXT_YUV_target, "__samplerExternal2DY2YEXT");
}
@@ -3100,6 +3209,8 @@ void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const
}
}
+#ifndef GLSLANG_WEB
+
void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
{
if (type.getQualifier().storage == EvqUniform)
@@ -3110,7 +3221,7 @@ void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, co
else if (type.getBasicType() == EbtAtomicUint && type.getQualifier().storage != EvqUniform)
error(loc, "atomic_uints can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
}
-#ifdef NV_EXTENSIONS
+
void TParseContext::accStructNVCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
{
if (type.getQualifier().storage == EvqUniform)
@@ -3123,7 +3234,8 @@ void TParseContext::accStructNVCheck(const TSourceLoc& loc, const TType& type, c
type.getBasicTypeString().c_str(), identifier.c_str());
}
-#endif
+
+#endif // GLSLANG_WEB
void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
{
@@ -3188,7 +3300,7 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q
break;
}
- if (!nonuniformOkay && qualifier.nonUniform)
+ if (!nonuniformOkay && qualifier.isNonUniform())
error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", "");
invariantCheck(loc, qualifier);
@@ -3202,7 +3314,7 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
if (! symbolTable.atGlobalLevel())
return;
- if (!(publicType.userDef && publicType.userDef->getBasicType() == EbtReference)) {
+ if (!(publicType.userDef && publicType.userDef->isReference())) {
if (qualifier.isMemoryQualifierImageAndSSBOOnly() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer) {
error(loc, "memory qualifiers cannot be used on this type", "", "");
} else if (qualifier.isMemory() && (publicType.basicType != EbtSampler) && !publicType.qualifier.isUniformOrBuffer()) {
@@ -3212,13 +3324,13 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
if (qualifier.storage == EvqBuffer &&
publicType.basicType != EbtBlock &&
- !qualifier.layoutBufferReference)
+ !qualifier.hasBufferReference())
error(loc, "buffers can be declared only as blocks", "buffer", "");
if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
return;
- if (publicType.shaderQualifiers.blendEquation)
+ if (publicType.shaderQualifiers.hasBlendEquation())
error(loc, "can only be applied to a standalone 'out'", "blend equation", "");
// now, knowing it is a shader in/out, do all the in/out semantic checks
@@ -3231,25 +3343,15 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble)
profileRequires(loc, EEsProfile, 300, nullptr, "shader input/output");
- if (!qualifier.flat
-#ifdef AMD_EXTENSIONS
- && !qualifier.explicitInterp
-#endif
-#ifdef NV_EXTENSIONS
- && !qualifier.pervertexNV
-#endif
- ) {
+ if (!qualifier.flat && !qualifier.isExplicitInterpolation() && !qualifier.isPervertexNV()) {
if (isTypeInt(publicType.basicType) ||
publicType.basicType == EbtDouble ||
- (publicType.userDef && (publicType.userDef->containsBasicType(EbtInt8) ||
- publicType.userDef->containsBasicType(EbtUint8) ||
- publicType.userDef->containsBasicType(EbtInt16) ||
- publicType.userDef->containsBasicType(EbtUint16) ||
- publicType.userDef->containsBasicType(EbtInt) ||
- publicType.userDef->containsBasicType(EbtUint) ||
- publicType.userDef->containsBasicType(EbtInt64) ||
- publicType.userDef->containsBasicType(EbtUint64) ||
- publicType.userDef->containsBasicType(EbtDouble)))) {
+ (publicType.userDef && ( publicType.userDef->containsBasicType(EbtInt)
+ || publicType.userDef->containsBasicType(EbtUint)
+ || publicType.userDef->contains16BitInt()
+ || publicType.userDef->contains8BitInt()
+ || publicType.userDef->contains64BitInt()
+ || publicType.userDef->containsDouble()))) {
if (qualifier.storage == EvqVaryingIn && language == EShLangFragment)
error(loc, "must be qualified as flat", TType::getBasicString(publicType.basicType), GetStorageQualifierString(qualifier.storage));
else if (qualifier.storage == EvqVaryingOut && language == EShLangVertex && version == 300)
@@ -3257,13 +3359,11 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
}
}
- if (qualifier.patch && qualifier.isInterpolation())
+ if (qualifier.isPatch() && qualifier.isInterpolation())
error(loc, "cannot use interpolation qualifiers with patch", "patch", "");
-#ifdef NV_EXTENSIONS
- if (qualifier.perTaskNV && publicType.basicType != EbtBlock)
+ if (qualifier.isTaskMemory() && publicType.basicType != EbtBlock)
error(loc, "taskNV variables can be declared only as blocks", "taskNV", "");
-#endif
if (qualifier.storage == EvqVaryingIn) {
switch (language) {
@@ -3281,18 +3381,6 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
if (qualifier.isAuxiliary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant)
error(loc, "vertex input cannot be further qualified", "", "");
break;
-
- case EShLangTessControl:
- if (qualifier.patch)
- error(loc, "can only use on output in tessellation-control shader", "patch", "");
- break;
-
- case EShLangTessEvaluation:
- break;
-
- case EShLangGeometry:
- break;
-
case EShLangFragment:
if (publicType.userDef) {
profileRequires(loc, EEsProfile, 300, nullptr, "fragment-shader struct input");
@@ -3303,12 +3391,16 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
requireProfile(loc, ~EEsProfile, "fragment-shader struct input containing an array");
}
break;
-
- case EShLangCompute:
+ case EShLangCompute:
if (! symbolTable.atBuiltInLevel())
error(loc, "global storage input qualifier cannot be used in a compute shader", "in", "");
break;
-
+#ifndef GLSLANG_WEB
+ case EShLangTessControl:
+ if (qualifier.patch)
+ error(loc, "can only use on output in tessellation-control shader", "patch", "");
+ break;
+#endif
default:
break;
}
@@ -3326,18 +3418,6 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
}
break;
-
- case EShLangTessControl:
- break;
-
- case EShLangTessEvaluation:
- if (qualifier.patch)
- error(loc, "can only use on input in tessellation-evaluation shader", "patch", "");
- break;
-
- case EShLangGeometry:
- break;
-
case EShLangFragment:
profileRequires(loc, EEsProfile, 300, nullptr, "fragment shader output");
if (publicType.basicType == EbtStruct) {
@@ -3359,7 +3439,12 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
case EShLangCompute:
error(loc, "global storage output qualifier cannot be used in a compute shader", "out", "");
break;
-
+#ifndef GLSLANG_WEB
+ case EShLangTessEvaluation:
+ if (qualifier.patch)
+ error(loc, "can only use on input in tessellation-evaluation shader", "patch", "");
+ break;
+#endif
default:
break;
}
@@ -3383,18 +3468,14 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
// Multiple interpolation qualifiers (mostly done later by 'individual qualifiers')
if (src.isInterpolation() && dst.isInterpolation())
-#ifdef AMD_EXTENSIONS
error(loc, "can only have one interpolation qualifier (flat, smooth, noperspective, __explicitInterpAMD)", "", "");
-#else
- error(loc, "can only have one interpolation qualifier (flat, smooth, noperspective)", "", "");
-#endif
// Ordering
- if (! force && ((profile != EEsProfile && version < 420) ||
- (profile == EEsProfile && version < 310))
+ if (! force && ((!isEsProfile() && version < 420) ||
+ (isEsProfile() && version < 310))
&& ! extensionTurnedOn(E_GL_ARB_shading_language_420pack)) {
// non-function parameters
- if (src.noContraction && (dst.invariant || dst.isInterpolation() || dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
+ if (src.isNoContraction() && (dst.invariant || dst.isInterpolation() || dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
error(loc, "precise qualifier must appear first", "", "");
if (src.invariant && (dst.isInterpolation() || dst.isAuxiliary() || dst.storage != EvqTemporary || dst.precision != EpqNone))
error(loc, "invariant qualifier must appear before interpolation, storage, and precision qualifiers ", "", "");
@@ -3406,7 +3487,7 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
error(loc, "precision qualifier must appear as last qualifier", "", "");
// function parameters
- if (src.noContraction && (dst.storage == EvqConst || dst.storage == EvqIn || dst.storage == EvqOut))
+ if (src.isNoContraction() && (dst.storage == EvqConst || dst.storage == EvqIn || dst.storage == EvqOut))
error(loc, "precise qualifier must appear first", "", "");
if (src.storage == EvqConst && (dst.storage == EvqIn || dst.storage == EvqOut))
error(loc, "in/out must appear before const", "", "");
@@ -3431,6 +3512,7 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
if (dst.precision == EpqNone || (force && src.precision != EpqNone))
dst.precision = src.precision;
+#ifndef GLSLANG_WEB
if (!force && ((src.coherent && (dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent)) ||
(src.devicecoherent && (dst.coherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent)) ||
(src.queuefamilycoherent && (dst.coherent || dst.devicecoherent || dst.workgroupcoherent || dst.subgroupcoherent)) ||
@@ -3438,6 +3520,7 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
(src.subgroupcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent)))) {
error(loc, "only one coherent/devicecoherent/queuefamilycoherent/workgroupcoherent/subgroupcoherent qualifier allowed", GetPrecisionQualifierString(src.precision), "");
}
+#endif
// Layout qualifiers
mergeObjectLayoutQualifiers(dst, src, false);
@@ -3445,19 +3528,17 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
bool repeated = false;
#define MERGE_SINGLETON(field) repeated |= dst.field && src.field; dst.field |= src.field;
MERGE_SINGLETON(invariant);
- MERGE_SINGLETON(noContraction);
MERGE_SINGLETON(centroid);
MERGE_SINGLETON(smooth);
MERGE_SINGLETON(flat);
+ MERGE_SINGLETON(specConstant);
+#ifndef GLSLANG_WEB
+ MERGE_SINGLETON(noContraction);
MERGE_SINGLETON(nopersp);
-#ifdef AMD_EXTENSIONS
MERGE_SINGLETON(explicitInterp);
-#endif
-#ifdef NV_EXTENSIONS
MERGE_SINGLETON(perPrimitiveNV);
MERGE_SINGLETON(perViewNV);
MERGE_SINGLETON(perTaskNV);
-#endif
MERGE_SINGLETON(patch);
MERGE_SINGLETON(sample);
MERGE_SINGLETON(coherent);
@@ -3470,8 +3551,8 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
MERGE_SINGLETON(restrict);
MERGE_SINGLETON(readonly);
MERGE_SINGLETON(writeonly);
- MERGE_SINGLETON(specConstant);
MERGE_SINGLETON(nonUniform);
+#endif
if (repeated)
error(loc, "replicated qualifiers", "", "");
@@ -3514,11 +3595,11 @@ void TParseContext::setDefaultPrecision(const TSourceLoc& loc, TPublicType& publ
// correlates with the declaration of defaultSamplerPrecision[]
int TParseContext::computeSamplerTypeIndex(TSampler& sampler)
{
- int arrayIndex = sampler.arrayed ? 1 : 0;
- int shadowIndex = sampler.shadow ? 1 : 0;
- int externalIndex = sampler.external? 1 : 0;
- int imageIndex = sampler.image ? 1 : 0;
- int msIndex = sampler.ms ? 1 : 0;
+ int arrayIndex = sampler.arrayed ? 1 : 0;
+ int shadowIndex = sampler.shadow ? 1 : 0;
+ int externalIndex = sampler.isExternal() ? 1 : 0;
+ int imageIndex = sampler.isImageClass() ? 1 : 0;
+ int msIndex = sampler.isMultiSample() ? 1 : 0;
int flattened = EsdNumDims * (EbtNumTypes * (2 * (2 * (2 * (2 * arrayIndex + msIndex) + imageIndex) + shadowIndex) +
externalIndex) + sampler.type) + sampler.dim;
@@ -3542,8 +3623,10 @@ void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType ba
if (! obeyPrecisionQualifiers() || parsingBuiltins)
return;
+#ifndef GLSLANG_WEB
if (baseType == EbtAtomicUint && qualifier.precision != EpqNone && qualifier.precision != EpqHigh)
error(loc, "atomic counters can only be highp", "atomic_uint", "");
+#endif
if (baseType == EbtFloat || baseType == EbtUint || baseType == EbtInt || baseType == EbtSampler || baseType == EbtAtomicUint) {
if (qualifier.precision == EpqNone) {
@@ -3562,8 +3645,7 @@ void TParseContext::parameterTypeCheck(const TSourceLoc& loc, TStorageQualifier
{
if ((qualifier == EvqOut || qualifier == EvqInOut) && type.isOpaque())
error(loc, "samplers and atomic_uints cannot be output parameters", type.getBasicTypeString().c_str(), "");
-
- if (!parsingBuiltins && type.containsBasicType(EbtFloat16))
+ if (!parsingBuiltins && type.contains16BitFloat())
requireFloat16Arithmetic(loc, type.getBasicTypeString().c_str(), "float16 types can only be in uniform block or buffer storage");
if (!parsingBuiltins && type.contains16BitInt())
requireInt16Arithmetic(loc, type.getBasicTypeString().c_str(), "(u)int16 types can only be in uniform block or buffer storage");
@@ -3726,51 +3808,53 @@ void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qua
(qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal && qualifier.storage != EvqShared && qualifier.storage != EvqConst))
error(loc, "only outermost dimension of an array of arrays can be a specialization constant", "[]", "");
+#ifndef GLSLANG_WEB
+
// desktop always allows outer-dimension-unsized variable arrays,
- if (profile != EEsProfile)
+ if (!isEsProfile())
return;
// for ES, if size isn't coming from an initializer, it has to be explicitly declared now,
// with very few exceptions
- // last member of ssbo block exception:
- if (qualifier.storage == EvqBuffer && lastMember)
- return;
-
// implicitly-sized io exceptions:
switch (language) {
case EShLangGeometry:
if (qualifier.storage == EvqVaryingIn)
- if ((profile == EEsProfile && version >= 320) ||
+ if ((isEsProfile() && version >= 320) ||
extensionsTurnedOn(Num_AEP_geometry_shader, AEP_geometry_shader))
return;
break;
case EShLangTessControl:
if ( qualifier.storage == EvqVaryingIn ||
- (qualifier.storage == EvqVaryingOut && ! qualifier.patch))
- if ((profile == EEsProfile && version >= 320) ||
+ (qualifier.storage == EvqVaryingOut && ! qualifier.isPatch()))
+ if ((isEsProfile() && version >= 320) ||
extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
return;
break;
case EShLangTessEvaluation:
- if ((qualifier.storage == EvqVaryingIn && ! qualifier.patch) ||
+ if ((qualifier.storage == EvqVaryingIn && ! qualifier.isPatch()) ||
qualifier.storage == EvqVaryingOut)
- if ((profile == EEsProfile && version >= 320) ||
+ if ((isEsProfile() && version >= 320) ||
extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader))
return;
break;
-#ifdef NV_EXTENSIONS
case EShLangMeshNV:
if (qualifier.storage == EvqVaryingOut)
- if ((profile == EEsProfile && version >= 320) ||
+ if ((isEsProfile() && version >= 320) ||
extensionTurnedOn(E_GL_NV_mesh_shader))
return;
break;
-#endif
default:
break;
}
+#endif
+
+ // last member of ssbo block exception:
+ if (qualifier.storage == EvqBuffer && lastMember)
+ return;
+
arraySizeRequiredCheck(loc, *arraySizes);
}
@@ -3811,6 +3895,7 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie
if (symbolTable.atGlobalLevel())
trackLinkage(*symbol);
+#ifndef GLSLANG_WEB
if (! symbolTable.atBuiltInLevel()) {
if (isIoResizeArray(type)) {
ioArraySymbolResizeList.push_back(symbol);
@@ -3818,6 +3903,7 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie
} else
fixIoArraySize(loc, symbol->getWritableType());
}
+#endif
return;
}
@@ -3855,6 +3941,7 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie
return;
}
+#ifndef GLSLANG_WEB
if (existingType.isSizedArray()) {
// be more leniant for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size
if (! (isIoResizeArray(type) && existingType.getOuterArraySize() == type.getOuterArraySize()))
@@ -3868,8 +3955,11 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie
if (isIoResizeArray(type))
checkIoArraysConsistency(loc);
+#endif
}
+#ifndef GLSLANG_WEB
+
// Policy and error check for needing a runtime sized array.
void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermTyped& base)
{
@@ -3883,7 +3973,7 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType
const TIntermBinary* binary = base.getAsBinaryNode();
if (binary != nullptr &&
binary->getOp() == EOpIndexDirectStruct &&
- binary->getLeft()->getBasicType() == EbtReference) {
+ binary->getLeft()->isReference()) {
const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
const int memberCount = (int)binary->getLeft()->getType().getReferentType()->getStruct()->size();
@@ -3893,8 +3983,8 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType
}
// check for additional things allowed by GL_EXT_nonuniform_qualifier
- if (base.getBasicType() == EbtSampler ||
- (base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer()))
+ if (base.getBasicType() == EbtSampler || base.getBasicType() == EbtAccStructNV ||
+ (base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer()))
requireExtensions(loc, 1, &E_GL_EXT_nonuniform_qualifier, "variable index");
else
error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable");
@@ -3910,7 +4000,7 @@ bool TParseContext::isRuntimeLength(const TIntermTyped& base) const
// is it the last member?
const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
- if (binary->getLeft()->getBasicType() == EbtReference)
+ if (binary->getLeft()->isReference())
return false;
const int memberCount = (int)binary->getLeft()->getType().getStruct()->size();
@@ -3922,27 +4012,34 @@ bool TParseContext::isRuntimeLength(const TIntermTyped& base) const
return false;
}
-#ifdef NV_EXTENSIONS
-// Fix mesh view output array dimension
-void TParseContext::resizeMeshViewDimension(const TSourceLoc& loc, TType& type)
+// Check if mesh perviewNV attributes have a view dimension
+// and resize it to gl_MaxMeshViewCountNV when implicitly sized.
+void TParseContext::checkAndResizeMeshViewDim(const TSourceLoc& loc, TType& type, bool isBlockMember)
{
// see if member is a per-view attribute
- if (type.getQualifier().isPerView()) {
- // since we don't have the maxMeshViewCountNV set during parsing builtins, we hardcode the value
+ if (!type.getQualifier().isPerView())
+ return;
+
+ if ((isBlockMember && type.isArray()) || (!isBlockMember && type.isArrayOfArrays())) {
+ // since we don't have the maxMeshViewCountNV set during parsing builtins, we hardcode the value.
int maxViewCount = parsingBuiltins ? 4 : resources.maxMeshViewCountNV;
+ // For block members, outermost array dimension is the view dimension.
+ // For non-block members, outermost array dimension is the vertex/primitive dimension
+ // and 2nd outermost is the view dimension.
+ int viewDim = isBlockMember ? 0 : 1;
+ int viewDimSize = type.getArraySizes()->getDimSize(viewDim);
- if (! type.isArray()) {
- error(loc, "requires an view array dimension", "perviewNV", "");
- }
- else if (!type.isUnsizedArray() && type.getOuterArraySize() != maxViewCount) {
+ if (viewDimSize != UnsizedArraySize && viewDimSize != maxViewCount)
error(loc, "mesh view output array size must be gl_MaxMeshViewCountNV or implicitly sized", "[]", "");
- }
- else if (type.isUnsizedArray()) {
- type.changeOuterArraySize(maxViewCount);
- }
+ else if (viewDimSize == UnsizedArraySize)
+ type.getArraySizes()->setDimSize(viewDim, maxViewCount);
+ }
+ else {
+ error(loc, "requires a view array dimension", "perviewNV", "");
}
}
-#endif
+
+#endif // GLSLANG_WEB
// Returns true if the first argument to the #line directive is the line number for the next line.
//
@@ -3955,7 +4052,7 @@ void TParseContext::resizeMeshViewDimension(const TSourceLoc& loc, TType& type)
// source string number source-string-number.
bool TParseContext::lineDirectiveShouldSetNextLine() const
{
- return profile == EEsProfile || version >= 330;
+ return isEsProfile() || version >= 330;
}
//
@@ -3986,18 +4083,19 @@ void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier
TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier,
const TQualifier& qualifier, const TShaderQualifiers& publicType)
{
+#ifndef GLSLANG_WEB
if (! builtInName(identifier) || symbolTable.atBuiltInLevel() || ! symbolTable.atGlobalLevel())
return nullptr;
- bool nonEsRedecls = (profile != EEsProfile && (version >= 130 || identifier == "gl_TexCoord"));
- bool esRedecls = (profile == EEsProfile &&
+ bool nonEsRedecls = (!isEsProfile() && (version >= 130 || identifier == "gl_TexCoord"));
+ bool esRedecls = (isEsProfile() &&
(version >= 320 || extensionsTurnedOn(Num_AEP_shader_io_blocks, AEP_shader_io_blocks)));
if (! esRedecls && ! nonEsRedecls)
return nullptr;
// Special case when using GL_ARB_separate_shader_objects
bool ssoPre150 = false; // means the only reason this variable is redeclared is due to this combination
- if (profile != EEsProfile && version <= 140 && extensionTurnedOn(E_GL_ARB_separate_shader_objects)) {
+ if (!isEsProfile() && version <= 140 && extensionTurnedOn(E_GL_ARB_separate_shader_objects)) {
if (identifier == "gl_Position" ||
identifier == "gl_PointSize" ||
identifier == "gl_ClipVertex" ||
@@ -4020,11 +4118,9 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
(identifier == "gl_Color" && language == EShLangFragment) ||
(identifier == "gl_FragStencilRefARB" && (nonEsRedecls && version >= 140)
&& language == EShLangFragment) ||
-#ifdef NV_EXTENSIONS
identifier == "gl_SampleMask" ||
identifier == "gl_Layer" ||
identifier == "gl_PrimitiveIndicesNV" ||
-#endif
identifier == "gl_TexCoord") {
// Find the existing symbol, if any.
@@ -4104,16 +4200,13 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
}
}
else if (
-#ifdef NV_EXTENSIONS
identifier == "gl_PrimitiveIndicesNV" ||
-#endif
identifier == "gl_FragStencilRefARB") {
if (qualifier.hasLayout())
error(loc, "cannot apply layout qualifier to", "redeclaration", symbol->getName().c_str());
if (qualifier.storage != EvqVaryingOut)
error(loc, "cannot change output storage qualification of", "redeclaration", symbol->getName().c_str());
}
-#ifdef NV_EXTENSIONS
else if (identifier == "gl_SampleMask") {
if (!publicType.layoutOverrideCoverage) {
error(loc, "redeclaration only allowed for override_coverage layout", "redeclaration", symbol->getName().c_str());
@@ -4126,12 +4219,12 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
symbolQualifier.layoutViewportRelative = qualifier.layoutViewportRelative;
symbolQualifier.layoutSecondaryViewportRelativeOffset = qualifier.layoutSecondaryViewportRelativeOffset;
}
-#endif
// TODO: semantics quality: separate smooth from nothing declared, then use IsInterpolation for several tests above
return symbol;
}
+#endif
return nullptr;
}
@@ -4143,16 +4236,13 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS
void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName,
const TString* instanceName, TArraySizes* arraySizes)
{
+#ifndef GLSLANG_WEB
const char* feature = "built-in block redeclaration";
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"
-#ifdef NV_EXTENSIONS
- && blockName != "gl_MeshPerVertexNV" && blockName != "gl_MeshPerPrimitiveNV"
-#endif
- )
- {
+ if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment" &&
+ blockName != "gl_MeshPerVertexNV" && blockName != "gl_MeshPerPrimitiveNV") {
error(loc, "cannot redeclare block: ", "block declaration", blockName.c_str());
return;
}
@@ -4211,7 +4301,6 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
TType& type = block->getWritableType();
-#ifdef NV_EXTENSIONS
// if gl_PerVertex is redeclared for the purpose of passing through "gl_Position"
// for passthrough purpose, the redeclared block should have the same qualifers as
// the current one
@@ -4221,7 +4310,6 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
type.getQualifier().layoutStream = currentBlockQualifier.layoutStream;
type.getQualifier().layoutXfbBuffer = currentBlockQualifier.layoutXfbBuffer;
}
-#endif
TTypeList::iterator member = type.getWritableStruct()->begin();
size_t numOriginalMembersFound = 0;
@@ -4254,7 +4342,6 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
error(memberLoc, "cannot change array size of redeclared block member", member->type->getFieldName().c_str(), "");
else if (! oldType.getQualifier().isPerView() && newType.isArray())
arrayLimitCheck(loc, member->type->getFieldName(), newType.getOuterArraySize());
-#ifdef NV_EXTENSIONS
if (oldType.getQualifier().isPerView() && ! newType.getQualifier().isPerView())
error(memberLoc, "missing perviewNV qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
else if (! oldType.getQualifier().isPerView() && newType.getQualifier().isPerView())
@@ -4274,7 +4361,6 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
error(memberLoc, "missing perprimitiveNV qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
else if (! oldType.getQualifier().isPerPrimitive() && newType.getQualifier().isPerPrimitive())
error(memberLoc, "cannot add perprimitiveNV qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
-#endif
if (newType.getQualifier().isMemory())
error(memberLoc, "cannot add memory qualifier to redeclared block member", member->type->getFieldName().c_str(), "");
if (newType.getQualifier().hasNonXfbLayout())
@@ -4365,6 +4451,7 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
// Save it in the AST for linker use.
trackLinkage(*block);
+#endif // GLSLANG_WEB
}
void TParseContext::paramCheckFixStorage(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type)
@@ -4392,6 +4479,7 @@ void TParseContext::paramCheckFixStorage(const TSourceLoc& loc, const TStorageQu
void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& qualifier, TType& type)
{
+#ifndef GLSLANG_WEB
if (qualifier.isMemory()) {
type.getQualifier().volatil = qualifier.volatil;
type.getQualifier().coherent = qualifier.coherent;
@@ -4404,6 +4492,7 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali
type.getQualifier().writeonly = qualifier.writeonly;
type.getQualifier().restrict = qualifier.restrict;
}
+#endif
if (qualifier.isAuxiliary() ||
qualifier.isInterpolation())
@@ -4412,9 +4501,9 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali
error(loc, "cannot use layout qualifiers on a function parameter", "", "");
if (qualifier.invariant)
error(loc, "cannot use invariant qualifier on a function parameter", "", "");
- if (qualifier.noContraction) {
+ if (qualifier.isNoContraction()) {
if (qualifier.isParamOutput())
- type.getQualifier().noContraction = true;
+ type.getQualifier().setNoContraction();
else
warn(loc, "qualifier has no effect on non-output parameters", "precise", "");
}
@@ -4455,12 +4544,15 @@ void TParseContext::opaqueCheck(const TSourceLoc& loc, const TType& type, const
void TParseContext::referenceCheck(const TSourceLoc& loc, const TType& type, const char* op)
{
+#ifndef GLSLANG_WEB
if (containsFieldWithBasicType(type, EbtReference))
error(loc, "can't use with reference types", op, "");
+#endif
}
void TParseContext::storage16BitAssignmentCheck(const TSourceLoc& loc, const TType& type, const char* op)
{
+#ifndef GLSLANG_WEB
if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtFloat16))
requireFloat16Arithmetic(loc, op, "can't use with structs containing float16");
@@ -4490,6 +4582,7 @@ void TParseContext::storage16BitAssignmentCheck(const TSourceLoc& loc, const TTy
if (type.isArray() && type.getBasicType() == EbtUint8)
requireInt8Arithmetic(loc, op, "can't use with arrays containing uint8");
+#endif
}
void TParseContext::specializationCheck(const TSourceLoc& loc, const TType& type, const char* op)
@@ -4541,6 +4634,7 @@ void TParseContext::structTypeCheck(const TSourceLoc& /*loc*/, TPublicType& publ
//
void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init, TIntermLoop* loop)
{
+#ifndef GLSLANG_WEB
// loop index init must exist and be a declaration, which shows up in the AST as an aggregate of size 1 of the declaration
bool badInit = false;
if (! init || ! init->getAsAggregate() || init->getAsAggregate()->getSequence().size() != 1)
@@ -4636,8 +4730,10 @@ void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init,
// the body
inductiveLoopBodyCheck(loop->getBody(), loopIndex, symbolTable);
+#endif
}
+#ifndef GLSLANG_WEB
// Do limit checks for built-in arrays.
void TParseContext::arrayLimitCheck(const TSourceLoc& loc, const TString& identifier, int size)
{
@@ -4647,13 +4743,12 @@ void TParseContext::arrayLimitCheck(const TSourceLoc& loc, const TString& identi
limitCheck(loc, size, "gl_MaxClipDistances", "gl_ClipDistance array size");
else if (identifier.compare("gl_CullDistance") == 0)
limitCheck(loc, size, "gl_MaxCullDistances", "gl_CullDistance array size");
-#ifdef NV_EXTENSIONS
else if (identifier.compare("gl_ClipDistancePerViewNV") == 0)
limitCheck(loc, size, "gl_MaxClipDistances", "gl_ClipDistancePerViewNV array size");
else if (identifier.compare("gl_CullDistancePerViewNV") == 0)
limitCheck(loc, size, "gl_MaxCullDistances", "gl_CullDistancePerViewNV array size");
-#endif
}
+#endif // GLSLANG_WEB
// See if the provided value is less than or equal to the symbol indicated by limit,
// which should be a constant in the symbol table.
@@ -4667,6 +4762,8 @@ void TParseContext::limitCheck(const TSourceLoc& loc, int value, const char* lim
error(loc, "must be less than or equal to", feature, "%s (%d)", limit, constArray[0].getIConst());
}
+#ifndef GLSLANG_WEB
+
//
// Do any additional error checking, etc., once we know the parsing is done.
//
@@ -4688,33 +4785,30 @@ void TParseContext::finish()
// about the stage itself.
switch (language) {
case EShLangGeometry:
- if (profile == EEsProfile && version == 310)
+ if (isEsProfile() && version == 310)
requireExtensions(getCurrentLoc(), Num_AEP_geometry_shader, AEP_geometry_shader, "geometry shaders");
break;
case EShLangTessControl:
case EShLangTessEvaluation:
- if (profile == EEsProfile && version == 310)
+ if (isEsProfile() && version == 310)
requireExtensions(getCurrentLoc(), Num_AEP_tessellation_shader, AEP_tessellation_shader, "tessellation shaders");
- else if (profile != EEsProfile && version < 400)
+ else if (!isEsProfile() && version < 400)
requireExtensions(getCurrentLoc(), 1, &E_GL_ARB_tessellation_shader, "tessellation shaders");
break;
case EShLangCompute:
- if (profile != EEsProfile && version < 430)
+ if (!isEsProfile() && version < 430)
requireExtensions(getCurrentLoc(), 1, &E_GL_ARB_compute_shader, "compute shaders");
break;
-#ifdef NV_EXTENSIONS
case EShLangTaskNV:
requireExtensions(getCurrentLoc(), 1, &E_GL_NV_mesh_shader, "task shaders");
break;
case EShLangMeshNV:
requireExtensions(getCurrentLoc(), 1, &E_GL_NV_mesh_shader, "mesh shaders");
break;
-#endif
default:
break;
}
-#ifdef NV_EXTENSIONS
// Set default outputs for GL_NV_geometry_shader_passthrough
if (language == EShLangGeometry && extensionTurnedOn(E_SPV_NV_geometry_shader_passthrough)) {
if (intermediate.getOutputPrimitive() == ElgNone) {
@@ -4734,8 +4828,8 @@ void TParseContext::finish()
}
}
}
-#endif
}
+#endif // GLSLANG_WEB
//
// Layout qualifier stuff.
@@ -4771,6 +4865,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
publicType.qualifier.layoutPacking = ElpStd140;
return;
}
+#ifndef GLSLANG_WEB
if (id == TQualifier::getLayoutPackingString(ElpStd430)) {
requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "std430");
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, "std430");
@@ -4810,20 +4905,12 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
intermediate.setUsePhysicalStorageBuffer();
return;
}
- if (language == EShLangGeometry || language == EShLangTessEvaluation
-#ifdef NV_EXTENSIONS
- || language == EShLangMeshNV
-#endif
- ) {
+ if (language == EShLangGeometry || language == EShLangTessEvaluation || language == EShLangMeshNV) {
if (id == TQualifier::getGeometryString(ElgTriangles)) {
publicType.shaderQualifiers.geometry = ElgTriangles;
return;
}
- if (language == EShLangGeometry
-#ifdef NV_EXTENSIONS
- || language == EShLangMeshNV
-#endif
- ) {
+ if (language == EShLangGeometry || language == EShLangMeshNV) {
if (id == TQualifier::getGeometryString(ElgPoints)) {
publicType.shaderQualifiers.geometry = ElgPoints;
return;
@@ -4832,10 +4919,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
publicType.shaderQualifiers.geometry = ElgLines;
return;
}
-#ifdef NV_EXTENSIONS
- if (language == EShLangGeometry)
-#endif
- {
+ if (language == EShLangGeometry) {
if (id == TQualifier::getGeometryString(ElgLineStrip)) {
publicType.shaderQualifiers.geometry = ElgLineStrip;
return;
@@ -4852,14 +4936,12 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
publicType.shaderQualifiers.geometry = ElgTriangleStrip;
return;
}
-#ifdef NV_EXTENSIONS
if (id == "passthrough") {
requireExtensions(loc, 1, &E_SPV_NV_geometry_shader_passthrough, "geometry shader passthrough");
publicType.qualifier.layoutPassthrough = true;
intermediate.setGeoPassthroughEXT();
return;
}
-#endif
}
} else {
assert(language == EShLangTessEvaluation);
@@ -4942,6 +5024,17 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
return;
}
}
+ for (TInterlockOrdering order = (TInterlockOrdering)(EioNone + 1); order < EioCount; order = (TInterlockOrdering)(order+1)) {
+ if (id == TQualifier::getInterlockOrderingString(order)) {
+ requireProfile(loc, ECoreProfile | ECompatibilityProfile, "fragment shader interlock layout qualifier");
+ profileRequires(loc, ECoreProfile | ECompatibilityProfile, 450, nullptr, "fragment shader interlock layout qualifier");
+ requireExtensions(loc, 1, &E_GL_ARB_fragment_shader_interlock, TQualifier::getInterlockOrderingString(order));
+ if (order == EioShadingRateInterlockOrdered || order == EioShadingRateInterlockUnordered)
+ requireExtensions(loc, 1, &E_GL_NV_shading_rate_image, TQualifier::getInterlockOrderingString(order));
+ publicType.shaderQualifiers.interlockOrdering = order;
+ return;
+ }
+ }
if (id.compare(0, 13, "blend_support") == 0) {
bool found = false;
for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
@@ -4958,7 +5051,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
error(loc, "unknown blend equation", "blend_support", "");
return;
}
-#ifdef NV_EXTENSIONS
if (id == "override_coverage") {
requireExtensions(loc, 1, &E_GL_NV_sample_mask_override_coverage, "sample mask override coverage");
publicType.shaderQualifiers.layoutOverrideCoverage = true;
@@ -4996,9 +5088,8 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
}
}
}
-#else
- }
#endif
+
error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
}
@@ -5063,7 +5154,8 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
return;
} else if (id == "location") {
profileRequires(loc, EEsProfile, 300, nullptr, "location");
- const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
+ const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
+ // GL_ARB_explicit_uniform_location requires 330 or GL_ARB_explicit_attrib_location we do not need to add it here
profileRequires(loc, ~EEsProfile, 330, 2, exts, "location");
if ((unsigned int)value >= TQualifier::layoutLocationEnd)
error(loc, "location is too large", id.c_str(), "");
@@ -5083,8 +5175,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
error(loc, "needs a literal integer", "set", "");
return;
} else if (id == "binding") {
+#ifndef GLSLANG_WEB
profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, "binding");
profileRequires(loc, EEsProfile, 310, nullptr, "binding");
+#endif
if ((unsigned int)value >= TQualifier::layoutBindingEnd)
error(loc, "binding is too large", id.c_str(), "");
else
@@ -5092,7 +5186,23 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
if (nonLiteral)
error(loc, "needs a literal integer", "binding", "");
return;
- } else if (id == "component") {
+ }
+ if (id == "constant_id") {
+ requireSpv(loc, "constant_id");
+ if (value >= (int)TQualifier::layoutSpecConstantIdEnd) {
+ error(loc, "specialization-constant id is too large", id.c_str(), "");
+ } else {
+ publicType.qualifier.layoutSpecConstantId = value;
+ publicType.qualifier.specConstant = true;
+ if (! intermediate.addUsedConstantId(value))
+ error(loc, "specialization-constant id already used", id.c_str(), "");
+ }
+ if (nonLiteral)
+ error(loc, "needs a literal integer", "constant_id", "");
+ return;
+ }
+#ifndef GLSLANG_WEB
+ if (id == "component") {
requireProfile(loc, ECoreProfile | ECompatibilityProfile, "component");
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, "component");
if ((unsigned)value >= TQualifier::layoutComponentEnd)
@@ -5102,7 +5212,8 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
if (nonLiteral)
error(loc, "needs a literal integer", "component", "");
return;
- } else if (id.compare(0, 4, "xfb_") == 0) {
+ }
+ if (id.compare(0, 4, "xfb_") == 0) {
// "Any shader making any static use (after preprocessing) of any of these
// *xfb_* qualifiers will cause the shader to be in a transform feedback
// capturing mode and hence responsible for describing the transform feedback
@@ -5148,7 +5259,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
return;
}
}
-
if (id == "input_attachment_index") {
requireVulkan(loc, "input_attachment_index");
if (value >= (int)TQualifier::layoutAttachmentEnd)
@@ -5159,20 +5269,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
error(loc, "needs a literal integer", "input_attachment_index", "");
return;
}
- if (id == "constant_id") {
- requireSpv(loc, "constant_id");
- if (value >= (int)TQualifier::layoutSpecConstantIdEnd) {
- error(loc, "specialization-constant id is too large", id.c_str(), "");
- } else {
- publicType.qualifier.layoutSpecConstantId = value;
- publicType.qualifier.specConstant = true;
- if (! intermediate.addUsedConstantId(value))
- error(loc, "specialization-constant id already used", id.c_str(), "");
- }
- if (nonLiteral)
- error(loc, "needs a literal integer", "constant_id", "");
- return;
- }
if (id == "num_views") {
requireExtensions(loc, Num_OVR_multiview_EXTs, OVR_multiview_EXTs, "num_views");
publicType.shaderQualifiers.numViews = value;
@@ -5180,8 +5276,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
error(loc, "needs a literal integer", "num_views", "");
return;
}
-
-#if NV_EXTENSIONS
if (language == EShLangVertex ||
language == EShLangTessControl ||
language == EShLangTessEvaluation ||
@@ -5194,7 +5288,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
return;
}
}
-#endif
if (id == "buffer_reference_align") {
requireExtensions(loc, 1, &E_GL_EXT_buffer_reference, "buffer_reference_align");
@@ -5206,11 +5299,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
error(loc, "needs a literal integer", "buffer_reference_align", "");
return;
}
+#endif
switch (language) {
- case EShLangVertex:
- break;
-
+#ifndef GLSLANG_WEB
case EShLangTessControl:
if (id == "vertices") {
if (value == 0)
@@ -5223,9 +5315,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
}
break;
- case EShLangTessEvaluation:
- break;
-
case EShLangGeometry:
if (id == "invocations") {
profileRequires(loc, ECompatibilityProfile | ECoreProfile, 400, nullptr, "invocations");
@@ -5275,7 +5364,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
}
break;
-#ifdef NV_EXTENSIONS
case EShLangMeshNV:
if (id == "max_vertices") {
requireExtensions(loc, 1, &E_GL_NV_mesh_shader, "max_vertices");
@@ -5302,16 +5390,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
#endif
case EShLangCompute:
if (id.compare(0, 11, "local_size_") == 0) {
-#ifdef NV_EXTENSIONS
+#ifndef GLSLANG_WEB
if (language == EShLangMeshNV || language == EShLangTaskNV) {
requireExtensions(loc, 1, &E_GL_NV_mesh_shader, "gl_WorkGroupSize");
- }
- else
-#endif
- {
+ } else {
profileRequires(loc, EEsProfile, 310, 0, "gl_WorkGroupSize");
profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_compute_shader, "gl_WorkGroupSize");
}
+#endif
if (nonLiteral)
error(loc, "needs a literal integer", "local_size", "");
if (id.size() == 12 && value == 0) {
@@ -5320,14 +5406,17 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
}
if (id == "local_size_x") {
publicType.shaderQualifiers.localSize[0] = value;
+ publicType.shaderQualifiers.localSizeNotDefault[0] = true;
return;
}
if (id == "local_size_y") {
publicType.shaderQualifiers.localSize[1] = value;
+ publicType.shaderQualifiers.localSizeNotDefault[1] = true;
return;
}
if (id == "local_size_z") {
publicType.shaderQualifiers.localSize[2] = value;
+ publicType.shaderQualifiers.localSizeNotDefault[2] = true;
return;
}
if (spvVersion.spv != 0) {
@@ -5375,53 +5464,50 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie
if (src.hasPacking())
dst.layoutPacking = src.layoutPacking;
+#ifndef GLSLANG_WEB
if (src.hasStream())
dst.layoutStream = src.layoutStream;
-
if (src.hasFormat())
dst.layoutFormat = src.layoutFormat;
-
if (src.hasXfbBuffer())
dst.layoutXfbBuffer = src.layoutXfbBuffer;
+ if (src.hasBufferReferenceAlign())
+ dst.layoutBufferReferenceAlign = src.layoutBufferReferenceAlign;
+#endif
if (src.hasAlign())
dst.layoutAlign = src.layoutAlign;
- if (src.hasBufferReferenceAlign())
- dst.layoutBufferReferenceAlign = src.layoutBufferReferenceAlign;
-
if (! inheritOnly) {
if (src.hasLocation())
dst.layoutLocation = src.layoutLocation;
- if (src.hasComponent())
- dst.layoutComponent = src.layoutComponent;
- if (src.hasIndex())
- dst.layoutIndex = src.layoutIndex;
-
if (src.hasOffset())
dst.layoutOffset = src.layoutOffset;
-
if (src.hasSet())
dst.layoutSet = src.layoutSet;
if (src.layoutBinding != TQualifier::layoutBindingEnd)
dst.layoutBinding = src.layoutBinding;
+ if (src.hasSpecConstantId())
+ dst.layoutSpecConstantId = src.layoutSpecConstantId;
+
+#ifndef GLSLANG_WEB
+ if (src.hasComponent())
+ dst.layoutComponent = src.layoutComponent;
+ if (src.hasIndex())
+ dst.layoutIndex = src.layoutIndex;
if (src.hasXfbStride())
dst.layoutXfbStride = src.layoutXfbStride;
if (src.hasXfbOffset())
dst.layoutXfbOffset = src.layoutXfbOffset;
if (src.hasAttachment())
dst.layoutAttachment = src.layoutAttachment;
- if (src.hasSpecConstantId())
- dst.layoutSpecConstantId = src.layoutSpecConstantId;
-
if (src.layoutPushConstant)
dst.layoutPushConstant = true;
if (src.layoutBufferReference)
dst.layoutBufferReference = true;
-#ifdef NV_EXTENSIONS
if (src.layoutPassthrough)
dst.layoutPassthrough = true;
if (src.layoutViewportRelative)
@@ -5490,17 +5576,15 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb
if (qualifier.hasPacking())
error(loc, "cannot specify packing on a variable declaration", "layout", "");
// "The offset qualifier can only be used on block members of blocks..."
- if (qualifier.hasOffset() && type.getBasicType() != EbtAtomicUint)
+ if (qualifier.hasOffset() && !type.isAtomic())
error(loc, "cannot specify on a variable declaration", "offset", "");
// "The align qualifier can only be used on blocks or block members..."
if (qualifier.hasAlign())
error(loc, "cannot specify on a variable declaration", "align", "");
- if (qualifier.layoutPushConstant)
+ if (qualifier.isPushConstant())
error(loc, "can only specify on a uniform block", "push_constant", "");
-#ifdef NV_EXTENSIONS
- if (qualifier.layoutShaderRecordNV)
+ if (qualifier.isShaderRecordNV())
error(loc, "can only specify on a buffer block", "shaderRecordNV", "");
-#endif
}
break;
default:
@@ -5564,17 +5648,15 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
case EvqVaryingOut:
if (type.getBasicType() == EbtBlock)
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, "location qualifier on in/out block");
-#ifdef NV_EXTENSIONS
if (type.getQualifier().isTaskMemory())
error(loc, "cannot apply to taskNV in/out blocks", "location", "");
-#endif
break;
case EvqUniform:
case EvqBuffer:
if (type.getBasicType() == EbtBlock)
error(loc, "cannot apply to uniform or buffer block", "location", "");
break;
-#ifdef NV_EXTENSIONS
+#ifndef GLSLANG_WEB
case EvqPayloadNV:
case EvqPayloadInNV:
case EvqHitAttrNV:
@@ -5597,6 +5679,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
error(loc, "fragment outputs sharing the same location must be the same basic type", "location", "%d", repeated);
}
+#ifndef GLSLANG_WEB
if (qualifier.hasXfbOffset() && qualifier.hasXfbBuffer()) {
int repeated = intermediate.addXfbBufferOffset(type);
if (repeated >= 0)
@@ -5608,25 +5691,20 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
if ((type.containsBasicType(EbtDouble) || type.containsBasicType(EbtInt64) || type.containsBasicType(EbtUint64)) &&
! IsMultipleOfPow2(qualifier.layoutXfbOffset, 8))
error(loc, "type contains double or 64-bit integer; xfb_offset must be a multiple of 8", "xfb_offset", "");
-#ifdef AMD_EXTENSIONS
else if ((type.containsBasicType(EbtBool) || type.containsBasicType(EbtFloat) ||
type.containsBasicType(EbtInt) || type.containsBasicType(EbtUint)) &&
! IsMultipleOfPow2(qualifier.layoutXfbOffset, 4))
error(loc, "must be a multiple of size of first component", "xfb_offset", "");
// ..., if applied to an aggregate containing a half float or 16-bit integer, the offset must also be a multiple of 2..."
- else if ((type.containsBasicType(EbtFloat16) || type.containsBasicType(EbtInt16) || type.containsBasicType(EbtUint16)) &&
+ else if ((type.contains16BitFloat() || type.containsBasicType(EbtInt16) || type.containsBasicType(EbtUint16)) &&
!IsMultipleOfPow2(qualifier.layoutXfbOffset, 2))
error(loc, "type contains half float or 16-bit integer; xfb_offset must be a multiple of 2", "xfb_offset", "");
-#else
- else if (! IsMultipleOfPow2(qualifier.layoutXfbOffset, 4))
- error(loc, "must be a multiple of size of first component", "xfb_offset", "");
-#endif
}
-
if (qualifier.hasXfbStride() && qualifier.hasXfbBuffer()) {
if (! intermediate.setXfbBufferStride(qualifier.layoutXfbBuffer, qualifier.layoutXfbStride))
error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer);
}
+#endif
if (qualifier.hasBinding()) {
// Binding checking, from the spec:
@@ -5649,15 +5727,19 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
lastBinding += type.getCumulativeArraySize();
else {
lastBinding += 1;
+#ifndef GLSLANG_WEB
if (spvVersion.vulkan == 0)
warn(loc, "assuming binding count of one for compile-time checking of binding numbers for unsized array", "[]", "");
+#endif
}
}
}
+#ifndef GLSLANG_WEB
if (spvVersion.vulkan == 0 && lastBinding >= resources.maxCombinedTextureImageUnits)
error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : "");
+#endif
}
- if (type.getBasicType() == EbtAtomicUint) {
+ if (type.isAtomic()) {
if (qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) {
error(loc, "atomic_uint binding is too large; see gl_MaxAtomicCounterBindings", "binding", "");
return;
@@ -5667,18 +5749,16 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
// some types require bindings
// atomic_uint
- if (type.getBasicType() == EbtAtomicUint)
+ if (type.isAtomic())
error(loc, "layout(binding=X) is required", "atomic_uint", "");
// SPIR-V
if (spvVersion.spv > 0) {
if (qualifier.isUniformOrBuffer()) {
- if (type.getBasicType() == EbtBlock && !qualifier.layoutPushConstant &&
-#ifdef NV_EXTENSIONS
- !qualifier.layoutShaderRecordNV &&
-#endif
- !qualifier.layoutAttachment &&
- !qualifier.layoutBufferReference)
+ if (type.getBasicType() == EbtBlock && !qualifier.isPushConstant() &&
+ !qualifier.isShaderRecordNV() &&
+ !qualifier.hasAttachment() &&
+ !qualifier.hasBufferReference())
error(loc, "uniform/buffer blocks require layout(binding=X)", "binding", "");
else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler)
error(loc, "sampler/texture/image requires layout(binding=X)", "binding", "");
@@ -5703,40 +5783,38 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
// Image format
if (qualifier.hasFormat()) {
if (! type.isImage())
- error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+ error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
else {
- if (type.getSampler().type == EbtFloat && qualifier.layoutFormat > ElfFloatGuard)
- error(loc, "does not apply to floating point images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
- if (type.getSampler().type == EbtInt && (qualifier.layoutFormat < ElfFloatGuard || qualifier.layoutFormat > ElfIntGuard))
- error(loc, "does not apply to signed integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
- if (type.getSampler().type == EbtUint && qualifier.layoutFormat < ElfIntGuard)
- error(loc, "does not apply to unsigned integer images", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
-
- if (profile == EEsProfile) {
+ if (type.getSampler().type == EbtFloat && qualifier.getFormat() > ElfFloatGuard)
+ error(loc, "does not apply to floating point images", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
+ if (type.getSampler().type == EbtInt && (qualifier.getFormat() < ElfFloatGuard || qualifier.getFormat() > ElfIntGuard))
+ error(loc, "does not apply to signed integer images", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
+ if (type.getSampler().type == EbtUint && qualifier.getFormat() < ElfIntGuard)
+ error(loc, "does not apply to unsigned integer images", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
+
+ if (isEsProfile()) {
// "Except for image variables qualified with the format qualifiers r32f, r32i, and r32ui, image variables must
// specify either memory qualifier readonly or the memory qualifier writeonly."
- if (! (qualifier.layoutFormat == ElfR32f || qualifier.layoutFormat == ElfR32i || qualifier.layoutFormat == ElfR32ui)) {
- if (! qualifier.readonly && ! qualifier.writeonly)
- error(loc, "format requires readonly or writeonly memory qualifier", TQualifier::getLayoutFormatString(qualifier.layoutFormat), "");
+ if (! (qualifier.getFormat() == ElfR32f || qualifier.getFormat() == ElfR32i || qualifier.getFormat() == ElfR32ui)) {
+ if (! qualifier.isReadOnly() && ! qualifier.isWriteOnly())
+ error(loc, "format requires readonly or writeonly memory qualifier", TQualifier::getLayoutFormatString(qualifier.getFormat()), "");
}
}
}
- } else if (type.isImage() && ! qualifier.writeonly) {
+ } else if (type.isImage() && ! qualifier.isWriteOnly()) {
const char *explanation = "image variables not declared 'writeonly' and without a format layout qualifier";
requireProfile(loc, ECoreProfile | ECompatibilityProfile, explanation);
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shader_image_load_formatted, explanation);
}
- if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock)
+ if (qualifier.isPushConstant() && type.getBasicType() != EbtBlock)
error(loc, "can only be used with a block", "push_constant", "");
- if (qualifier.layoutBufferReference && type.getBasicType() != EbtBlock)
+ if (qualifier.hasBufferReference() && type.getBasicType() != EbtBlock)
error(loc, "can only be used with a block", "buffer_reference", "");
-#ifdef NV_EXTENSIONS
- if (qualifier.layoutShaderRecordNV && type.getBasicType() != EbtBlock)
+ if (qualifier.isShaderRecordNV() && type.getBasicType() != EbtBlock)
error(loc, "can only be used with a block", "shaderRecordNV", "");
-#endif
// input attachment
if (type.isSubpass()) {
@@ -5793,10 +5871,11 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
// output block declarations, and output block member declarations."
switch (qualifier.storage) {
+#ifndef GLSLANG_WEB
case EvqVaryingIn:
{
const char* feature = "location qualifier on input";
- if (profile == EEsProfile && version < 310)
+ if (isEsProfile() && version < 310)
requireStage(loc, EShLangVertex, feature);
else
requireStage(loc, (EShLanguageMask)~EShLangComputeMask, feature);
@@ -5813,7 +5892,7 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
case EvqVaryingOut:
{
const char* feature = "location qualifier on output";
- if (profile == EEsProfile && version < 310)
+ if (isEsProfile() && version < 310)
requireStage(loc, EShLangFragment, feature);
else
requireStage(loc, (EShLanguageMask)~EShLangComputeMask, feature);
@@ -5827,12 +5906,14 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
}
break;
}
+#endif
case EvqUniform:
case EvqBuffer:
{
const char* feature = "location qualifier on uniform or buffer";
- requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
- profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, nullptr, feature);
+ requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile | ENoProfile, feature);
+ profileRequires(loc, ~EEsProfile, 330, E_GL_ARB_explicit_attrib_location, feature);
+ profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_explicit_uniform_location, feature);
profileRequires(loc, EEsProfile, 310, nullptr, feature);
break;
}
@@ -5867,18 +5948,17 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
error(loc, "offset/align can only be used on a uniform or buffer", "layout", "");
}
}
- if (qualifier.layoutPushConstant) {
+ if (qualifier.isPushConstant()) {
if (qualifier.storage != EvqUniform)
error(loc, "can only be used with a uniform", "push_constant", "");
if (qualifier.hasSet())
error(loc, "cannot be used with push_constant", "set", "");
}
- if (qualifier.layoutBufferReference) {
+ if (qualifier.hasBufferReference()) {
if (qualifier.storage != EvqBuffer)
error(loc, "can only be used with buffer", "buffer_reference", "");
}
-#ifdef NV_EXTENSIONS
- if (qualifier.layoutShaderRecordNV) {
+ if (qualifier.isShaderRecordNV()) {
if (qualifier.storage != EvqBuffer)
error(loc, "can only be used with a buffer", "shaderRecordNV", "");
if (qualifier.hasBinding())
@@ -5890,12 +5970,12 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
if (qualifier.storage == EvqHitAttrNV && qualifier.hasLayout()) {
error(loc, "cannot apply layout qualifiers to hitAttributeNV variable", "hitAttributeNV", "");
}
-#endif
}
// For places that can't have shader-level layout qualifiers
void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQualifiers& shaderQualifiers)
{
+#ifndef GLSLANG_WEB
const char* message = "can only apply to a standalone qualifier";
if (shaderQualifiers.geometry != ElgNone)
@@ -5908,10 +5988,6 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua
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", "");
@@ -5919,36 +5995,38 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua
error(loc, message, "local_size id", "");
}
if (shaderQualifiers.vertices != TQualifier::layoutNotSet) {
- if (language == EShLangGeometry
-#ifdef NV_EXTENSIONS
- || language == EShLangMeshNV
-#endif
- )
+ if (language == EShLangGeometry || language == EShLangMeshNV)
error(loc, message, "max_vertices", "");
else if (language == EShLangTessControl)
error(loc, message, "vertices", "");
else
assert(0);
}
-#ifdef NV_EXTENSIONS
+ if (shaderQualifiers.earlyFragmentTests)
+ error(loc, message, "early_fragment_tests", "");
+ if (shaderQualifiers.postDepthCoverage)
+ error(loc, message, "post_depth_coverage", "");
if (shaderQualifiers.primitives != TQualifier::layoutNotSet) {
if (language == EShLangMeshNV)
error(loc, message, "max_primitives", "");
else
assert(0);
}
-#endif
- if (shaderQualifiers.blendEquation)
+ if (shaderQualifiers.hasBlendEquation())
error(loc, message, "blend equation", "");
if (shaderQualifiers.numViews != TQualifier::layoutNotSet)
error(loc, message, "num_views", "");
+ if (shaderQualifiers.interlockOrdering != EioNone)
+ error(loc, message, TQualifier::getInterlockOrderingString(shaderQualifiers.interlockOrdering), "");
+#endif
}
// Correct and/or advance an object's offset layout qualifier.
void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol)
{
const TQualifier& qualifier = symbol.getType().getQualifier();
- if (symbol.getType().getBasicType() == EbtAtomicUint) {
+#ifndef GLSLANG_WEB
+ if (symbol.getType().isAtomic()) {
if (qualifier.hasBinding() && (int)qualifier.layoutBinding < resources.maxAtomicCounterBindings) {
// Set the offset
@@ -5957,6 +6035,10 @@ void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol)
offset = qualifier.layoutOffset;
else
offset = atomicUintOffsets[qualifier.layoutBinding];
+
+ if (offset % 4 != 0)
+ error(loc, "atomic counters offset should align based on 4:", "offset", "%d", offset);
+
symbol.getWritableType().getQualifier().layoutOffset = offset;
// Check for overlap
@@ -5977,6 +6059,7 @@ void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol)
atomicUintOffsets[qualifier.layoutBinding] = offset + numOffsets;
}
}
+#endif
}
//
@@ -5986,13 +6069,16 @@ void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol)
//
const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn)
{
- const TFunction* function = nullptr;
-
if (symbolTable.isFunctionNameVariable(call.getName())) {
error(loc, "can't use function syntax on variable", call.getName().c_str(), "");
return nullptr;
}
+#ifdef GLSLANG_WEB
+ return findFunctionExact(loc, call, builtIn);
+#endif
+
+ const TFunction* function = nullptr;
bool explicitTypesEnabled = extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types) ||
extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_int8) ||
extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_int16) ||
@@ -6002,10 +6088,10 @@ const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunct
extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float32) ||
extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float64);
- if (profile == EEsProfile || version < 120)
+ if (isEsProfile() || version < 120)
function = findFunctionExact(loc, call, builtIn);
else if (version < 400)
- function = findFunction120(loc, call, builtIn);
+ function = extensionTurnedOn(E_GL_ARB_gpu_shader_fp64) ? findFunction400(loc, call, builtIn) : findFunction120(loc, call, builtIn);
else if (explicitTypesEnabled)
function = findFunctionExplicitTypes(loc, call, builtIn);
else
@@ -6164,6 +6250,8 @@ const TFunction* TParseContext::findFunction400(const TSourceLoc& loc, const TFu
}
if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
return false;
+ if (from.isCoopMat() && to.isCoopMat())
+ return from.sameCoopMatBaseType(to);
return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType());
};
@@ -6238,6 +6326,8 @@ const TFunction* TParseContext::findFunctionExplicitTypes(const TSourceLoc& loc,
}
if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
return false;
+ if (from.isCoopMat() && to.isCoopMat())
+ return from.sameCoopMatBaseType(to);
return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType());
};
@@ -6289,21 +6379,26 @@ const TFunction* TParseContext::findFunctionExplicitTypes(const TSourceLoc& loc,
return bestMatch;
}
-// When a declaration includes a type, but not a variable name, it can be
+// When a declaration includes a type, but not a variable name, it can be used
// to establish defaults.
void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType& publicType)
{
- if (publicType.basicType == EbtAtomicUint && publicType.qualifier.hasBinding() && publicType.qualifier.hasOffset()) {
+#ifndef GLSLANG_WEB
+ if (publicType.basicType == EbtAtomicUint && publicType.qualifier.hasBinding()) {
if (publicType.qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) {
error(loc, "atomic_uint binding is too large", "binding", "");
return;
}
- atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset;
+
+ if(publicType.qualifier.hasOffset()) {
+ atomicUintOffsets[publicType.qualifier.layoutBinding] = publicType.qualifier.layoutOffset;
+ }
return;
}
- if (publicType.qualifier.hasLayout() && !publicType.qualifier.layoutBufferReference)
+ if (publicType.qualifier.hasLayout() && !publicType.qualifier.hasBufferReference())
warn(loc, "useless application of layout qualifier", "layout", "");
+#endif
}
//
@@ -6334,12 +6429,20 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
if (!publicType.typeParameters || publicType.typeParameters->getNumDims() != 4) {
error(loc, "expected four type parameters", identifier.c_str(), "");
}
- if (publicType.typeParameters &&
- publicType.typeParameters->getDimSize(0) != 16 &&
- publicType.typeParameters->getDimSize(0) != 32 &&
- publicType.typeParameters->getDimSize(0) != 64) {
- error(loc, "expected 16, 32, or 64 bits for first type parameter", identifier.c_str(), "");
+ if (publicType.typeParameters) {
+ if (isTypeFloat(publicType.basicType) &&
+ publicType.typeParameters->getDimSize(0) != 16 &&
+ publicType.typeParameters->getDimSize(0) != 32 &&
+ publicType.typeParameters->getDimSize(0) != 64) {
+ error(loc, "expected 16, 32, or 64 bits for first type parameter", identifier.c_str(), "");
+ }
+ if (isTypeInt(publicType.basicType) &&
+ publicType.typeParameters->getDimSize(0) != 8 &&
+ publicType.typeParameters->getDimSize(0) != 32) {
+ error(loc, "expected 8 or 32 bits for first type parameter", identifier.c_str(), "");
+ }
}
+
} else {
if (publicType.typeParameters && publicType.typeParameters->getNumDims() != 0) {
error(loc, "unexpected type parameters", identifier.c_str(), "");
@@ -6355,17 +6458,18 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
nonInitConstCheck(loc, identifier, type);
samplerCheck(loc, type, identifier, initializer);
- atomicUintCheck(loc, type, identifier);
transparentOpaqueCheck(loc, type, identifier);
-#ifdef NV_EXTENSIONS
+#ifndef GLSLANG_WEB
+ atomicUintCheck(loc, type, identifier);
accStructNVCheck(loc, type, identifier);
+ checkAndResizeMeshViewDim(loc, type, /*isBlockMember*/ false);
#endif
- if (type.getQualifier().storage == EvqConst && type.containsBasicType(EbtReference)) {
+ if (type.getQualifier().storage == EvqConst && type.containsReference()) {
error(loc, "variables with reference type can't have qualifier 'const'", "qualifier", "");
}
if (type.getQualifier().storage != EvqUniform && type.getQualifier().storage != EvqBuffer) {
- if (type.containsBasicType(EbtFloat16))
+ if (type.contains16BitFloat())
requireFloat16Arithmetic(loc, "qualifier", "float16 types can only be in uniform block or buffer storage");
if (type.contains16BitInt())
requireInt16Arithmetic(loc, "qualifier", "(u)int16 types can only be in uniform block or buffer storage");
@@ -6373,13 +6477,12 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
requireInt8Arithmetic(loc, "qualifier", "(u)int8 types can only be in uniform block or buffer storage");
}
- if (type.getQualifier().storage == EvqShared &&
- type.containsCoopMat())
+ if (type.getQualifier().storage == EvqShared && type.containsCoopMat())
error(loc, "qualifier", "Cooperative matrix types must not be used in shared memory", "");
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", "");
- if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.layoutDepth != EldNone)
+ if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.getDepth() != EldNone)
error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", "");
// Check for redeclaration of built-ins and/or attempting to declare a reserved name
@@ -6435,12 +6538,14 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
// Pick up global defaults from the provide global defaults into dst.
void TParseContext::inheritGlobalDefaults(TQualifier& dst) const
{
+#ifndef GLSLANG_WEB
if (dst.storage == EvqVaryingOut) {
if (! dst.hasStream() && language == EShLangGeometry)
dst.layoutStream = globalOutputDefaults.layoutStream;
if (! dst.hasXfbBuffer())
dst.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer;
}
+#endif
}
//
@@ -6469,7 +6574,9 @@ TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, const TString&
// make a new variable
TVariable* variable = new TVariable(&identifier, type);
+#ifndef GLSLANG_WEB
ioArrayCheck(loc, type, identifier);
+#endif
// add variable to symbol table
if (symbolTable.insert(*variable)) {
@@ -6496,7 +6603,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
//
TStorageQualifier qualifier = variable->getType().getQualifier().storage;
if (! (qualifier == EvqTemporary || qualifier == EvqGlobal || qualifier == EvqConst ||
- (qualifier == EvqUniform && profile != EEsProfile && version >= 120))) {
+ (qualifier == EvqUniform && !isEsProfile() && version >= 120))) {
error(loc, " cannot initialize this type of qualifier ", variable->getType().getStorageQualifierString(), "");
return nullptr;
}
@@ -6514,7 +6621,9 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
TType skeletalType;
skeletalType.shallowCopy(variable->getType());
skeletalType.getQualifier().makeTemporary();
+#ifndef GLSLANG_WEB
initializer = convertInitializerList(loc, skeletalType, initializer);
+#endif
if (! initializer) {
// error recovery; don't leave const without constant values
if (qualifier == EvqConst)
@@ -6568,7 +6677,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
// qualifier any initializer must be a constant expression."
if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
const char* initFeature = "non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)";
- if (profile == EEsProfile) {
+ if (isEsProfile()) {
if (relaxedErrors() && ! extensionTurnedOn(E_GL_EXT_shader_non_constant_global_initializers))
warn(loc, "not allowed in this version", initFeature, "");
else
@@ -6819,7 +6928,7 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
// This avoids requesting a matrix of a new type that is going to be discarded anyway.
// TODO: This could be generalized to more type combinations, but that would require
// more extensive testing and full algorithm rework. For now, the need to do two changes makes
- // the recursive call work, and avoids the most aggregious case of creating integer matrices.
+ // the recursive call work, and avoids the most egregious case of creating integer matrices.
if (node->getType().isMatrix() && (type.isScalar() || type.isVector()) &&
type.isFloatingDomain() != node->getType().isFloatingDomain()) {
TType transitionType(node->getBasicType(), glslang::EvqTemporary, type.getVectorSize(), 0, 0, node->isVector());
@@ -6850,6 +6959,35 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
basicOp = EOpConstructFloat;
break;
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ basicOp = EOpConstructInt;
+ break;
+
+ case EOpConstructUVec2:
+ if (node->getType().getBasicType() == EbtReference) {
+ requireExtensions(loc, 1, &E_GL_EXT_buffer_reference_uvec2, "reference conversion to uvec2");
+ TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvPtrToUvec2, true, node,
+ type);
+ return newNode;
+ }
+ case EOpConstructUVec3:
+ case EOpConstructUVec4:
+ case EOpConstructUint:
+ basicOp = EOpConstructUint;
+ break;
+
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ basicOp = EOpConstructBool;
+ break;
+
+#ifndef GLSLANG_WEB
+
case EOpConstructDVec2:
case EOpConstructDVec3:
case EOpConstructDVec4:
@@ -6880,6 +7018,22 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
case EOpConstructF16Mat4x4:
case EOpConstructFloat16:
basicOp = EOpConstructFloat16;
+ // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types,
+ // so construct a 32-bit type and convert
+ if (!intermediate.getArithemeticFloat16Enabled()) {
+ TType tempType(EbtFloat, EvqTemporary, type.getVectorSize());
+ newNode = node;
+ if (tempType != newNode->getType()) {
+ TOperator aggregateOp;
+ if (op == EOpConstructFloat16)
+ aggregateOp = EOpConstructFloat;
+ else
+ aggregateOp = (TOperator)(EOpConstructVec2 + op - EOpConstructF16Vec2);
+ newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
+ }
+ newNode = intermediate.addConversion(EbtFloat16, newNode);
+ return newNode;
+ }
break;
case EOpConstructI8Vec2:
@@ -6887,6 +7041,22 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
case EOpConstructI8Vec4:
case EOpConstructInt8:
basicOp = EOpConstructInt8;
+ // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types,
+ // so construct a 32-bit type and convert
+ if (!intermediate.getArithemeticInt8Enabled()) {
+ TType tempType(EbtInt, EvqTemporary, type.getVectorSize());
+ newNode = node;
+ if (tempType != newNode->getType()) {
+ TOperator aggregateOp;
+ if (op == EOpConstructInt8)
+ aggregateOp = EOpConstructInt;
+ else
+ aggregateOp = (TOperator)(EOpConstructIVec2 + op - EOpConstructI8Vec2);
+ newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
+ }
+ newNode = intermediate.addConversion(EbtInt8, newNode);
+ return newNode;
+ }
break;
case EOpConstructU8Vec2:
@@ -6894,6 +7064,22 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
case EOpConstructU8Vec4:
case EOpConstructUint8:
basicOp = EOpConstructUint8;
+ // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types,
+ // so construct a 32-bit type and convert
+ if (!intermediate.getArithemeticInt8Enabled()) {
+ TType tempType(EbtUint, EvqTemporary, type.getVectorSize());
+ newNode = node;
+ if (tempType != newNode->getType()) {
+ TOperator aggregateOp;
+ if (op == EOpConstructUint8)
+ aggregateOp = EOpConstructUint;
+ else
+ aggregateOp = (TOperator)(EOpConstructUVec2 + op - EOpConstructU8Vec2);
+ newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
+ }
+ newNode = intermediate.addConversion(EbtUint8, newNode);
+ return newNode;
+ }
break;
case EOpConstructI16Vec2:
@@ -6901,6 +7087,22 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
case EOpConstructI16Vec4:
case EOpConstructInt16:
basicOp = EOpConstructInt16;
+ // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types,
+ // so construct a 32-bit type and convert
+ if (!intermediate.getArithemeticInt16Enabled()) {
+ TType tempType(EbtInt, EvqTemporary, type.getVectorSize());
+ newNode = node;
+ if (tempType != newNode->getType()) {
+ TOperator aggregateOp;
+ if (op == EOpConstructInt16)
+ aggregateOp = EOpConstructInt;
+ else
+ aggregateOp = (TOperator)(EOpConstructIVec2 + op - EOpConstructI16Vec2);
+ newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
+ }
+ newNode = intermediate.addConversion(EbtInt16, newNode);
+ return newNode;
+ }
break;
case EOpConstructU16Vec2:
@@ -6908,20 +7110,22 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
case EOpConstructU16Vec4:
case EOpConstructUint16:
basicOp = EOpConstructUint16;
- break;
-
- case EOpConstructIVec2:
- case EOpConstructIVec3:
- case EOpConstructIVec4:
- case EOpConstructInt:
- basicOp = EOpConstructInt;
- break;
-
- case EOpConstructUVec2:
- case EOpConstructUVec3:
- case EOpConstructUVec4:
- case EOpConstructUint:
- basicOp = EOpConstructUint;
+ // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types,
+ // so construct a 32-bit type and convert
+ if (!intermediate.getArithemeticInt16Enabled()) {
+ TType tempType(EbtUint, EvqTemporary, type.getVectorSize());
+ newNode = node;
+ if (tempType != newNode->getType()) {
+ TOperator aggregateOp;
+ if (op == EOpConstructUint16)
+ aggregateOp = EOpConstructUint;
+ else
+ aggregateOp = (TOperator)(EOpConstructUVec2 + op - EOpConstructU16Vec2);
+ newNode = intermediate.setAggregateOperator(newNode, aggregateOp, tempType, node->getLoc());
+ }
+ newNode = intermediate.addConversion(EbtUint16, newNode);
+ return newNode;
+ }
break;
case EOpConstructI64Vec2:
@@ -6932,7 +7136,7 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
break;
case EOpConstructUint64:
- if (type.isScalar() && node->getType().getBasicType() == EbtReference) {
+ if (type.isScalar() && node->getType().isReference()) {
TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvPtrToUint64, true, node, type);
return newNode;
}
@@ -6943,27 +7147,27 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
basicOp = EOpConstructUint64;
break;
- case EOpConstructBVec2:
- case EOpConstructBVec3:
- case EOpConstructBVec4:
- case EOpConstructBool:
- basicOp = EOpConstructBool;
- break;
-
case EOpConstructNonuniform:
// Make a nonuniform copy of node
- newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpCopyObject, true, node, node->getType());
- newNode->getWritableType().getQualifier().nonUniform = true;
+ newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpCopyObject, true, node, type);
return newNode;
case EOpConstructReference:
// construct reference from reference
- if (node->getType().getBasicType() == EbtReference) {
+ if (node->getType().isReference()) {
newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConstructReference, true, node, type);
return newNode;
// construct reference from uint64
} else if (node->getType().isScalar() && node->getType().getBasicType() == EbtUint64) {
- TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUint64ToPtr, true, node, type);
+ TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUint64ToPtr, true, node,
+ type);
+ return newNode;
+ // construct reference from uvec2
+ } else if (node->getType().isVector() && node->getType().getBasicType() == EbtUint &&
+ node->getVectorSize() == 2) {
+ requireExtensions(loc, 1, &E_GL_EXT_buffer_reference_uvec2, "uvec2 conversion to reference");
+ TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUvec2ToPtr, true, node,
+ type);
return newNode;
} else {
return nullptr;
@@ -6976,19 +7180,75 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
}
node = intermediate.setAggregateOperator(node, EOpConstructCooperativeMatrix, type, node->getLoc());
} else {
+ TOperator op = EOpNull;
switch (type.getBasicType()) {
default:
assert(0);
break;
+ case EbtInt:
+ switch (node->getType().getBasicType()) {
+ case EbtFloat: op = EOpConvFloatToInt; break;
+ case EbtFloat16: op = EOpConvFloat16ToInt; break;
+ case EbtUint8: op = EOpConvUint8ToInt; break;
+ case EbtInt8: op = EOpConvInt8ToInt; break;
+ case EbtUint: op = EOpConvUintToInt; break;
+ default: assert(0);
+ }
+ break;
+ case EbtUint:
+ switch (node->getType().getBasicType()) {
+ case EbtFloat: op = EOpConvFloatToUint; break;
+ case EbtFloat16: op = EOpConvFloat16ToUint; break;
+ case EbtUint8: op = EOpConvUint8ToUint; break;
+ case EbtInt8: op = EOpConvInt8ToUint; break;
+ case EbtInt: op = EOpConvIntToUint; break;
+ case EbtUint: op = EOpConvUintToInt8; break;
+ default: assert(0);
+ }
+ break;
+ case EbtInt8:
+ switch (node->getType().getBasicType()) {
+ case EbtFloat: op = EOpConvFloatToInt8; break;
+ case EbtFloat16: op = EOpConvFloat16ToInt8; break;
+ case EbtUint8: op = EOpConvUint8ToInt8; break;
+ case EbtInt: op = EOpConvIntToInt8; break;
+ case EbtUint: op = EOpConvUintToInt8; break;
+ default: assert(0);
+ }
+ break;
+ case EbtUint8:
+ switch (node->getType().getBasicType()) {
+ case EbtFloat: op = EOpConvFloatToUint8; break;
+ case EbtFloat16: op = EOpConvFloat16ToUint8; break;
+ case EbtInt8: op = EOpConvInt8ToUint8; break;
+ case EbtInt: op = EOpConvIntToUint8; break;
+ case EbtUint: op = EOpConvUintToUint8; break;
+ default: assert(0);
+ }
+ break;
case EbtFloat:
- assert(node->getType().getBasicType() == EbtFloat16);
- node = intermediate.addUnaryNode(EOpConvFloat16ToFloat, node, node->getLoc(), type);
+ switch (node->getType().getBasicType()) {
+ case EbtFloat16: op = EOpConvFloat16ToFloat; break;
+ case EbtInt8: op = EOpConvInt8ToFloat; break;
+ case EbtUint8: op = EOpConvUint8ToFloat; break;
+ case EbtInt: op = EOpConvIntToFloat; break;
+ case EbtUint: op = EOpConvUintToFloat; break;
+ default: assert(0);
+ }
break;
case EbtFloat16:
- assert(node->getType().getBasicType() == EbtFloat);
- node = intermediate.addUnaryNode(EOpConvFloatToFloat16, node, node->getLoc(), type);
+ switch (node->getType().getBasicType()) {
+ case EbtFloat: op = EOpConvFloatToFloat16; break;
+ case EbtInt8: op = EOpConvInt8ToFloat16; break;
+ case EbtUint8: op = EOpConvUint8ToFloat16; break;
+ case EbtInt: op = EOpConvIntToFloat16; break;
+ case EbtUint: op = EOpConvUintToFloat16; break;
+ default: assert(0);
+ }
break;
}
+
+ node = intermediate.addUnaryNode(op, node, node->getLoc(), type);
// If it's a (non-specialization) constant, it must be folded.
if (node->getAsUnaryNode()->getOperand()->getAsConstantUnion())
return node->getAsUnaryNode()->getOperand()->getAsConstantUnion()->fold(op, node->getType());
@@ -6996,6 +7256,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
return node;
+#endif // GLSLANG_WEB
+
default:
error(loc, "unsupported construction", "", "");
@@ -7037,6 +7299,23 @@ TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType&
return converted;
}
+// If a memory qualifier is present in 'to', also make it present in 'from'.
+void TParseContext::inheritMemoryQualifiers(const TQualifier& from, TQualifier& to)
+{
+#ifndef GLSLANG_WEB
+ if (from.isReadOnly())
+ to.readonly = from.readonly;
+ if (from.isWriteOnly())
+ to.writeonly = from.writeonly;
+ if (from.coherent)
+ to.coherent = from.coherent;
+ if (from.volatil)
+ to.volatil = from.volatil;
+ if (from.restrict)
+ to.restrict = from.restrict;
+#endif
+}
+
//
// Do everything needed to add an interface block.
//
@@ -7052,7 +7331,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
requireProfile(loc, ~EEsProfile, "array-of-array of block");
}
- // fix and check for member storage qualifiers and types that don't belong within a block
+ // Inherit and check member storage qualifiers WRT to the block-level qualifier.
for (unsigned int member = 0; member < typeList.size(); ++member) {
TType& memberType = *typeList[member].type;
TQualifier& memberQualifier = memberType.getQualifier();
@@ -7061,7 +7340,8 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
if (memberQualifier.storage != EvqTemporary && memberQualifier.storage != EvqGlobal && memberQualifier.storage != currentBlockQualifier.storage)
error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), "");
memberQualifier.storage = currentBlockQualifier.storage;
-#ifdef NV_EXTENSIONS
+#ifndef GLSLANG_WEB
+ inheritMemoryQualifiers(currentBlockQualifier, memberQualifier);
if (currentBlockQualifier.perPrimitiveNV)
memberQualifier.perPrimitiveNV = currentBlockQualifier.perPrimitiveNV;
if (currentBlockQualifier.perViewNV)
@@ -7114,18 +7394,13 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
// Special case for "push_constant uniform", which has a default of std430,
// contrary to normal uniform defaults, and can't have a default tracked for it.
- if ((currentBlockQualifier.layoutPushConstant && !currentBlockQualifier.hasPacking())
-#ifdef NV_EXTENSIONS
- || (currentBlockQualifier.layoutShaderRecordNV && !currentBlockQualifier.hasPacking())
-#endif
- )
+ if ((currentBlockQualifier.isPushConstant() && !currentBlockQualifier.hasPacking()) ||
+ (currentBlockQualifier.isShaderRecordNV() && !currentBlockQualifier.hasPacking()))
currentBlockQualifier.layoutPacking = ElpStd430;
-#ifdef NV_EXTENSIONS
// Special case for "taskNV in/out", which has a default of std430,
- if (currentBlockQualifier.perTaskNV && !currentBlockQualifier.hasPacking())
+ if (currentBlockQualifier.isTaskMemory() && !currentBlockQualifier.hasPacking())
currentBlockQualifier.layoutPacking = ElpStd430;
-#endif
// fix and check for member layout qualifiers
@@ -7143,12 +7418,11 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
bool memberWithLocation = false;
bool memberWithoutLocation = false;
-#ifdef NV_EXTENSIONS
bool memberWithPerViewQualifier = false;
-#endif
for (unsigned int member = 0; member < typeList.size(); ++member) {
TQualifier& memberQualifier = typeList[member].type->getQualifier();
const TSourceLoc& memberLoc = typeList[member].loc;
+#ifndef GLSLANG_WEB
if (memberQualifier.hasStream()) {
if (defaultQualification.layoutStream != memberQualifier.layoutStream)
error(memberLoc, "member cannot contradict block", "stream", "");
@@ -7162,12 +7436,14 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
if (defaultQualification.layoutXfbBuffer != memberQualifier.layoutXfbBuffer)
error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_buffer", "");
}
+#endif
if (memberQualifier.hasPacking())
error(memberLoc, "member of block cannot have a packing layout qualifier", typeList[member].type->getFieldName().c_str(), "");
if (memberQualifier.hasLocation()) {
const char* feature = "location on block member";
switch (currentBlockQualifier.storage) {
+#ifndef GLSLANG_WEB
case EvqVaryingIn:
case EvqVaryingOut:
requireProfile(memberLoc, ECoreProfile | ECompatibilityProfile | EEsProfile, feature);
@@ -7175,6 +7451,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
profileRequires(memberLoc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature);
memberWithLocation = true;
break;
+#endif
default:
error(memberLoc, "can only use in an in/out block", feature, "");
break;
@@ -7191,11 +7468,9 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
error(memberLoc, "can only be used with std140, std430, or scalar layout packing", "offset/align", "");
}
-#ifdef NV_EXTENSIONS
if (memberQualifier.isPerView()) {
memberWithPerViewQualifier = true;
}
-#endif
TQualifier newMemberQualification = defaultQualification;
mergeQualifiers(memberLoc, newMemberQualification, memberQualifier, false);
@@ -7204,6 +7479,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
layoutMemberLocationArrayCheck(loc, memberWithLocation, arraySizes);
+#ifndef GLSLANG_WEB
// Ensure that the block has an XfbBuffer assigned. This is needed
// because if the block has a XfbOffset assigned, then it is
// assumed that it has implicitly assigned the current global
@@ -7213,6 +7489,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
if (!currentBlockQualifier.hasXfbBuffer() && currentBlockQualifier.hasXfbOffset())
currentBlockQualifier.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer;
}
+#endif
// Process the members
fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation);
@@ -7221,10 +7498,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
for (unsigned int member = 0; member < typeList.size(); ++member)
layoutTypeCheck(typeList[member].loc, *typeList[member].type);
-#ifdef NV_EXTENSIONS
+#ifndef GLSLANG_WEB
if (memberWithPerViewQualifier) {
for (unsigned int member = 0; member < typeList.size(); ++member) {
- resizeMeshViewDimension(typeList[member].loc, *typeList[member].type);
+ checkAndResizeMeshViewDim(typeList[member].loc, *typeList[member].type, /*isBlockMember*/ true);
}
}
#endif
@@ -7240,10 +7517,11 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
TType blockType(&typeList, *blockName, currentBlockQualifier);
if (arraySizes != nullptr)
blockType.transferArraySizes(arraySizes);
- else
- ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName);
- if (currentBlockQualifier.layoutBufferReference) {
+#ifndef GLSLANG_WEB
+ if (arraySizes == nullptr)
+ ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName);
+ if (currentBlockQualifier.hasBufferReference()) {
if (currentBlockQualifier.storage != EvqBuffer)
error(loc, "can only be used with buffer", "buffer_reference", "");
@@ -7255,7 +7533,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
TVariable* blockNameVar = new TVariable(blockName, blockNameType, true);
if (! symbolTable.insert(*blockNameVar)) {
TSymbol* existingName = symbolTable.find(*blockName);
- if (existingName->getType().getBasicType() == EbtReference &&
+ if (existingName->getType().isReference() &&
existingName->getType().getReferentType()->getStruct() &&
existingName->getType().getReferentType()->getStruct()->size() == 0 &&
existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
@@ -7267,7 +7545,9 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
if (!instanceName) {
return;
}
- } else {
+ } else
+#endif
+ {
//
// Don't make a user-defined type out of block name; that will cause an error
// if the same block name gets reused in a different interface.
@@ -7315,12 +7595,14 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
// Check for general layout qualifier errors
layoutObjectCheck(loc, variable);
+#ifndef GLSLANG_WEB
// fix up
if (isIoResizeArray(blockType)) {
ioArraySymbolResizeList.push_back(&variable);
checkIoArraysConsistency(loc, true);
} else
fixIoArraySize(loc, variable.getWritableType());
+#endif
// Save it in the AST for linker use.
trackLinkage(variable);
@@ -7333,8 +7615,8 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q
switch (qualifier.storage) {
case EvqUniform:
profileRequires(loc, EEsProfile, 300, nullptr, "uniform block");
- profileRequires(loc, ENoProfile, 140, nullptr, "uniform block");
- if (currentBlockQualifier.layoutPacking == ElpStd430 && ! currentBlockQualifier.layoutPushConstant)
+ profileRequires(loc, ENoProfile, 140, E_GL_ARB_uniform_buffer_object, "uniform block");
+ if (currentBlockQualifier.layoutPacking == ElpStd430 && ! currentBlockQualifier.isPushConstant())
requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "std430 requires the buffer storage qualifier");
break;
case EvqBuffer:
@@ -7346,41 +7628,28 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q
profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "input block");
// It is a compile-time error to have an input block in a vertex shader or an output block in a fragment shader
// "Compute shaders do not permit user-defined input variables..."
- requireStage(loc, (EShLanguageMask)(EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask|EShLangFragmentMask
-#ifdef NV_EXTENSIONS
- |EShLangMeshNVMask
-#endif
- ), "input block");
+ requireStage(loc, (EShLanguageMask)(EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask|
+ EShLangFragmentMask|EShLangMeshNVMask), "input block");
if (language == EShLangFragment) {
profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "fragment input block");
- }
-#ifdef NV_EXTENSIONS
- else if (language == EShLangMeshNV && ! qualifier.isTaskMemory()) {
+ } else if (language == EShLangMeshNV && ! qualifier.isTaskMemory()) {
error(loc, "input blocks cannot be used in a mesh shader", "out", "");
}
-#endif
break;
case EvqVaryingOut:
profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "output block");
- requireStage(loc, (EShLanguageMask)(EShLangVertexMask|EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask
-#ifdef NV_EXTENSIONS
- |EShLangMeshNVMask|EShLangTaskNVMask
-#endif
- ), "output block");
+ requireStage(loc, (EShLanguageMask)(EShLangVertexMask|EShLangTessControlMask|EShLangTessEvaluationMask|
+ EShLangGeometryMask|EShLangMeshNVMask|EShLangTaskNVMask), "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, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "vertex output block");
- }
-#ifdef NV_EXTENSIONS
- else if (language == EShLangMeshNV && qualifier.isTaskMemory()) {
+ } else if (language == EShLangMeshNV && qualifier.isTaskMemory()) {
error(loc, "can only use on input blocks in mesh shader", "taskNV", "");
- }
- else if (language == EShLangTaskNV && ! qualifier.isTaskMemory()) {
+ } else if (language == EShLangTaskNV && ! qualifier.isTaskMemory()) {
error(loc, "output blocks cannot be used in a task shader", "out", "");
}
-#endif
break;
-#ifdef NV_EXTENSIONS
+#ifndef GLSLANG_WEB
case EvqPayloadNV:
profileRequires(loc, ~EEsProfile, 460, E_GL_NV_ray_tracing, "rayPayloadNV block");
requireStage(loc, (EShLanguageMask)(EShLangRayGenNVMask | EShLangAnyHitNVMask | EShLangClosestHitNVMask | EShLangMissNVMask),
@@ -7435,18 +7704,16 @@ void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier&
error(loc, "cannot use interpolation qualifiers on an interface block", "flat/smooth/noperspective", "");
if (qualifier.centroid)
error(loc, "cannot use centroid qualifier on an interface block", "centroid", "");
- if (qualifier.sample)
+ if (qualifier.isSample())
error(loc, "cannot use sample qualifier on an interface block", "sample", "");
if (qualifier.invariant)
error(loc, "cannot use invariant qualifier on an interface block", "invariant", "");
- if (qualifier.layoutPushConstant)
+ if (qualifier.isPushConstant())
intermediate.addPushConstantCount();
-#ifdef NV_EXTENSIONS
- if (qualifier.layoutShaderRecordNV)
+ if (qualifier.isShaderRecordNV())
intermediate.addShaderRecordNVCount();
- if (qualifier.perTaskNV)
+ if (qualifier.isTaskMemory())
intermediate.addTaskNVCount();
-#endif
}
//
@@ -7495,6 +7762,7 @@ void TParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifi
void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
{
+#ifndef GLSLANG_WEB
// "If a block is qualified with xfb_offset, all its
// members are assigned transform feedback buffer offsets. If a block is not qualified with xfb_offset, any
// members of that block not qualified with an xfb_offset will not be assigned transform feedback buffer
@@ -7507,24 +7775,18 @@ void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
for (unsigned int member = 0; member < typeList.size(); ++member) {
TQualifier& memberQualifier = typeList[member].type->getQualifier();
bool contains64BitType = false;
-#ifdef AMD_EXTENSIONS
bool contains32BitType = false;
bool contains16BitType = false;
int memberSize = intermediate.computeTypeXfbSize(*typeList[member].type, contains64BitType, contains32BitType, contains16BitType);
-#else
- int memberSize = intermediate.computeTypeXfbSize(*typeList[member].type, contains64BitType);
-#endif
// see if we need to auto-assign an offset to this member
if (! memberQualifier.hasXfbOffset()) {
// "if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8"
if (contains64BitType)
RoundToPow2(nextOffset, 8);
-#ifdef AMD_EXTENSIONS
else if (contains32BitType)
RoundToPow2(nextOffset, 4);
else if (contains16BitType)
RoundToPow2(nextOffset, 2);
-#endif
memberQualifier.layoutXfbOffset = nextOffset;
} else
nextOffset = memberQualifier.layoutXfbOffset;
@@ -7534,6 +7796,7 @@ void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
// The above gave all block members an offset, so we can take it off the block now,
// which will avoid double counting the offset usage.
qualifier.layoutXfbOffset = TQualifier::layoutXfbOffsetEnd;
+#endif
}
// Calculate and save the offset of each block member, using the recursively
@@ -7610,7 +7873,7 @@ void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qua
// a qualifier to an existing symbol. Detect this and create the block reference
// type with an empty type list, which will be filled in later in
// TParseContext::declareBlock.
- if (!symbol && qualifier.layoutBufferReference) {
+ if (!symbol && qualifier.hasBufferReference()) {
TTypeList typeList;
TType blockType(&typeList, identifier, qualifier);;
TType blockNameType(EbtReference, blockType, identifier);
@@ -7650,10 +7913,10 @@ void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qua
error(loc, "cannot change qualification after use", "invariant", "");
symbol->getWritableType().getQualifier().invariant = true;
invariantCheck(loc, symbol->getType().getQualifier());
- } else if (qualifier.noContraction) {
+ } else if (qualifier.isNoContraction()) {
if (intermediate.inIoAccessed(identifier))
error(loc, "cannot change qualification after use", "precise", "");
- symbol->getWritableType().getQualifier().noContraction = true;
+ symbol->getWritableType().getQualifier().setNoContraction();
} else if (qualifier.specConstant) {
symbol->getWritableType().getQualifier().makeSpecConstant();
if (qualifier.hasSpecConstantId())
@@ -7676,7 +7939,7 @@ void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qual
bool pipeOut = qualifier.isPipeOutput();
bool pipeIn = qualifier.isPipeInput();
- if (version >= 300 || (profile != EEsProfile && version >= 420)) {
+ if (version >= 300 || (!isEsProfile() && version >= 420)) {
if (! pipeOut)
error(loc, "can only apply to an output", "invariant", "");
} else {
@@ -7691,12 +7954,9 @@ void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qual
//
void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, const TPublicType& publicType)
{
+#ifndef GLSLANG_WEB
if (publicType.shaderQualifiers.vertices != TQualifier::layoutNotSet) {
-#ifdef NV_EXTENSIONS
assert(language == EShLangTessControl || language == EShLangGeometry || language == EShLangMeshNV);
-#else
- assert(language == EShLangTessControl || language == EShLangGeometry);
-#endif
const char* id = (language == EShLangTessControl) ? "vertices" : "max_vertices";
if (publicType.qualifier.storage != EvqVaryingOut)
@@ -7707,7 +7967,6 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
if (language == EShLangTessControl)
checkIoArraysConsistency(loc);
}
-#ifdef NV_EXTENSIONS
if (publicType.shaderQualifiers.primitives != TQualifier::layoutNotSet) {
assert(language == EShLangMeshNV);
const char* id = "max_primitives";
@@ -7717,7 +7976,6 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
if (! intermediate.setPrimitives(publicType.shaderQualifiers.primitives))
error(loc, "cannot change previously set layout value", id, "");
}
-#endif
if (publicType.shaderQualifiers.invocations != TQualifier::layoutNotSet) {
if (publicType.qualifier.storage != EvqVaryingIn)
error(loc, "can only apply to 'in'", "invocations", "");
@@ -7734,12 +7992,10 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
case ElgTrianglesAdjacency:
case ElgQuads:
case ElgIsolines:
-#ifdef NV_EXTENSIONS
if (language == EShLangMeshNV) {
error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
break;
}
-#endif
if (intermediate.setInputPrimitive(publicType.shaderQualifiers.geometry)) {
if (language == EShLangGeometry)
checkIoArraysConsistency(loc);
@@ -7751,14 +8007,12 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
}
} else if (publicType.qualifier.storage == EvqVaryingOut) {
switch (publicType.shaderQualifiers.geometry) {
-#ifdef NV_EXTENSIONS
case ElgLines:
case ElgTriangles:
if (language != EShLangMeshNV) {
error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
break;
}
-#endif
// Fall through
case ElgPoints:
case ElgLineStrip:
@@ -7792,8 +8046,9 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
else
error(loc, "can only apply to 'in'", "point_mode", "");
}
+#endif
for (int i = 0; i < 3; ++i) {
- if (publicType.shaderQualifiers.localSize[i] > 1) {
+ if (publicType.shaderQualifiers.localSizeNotDefault[i]) {
if (publicType.qualifier.storage == EvqVaryingIn) {
if (! intermediate.setLocalSize(i, publicType.shaderQualifiers.localSize[i]))
error(loc, "cannot change previously set size", "local_size", "");
@@ -7809,7 +8064,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
if (intermediate.getLocalSize(i) > (unsigned int)max)
error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", "");
}
-#ifdef NV_EXTENSIONS
+#ifndef GLSLANG_WEB
else if (language == EShLangMeshNV) {
switch (i) {
case 0: max = resources.maxMeshWorkGroupSizeX_NV; break;
@@ -7819,8 +8074,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
}
if (intermediate.getLocalSize(i) > (unsigned int)max)
error(loc, "too large; see gl_MaxMeshWorkGroupSizeNV", "local_size", "");
- }
- else if (language == EShLangTaskNV) {
+ } else if (language == EShLangTaskNV) {
switch (i) {
case 0: max = resources.maxTaskWorkGroupSizeX_NV; break;
case 1: max = resources.maxTaskWorkGroupSizeY_NV; break;
@@ -7855,6 +8109,8 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
workGroupSize->getWritableType().getQualifier().specConstant = true;
}
}
+
+#ifndef GLSLANG_WEB
if (publicType.shaderQualifiers.earlyFragmentTests) {
if (publicType.qualifier.storage == EvqVaryingIn)
intermediate.setEarlyFragmentTests();
@@ -7867,12 +8123,19 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
else
error(loc, "can only apply to 'in'", "post_coverage_coverage", "");
}
- if (publicType.shaderQualifiers.blendEquation) {
+ if (publicType.shaderQualifiers.hasBlendEquation()) {
if (publicType.qualifier.storage != EvqVaryingOut)
error(loc, "can only apply to 'out'", "blend equation", "");
}
+ if (publicType.shaderQualifiers.interlockOrdering) {
+ if (publicType.qualifier.storage == EvqVaryingIn) {
+ if (!intermediate.setInterlockOrdering(publicType.shaderQualifiers.interlockOrdering))
+ error(loc, "cannot change previously set fragment shader interlock ordering", TQualifier::getInterlockOrderingString(publicType.shaderQualifiers.interlockOrdering), "");
+ }
+ else
+ error(loc, "can only apply to 'in'", TQualifier::getInterlockOrderingString(publicType.shaderQualifiers.interlockOrdering), "");
+ }
-#ifdef NV_EXTENSIONS
if (publicType.shaderQualifiers.layoutDerivativeGroupQuads &&
publicType.shaderQualifiers.layoutDerivativeGroupLinear) {
error(loc, "cannot be both specified", "derivative_group_quadsNV and derivative_group_linearNV", "");
@@ -7917,6 +8180,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
qualifier.isInterpolation() ||
qualifier.precision != EpqNone)
error(loc, "cannot use auxiliary, memory, interpolation, or precision qualifier in a default qualifier declaration (declaration with no type)", "qualifier", "");
+
// "The offset qualifier can only be used on block members of blocks..."
// "The align qualifier can only be used on blocks or block members..."
if (qualifier.hasOffset() ||
@@ -7941,6 +8205,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
case EvqVaryingIn:
break;
case EvqVaryingOut:
+#ifndef GLSLANG_WEB
if (qualifier.hasStream())
globalOutputDefaults.layoutStream = qualifier.layoutStream;
if (qualifier.hasXfbBuffer())
@@ -7949,6 +8214,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
if (! intermediate.setXfbBufferStride(globalOutputDefaults.layoutXfbBuffer, qualifier.layoutXfbStride))
error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer);
}
+#endif
break;
default:
error(loc, "default qualifier requires 'uniform', 'buffer', 'in', or 'out' storage qualification", "", "");
@@ -7961,16 +8227,14 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
error(loc, "cannot declare a default, use a full declaration", "location/component/index", "");
if (qualifier.hasXfbOffset())
error(loc, "cannot declare a default, use a full declaration", "xfb_offset", "");
- if (qualifier.layoutPushConstant)
+ if (qualifier.isPushConstant())
error(loc, "cannot declare a default, can only be used on a block", "push_constant", "");
- if (qualifier.layoutBufferReference)
+ if (qualifier.hasBufferReference())
error(loc, "cannot declare a default, can only be used on a block", "buffer_reference", "");
if (qualifier.hasSpecConstantId())
error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", "");
-#ifdef NV_EXTENSIONS
- if (qualifier.layoutShaderRecordNV)
+ if (qualifier.isShaderRecordNV())
error(loc, "cannot declare a default, can only be used on a block", "shaderRecordNV", "");
-#endif
}
//
@@ -8037,7 +8301,7 @@ TIntermNode* TParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expre
// "it is an error to have no statement between a label and the end of the switch statement."
// The specifications were updated to remove this (being ill-defined what a "statement" was),
// so, this became a warning. However, 3.0 tests still check for the error.
- if (profile == EEsProfile && version <= 300 && ! relaxedErrors())
+ if (isEsProfile() && version <= 300 && ! relaxedErrors())
error(loc, "last case/default label not followed by statements", "switch", "");
else
warn(loc, "last case/default label not followed by statements", "switch", "");