Add-support-for-SPV_NV_mesh_shader

This commit is contained in:
Chao Chen 2018-09-19 11:41:59 -07:00
parent 3a1379667d
commit 3c3669904c
41 changed files with 6976 additions and 4237 deletions

View file

@ -491,7 +491,8 @@ 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() &&
@ -499,7 +500,9 @@ bool TParseContext::isIoResizeArray(const TType& type) const
(language == EShLangTessControl && type.getQualifier().storage == EvqVaryingOut && ! type.getQualifier().patch)
#ifdef NV_EXTENSIONS
||
(language == EShLangFragment && type.getQualifier().storage == EvqVaryingIn && type.getQualifier().pervertexNV)
(language == EShLangFragment && type.getQualifier().storage == EvqVaryingIn && type.getQualifier().pervertexNV) ||
(language == EShLangMeshNV && type.getQualifier().storage == EvqVaryingOut && !type.getQualifier().perTaskNV)
#endif
);
}
@ -551,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);
}
@ -565,9 +568,9 @@ 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;
@ -581,6 +584,11 @@ void TParseContext::checkIoArraysConsistency(const TSourceLoc& loc, bool tailOnl
)
feature = "vertices";
#ifdef NV_EXTENSIONS
else if (language == EShLangMeshNV) {
feature = isPerPrimitive ? "max_primitives" : "max_vertices";
}
#endif
else
feature = "unknown";
@ -593,7 +601,7 @@ 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());
@ -602,6 +610,13 @@ int TParseContext::getIoArrayImplicitSize() const
#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
@ -622,6 +637,8 @@ void TParseContext::checkIoArrayConsistency(const TSourceLoc& loc, int requiredS
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);
@ -1322,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))
@ -3070,6 +3094,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:
@ -3257,6 +3286,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);
@ -3599,7 +3633,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());
}
@ -3652,7 +3686,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.
@ -3688,6 +3722,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
@ -3878,7 +3934,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;
}
@ -4054,7 +4115,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());
@ -4471,44 +4532,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);
@ -4863,10 +4937,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;
@ -5013,9 +5114,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:
@ -5104,6 +5206,10 @@ 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:
@ -5355,7 +5461,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()) {
@ -5367,7 +5473,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())
@ -5408,13 +5514,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)
@ -6445,6 +6563,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())
@ -6490,6 +6616,12 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
if (currentBlockQualifier.layoutPushConstant && !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())
currentBlockQualifier.layoutPacking = ElpStd430;
#endif
// fix and check for member layout qualifiers
mergeObjectLayoutQualifiers(defaultQualification, currentBlockQualifier, true);
@ -6504,6 +6636,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;
@ -6547,6 +6682,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;
@ -6561,6 +6702,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);
@ -6624,7 +6773,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());
@ -6652,16 +6801,39 @@ 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;
default:
error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), "");
@ -6699,6 +6871,10 @@ 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.perTaskNV)
intermediate.addTaskNVCount();
#endif
}
//
@ -6784,7 +6960,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;
@ -6916,7 +7092,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)
@ -6927,6 +7107,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", "");
@ -6943,6 +7134,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);
@ -6954,6 +7151,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:
@ -6993,14 +7199,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");