diff options
Diffstat (limited to 'glslang/MachineIndependent/ParseHelper.cpp')
-rw-r--r-- | glslang/MachineIndependent/ParseHelper.cpp | 380 |
1 files changed, 337 insertions, 43 deletions
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index e2ac43ca..515137b7 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -608,6 +608,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 +845,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 +1035,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 +1182,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 +1406,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 +1693,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 +1950,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 +2385,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: @@ -2807,6 +2909,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 +3246,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 +3650,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 +3676,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 +3791,32 @@ 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) + 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; @@ -4168,7 +4327,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 +4671,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"); @@ -5101,7 +5260,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 +5361,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 +5635,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; @@ -5670,6 +5851,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 +6158,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 +6173,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 +6196,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 +6318,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 } } @@ -6282,6 +6485,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) case EvqHitAttr: case EvqCallableData: case EvqCallableDataIn: + case EvqHitObjectAttrNV: break; #endif default: @@ -6402,7 +6606,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 +6625,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); @@ -7066,7 +7270,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 +7287,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 +7441,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 +7936,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 +8078,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 +8101,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 +8457,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 +8532,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 +8871,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(), ""); @@ -9456,4 +9716,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 |