|
|
@@ -491,12 +491,20 @@ void TParseContext::makeEditable(TSymbol*& symbol)
|
|
|
ioArraySymbolResizeList.push_back(symbol);
|
|
|
}
|
|
|
|
|
|
-// Return true if this is a geometry shader input array or tessellation control output array.
|
|
|
+// Return true if this is a geometry shader input array or tessellation control output array
|
|
|
+// or mesh shader output array.
|
|
|
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));
|
|
|
+ (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
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
// If an array is not isIoResizeArray() but is an io array, make sure it has the right size
|
|
|
@@ -546,7 +554,7 @@ void TParseContext::handleIoResizeArrayAccess(const TSourceLoc& /*loc*/, TInterm
|
|
|
|
|
|
// fix array size, if it can be fixed and needs to be fixed (will allow variable indexing)
|
|
|
if (symbolNode->getType().isUnsizedArray()) {
|
|
|
- int newSize = getIoArrayImplicitSize();
|
|
|
+ int newSize = getIoArrayImplicitSize(symbolNode->getType().getQualifier().isPerPrimitive());
|
|
|
if (newSize > 0)
|
|
|
symbolNode->getWritableType().changeOuterArraySize(newSize);
|
|
|
}
|
|
|
@@ -560,17 +568,27 @@ void TParseContext::handleIoResizeArrayAccess(const TSourceLoc& /*loc*/, TInterm
|
|
|
// Types without an array size will be given one.
|
|
|
// Types already having a size that is wrong will get an error.
|
|
|
//
|
|
|
-void TParseContext::checkIoArraysConsistency(const TSourceLoc& loc, bool tailOnly)
|
|
|
+void TParseContext::checkIoArraysConsistency(const TSourceLoc& loc, bool tailOnly, bool isPerPrimitive)
|
|
|
{
|
|
|
- int requiredSize = getIoArrayImplicitSize();
|
|
|
+ int requiredSize = getIoArrayImplicitSize(isPerPrimitive);
|
|
|
if (requiredSize == 0)
|
|
|
return;
|
|
|
|
|
|
const char* feature;
|
|
|
if (language == EShLangGeometry)
|
|
|
feature = TQualifier::getGeometryString(intermediate.getInputPrimitive());
|
|
|
- else if (language == EShLangTessControl)
|
|
|
+ else if (language == EShLangTessControl
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ || language == EShLangFragment
|
|
|
+#endif
|
|
|
+ )
|
|
|
+
|
|
|
feature = "vertices";
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ else if (language == EShLangMeshNV) {
|
|
|
+ feature = isPerPrimitive ? "max_primitives" : "max_vertices";
|
|
|
+ }
|
|
|
+#endif
|
|
|
else
|
|
|
feature = "unknown";
|
|
|
|
|
|
@@ -583,12 +601,24 @@ void TParseContext::checkIoArraysConsistency(const TSourceLoc& loc, bool tailOnl
|
|
|
checkIoArrayConsistency(loc, requiredSize, feature, ioArraySymbolResizeList[i]->getWritableType(), ioArraySymbolResizeList[i]->getName());
|
|
|
}
|
|
|
|
|
|
-int TParseContext::getIoArrayImplicitSize() const
|
|
|
+int TParseContext::getIoArrayImplicitSize(bool isPerPrimitive) const
|
|
|
{
|
|
|
if (language == EShLangGeometry)
|
|
|
return TQualifier::mapGeometryToSize(intermediate.getInputPrimitive());
|
|
|
else if (language == EShLangTessControl)
|
|
|
return intermediate.getVertices() != TQualifier::layoutNotSet ? intermediate.getVertices() : 0;
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ else if (language == EShLangFragment)
|
|
|
+ return 3; //Number of vertices for Fragment shader is always three.
|
|
|
+ else if (language == EShLangMeshNV) {
|
|
|
+ if (isPerPrimitive) {
|
|
|
+ return intermediate.getPrimitives() != TQualifier::layoutNotSet ? intermediate.getPrimitives() : 0;
|
|
|
+ } else {
|
|
|
+ return intermediate.getVertices() != TQualifier::layoutNotSet ? intermediate.getVertices() : 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
else
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -602,6 +632,14 @@ 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);
|
|
|
}
|
|
|
@@ -1301,8 +1339,15 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction
|
|
|
// 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")
|
|
|
- length = getIoArrayImplicitSize();
|
|
|
+ if (name == "gl_in" || name == "gl_out"
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ || name == "gl_MeshVerticesNV"
|
|
|
+ || name == "gl_MeshPrimitivesNV"
|
|
|
+#endif
|
|
|
+ )
|
|
|
+ {
|
|
|
+ length = getIoArrayImplicitSize(type.getQualifier().isPerPrimitive());
|
|
|
+ }
|
|
|
}
|
|
|
if (length == 0) {
|
|
|
if (intermNode->getAsSymbolNode() && isIoResizeArray(type))
|
|
|
@@ -2917,6 +2962,20 @@ 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)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtAccStructNV))
|
|
|
+ error(loc, "non-uniform struct contains an accelerationStructureNVX:", type.getBasicTypeString().c_str(), identifier.c_str());
|
|
|
+ else if (type.getBasicType() == EbtAccStructNV && type.getQualifier().storage != EvqUniform)
|
|
|
+ error(loc, "accelerationStructureNVX can only be used in uniform variables or function parameters:",
|
|
|
+ type.getBasicTypeString().c_str(), identifier.c_str());
|
|
|
+
|
|
|
+}
|
|
|
+#endif
|
|
|
|
|
|
void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
|
|
|
{
|
|
|
@@ -3020,11 +3079,14 @@ 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
|
|
|
- if (! qualifier.flat && ! qualifier.explicitInterp) {
|
|
|
-#else
|
|
|
- if (!qualifier.flat) {
|
|
|
+ && !qualifier.explicitInterp
|
|
|
#endif
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ && !qualifier.pervertexNV
|
|
|
+#endif
|
|
|
+ ) {
|
|
|
if (isTypeInt(publicType.basicType) ||
|
|
|
publicType.basicType == EbtDouble ||
|
|
|
(publicType.userDef && (publicType.userDef->containsBasicType(EbtInt8) ||
|
|
|
@@ -3046,6 +3108,11 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
|
|
|
if (qualifier.patch && qualifier.isInterpolation())
|
|
|
error(loc, "cannot use interpolation qualifiers with patch", "patch", "");
|
|
|
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (qualifier.perTaskNV && publicType.basicType != EbtBlock)
|
|
|
+ error(loc, "taskNV variables can be declared only as blocks", "taskNV", "");
|
|
|
+#endif
|
|
|
+
|
|
|
if (qualifier.storage == EvqVaryingIn) {
|
|
|
switch (language) {
|
|
|
case EShLangVertex:
|
|
|
@@ -3233,6 +3300,11 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
|
|
|
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);
|
|
|
@@ -3575,7 +3647,7 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie
|
|
|
if (! symbolTable.atBuiltInLevel()) {
|
|
|
if (isIoResizeArray(type)) {
|
|
|
ioArraySymbolResizeList.push_back(symbol);
|
|
|
- checkIoArraysConsistency(loc, true);
|
|
|
+ checkIoArraysConsistency(loc, true, type.getQualifier().isPerPrimitive());
|
|
|
} else
|
|
|
fixIoArraySize(loc, symbol->getWritableType());
|
|
|
}
|
|
|
@@ -3628,7 +3700,7 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie
|
|
|
existingType.updateArraySizes(type);
|
|
|
|
|
|
if (isIoResizeArray(type))
|
|
|
- checkIoArraysConsistency(loc);
|
|
|
+ checkIoArraysConsistency(loc, false, type.getQualifier().isPerPrimitive());
|
|
|
}
|
|
|
|
|
|
// Policy and error check for needing a runtime sized array.
|
|
|
@@ -3664,6 +3736,28 @@ 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)
|
|
|
+{
|
|
|
+ // 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
|
|
|
+ int maxViewCount = parsingBuiltins ? 4 : resources.maxMeshViewCountNV;
|
|
|
+
|
|
|
+ if (! type.isArray()) {
|
|
|
+ error(loc, "requires an view array dimension", "perviewNV", "");
|
|
|
+ }
|
|
|
+ else if (!type.isUnsizedArray() && type.getOuterArraySize() != maxViewCount) {
|
|
|
+ error(loc, "mesh view output array size must be gl_MaxMeshViewCountNV or implicitly sized", "[]", "");
|
|
|
+ }
|
|
|
+ else if (type.isUnsizedArray()) {
|
|
|
+ type.changeOuterArraySize(maxViewCount);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
// Returns true if the first argument to the #line directive is the line number for the next line.
|
|
|
//
|
|
|
// Desktop, pre-version 3.30: "After processing this directive
|
|
|
@@ -3854,7 +3948,12 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
|
|
|
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") {
|
|
|
+ if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment"
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ && blockName != "gl_MeshPerVertexNV" && blockName != "gl_MeshPerPrimitiveNV"
|
|
|
+#endif
|
|
|
+ )
|
|
|
+ {
|
|
|
error(loc, "cannot redeclare block: ", "block declaration", blockName.c_str());
|
|
|
return;
|
|
|
}
|
|
|
@@ -4030,7 +4129,7 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
|
|
|
// Tracking for implicit sizing of array
|
|
|
if (isIoResizeArray(block->getType())) {
|
|
|
ioArraySymbolResizeList.push_back(block);
|
|
|
- checkIoArraysConsistency(loc, true);
|
|
|
+ checkIoArraysConsistency(loc, true, block->getType().getQualifier().isPerPrimitive());
|
|
|
} else if (block->getType().isArray())
|
|
|
fixIoArraySize(loc, block->getWritableType());
|
|
|
|
|
|
@@ -4447,44 +4546,57 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|
|
publicType.qualifier.layoutPushConstant = true;
|
|
|
return;
|
|
|
}
|
|
|
- if (language == EShLangGeometry || language == EShLangTessEvaluation) {
|
|
|
+ if (language == EShLangGeometry || language == EShLangTessEvaluation
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ || language == EShLangMeshNV
|
|
|
+#endif
|
|
|
+ ) {
|
|
|
if (id == TQualifier::getGeometryString(ElgTriangles)) {
|
|
|
publicType.shaderQualifiers.geometry = ElgTriangles;
|
|
|
return;
|
|
|
}
|
|
|
- if (language == EShLangGeometry) {
|
|
|
+ if (language == EShLangGeometry
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ || language == EShLangMeshNV
|
|
|
+#endif
|
|
|
+ ) {
|
|
|
if (id == TQualifier::getGeometryString(ElgPoints)) {
|
|
|
publicType.shaderQualifiers.geometry = ElgPoints;
|
|
|
return;
|
|
|
}
|
|
|
- if (id == TQualifier::getGeometryString(ElgLineStrip)) {
|
|
|
- publicType.shaderQualifiers.geometry = ElgLineStrip;
|
|
|
- return;
|
|
|
- }
|
|
|
if (id == TQualifier::getGeometryString(ElgLines)) {
|
|
|
publicType.shaderQualifiers.geometry = ElgLines;
|
|
|
return;
|
|
|
}
|
|
|
- if (id == TQualifier::getGeometryString(ElgLinesAdjacency)) {
|
|
|
- publicType.shaderQualifiers.geometry = ElgLinesAdjacency;
|
|
|
- return;
|
|
|
- }
|
|
|
- if (id == TQualifier::getGeometryString(ElgTrianglesAdjacency)) {
|
|
|
- publicType.shaderQualifiers.geometry = ElgTrianglesAdjacency;
|
|
|
- return;
|
|
|
- }
|
|
|
- if (id == TQualifier::getGeometryString(ElgTriangleStrip)) {
|
|
|
- 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;
|
|
|
- }
|
|
|
+ if (language == EShLangGeometry)
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ if (id == TQualifier::getGeometryString(ElgLineStrip)) {
|
|
|
+ publicType.shaderQualifiers.geometry = ElgLineStrip;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (id == TQualifier::getGeometryString(ElgLinesAdjacency)) {
|
|
|
+ publicType.shaderQualifiers.geometry = ElgLinesAdjacency;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (id == TQualifier::getGeometryString(ElgTrianglesAdjacency)) {
|
|
|
+ publicType.shaderQualifiers.geometry = ElgTrianglesAdjacency;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (id == TQualifier::getGeometryString(ElgTriangleStrip)) {
|
|
|
+ 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);
|
|
|
|
|
|
@@ -4598,6 +4710,27 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|
|
publicType.qualifier.layoutViewportRelative = true;
|
|
|
return;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ if (language == EShLangRayGenNV || language == EShLangIntersectNV ||
|
|
|
+ language == EShLangAnyHitNV || language == EShLangClosestHitNV ||
|
|
|
+ language == EShLangMissNV || language == EShLangCallableNV) {
|
|
|
+ if (id == "shaderrecordnvx") {
|
|
|
+ publicType.qualifier.layoutShaderRecordNV = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (language == EShLangCompute) {
|
|
|
+ if (id.compare(0, 17, "derivative_group_") == 0) {
|
|
|
+ requireExtensions(loc, 1, &E_GL_NV_compute_shader_derivatives, "compute shader derivatives");
|
|
|
+ if (id == "derivative_group_quadsnv") {
|
|
|
+ publicType.shaderQualifiers.layoutDerivativeGroupQuads = true;
|
|
|
+ return;
|
|
|
+ } else if (id == "derivative_group_linearnv") {
|
|
|
+ publicType.shaderQualifiers.layoutDerivativeGroupLinear = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
#else
|
|
|
}
|
|
|
@@ -4827,10 +4960,37 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ case EShLangMeshNV:
|
|
|
+ if (id == "max_vertices") {
|
|
|
+ publicType.shaderQualifiers.vertices = value;
|
|
|
+ if (value > resources.maxMeshOutputVerticesNV)
|
|
|
+ error(loc, "too large, must be less than gl_MaxMeshOutputVerticesNV", "max_vertices", "");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (id == "max_primitives") {
|
|
|
+ publicType.shaderQualifiers.primitives = value;
|
|
|
+ if (value > resources.maxMeshOutputPrimitivesNV)
|
|
|
+ error(loc, "too large, must be less than gl_MaxMeshOutputPrimitivesNV", "max_primitives", "");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // Fall through
|
|
|
+
|
|
|
+ case EShLangTaskNV:
|
|
|
+ // Fall through
|
|
|
+#endif
|
|
|
case EShLangCompute:
|
|
|
if (id.compare(0, 11, "local_size_") == 0) {
|
|
|
- profileRequires(loc, EEsProfile, 310, 0, "gl_WorkGroupSize");
|
|
|
- profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_compute_shader, "gl_WorkGroupSize");
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (language == EShLangMeshNV || language == EShLangTaskNV) {
|
|
|
+ profileRequires(loc, ~EEsProfile, 450, E_GL_NV_mesh_shader, "gl_WorkGroupSize");
|
|
|
+ }
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ profileRequires(loc, EEsProfile, 310, 0, "gl_WorkGroupSize");
|
|
|
+ profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_compute_shader, "gl_WorkGroupSize");
|
|
|
+ }
|
|
|
if (id.size() == 12 && value == 0) {
|
|
|
error(loc, "must be at least 1", id.c_str(), "");
|
|
|
return;
|
|
|
@@ -4939,6 +5099,10 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie
|
|
|
dst.layoutViewportRelative = true;
|
|
|
if (src.layoutSecondaryViewportRelativeOffset != -2048)
|
|
|
dst.layoutSecondaryViewportRelativeOffset = src.layoutSecondaryViewportRelativeOffset;
|
|
|
+ if (src.layoutShaderRecordNV)
|
|
|
+ dst.layoutShaderRecordNV = true;
|
|
|
+ if (src.pervertexNV)
|
|
|
+ dst.pervertexNV = true;
|
|
|
#endif
|
|
|
}
|
|
|
}
|
|
|
@@ -4975,9 +5139,10 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb
|
|
|
switch (qualifier.storage) {
|
|
|
case EvqVaryingIn:
|
|
|
case EvqVaryingOut:
|
|
|
- if (type.getBasicType() != EbtBlock ||
|
|
|
- (!(*type.getStruct())[0].type->getQualifier().hasLocation() &&
|
|
|
- (*type.getStruct())[0].type->getQualifier().builtIn == EbvNone))
|
|
|
+ if (!type.getQualifier().isTaskMemory() &&
|
|
|
+ (type.getBasicType() != EbtBlock ||
|
|
|
+ (!(*type.getStruct())[0].type->getQualifier().hasLocation() &&
|
|
|
+ (*type.getStruct())[0].type->getQualifier().builtIn == EbvNone)))
|
|
|
error(loc, "SPIR-V requires location for user input/output", "location", "");
|
|
|
break;
|
|
|
default:
|
|
|
@@ -5003,6 +5168,10 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb
|
|
|
error(loc, "cannot specify on a variable declaration", "align", "");
|
|
|
if (qualifier.layoutPushConstant)
|
|
|
error(loc, "can only specify on a uniform block", "push_constant", "");
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (qualifier.layoutShaderRecordNV)
|
|
|
+ error(loc, "can only specify on a buffer block", "shaderRecordNVX", "");
|
|
|
+#endif
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
@@ -5066,12 +5235,22 @@ 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
|
|
|
+ case EvqPayloadNV:
|
|
|
+ case EvqPayloadInNV:
|
|
|
+ case EvqHitAttrNV:
|
|
|
+ break;
|
|
|
+#endif
|
|
|
default:
|
|
|
error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", "");
|
|
|
break;
|
|
|
@@ -5155,7 +5334,10 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|
|
if (spvVersion.spv > 0) {
|
|
|
if (qualifier.isUniformOrBuffer()) {
|
|
|
if (type.getBasicType() == EbtBlock && !qualifier.layoutPushConstant &&
|
|
|
- !qualifier.layoutAttachment)
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ !qualifier.layoutShaderRecordNV &&
|
|
|
+#endif
|
|
|
+ !qualifier.layoutAttachment)
|
|
|
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", "");
|
|
|
@@ -5207,6 +5389,11 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|
|
if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock)
|
|
|
error(loc, "can only be used with a block", "push_constant", "");
|
|
|
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (qualifier.layoutShaderRecordNV && type.getBasicType() != EbtBlock)
|
|
|
+ error(loc, "can only be used with a block", "shaderRecordNVX", "");
|
|
|
+#endif
|
|
|
+
|
|
|
// input attachment
|
|
|
if (type.isSubpass()) {
|
|
|
if (! qualifier.hasAttachment())
|
|
|
@@ -5317,7 +5504,7 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
|
|
|
}
|
|
|
|
|
|
if (qualifier.hasBinding()) {
|
|
|
- if (! qualifier.isUniformOrBuffer())
|
|
|
+ if (! qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory())
|
|
|
error(loc, "requires uniform or buffer storage qualifier", "binding", "");
|
|
|
}
|
|
|
if (qualifier.hasStream()) {
|
|
|
@@ -5329,7 +5516,7 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
|
|
|
error(loc, "can only be used on an output", "xfb layout qualifier", "");
|
|
|
}
|
|
|
if (qualifier.hasUniformLayout()) {
|
|
|
- if (! qualifier.isUniformOrBuffer()) {
|
|
|
+ if (! qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory()) {
|
|
|
if (qualifier.hasMatrix() || qualifier.hasPacking())
|
|
|
error(loc, "matrix or packing qualifiers can only be used on a uniform or buffer", "layout", "");
|
|
|
if (qualifier.hasOffset() || qualifier.hasAlign())
|
|
|
@@ -5342,6 +5529,16 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
|
|
|
if (qualifier.hasSet())
|
|
|
error(loc, "cannot be used with push_constant", "set", "");
|
|
|
}
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (qualifier.layoutShaderRecordNV) {
|
|
|
+ if (qualifier.storage != EvqBuffer)
|
|
|
+ error(loc, "can only be used with a buffer", "shaderRecordNVX", "");
|
|
|
+ if (qualifier.hasBinding())
|
|
|
+ error(loc, "cannot be used with shaderRecordNVX", "binding", "");
|
|
|
+ if (qualifier.hasSet())
|
|
|
+ error(loc, "cannot be used with shaderRecordNVX", "set", "");
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
// For places that can't have shader-level layout qualifiers
|
|
|
@@ -5370,13 +5567,25 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua
|
|
|
error(loc, message, "local_size id", "");
|
|
|
}
|
|
|
if (shaderQualifiers.vertices != TQualifier::layoutNotSet) {
|
|
|
- if (language == EShLangGeometry)
|
|
|
+ if (language == EShLangGeometry
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ || language == EShLangMeshNV
|
|
|
+#endif
|
|
|
+ )
|
|
|
error(loc, message, "max_vertices", "");
|
|
|
else if (language == EShLangTessControl)
|
|
|
error(loc, message, "vertices", "");
|
|
|
else
|
|
|
assert(0);
|
|
|
}
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (shaderQualifiers.primitives != TQualifier::layoutNotSet) {
|
|
|
+ if (language == EShLangMeshNV)
|
|
|
+ error(loc, message, "max_primitives", "");
|
|
|
+ else
|
|
|
+ assert(0);
|
|
|
+ }
|
|
|
+#endif
|
|
|
if (shaderQualifiers.blendEquation)
|
|
|
error(loc, message, "blend equation", "");
|
|
|
if (shaderQualifiers.numViews != TQualifier::layoutNotSet)
|
|
|
@@ -5759,6 +5968,9 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|
|
samplerCheck(loc, type, identifier, initializer);
|
|
|
atomicUintCheck(loc, type, identifier);
|
|
|
transparentOpaqueCheck(loc, type, identifier);
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ accStructNVCheck(loc, type, identifier);
|
|
|
+#endif
|
|
|
|
|
|
if (type.getQualifier().storage != EvqUniform && type.getQualifier().storage != EvqBuffer) {
|
|
|
if (type.containsBasicType(EbtFloat16))
|
|
|
@@ -6407,6 +6619,14 @@ 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
|
|
|
+ if (currentBlockQualifier.perPrimitiveNV)
|
|
|
+ memberQualifier.perPrimitiveNV = currentBlockQualifier.perPrimitiveNV;
|
|
|
+ if (currentBlockQualifier.perViewNV)
|
|
|
+ memberQualifier.perViewNV = currentBlockQualifier.perViewNV;
|
|
|
+ if (currentBlockQualifier.perTaskNV)
|
|
|
+ memberQualifier.perTaskNV = currentBlockQualifier.perTaskNV;
|
|
|
+#endif
|
|
|
if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary()))
|
|
|
error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), "");
|
|
|
if (memberType.isArray())
|
|
|
@@ -6449,8 +6669,18 @@ 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())
|
|
|
+ if ((currentBlockQualifier.layoutPushConstant && !currentBlockQualifier.hasPacking())
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ || (currentBlockQualifier.layoutShaderRecordNV && !currentBlockQualifier.hasPacking())
|
|
|
+#endif
|
|
|
+ )
|
|
|
+ currentBlockQualifier.layoutPacking = ElpStd430;
|
|
|
+
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ // Special case for "taskNV in/out", which has a default of std430,
|
|
|
+ if (currentBlockQualifier.perTaskNV && !currentBlockQualifier.hasPacking())
|
|
|
currentBlockQualifier.layoutPacking = ElpStd430;
|
|
|
+#endif
|
|
|
|
|
|
// fix and check for member layout qualifiers
|
|
|
|
|
|
@@ -6466,6 +6696,9 @@ 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;
|
|
|
@@ -6509,6 +6742,12 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|
|
error(memberLoc, "can only be used with std140 or std430 layout packing", "offset/align", "");
|
|
|
}
|
|
|
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (memberQualifier.isPerView()) {
|
|
|
+ memberWithPerViewQualifier = true;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
TQualifier newMemberQualification = defaultQualification;
|
|
|
mergeQualifiers(memberLoc, newMemberQualification, memberQualifier, false);
|
|
|
memberQualifier = newMemberQualification;
|
|
|
@@ -6523,6 +6762,14 @@ 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
|
|
|
+ if (memberWithPerViewQualifier) {
|
|
|
+ for (unsigned int member = 0; member < typeList.size(); ++member) {
|
|
|
+ resizeMeshViewDimension(typeList[member].loc, *typeList[member].type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
// reverse merge, so that currentBlockQualifier now has all layout information
|
|
|
// (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers)
|
|
|
mergeObjectLayoutQualifiers(currentBlockQualifier, defaultQualification, true);
|
|
|
@@ -6586,7 +6833,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|
|
// fix up
|
|
|
if (isIoResizeArray(blockType)) {
|
|
|
ioArraySymbolResizeList.push_back(&variable);
|
|
|
- checkIoArraysConsistency(loc, true);
|
|
|
+ checkIoArraysConsistency(loc, true, blockType.getQualifier().isPerPrimitive());
|
|
|
} else
|
|
|
fixIoArraySize(loc, variable.getWritableType());
|
|
|
|
|
|
@@ -6614,17 +6861,56 @@ 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), "input block");
|
|
|
- if (language == EShLangFragment)
|
|
|
+ requireStage(loc, (EShLanguageMask)(EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask|EShLangFragmentMask
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ |EShLangMeshNVMask
|
|
|
+#endif
|
|
|
+ ), "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()) {
|
|
|
+ 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), "output block");
|
|
|
+ requireStage(loc, (EShLanguageMask)(EShLangVertexMask|EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ |EShLangMeshNVMask|EShLangTaskNVMask
|
|
|
+#endif
|
|
|
+ ), "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)
|
|
|
+ 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()) {
|
|
|
+ error(loc, "can only use on input blocks in mesh shader", "taskNV", "");
|
|
|
+ }
|
|
|
+ else if (language == EShLangTaskNV && ! qualifier.isTaskMemory()) {
|
|
|
+ error(loc, "output blocks cannot be used in a task shader", "out", "");
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ break;
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ case EvqPayloadNV:
|
|
|
+ profileRequires(loc, ~EEsProfile, 450, E_GL_NVX_raytracing, "rayPayloadNVX block");
|
|
|
+ requireStage(loc, (EShLanguageMask)(EShLangRayGenNVMask | EShLangAnyHitNVMask | EShLangClosestHitNVMask | EShLangMissNVMask),
|
|
|
+ "rayPayloadNVX block");
|
|
|
+ break;
|
|
|
+ case EvqPayloadInNV:
|
|
|
+ profileRequires(loc, ~EEsProfile, 450, E_GL_NVX_raytracing, "rayPayloadInNVX block");
|
|
|
+ requireStage(loc, (EShLanguageMask)(EShLangAnyHitNVMask | EShLangClosestHitNVMask | EShLangMissNVMask),
|
|
|
+ "rayPayloadInNVX block");
|
|
|
break;
|
|
|
+ case EvqHitAttrNV:
|
|
|
+ profileRequires(loc, ~EEsProfile, 450, E_GL_NVX_raytracing, "hitAttributeNVX block");
|
|
|
+ requireStage(loc, (EShLanguageMask)(EShLangIntersectNVMask | EShLangAnyHitNVMask | EShLangClosestHitNVMask), "hitAttributeNVX block");
|
|
|
+ break;
|
|
|
+#endif
|
|
|
default:
|
|
|
error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), "");
|
|
|
break;
|
|
|
@@ -6661,6 +6947,12 @@ void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier&
|
|
|
error(loc, "cannot use invariant qualifier on an interface block", "invariant", "");
|
|
|
if (qualifier.layoutPushConstant)
|
|
|
intermediate.addPushConstantCount();
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (qualifier.layoutShaderRecordNV)
|
|
|
+ intermediate.addShaderRecordNVCount();
|
|
|
+ if (qualifier.perTaskNV)
|
|
|
+ intermediate.addTaskNVCount();
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
//
|
|
|
@@ -6746,7 +7038,7 @@ void TParseContext::fixBlockXfbOffsets(TQualifier& qualifier, TTypeList& typeLis
|
|
|
//
|
|
|
void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typeList)
|
|
|
{
|
|
|
- if (! qualifier.isUniformOrBuffer())
|
|
|
+ if (!qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory())
|
|
|
return;
|
|
|
if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430)
|
|
|
return;
|
|
|
@@ -6878,7 +7170,11 @@ void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qual
|
|
|
void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, const TPublicType& publicType)
|
|
|
{
|
|
|
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)
|
|
|
@@ -6889,6 +7185,17 @@ 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";
|
|
|
+
|
|
|
+ if (publicType.qualifier.storage != EvqVaryingOut)
|
|
|
+ error(loc, "can only apply to 'out'", id, "");
|
|
|
+ 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", "");
|
|
|
@@ -6905,6 +7212,12 @@ 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);
|
|
|
@@ -6916,6 +7229,15 @@ 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:
|
|
|
case ElgTriangleStrip:
|
|
|
@@ -6955,14 +7277,41 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|
|
error(loc, "cannot change previously set size", "local_size", "");
|
|
|
else {
|
|
|
int max = 0;
|
|
|
- switch (i) {
|
|
|
- case 0: max = resources.maxComputeWorkGroupSizeX; break;
|
|
|
- case 1: max = resources.maxComputeWorkGroupSizeY; break;
|
|
|
- case 2: max = resources.maxComputeWorkGroupSizeZ; break;
|
|
|
- default: break;
|
|
|
+ if (language == EShLangCompute) {
|
|
|
+ switch (i) {
|
|
|
+ case 0: max = resources.maxComputeWorkGroupSizeX; break;
|
|
|
+ case 1: max = resources.maxComputeWorkGroupSizeY; break;
|
|
|
+ case 2: max = resources.maxComputeWorkGroupSizeZ; break;
|
|
|
+ default: break;
|
|
|
+ }
|
|
|
+ if (intermediate.getLocalSize(i) > (unsigned int)max)
|
|
|
+ error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", "");
|
|
|
+ }
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ else if (language == EShLangMeshNV) {
|
|
|
+ switch (i) {
|
|
|
+ case 0: max = resources.maxMeshWorkGroupSizeX_NV; break;
|
|
|
+ case 1: max = resources.maxMeshWorkGroupSizeY_NV; break;
|
|
|
+ case 2: max = resources.maxMeshWorkGroupSizeZ_NV; break;
|
|
|
+ default: break;
|
|
|
+ }
|
|
|
+ if (intermediate.getLocalSize(i) > (unsigned int)max)
|
|
|
+ error(loc, "too large; see gl_MaxMeshWorkGroupSizeNV", "local_size", "");
|
|
|
+ }
|
|
|
+ else if (language == EShLangTaskNV) {
|
|
|
+ switch (i) {
|
|
|
+ case 0: max = resources.maxTaskWorkGroupSizeX_NV; break;
|
|
|
+ case 1: max = resources.maxTaskWorkGroupSizeY_NV; break;
|
|
|
+ case 2: max = resources.maxTaskWorkGroupSizeZ_NV; break;
|
|
|
+ default: break;
|
|
|
+ }
|
|
|
+ if (intermediate.getLocalSize(i) > (unsigned int)max)
|
|
|
+ error(loc, "too large; see gl_MaxTaskWorkGroupSizeNV", "local_size", "");
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ else {
|
|
|
+ assert(0);
|
|
|
}
|
|
|
- if (intermediate.getLocalSize(i) > (unsigned int)max)
|
|
|
- error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", "");
|
|
|
|
|
|
// Fix the existing constant gl_WorkGroupSize with this new information.
|
|
|
TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
|
|
|
@@ -7001,6 +7350,36 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|
|
error(loc, "can only apply to 'out'", "blend equation", "");
|
|
|
}
|
|
|
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (publicType.shaderQualifiers.layoutDerivativeGroupQuads &&
|
|
|
+ publicType.shaderQualifiers.layoutDerivativeGroupLinear) {
|
|
|
+ error(loc, "cannot be both specified", "derivative_group_quadsNV and derivative_group_linearNV", "");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (publicType.shaderQualifiers.layoutDerivativeGroupQuads) {
|
|
|
+ if (publicType.qualifier.storage == EvqVaryingIn) {
|
|
|
+ if ((intermediate.getLocalSize(0) & 1) ||
|
|
|
+ (intermediate.getLocalSize(1) & 1))
|
|
|
+ error(loc, "requires local_size_x and local_size_y to be multiple of two", "derivative_group_quadsNV", "");
|
|
|
+ else
|
|
|
+ intermediate.setLayoutDerivativeMode(LayoutDerivativeGroupQuads);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ error(loc, "can only apply to 'in'", "derivative_group_quadsNV", "");
|
|
|
+ }
|
|
|
+ if (publicType.shaderQualifiers.layoutDerivativeGroupLinear) {
|
|
|
+ if (publicType.qualifier.storage == EvqVaryingIn) {
|
|
|
+ if((intermediate.getLocalSize(0) *
|
|
|
+ intermediate.getLocalSize(1) *
|
|
|
+ intermediate.getLocalSize(2)) % 4 != 0)
|
|
|
+ error(loc, "requires total group size to be multiple of four", "derivative_group_linearNV", "");
|
|
|
+ else
|
|
|
+ intermediate.setLayoutDerivativeMode(LayoutDerivativeGroupLinear);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ error(loc, "can only apply to 'in'", "derivative_group_linearNV", "");
|
|
|
+ }
|
|
|
+#endif
|
|
|
const TQualifier& qualifier = publicType.qualifier;
|
|
|
|
|
|
if (qualifier.isAuxiliary() ||
|
|
|
@@ -7056,6 +7435,10 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|
|
error(loc, "cannot declare a default, can only be used on a block", "push_constant", "");
|
|
|
if (qualifier.hasSpecConstantId())
|
|
|
error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", "");
|
|
|
+#ifdef NV_EXTENSIONS
|
|
|
+ if (qualifier.layoutShaderRecordNV)
|
|
|
+ error(loc, "cannot declare a default, can only be used on a block", "shaderRecordNVX", "");
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
//
|