aboutsummaryrefslogtreecommitdiff
path: root/glslang/MachineIndependent/ParseHelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'glslang/MachineIndependent/ParseHelper.cpp')
-rw-r--r--glslang/MachineIndependent/ParseHelper.cpp380
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