diff options
Diffstat (limited to 'thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp')
-rw-r--r-- | thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp | 464 |
1 files changed, 408 insertions, 56 deletions
diff --git a/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp b/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp index e2ac43ca19..c6f947d9b2 100644 --- a/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp +++ b/thirdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp @@ -80,10 +80,6 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b globalBufferDefaults.layoutMatrix = ElmColumnMajor; globalBufferDefaults.layoutPacking = spvVersion.spv != 0 ? ElpStd430 : ElpShared; - // use storage buffer on SPIR-V 1.3 and up - if (spvVersion.spv >= EShTargetSpv_1_3) - intermediate.setUseStorageBuffer(); - globalInputDefaults.clear(); globalOutputDefaults.clear(); @@ -608,6 +604,15 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn #ifndef GLSLANG_WEB if (base->getType().isUnsizedArray()) { base->getWritableType().updateImplicitArraySize(indexValue + 1); + base->getWritableType().setImplicitlySized(true); + if (base->getQualifier().builtIn == EbvClipDistance && + indexValue >= resources.maxClipDistances) { + error(loc, "gl_ClipDistance", "[", "array index out of range '%d'", indexValue); + } + else if (base->getQualifier().builtIn == EbvCullDistance && + indexValue >= resources.maxCullDistances) { + error(loc, "gl_CullDistance", "[", "array index out of range '%d'", indexValue); + } // 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(); @@ -836,12 +841,16 @@ int TParseContext::getIoArrayImplicitSize(const TQualifier &qualifier, TString * } else if (language == EShLangMesh) { unsigned int maxPrimitives = intermediate.getPrimitives() != TQualifier::layoutNotSet ? intermediate.getPrimitives() : 0; - if (qualifier.builtIn == EbvPrimitiveIndicesNV || qualifier.builtIn == EbvPrimitiveTriangleIndicesEXT || - qualifier.builtIn == EbvPrimitiveLineIndicesEXT || qualifier.builtIn == EbvPrimitivePointIndicesEXT) { + if (qualifier.builtIn == EbvPrimitiveIndicesNV) { expectedSize = maxPrimitives * TQualifier::mapGeometryToSize(intermediate.getOutputPrimitive()); str = "max_primitives*"; str += TQualifier::getGeometryString(intermediate.getOutputPrimitive()); } + else if (qualifier.builtIn == EbvPrimitiveTriangleIndicesEXT || qualifier.builtIn == EbvPrimitiveLineIndicesEXT || + qualifier.builtIn == EbvPrimitivePointIndicesEXT) { + expectedSize = maxPrimitives; + str = "max_primitives"; + } else if (qualifier.isPerPrimitive()) { expectedSize = maxPrimitives; str = "max_primitives"; @@ -1022,14 +1031,22 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm inheritMemoryQualifiers(base->getQualifier(), result->getWritableType().getQualifier()); } else { auto baseSymbol = base; - while (baseSymbol->getAsSymbolNode() == nullptr) - baseSymbol = baseSymbol->getAsBinaryNode()->getLeft(); - TString structName; - structName.append("\'").append(baseSymbol->getAsSymbolNode()->getName().c_str()).append( "\'"); - error(loc, "no such field in structure", field.c_str(), structName.c_str()); + while (baseSymbol->getAsSymbolNode() == nullptr) { + auto binaryNode = baseSymbol->getAsBinaryNode(); + if (binaryNode == nullptr) break; + baseSymbol = binaryNode->getLeft(); + } + if (baseSymbol->getAsSymbolNode() != nullptr) { + TString structName; + structName.append("\'").append(baseSymbol->getAsSymbolNode()->getName().c_str()).append("\'"); + error(loc, "no such field in structure", field.c_str(), structName.c_str()); + } 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(intermediate.getEnhancedMsgs()).c_str()); + error(loc, "does not apply to this type:", field.c_str(), + base->getType().getCompleteString(intermediate.getEnhancedMsgs()).c_str()); // Propagate noContraction up the dereference chain if (base->getQualifier().isNoContraction()) @@ -1161,7 +1178,7 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct if (symbol && builtIn && function.getBuiltInOp() == EOpSpirvInst) symbol = nullptr; #endif - const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0; + const TFunction* prevDec = symbol ? symbol->getAsFunction() : nullptr; if (prevDec) { if (prevDec->isPrototyped() && prototype) profileRequires(loc, EEsProfile, 300, nullptr, "multiple prototypes for same function"); @@ -1385,7 +1402,8 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction #endif const TType& argType = arg->getAsTyped()->getType(); const TQualifier& argQualifier = argType.getQualifier(); - if (argQualifier.isMemory() && (argType.containsOpaque() || argType.isReference())) { + bool containsBindlessSampler = intermediate.getBindlessMode() && argType.containsSampler(); + if (argQualifier.isMemory() && !containsBindlessSampler && (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) @@ -1671,9 +1689,13 @@ TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermType error(loc, "type does not match, or is not convertible to, the function's return type", "return", ""); branch = intermediate.addBranch(EOpReturn, value, loc); } - } else + } else { + if (value->getType().isTexture() || value->getType().isImage()) { + if (!extensionTurnedOn(E_GL_ARB_bindless_texture)) + error(loc, "sampler or image can be used as return type only when the extension GL_ARB_bindless_texture enabled", "return", ""); + } branch = intermediate.addBranch(EOpReturn, value, loc); - + } branch->updatePrecision(currentFunctionType->getQualifier().precision); return branch; } @@ -1924,6 +1946,9 @@ TIntermTyped* TParseContext::addAssign(const TSourceLoc& loc, TOperator op, TInt if ((op == EOpAddAssign || op == EOpSubAssign) && left->isReference()) requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "+= and -= on a buffer reference"); + if (op == EOpAssign && left->getBasicType() == EbtSampler && right->getBasicType() == EbtSampler) + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "sampler assignment for bindless texture"); + return intermediate.addAssign(op, left, right, loc); } @@ -2356,6 +2381,79 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan } break; + case EOpHitObjectTraceRayNV: + if (!(*argp)[11]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "payload number", ""); + else { + unsigned int location = (*argp)[11]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0) + error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location); + } + break; + case EOpHitObjectTraceRayMotionNV: + if (!(*argp)[12]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "payload number", ""); + else { + unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0) + error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location); + } + break; + case EOpHitObjectExecuteShaderNV: + if (!(*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "payload number", ""); + else { + unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0) + error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location); + } + break; + case EOpHitObjectRecordHitNV: + if (!(*argp)[12]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpHitObjectRecordHitMotionNV: + if (!(*argp)[13]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[13]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpHitObjectRecordHitWithIndexNV: + if (!(*argp)[11]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[11]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpHitObjectRecordHitWithIndexMotionNV: + if (!(*argp)[12]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpHitObjectGetAttributesNV: + if (!(*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpRayQueryGetIntersectionType: case EOpRayQueryGetIntersectionT: case EOpRayQueryGetIntersectionInstanceCustomIndex: @@ -2369,6 +2467,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan case EOpRayQueryGetIntersectionObjectRayOrigin: case EOpRayQueryGetIntersectionObjectToWorld: case EOpRayQueryGetIntersectionWorldToObject: + case EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: if (!(*argp)[1]->getAsConstantUnion()) error(loc, "argument must be compile-time constant", "committed", ""); break; @@ -2807,6 +2906,14 @@ TFunction* TParseContext::handleConstructorCall(const TSourceLoc& loc, const TPu profileRequires(loc, EEsProfile, 300, nullptr, "arrayed constructor"); } + // Reuse EOpConstructTextureSampler for bindless image constructor + // uvec2 imgHandle; + // imageLoad(image1D(imgHandle), 0); + if (type.isImage() && extensionTurnedOn(E_GL_ARB_bindless_texture)) + { + intermediate.setBindlessImageMode(currentCaller, AstRefTypeFunc); + } + TOperator op = intermediate.mapTypeToConstructorOp(type); if (op == EOpNull) { @@ -3136,7 +3243,7 @@ void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* iden ppWarn(loc, "\"defined\" is (un)defined:", op, identifier); else ppError(loc, "\"defined\" can't be (un)defined:", op, identifier); - else if (strstr(identifier, "__") != 0 && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) { + else if (strstr(identifier, "__") != nullptr && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) { // The extension GL_EXT_spirv_intrinsics allows us to declare macros prefixed with "__". if (isEsProfile() && version >= 300 && (strcmp(identifier, "__LINE__") == 0 || @@ -3540,8 +3647,13 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T return true; } if (op != EOpConstructStruct && op != EOpConstructNonuniform && typed->getBasicType() == EbtSampler) { - error(loc, "cannot convert a sampler", constructorString.c_str(), ""); - return true; + if (op == EOpConstructUVec2 && extensionTurnedOn(E_GL_ARB_bindless_texture)) { + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeFunc); + } + else { + error(loc, "cannot convert a sampler", constructorString.c_str(), ""); + return true; + } } if (op != EOpConstructStruct && typed->isAtomic()) { error(loc, "cannot convert an atomic_uint", constructorString.c_str(), ""); @@ -3561,6 +3673,26 @@ bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const { TString constructorName = function.getType().getBasicTypeString(); // TODO: performance: should not be making copy; interface needs to change const char* token = constructorName.c_str(); + // verify the constructor for bindless texture, the input must be ivec2 or uvec2 + if (function.getParamCount() == 1) { + TType* pType = function[0].type; + TBasicType basicType = pType->getBasicType(); + bool isIntegerVec2 = ((basicType == EbtUint || basicType == EbtInt) && pType->getVectorSize() == 2); + bool bindlessMode = extensionTurnedOn(E_GL_ARB_bindless_texture); + if (isIntegerVec2 && bindlessMode) { + if (pType->getSampler().isImage()) + intermediate.setBindlessImageMode(currentCaller, AstRefTypeFunc); + else + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeFunc); + return false; + } else { + if (!bindlessMode) + error(loc, "sampler-constructor requires the extension GL_ARB_bindless_texture enabled", token, ""); + else + error(loc, "sampler-constructor requires the input to be ivec2 or uvec2", token, ""); + return true; + } + } // exactly two arguments needed if (function.getParamCount() != 2) { @@ -3656,13 +3788,35 @@ void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const if (type.getQualifier().storage == EvqUniform) return; - if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtSampler)) - error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str()); + if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtSampler)) { + // For bindless texture, sampler can be declared as an struct member + if (extensionTurnedOn(E_GL_ARB_bindless_texture)) { + if (type.getSampler().isImage()) + intermediate.setBindlessImageMode(currentCaller, AstRefTypeVar); + else + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeVar); + } + else { + error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str()); + } + } else if (type.getBasicType() == EbtSampler && type.getQualifier().storage != EvqUniform) { - // non-uniform sampler - // not yet: okay if it has an initializer - // if (! initializer) - error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); + // For bindless texture, sampler can be declared as an input/output/block member + if (extensionTurnedOn(E_GL_ARB_bindless_texture)) { + if (type.getSampler().isImage()) + intermediate.setBindlessImageMode(currentCaller, AstRefTypeVar); + else + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeVar); + } + else { + // non-uniform sampler + // not yet: okay if it has an initializer + // if (! initializer) + if (type.getSampler().isAttachmentEXT() && type.getQualifier().storage != EvqTileImageEXT) + error(loc, "can only be used in tileImageEXT variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); + else if (type.getQualifier().storage != EvqTileImageEXT) + error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); + } } } @@ -3728,7 +3882,7 @@ void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType) // // Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level. // -void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck) +void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck, const TPublicType* publicType) { bool nonuniformOkay = false; @@ -3764,6 +3918,11 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q { requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "default std430 layout for uniform"); } + + if (publicType != nullptr && publicType->isImage() && + (qualifier.layoutFormat > ElfExtSizeGuard && qualifier.layoutFormat < ElfCount)) + qualifier.layoutFormat = mapLegacyLayoutFormat(qualifier.layoutFormat, publicType->sampler.getBasicType()); + break; default: break; @@ -3824,8 +3983,10 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali return; } - if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble) - profileRequires(loc, EEsProfile, 300, nullptr, "shader input/output"); + if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble) { + profileRequires(loc, EEsProfile, 300, nullptr, "non-float shader input/output"); + profileRequires(loc, ~EEsProfile, 130, nullptr, "non-float shader input/output"); + } if (!qualifier.flat && !qualifier.isExplicitInterpolation() && !qualifier.isPervertexNV() && !qualifier.isPervertexEXT()) { if (isTypeInt(publicType.basicType) || @@ -3856,7 +4017,7 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali switch (language) { case EShLangVertex: if (publicType.basicType == EbtStruct) { - error(loc, "cannot be a structure or array", GetStorageQualifierString(qualifier.storage), ""); + error(loc, "cannot be a structure", GetStorageQualifierString(qualifier.storage), ""); return; } if (publicType.arraySizes) { @@ -4071,7 +4232,7 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons if (dstSpirvDecorate.decorates.find(decorateString.first) != dstSpirvDecorate.decorates.end()) error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate_string", "(decoration=%u)", decorateString.first); else - dstSpirvDecorate.decorates.insert(decorateString); + dstSpirvDecorate.decorateStrings.insert(decorateString); } } else { dst.spirvDecorate = src.spirvDecorate; @@ -4168,7 +4329,7 @@ void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType ba void TParseContext::parameterTypeCheck(const TSourceLoc& loc, TStorageQualifier qualifier, const TType& type) { - if ((qualifier == EvqOut || qualifier == EvqInOut) && type.isOpaque()) + if ((qualifier == EvqOut || qualifier == EvqInOut) && type.isOpaque() && !intermediate.getBindlessMode()) error(loc, "samplers and atomic_uints cannot be output parameters", type.getBasicTypeString().c_str(), ""); if (!parsingBuiltins && type.contains16BitFloat()) requireFloat16Arithmetic(loc, type.getBasicTypeString().c_str(), "float16 types can only be in uniform block or buffer storage"); @@ -4512,7 +4673,7 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType // check for additional things allowed by GL_EXT_nonuniform_qualifier if (base.getBasicType() == EbtSampler || base.getBasicType() == EbtAccStruct || base.getBasicType() == EbtRayQuery || - (base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer())) + base.getBasicType() == EbtHitObjectNV || (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"); @@ -5015,6 +5176,7 @@ void TParseContext::paramCheckFixStorage(const TSourceLoc& loc, const TStorageQu case EvqIn: case EvqOut: case EvqInOut: + case EvqTileImageEXT: type.getQualifier().storage = qualifier; break; case EvqGlobal: @@ -5101,7 +5263,7 @@ void TParseContext::arrayObjectCheck(const TSourceLoc& loc, const TType& type, c void TParseContext::opaqueCheck(const TSourceLoc& loc, const TType& type, const char* op) { - if (containsFieldWithBasicType(type, EbtSampler)) + if (containsFieldWithBasicType(type, EbtSampler) && !extensionTurnedOn(E_GL_ARB_bindless_texture)) error(loc, "can't use with samplers or structs containing samplers", op, ""); } @@ -5202,7 +5364,7 @@ void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init, bool badInit = false; if (! init || ! init->getAsAggregate() || init->getAsAggregate()->getSequence().size() != 1) badInit = true; - TIntermBinary* binaryInit = 0; + TIntermBinary* binaryInit = nullptr; if (! badInit) { // get the declaration assignment binaryInit = init->getAsAggregate()->getSequence()[0]->getAsBinaryNode(); @@ -5476,6 +5638,28 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi intermediate.setUsePhysicalStorageBuffer(); return; } + if (id == "bindless_sampler") { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bindless_sampler"); + publicType.qualifier.layoutBindlessSampler = true; + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeLayout); + return; + } + if (id == "bindless_image") { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bindless_image"); + publicType.qualifier.layoutBindlessImage = true; + intermediate.setBindlessImageMode(currentCaller, AstRefTypeLayout); + return; + } + if (id == "bound_sampler") { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bound_sampler"); + publicType.qualifier.layoutBindlessSampler = false; + return; + } + if (id == "bound_image") { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bound_image"); + publicType.qualifier.layoutBindlessImage = false; + return; + } if (language == EShLangGeometry || language == EShLangTessEvaluation || language == EShLangMesh) { if (id == TQualifier::getGeometryString(ElgTriangles)) { publicType.shaderQualifiers.geometry = ElgTriangles; @@ -5600,6 +5784,22 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.shaderQualifiers.postDepthCoverage = true; return; } + /* id is transformed into lower case in the beginning of this function. */ + if (id == "non_coherent_color_attachment_readext") { + requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_color_attachment_readEXT"); + publicType.shaderQualifiers.nonCoherentColorAttachmentReadEXT = true; + return; + } + if (id == "non_coherent_depth_attachment_readext") { + requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_depth_attachment_readEXT"); + publicType.shaderQualifiers.nonCoherentDepthAttachmentReadEXT = true; + return; + } + if (id == "non_coherent_stencil_attachment_readext") { + requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_stencil_attachment_readEXT"); + publicType.shaderQualifiers.nonCoherentStencilAttachmentReadEXT = true; + return; + } for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth+1)) { if (id == TQualifier::getLayoutDepthString(depth)) { requireProfile(loc, ECoreProfile | ECompatibilityProfile, "depth layout qualifier"); @@ -5670,6 +5870,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi } publicType.qualifier.layoutShaderRecord = true; return; + } else if (id == "hitobjectshaderrecordnv") { + requireExtensions(loc, 1, &E_GL_NV_shader_invocation_reorder, "hitobject shader record NV"); + publicType.qualifier.layoutHitObjectShaderRecordNV = true; + return; } } @@ -5973,8 +6177,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi if (id == "max_vertices") { requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "max_vertices"); publicType.shaderQualifiers.vertices = value; - if (value > resources.maxMeshOutputVerticesNV) - error(loc, "too large, must be less than gl_MaxMeshOutputVerticesNV", "max_vertices", ""); + int max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? resources.maxMeshOutputVerticesEXT + : resources.maxMeshOutputVerticesNV; + if (value > max) { + TString maxsErrtring = "too large, must be less than "; + maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ? "gl_MaxMeshOutputVerticesEXT" + : "gl_MaxMeshOutputVerticesNV"); + error(loc, maxsErrtring.c_str(), "max_vertices", ""); + } if (nonLiteral) error(loc, "needs a literal integer", "max_vertices", ""); return; @@ -5982,8 +6192,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi if (id == "max_primitives") { requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "max_primitives"); publicType.shaderQualifiers.primitives = value; - if (value > resources.maxMeshOutputPrimitivesNV) - error(loc, "too large, must be less than gl_MaxMeshOutputPrimitivesNV", "max_primitives", ""); + int max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? resources.maxMeshOutputPrimitivesEXT + : resources.maxMeshOutputPrimitivesNV; + if (value > max) { + TString maxsErrtring = "too large, must be less than "; + maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ? "gl_MaxMeshOutputPrimitivesEXT" + : "gl_MaxMeshOutputPrimitivesNV"); + error(loc, maxsErrtring.c_str(), "max_primitives", ""); + } if (nonLiteral) error(loc, "needs a literal integer", "max_primitives", ""); return; @@ -5999,7 +6215,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi if (language == EShLangMesh || language == EShLangTask) { requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "gl_WorkGroupSize"); } else { - profileRequires(loc, EEsProfile, 310, 0, "gl_WorkGroupSize"); + profileRequires(loc, EEsProfile, 310, nullptr, "gl_WorkGroupSize"); profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_compute_shader, "gl_WorkGroupSize"); } #endif @@ -6121,10 +6337,16 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie dst.layoutSecondaryViewportRelativeOffset = src.layoutSecondaryViewportRelativeOffset; if (src.layoutShaderRecord) dst.layoutShaderRecord = true; + if (src.layoutBindlessSampler) + dst.layoutBindlessSampler = true; + if (src.layoutBindlessImage) + dst.layoutBindlessImage = true; if (src.pervertexNV) dst.pervertexNV = true; if (src.pervertexEXT) dst.pervertexEXT = true; + if (src.layoutHitObjectShaderRecordNV) + dst.layoutHitObjectShaderRecordNV = true; #endif } } @@ -6272,6 +6494,8 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) case EvqBuffer: if (type.getBasicType() == EbtBlock) error(loc, "cannot apply to uniform or buffer block", "location", ""); + else if (type.getBasicType() == EbtSampler && type.getSampler().isAttachmentEXT()) + error(loc, "only applies to", "location", "%s with storage tileImageEXT", type.getBasicTypeString().c_str()); break; case EvqtaskPayloadSharedEXT: error(loc, "cannot apply to taskPayloadSharedEXT", "location", ""); @@ -6282,8 +6506,11 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) case EvqHitAttr: case EvqCallableData: case EvqCallableDataIn: + case EvqHitObjectAttrNV: break; #endif + case EvqTileImageEXT: + break; default: error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", ""); break; @@ -6293,10 +6520,10 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) int repeated = intermediate.addUsedLocation(qualifier, type, typeCollision); if (repeated >= 0 && ! typeCollision) error(loc, "overlapping use of location", "location", "%d", repeated); - // "fragment-shader outputs ... if two variables are placed within the same + // "fragment-shader outputs/tileImageEXT ... if two variables are placed within the same // location, they must have the same underlying type (floating-point or integer)" - if (typeCollision && language == EShLangFragment && qualifier.isPipeOutput()) - error(loc, "fragment outputs sharing the same location must be the same basic type", "location", "%d", repeated); + if (typeCollision && language == EShLangFragment && (qualifier.isPipeOutput() || qualifier.storage == EvqTileImageEXT)) + error(loc, "fragment outputs or tileImageEXTs sharing the same location", "location", "%d must be the same basic type", repeated); } #ifndef GLSLANG_WEB @@ -6380,7 +6607,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) !qualifier.hasAttachment() && !qualifier.hasBufferReference()) error(loc, "uniform/buffer blocks require layout(binding=X)", "binding", ""); - else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler) + else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler && !type.getSampler().isAttachmentEXT()) error(loc, "sampler/texture/image requires layout(binding=X)", "binding", ""); } } @@ -6402,7 +6629,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) // Image format if (qualifier.hasFormat()) { - if (! type.isImage()) + if (! type.isImage() && !intermediate.getBindlessImageMode()) error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.getFormat()), ""); else { if (type.getSampler().type == EbtFloat && qualifier.getFormat() > ElfFloatGuard) @@ -6421,7 +6648,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) } } } - } else if (type.isImage() && ! qualifier.isWriteOnly()) { + } else if (type.isImage() && ! qualifier.isWriteOnly() && !intermediate.getBindlessImageMode()) { 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); @@ -6442,6 +6669,8 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) // input attachment if (type.isSubpass()) { + if (extensionTurnedOn(E_GL_EXT_shader_tile_image)) + error(loc, "can not be used with GL_EXT_shader_tile_image enabled", type.getSampler().getString().c_str(), ""); if (! qualifier.hasAttachment()) error(loc, "requires an input_attachment_index layout qualifier", "subpass", ""); } else { @@ -6609,6 +6838,14 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier error(loc, "cannot be used with shaderRecordNV", "set", ""); } + + if (qualifier.storage == EvqTileImageEXT) { + if (qualifier.hasSet()) + error(loc, "cannot be used with tileImageEXT", "set", ""); + if (!qualifier.hasLocation()) + error(loc, "can only be used with an explicit location", "tileImageEXT", ""); + } + if (qualifier.storage == EvqHitAttr && qualifier.hasLayout()) { error(loc, "cannot apply layout qualifiers to hitAttributeNV variable", "hitAttributeNV", ""); } @@ -6648,6 +6885,12 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua error(loc, message, "early_fragment_tests", ""); if (shaderQualifiers.postDepthCoverage) error(loc, message, "post_depth_coverage", ""); + if (shaderQualifiers.nonCoherentColorAttachmentReadEXT) + error(loc, message, "non_coherent_color_attachment_readEXT", ""); + if (shaderQualifiers.nonCoherentDepthAttachmentReadEXT) + error(loc, message, "non_coherent_depth_attachment_readEXT", ""); + if (shaderQualifiers.nonCoherentStencilAttachmentReadEXT) + error(loc, message, "non_coherent_stencil_attachment_readEXT", ""); if (shaderQualifiers.primitives != TQualifier::layoutNotSet) { if (language == EShLangMesh) error(loc, message, "max_primitives", ""); @@ -7066,7 +7309,7 @@ TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, T realFunc.addParameter(TParameter().copyParam((*function)[i])); } - TParameter tmpP = { 0, &uintType }; + TParameter tmpP = { nullptr, &uintType }; realFunc.addParameter(TParameter().copyParam(tmpP)); arguments = intermediate.growAggregate(arguments, intermediate.addConstantUnion(1, loc, true)); @@ -7083,7 +7326,7 @@ TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, T realFunc.addParameter(TParameter().copyParam((*function)[i])); } - TParameter tmpP = { 0, &uintType }; + TParameter tmpP = { nullptr, &uintType }; realFunc.addParameter(TParameter().copyParam(tmpP)); arguments = intermediate.growAggregate(arguments, intermediate.addConstantUnion(-1, loc, true)); @@ -7237,7 +7480,10 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden if (initializer) { if (type.getBasicType() == EbtRayQuery) { error(loc, "ray queries can only be initialized by using the rayQueryInitializeEXT intrinsic:", "=", identifier.c_str()); + } else if (type.getBasicType() == EbtHitObjectNV) { + error(loc, "hit objects cannot be initialized using initializers", "=", identifier.c_str()); } + } if (type.isCoopMat()) { @@ -7729,12 +7975,14 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* // Combined texture-sampler constructors are completely semantic checked // in constructorTextureSamplerError() if (op == EOpConstructTextureSampler) { - if (aggrNode->getSequence()[1]->getAsTyped()->getType().getSampler().shadow) { - // Transfer depth into the texture (SPIR-V image) type, as a hint - // for tools to know this texture/image is a depth image. - aggrNode->getSequence()[0]->getAsTyped()->getWritableType().getSampler().shadow = true; + if (aggrNode != nullptr) { + if (aggrNode->getSequence()[1]->getAsTyped()->getType().getSampler().shadow) { + // Transfer depth into the texture (SPIR-V image) type, as a hint + // for tools to know this texture/image is a depth image. + aggrNode->getSequence()[0]->getAsTyped()->getWritableType().getSampler().shadow = true; + } + return intermediate.setAggregateOperator(aggrNode, op, type, loc); } - return intermediate.setAggregateOperator(aggrNode, op, type, loc); } TTypeList::const_iterator memberTypes; @@ -7869,6 +8117,16 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvPtrToUvec2, true, node, type); return newNode; + } else if (node->getType().getBasicType() == EbtSampler) { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "sampler conversion to uvec2"); + // force the basic type of the constructor param to uvec2, otherwise spv builder will + // report some errors + TIntermTyped* newSrcNode = intermediate.createConversion(EbtUint, node); + newSrcNode->getAsTyped()->getWritableType().setVectorSize(2); + + TIntermTyped* newNode = + intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConstructUVec2, false, newSrcNode, type); + return newNode; } case EOpConstructUVec3: case EOpConstructUVec4: @@ -7882,7 +8140,15 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EOpConstructBool: basicOp = EOpConstructBool; break; - + case EOpConstructTextureSampler: + if ((node->getType().getBasicType() == EbtUint || node->getType().getBasicType() == EbtInt) && + node->getType().getVectorSize() == 2) { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "ivec2/uvec2 convert to texture handle"); + // No matter ivec2 or uvec2, Set EOpPackUint2x32 just to generate an opBitcast op code + TIntermTyped* newNode = + intermediate.addBuiltInFunctionCall(node->getLoc(), EOpPackUint2x32, true, node, type); + return newNode; + } #ifndef GLSLANG_WEB case EOpConstructDVec2: @@ -8230,6 +8496,30 @@ void TParseContext::inheritMemoryQualifiers(const TQualifier& from, TQualifier& } // +// Update qualifier layoutBindlessImage & layoutBindlessSampler on block member +// +void TParseContext::updateBindlessQualifier(TType& memberType) +{ + if (memberType.containsSampler()) { + if (memberType.isStruct()) { + TTypeList* typeList = memberType.getWritableStruct(); + for (unsigned int member = 0; member < typeList->size(); ++member) { + TType* subMemberType = (*typeList)[member].type; + updateBindlessQualifier(*subMemberType); + } + } + else if (memberType.getSampler().isImage()) { + intermediate.setBindlessImageMode(currentCaller, AstRefTypeLayout); + memberType.getQualifier().layoutBindlessImage = true; + } + else { + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeLayout); + memberType.getQualifier().layoutBindlessSampler = true; + } + } +} + +// // Do everything needed to add an interface block. // void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, @@ -8281,8 +8571,13 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con } } - if (memberType.containsOpaque()) - error(memberLoc, "member of block cannot be or contain a sampler, image, or atomic_uint type", typeList[member].type->getFieldName().c_str(), ""); + // For bindless texture, sampler can be declared as uniform/storage block member, + if (memberType.containsOpaque()) { + if (memberType.containsSampler() && extensionTurnedOn(E_GL_ARB_bindless_texture)) + updateBindlessQualifier(memberType); + else + error(memberLoc, "member of block cannot be or contain a sampler, image, or atomic_uint type", typeList[member].type->getFieldName().c_str(), ""); + } if (memberType.containsCoopMat()) error(memberLoc, "member of block cannot be or contain a cooperative matrix type", typeList[member].type->getFieldName().c_str(), ""); @@ -8615,6 +8910,10 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "callableDataInNV block"); requireStage(loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInNV block"); break; + case EvqHitObjectAttrNV: + profileRequires(loc, ~EEsProfile, 460, E_GL_NV_shader_invocation_reorder, "hitObjectAttributeNV block"); + requireStage(loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | EShLangMissMask), "hitObjectAttributeNV block"); + break; #endif default: error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), ""); @@ -8771,7 +9070,8 @@ void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typ // "The specified offset must be a multiple // of the base alignment of the type of the block member it qualifies, or a compile-time error results." if (! IsMultipleOfPow2(memberQualifier.layoutOffset, memberAlignment)) - error(memberLoc, "must be a multiple of the member's alignment", "offset", ""); + error(memberLoc, "must be a multiple of the member's alignment", "offset", + "(layout offset = %d | member alignment = %d)", memberQualifier.layoutOffset, memberAlignment); // GLSL: "It is a compile-time error to specify an offset that is smaller than the offset of the previous // member in the block or that lies within the previous member of the block" @@ -9200,6 +9500,24 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con else error(loc, "can only apply to 'in'", "post_coverage_coverage", ""); } + if (publicType.shaderQualifiers.nonCoherentColorAttachmentReadEXT) { + if (publicType.qualifier.storage == EvqVaryingIn) + intermediate.setNonCoherentColorAttachmentReadEXT(); + else + error(loc, "can only apply to 'in'", "non_coherent_color_attachment_readEXT", ""); + } + if (publicType.shaderQualifiers.nonCoherentDepthAttachmentReadEXT) { + if (publicType.qualifier.storage == EvqVaryingIn) + intermediate.setNonCoherentDepthAttachmentReadEXT(); + else + error(loc, "can only apply to 'in'", "non_coherent_depth_attachment_readEXT", ""); + } + if (publicType.shaderQualifiers.nonCoherentStencilAttachmentReadEXT) { + if (publicType.qualifier.storage == EvqVaryingIn) + intermediate.setNonCoherentStencilAttachmentReadEXT(); + else + error(loc, "can only apply to 'in'", "non_coherent_stencil_attachment_readEXT", ""); + } if (publicType.shaderQualifiers.hasBlendEquation()) { if (publicType.qualifier.storage != EvqVaryingOut) error(loc, "can only apply to 'out'", "blend equation", ""); @@ -9456,4 +9774,38 @@ const TTypeList* TParseContext::recordStructCopy(TStructRecord& record, const TT return originStruct; } +TLayoutFormat TParseContext::mapLegacyLayoutFormat(TLayoutFormat legacyLayoutFormat, TBasicType imageType) +{ + TLayoutFormat layoutFormat = ElfNone; + if (imageType == EbtFloat) { + switch (legacyLayoutFormat) { + case ElfSize1x16: layoutFormat = ElfR16f; break; + case ElfSize1x32: layoutFormat = ElfR32f; break; + case ElfSize2x32: layoutFormat = ElfRg32f; break; + case ElfSize4x32: layoutFormat = ElfRgba32f; break; + default: break; + } + } else if (imageType == EbtUint) { + switch (legacyLayoutFormat) { + case ElfSize1x8: layoutFormat = ElfR8ui; break; + case ElfSize1x16: layoutFormat = ElfR16ui; break; + case ElfSize1x32: layoutFormat = ElfR32ui; break; + case ElfSize2x32: layoutFormat = ElfRg32ui; break; + case ElfSize4x32: layoutFormat = ElfRgba32ui; break; + default: break; + } + } else if (imageType == EbtInt) { + switch (legacyLayoutFormat) { + case ElfSize1x8: layoutFormat = ElfR8i; break; + case ElfSize1x16: layoutFormat = ElfR16i; break; + case ElfSize1x32: layoutFormat = ElfR32i; break; + case ElfSize2x32: layoutFormat = ElfRg32i; break; + case ElfSize4x32: layoutFormat = ElfRgba32i; break; + default: break; + } + } + + return layoutFormat; +} + } // end namespace glslang |