Add missing callgraph clean for bindless status flag.
Add test cases. Add support to check special extensions not be available for Vulkan when using GLSL.
type.getQualifier().storage == glslang::EvqUniform) {
if (type.isAtomic())
return spv::StorageClassAtomicCounter;
- if (type.containsOpaque())
+ if (type.containsOpaque() && !glslangIntermediate->getBindlessMode())
return spv::StorageClassUniformConstant;
}
return true;
if (glslangIntermediate->getSource() == glslang::EShSourceHlsl)
return paramType.getBasicType() == glslang::EbtBlock;
- return paramType.containsOpaque() || // sampler, etc.
+ return (paramType.containsOpaque() && !glslangIntermediate->getBindlessMode()) || // sampler, etc.
#ifndef GLSLANG_WEB
paramType.getQualifier().isSpirvByReference() || // spirv_by_reference
#endif
--- /dev/null
+#version 460 compatibility
+
+#extension GL_ARB_bindless_texture: require
+
+#if !defined GL_ARB_bindless_texture
+# error GL_ARB_bindless_texture is not defined
+#elif GL_ARB_bindless_texture != 1
+# error GL_ARB_bindless_texture is not equal to 1
+#endif
+
+// Valid usage cases
+layout(bindless_sampler) uniform sampler2D s0; // case0: bindless layout
+in sampler2D s1; // case1: sampler as an input
+uniform uvec2 s2; // case2: uvec2 as sampler constructor
+uniform ivec2 s3; // case3: ivec2 as sampler constructor
+uniform int index;
+in sampler2D s4[2][3]; // case4: sampler arrays of arrays
+uniform BB {sampler2D s5;} bbs5[2]; // case5: uniform block member as a sampler
+in samplerBuffer s6; // case6: samplerBuffer input
+uniform UBO9 {samplerBuffer s7;}; // case7: samplerBuffer as an uniform block member
+buffer SSBO10 {samplerBuffer s8;}; // case8: samplerBuffer as an ssbo member
+layout(rgba8, bindless_image) in image2D i9; // case9: bindless image as an input
+
+
+uniform vec2 coord; // bindless coord 2-D
+uniform int icoord; // bindless coord 1-D
+out vec4 color0;
+out vec4 color1;
+out vec4 color2;
+out vec4 color3;
+out vec4 color4;
+out vec4 color5;
+out vec4 color6;
+out vec4 color7;
+out vec4 color8;
+out vec4 color9;
+
+void main()
+{
+ color0 = texture(s0, coord);
+ color1 = texture(s1, coord);
+ color2 = texture(sampler2D(s2), coord);
+ color3 = texture(sampler2D(s3), coord);
+ color4 = texture(s4[index][index], coord);
+ color5 = texture(bbs5[index].s5, coord);
+ color6 = texelFetch(s6, icoord);
+ color7 = texelFetch(s7, icoord);
+ color8 = texelFetch(s8, icoord);
+ color9 = imageLoad(i9, ivec2(0,0));
+}
\ No newline at end of file
--- /dev/null
+GL_ARB_bindless_texture.frag
+Shader version: 460
+Requested GL_ARB_bindless_texture
+0:? Sequence
+0:38 Function Definition: main( ( global void)
+0:38 Function Parameters:
+0:40 Sequence
+0:40 move second child to first child ( temp 4-component vector of float)
+0:40 'color0' ( out 4-component vector of float)
+0:40 texture ( global 4-component vector of float)
+0:40 's0' ( uniform sampler2D)
+0:40 'coord' ( uniform 2-component vector of float)
+0:41 move second child to first child ( temp 4-component vector of float)
+0:41 'color1' ( out 4-component vector of float)
+0:41 texture ( global 4-component vector of float)
+0:41 's1' ( smooth in sampler2D)
+0:41 'coord' ( uniform 2-component vector of float)
+0:42 move second child to first child ( temp 4-component vector of float)
+0:42 'color2' ( out 4-component vector of float)
+0:42 texture ( global 4-component vector of float)
+0:42 packUint2x32 ( temp sampler2D)
+0:42 's2' ( uniform 2-component vector of uint)
+0:42 'coord' ( uniform 2-component vector of float)
+0:43 move second child to first child ( temp 4-component vector of float)
+0:43 'color3' ( out 4-component vector of float)
+0:43 texture ( global 4-component vector of float)
+0:43 packUint2x32 ( temp sampler2D)
+0:43 's3' ( uniform 2-component vector of int)
+0:43 'coord' ( uniform 2-component vector of float)
+0:44 move second child to first child ( temp 4-component vector of float)
+0:44 'color4' ( out 4-component vector of float)
+0:44 texture ( global 4-component vector of float)
+0:44 indirect index ( smooth temp sampler2D)
+0:44 indirect index ( smooth temp 3-element array of sampler2D)
+0:44 's4' ( smooth in 2-element array of 3-element array of sampler2D)
+0:44 'index' ( uniform int)
+0:44 'index' ( uniform int)
+0:44 'coord' ( uniform 2-component vector of float)
+0:45 move second child to first child ( temp 4-component vector of float)
+0:45 'color5' ( out 4-component vector of float)
+0:45 texture ( global 4-component vector of float)
+0:45 s5: direct index for structure (layout( column_major shared layoutBindlessSampler) uniform sampler2D)
+0:45 indirect index (layout( column_major shared) temp block{layout( column_major shared layoutBindlessSampler) uniform sampler2D s5})
+0:45 'bbs5' (layout( column_major shared) uniform 2-element array of block{layout( column_major shared layoutBindlessSampler) uniform sampler2D s5})
+0:45 'index' ( uniform int)
+0:45 Constant:
+0:45 0 (const int)
+0:45 'coord' ( uniform 2-component vector of float)
+0:46 move second child to first child ( temp 4-component vector of float)
+0:46 'color6' ( out 4-component vector of float)
+0:46 textureFetch ( global 4-component vector of float)
+0:46 's6' ( smooth in samplerBuffer)
+0:46 'icoord' ( uniform int)
+0:47 move second child to first child ( temp 4-component vector of float)
+0:47 'color7' ( out 4-component vector of float)
+0:47 textureFetch ( global 4-component vector of float)
+0:47 s7: direct index for structure (layout( column_major shared layoutBindlessSampler) uniform samplerBuffer)
+0:47 'anon@0' (layout( column_major shared) uniform block{layout( column_major shared layoutBindlessSampler) uniform samplerBuffer s7})
+0:47 Constant:
+0:47 0 (const uint)
+0:47 'icoord' ( uniform int)
+0:48 move second child to first child ( temp 4-component vector of float)
+0:48 'color8' ( out 4-component vector of float)
+0:48 textureFetch ( global 4-component vector of float)
+0:48 s8: direct index for structure (layout( column_major shared layoutBindlessSampler) buffer samplerBuffer)
+0:48 'anon@1' (layout( column_major shared) buffer block{layout( column_major shared layoutBindlessSampler) buffer samplerBuffer s8})
+0:48 Constant:
+0:48 0 (const uint)
+0:48 'icoord' ( uniform int)
+0:49 move second child to first child ( temp 4-component vector of float)
+0:49 'color9' ( out 4-component vector of float)
+0:49 imageLoad ( global 4-component vector of float)
+0:49 'i9' (layout( rgba8 layoutBindlessImage) smooth in image2D)
+0:49 Constant:
+0:49 0 (const int)
+0:49 0 (const int)
+0:? Linker Objects
+0:? 's0' ( uniform sampler2D)
+0:? 's1' ( smooth in sampler2D)
+0:? 's2' ( uniform 2-component vector of uint)
+0:? 's3' ( uniform 2-component vector of int)
+0:? 'index' ( uniform int)
+0:? 's4' ( smooth in 2-element array of 3-element array of sampler2D)
+0:? 'bbs5' (layout( column_major shared) uniform 2-element array of block{layout( column_major shared layoutBindlessSampler) uniform sampler2D s5})
+0:? 's6' ( smooth in samplerBuffer)
+0:? 'anon@0' (layout( column_major shared) uniform block{layout( column_major shared layoutBindlessSampler) uniform samplerBuffer s7})
+0:? 'anon@1' (layout( column_major shared) buffer block{layout( column_major shared layoutBindlessSampler) buffer samplerBuffer s8})
+0:? 'i9' (layout( rgba8 layoutBindlessImage) smooth in image2D)
+0:? 'coord' ( uniform 2-component vector of float)
+0:? 'icoord' ( uniform int)
+0:? 'color0' ( out 4-component vector of float)
+0:? 'color1' ( out 4-component vector of float)
+0:? 'color2' ( out 4-component vector of float)
+0:? 'color3' ( out 4-component vector of float)
+0:? 'color4' ( out 4-component vector of float)
+0:? 'color5' ( out 4-component vector of float)
+0:? 'color6' ( out 4-component vector of float)
+0:? 'color7' ( out 4-component vector of float)
+0:? 'color8' ( out 4-component vector of float)
+0:? 'color9' ( out 4-component vector of float)
+
+
+Linked fragment stage:
+
+
+Shader version: 460
+Requested GL_ARB_bindless_texture
+0:? Sequence
+0:38 Function Definition: main( ( global void)
+0:38 Function Parameters:
+0:40 Sequence
+0:40 move second child to first child ( temp 4-component vector of float)
+0:40 'color0' ( out 4-component vector of float)
+0:40 texture ( global 4-component vector of float)
+0:40 's0' ( uniform sampler2D)
+0:40 'coord' ( uniform 2-component vector of float)
+0:41 move second child to first child ( temp 4-component vector of float)
+0:41 'color1' ( out 4-component vector of float)
+0:41 texture ( global 4-component vector of float)
+0:41 's1' ( smooth in sampler2D)
+0:41 'coord' ( uniform 2-component vector of float)
+0:42 move second child to first child ( temp 4-component vector of float)
+0:42 'color2' ( out 4-component vector of float)
+0:42 texture ( global 4-component vector of float)
+0:42 packUint2x32 ( temp sampler2D)
+0:42 's2' ( uniform 2-component vector of uint)
+0:42 'coord' ( uniform 2-component vector of float)
+0:43 move second child to first child ( temp 4-component vector of float)
+0:43 'color3' ( out 4-component vector of float)
+0:43 texture ( global 4-component vector of float)
+0:43 packUint2x32 ( temp sampler2D)
+0:43 's3' ( uniform 2-component vector of int)
+0:43 'coord' ( uniform 2-component vector of float)
+0:44 move second child to first child ( temp 4-component vector of float)
+0:44 'color4' ( out 4-component vector of float)
+0:44 texture ( global 4-component vector of float)
+0:44 indirect index ( smooth temp sampler2D)
+0:44 indirect index ( smooth temp 3-element array of sampler2D)
+0:44 's4' ( smooth in 2-element array of 3-element array of sampler2D)
+0:44 'index' ( uniform int)
+0:44 'index' ( uniform int)
+0:44 'coord' ( uniform 2-component vector of float)
+0:45 move second child to first child ( temp 4-component vector of float)
+0:45 'color5' ( out 4-component vector of float)
+0:45 texture ( global 4-component vector of float)
+0:45 s5: direct index for structure (layout( column_major shared layoutBindlessSampler) uniform sampler2D)
+0:45 indirect index (layout( column_major shared) temp block{layout( column_major shared layoutBindlessSampler) uniform sampler2D s5})
+0:45 'bbs5' (layout( column_major shared) uniform 2-element array of block{layout( column_major shared layoutBindlessSampler) uniform sampler2D s5})
+0:45 'index' ( uniform int)
+0:45 Constant:
+0:45 0 (const int)
+0:45 'coord' ( uniform 2-component vector of float)
+0:46 move second child to first child ( temp 4-component vector of float)
+0:46 'color6' ( out 4-component vector of float)
+0:46 textureFetch ( global 4-component vector of float)
+0:46 's6' ( smooth in samplerBuffer)
+0:46 'icoord' ( uniform int)
+0:47 move second child to first child ( temp 4-component vector of float)
+0:47 'color7' ( out 4-component vector of float)
+0:47 textureFetch ( global 4-component vector of float)
+0:47 s7: direct index for structure (layout( column_major shared layoutBindlessSampler) uniform samplerBuffer)
+0:47 'anon@0' (layout( column_major shared) uniform block{layout( column_major shared layoutBindlessSampler) uniform samplerBuffer s7})
+0:47 Constant:
+0:47 0 (const uint)
+0:47 'icoord' ( uniform int)
+0:48 move second child to first child ( temp 4-component vector of float)
+0:48 'color8' ( out 4-component vector of float)
+0:48 textureFetch ( global 4-component vector of float)
+0:48 s8: direct index for structure (layout( column_major shared layoutBindlessSampler) buffer samplerBuffer)
+0:48 'anon@1' (layout( column_major shared) buffer block{layout( column_major shared layoutBindlessSampler) buffer samplerBuffer s8})
+0:48 Constant:
+0:48 0 (const uint)
+0:48 'icoord' ( uniform int)
+0:49 move second child to first child ( temp 4-component vector of float)
+0:49 'color9' ( out 4-component vector of float)
+0:49 imageLoad ( global 4-component vector of float)
+0:49 'i9' (layout( rgba8 layoutBindlessImage) smooth in image2D)
+0:49 Constant:
+0:49 0 (const int)
+0:49 0 (const int)
+0:? Linker Objects
+0:? 's0' ( uniform sampler2D)
+0:? 's1' ( smooth in sampler2D)
+0:? 's2' ( uniform 2-component vector of uint)
+0:? 's3' ( uniform 2-component vector of int)
+0:? 'index' ( uniform int)
+0:? 's4' ( smooth in 2-element array of 3-element array of sampler2D)
+0:? 'bbs5' (layout( column_major shared) uniform 2-element array of block{layout( column_major shared layoutBindlessSampler) uniform sampler2D s5})
+0:? 's6' ( smooth in samplerBuffer)
+0:? 'anon@0' (layout( column_major shared) uniform block{layout( column_major shared layoutBindlessSampler) uniform samplerBuffer s7})
+0:? 'anon@1' (layout( column_major shared) buffer block{layout( column_major shared layoutBindlessSampler) buffer samplerBuffer s8})
+0:? 'i9' (layout( rgba8 layoutBindlessImage) smooth in image2D)
+0:? 'coord' ( uniform 2-component vector of float)
+0:? 'icoord' ( uniform int)
+0:? 'color0' ( out 4-component vector of float)
+0:? 'color1' ( out 4-component vector of float)
+0:? 'color2' ( out 4-component vector of float)
+0:? 'color3' ( out 4-component vector of float)
+0:? 'color4' ( out 4-component vector of float)
+0:? 'color5' ( out 4-component vector of float)
+0:? 'color6' ( out 4-component vector of float)
+0:? 'color7' ( out 4-component vector of float)
+0:? 'color8' ( out 4-component vector of float)
+0:? 'color9' ( out 4-component vector of float)
+
ERROR: 0:8: 'binding' : sampler/texture/image requires layout(binding=X)
ERROR: 0:9: 'binding' : sampler/texture/image requires layout(binding=X)
ERROR: 0:10: 'binding' : sampler/texture/image requires layout(binding=X)
-ERROR: 0:14: 'sampler2D' : sampler-constructor requires two arguments
+ERROR: 0:14: 'sampler2D' : sampler-constructor requires the extension GL_ARB_bindless_texture enabled
ERROR: 0:15: 'sampler2D' : sampler-constructor first argument must be a scalar *texture* type
ERROR: 0:16: 'sampler2D' : sampler-constructor first argument must be a scalar *texture* type
ERROR: 0:17: 'sampler2D' : sampler-constructor second argument must be a scalar sampler or samplerShadow
ElfR16ui,
ElfR8ui,
ElfR64ui,
+ ElfExtSizeGuard, // to help with comparisons
+ ElfSize1x8,
+ ElfSize1x16,
+ ElfSize1x32,
+ ElfSize2x32,
+ ElfSize4x32,
ElfCount
};
// -2048 as the default value indicating layoutSecondaryViewportRelative is not set
layoutSecondaryViewportRelativeOffset = -2048;
layoutShaderRecord = false;
+ layoutBindlessSampler = false;
+ layoutBindlessImage = false;
layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd;
layoutFormat = ElfNone;
#endif
// GL_EXT_spirv_intrinsics
int spirvStorageClass;
TSpirvDecorate* spirvDecorate;
+
+ bool layoutBindlessSampler;
+ bool layoutBindlessImage;
#endif
bool hasUniformLayout() const
{
return nonUniform;
}
+ bool isBindlessSampler() const
+ {
+ return layoutBindlessSampler;
+ }
+ bool isBindlessImage() const
+ {
+ return layoutBindlessImage;
+ }
// GL_EXT_spirv_intrinsics
bool hasSprivDecorate() const { return spirvDecorate != nullptr; }
case ElfR8ui: return "r8ui";
case ElfR64ui: return "r64ui";
case ElfR64i: return "r64i";
+ case ElfSize1x8: return "size1x8";
+ case ElfSize1x16: return "size1x16";
+ case ElfSize1x32: return "size1x32";
+ case ElfSize2x32: return "size2x32";
+ case ElfSize4x32: return "size4x32";
default: return "none";
}
}
virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); }
virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
virtual bool isTexture() const { return basicType == EbtSampler && getSampler().isTexture(); }
+ virtual bool isBindlessImage() const { return isImage() && qualifier.layoutBindlessImage; }
+ virtual bool isBindlessTexture() const { return isTexture() && qualifier.layoutBindlessSampler; }
// Check the block-name convention of creating a block without populating it's members:
virtual bool isUnusableName() const { return isStruct() && structure == nullptr; }
virtual bool isParameterized() const { return typeParameters != nullptr; }
return contains([](const TType* t) { return t->isOpaque(); } );
}
+ virtual bool containsSampler() const
+ {
+ return contains([](const TType* t) { return t->isTexture() || t->isImage(); });
+ }
+
// Recursively checks if the type contains a built-in variable
virtual bool containsBuiltIn() const
{
}
if (qualifier.layoutShaderRecord)
appendStr(" shaderRecordNV");
-
+ if (qualifier.layoutBindlessSampler)
+ appendStr(" layoutBindlessSampler");
+ if (qualifier.layoutBindlessImage)
+ appendStr(" layoutBindlessImage");
appendStr(")");
}
}
void setStruct(TTypeList* s) { assert(isStruct()); structure = s; }
TTypeList* getWritableStruct() const { assert(isStruct()); return structure; } // This should only be used when known to not be sharing with other threads
void setBasicType(const TBasicType& t) { basicType = t; }
+ void setVectorSize(int s) { vectorSize = s; }
int computeNumComponents() const
{
case EbtInt64: newOp = EOpConvInt64ToUint; break;
case EbtUint64: newOp = EOpConvUint64ToUint; break;
#endif
+ // For bindless texture type conversion, add a dummy convert op, just
+ // to generate a new TIntermTyped
+ // uvec2(any sampler type)
+ // uvec2(any image type)
+ case EbtSampler: newOp = EOpConvIntToUint; break;
default:
return false;
}
//
switch (node->getBasicType()) {
case EbtSampler:
- message = "can't modify a sampler";
+ if (extensionTurnedOn(E_GL_ARB_bindless_texture) == false)
+ message = "can't modify a sampler";
break;
case EbtVoid:
message = "can't modify void";
#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)
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;
}
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);
}
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) {
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(), "");
{
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) {
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());
+ }
}
}
//
// 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;
{
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;
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");
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, "");
}
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;
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)
// 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)
}
}
}
- } 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);
// 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;
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:
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:
}
//
+// 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,
}
}
- 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(), "");
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
void accStructCheck(const TSourceLoc & loc, const TType & type, const TString & identifier);
void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier);
void memberQualifierCheck(glslang::TPublicType&);
- void globalQualifierFixCheck(const TSourceLoc&, TQualifier&, bool isMemberCheck = false);
+ void globalQualifierFixCheck(const TSourceLoc&, TQualifier&, bool isMemberCheck = false, const TPublicType* publicType = nullptr);
void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&);
bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force);
void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
void invariantCheck(const TSourceLoc&, const TQualifier&);
void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
+ void updateBindlessQualifier(TType& memberType);
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body);
const TTypeList* recordStructCopy(TStructRecord&, const TType*, const TType*);
+ TLayoutFormat mapLegacyLayoutFormat(TLayoutFormat legacyLayoutFormat, TBasicType imageType);
#ifndef GLSLANG_WEB
TAttributeType attributeFromName(const TString& name) const;
virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
virtual const TParameter& operator[](int i) const { return parameters[i]; }
+ const TQualifier& getQualifier() const { return returnType.getQualifier(); }
#ifndef GLSLANG_WEB
virtual void setSpirvInstruction(const TSpirvInstruction& inst)
extensionBehavior[E_GL_ARB_texture_query_lod] = EBhDisable;
extensionBehavior[E_GL_ARB_vertex_attrib_64bit] = EBhDisable;
extensionBehavior[E_GL_ARB_draw_instanced] = EBhDisable;
+ extensionBehavior[E_GL_ARB_bindless_texture] = EBhDisable;
extensionBehavior[E_GL_ARB_fragment_coord_conventions] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_float16] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_atomic_float] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_atomic_float2] = EBhDisable;
+
+ // Record extensions not for spv.
+ spvUnsupportedExt.push_back(E_GL_ARB_bindless_texture);
}
#endif // GLSLANG_WEB
} else { // !isEsProfile()
preamble =
- "#define GL_FRAGMENT_PRECISION_HIGH 1\n"
"#define GL_ARB_texture_rectangle 1\n"
"#define GL_ARB_shading_language_420pack 1\n"
"#define GL_ARB_texture_gather 1\n"
"#define GL_ARB_vertex_attrib_64bit 1\n"
"#define GL_ARB_draw_instanced 1\n"
"#define GL_ARB_fragment_coord_conventions 1\n"
+ "#define GL_ARB_bindless_texture 1\n"
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
"#define GL_EXT_shader_image_load_formatted 1\n"
"#define GL_EXT_post_depth_coverage 1\n"
preamble += "#define GL_EXT_null_initializer 1\n";
preamble += "#define GL_EXT_subgroup_uniform_control_flow 1\n";
}
+ if (version >= 130) {
+ preamble +="#define GL_FRAGMENT_PRECISION_HIGH 1\n";
+ }
+
#endif // GLSLANG_WEB
}
minSpvVersion = iter->second;
requireSpv(loc, extension, minSpvVersion);
}
+
+ if (spvVersion.spv != 0){
+ for (auto ext : spvUnsupportedExt){
+ if (strcmp(extension, ext.c_str()) == 0)
+ error(loc, "not allowed when using generating SPIR-V codes", extension, "");
+ }
+ }
}
// Call for any operation needing full GLSL integer data-type support.
const char* const E_GL_ARB_vertex_attrib_64bit = "GL_ARB_vertex_attrib_64bit";
const char* const E_GL_ARB_draw_instanced = "GL_ARB_draw_instanced";
const char* const E_GL_ARB_fragment_coord_conventions = "GL_ARB_fragment_coord_conventions";
+const char* const E_GL_ARB_bindless_texture = "GL_ARB_bindless_texture";
const char* const E_GL_KHR_shader_subgroup_basic = "GL_KHR_shader_subgroup_basic";
const char* const E_GL_KHR_shader_subgroup_vote = "GL_KHR_shader_subgroup_vote";
parseContext.precisionQualifierCheck($$.loc, $$.basicType, $$.qualifier);
}
| type_qualifier type_specifier {
- parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
+ parseContext.globalQualifierFixCheck($1.loc, $1.qualifier, false, &$2);
parseContext.globalQualifierTypeCheck($1.loc, $1.qualifier, $2);
if ($2.arraySizes) {
parseContext.precisionQualifierCheck($$.loc, $$.basicType, $$.qualifier);
}
| type_qualifier type_specifier {
- parseContext.globalQualifierFixCheck($1.loc, $1.qualifier);
+ parseContext.globalQualifierFixCheck($1.loc, $1.qualifier, false, &$2);
parseContext.globalQualifierTypeCheck($1.loc, $1.qualifier, $2);
if ($2.arraySizes) {
case 136: /* fully_specified_type: type_qualifier type_specifier */
#line 1220 "MachineIndependent/glslang.y"
{
- parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier);
+ parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, false, &(yyvsp[0].interm.type));
parseContext.globalQualifierTypeCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, (yyvsp[0].interm.type));
if ((yyvsp[0].interm.type).arraySizes) {
if (! keepUncalled) {
for (int f = 0; f < (int)functionSequence.size(); ++f) {
if (! reachable[f])
+ {
+ resetTopLevelUncalledStatus(functionSequence[f]->getAsAggregate()->getName());
functionSequence[f] = nullptr;
+ }
}
functionSequence.erase(std::remove(functionSequence.begin(), functionSequence.end(), nullptr), functionSequence.end());
}
case EbtInt16:
case EbtUint16: size = 2; return 2;
case EbtReference: size = 8; return 8;
+ case EbtSampler:
+ {
+ if (type.isBindlessImage() || type.isBindlessTexture()) {
+ size = 8; return 8;
+ }
+ else {
+ size = 4; return 4;
+ }
+ }
default: size = 4; return 4;
}
}
LayoutDerivativeGroupLinear, // derivative_group_linearNV
};
+//
+// Status type on AST level. Some uncalled status or functions would be reset in call graph.
+// Currently we will keep status set by explicitly declared layout or variable decl.
+//
+enum AstRefType {
+ AstRefTypeVar, // Status set by variable decl
+ AstRefTypeFunc, // Status set by function decl
+ AstRefTypeLayout, // Status set by layout decl
+};
+
class TIdMaps {
public:
TMap<TString, long long>& operator[](long long i) { return maps[i]; }
useVariablePointers = true;
processes.addProcess("use-variable-pointers");
}
+ // Set the global flag for bindless texture
+ void setBindlessTextureMode(const TString& currentCaller, AstRefType type)
+ {
+ // When type is not func, currentCaller should be "" (empty string)
+ bindlessTextureModeCaller[currentCaller] = type;
+ }
+
+ // Get the global flag for bindless texture
+ bool getBindlessTextureMode() const
+ {
+ return (bindlessTextureModeCaller.size() > 0);
+ }
+
+ // Set the global flag for bindless image
+ void setBindlessImageMode(const TString& currentCaller, AstRefType type)
+ {
+ // When type is not func, currentCaller should be "" (empty string)
+ bindlessImageModeCaller[currentCaller] = type;
+ }
+
+ // Get the global flag for bindless image
+ bool getBindlessImageMode() const
+ {
+ return (bindlessImageModeCaller.size() > 0);
+ }
+
+ // Get the global flag for bindless texture
+ bool resetTopLevelUncalledStatus(const TString& deadCaller)
+ {
+ // For reflection collection purpose, currently uniform layout setting and some
+ // flags introduced by variables (IO, global, etc,.) won't be reset here.
+ // Remove each global status (AST top level) introduced by uncalled functions.
+ // If a status is set by several functions, keep those which in call graph.
+ bool result = false;
+
+ // For two types of bindless mode flag, we would only reset which is set by an uncalled function.
+ // If one status flag's key in caller vec is empty, it should be come from a non-function setting.
+ if (!bindlessTextureModeCaller.empty()) {
+ auto caller = bindlessTextureModeCaller.find(deadCaller);
+ if (caller != bindlessTextureModeCaller.end() && bindlessTextureModeCaller[deadCaller] == AstRefTypeFunc) {
+ bindlessTextureModeCaller.erase(caller);
+ result = true;
+ }
+ }
+ if (!bindlessImageModeCaller.empty()) {
+ auto caller = bindlessImageModeCaller.find(deadCaller);
+ if (caller != bindlessImageModeCaller.end() && bindlessImageModeCaller[deadCaller] == AstRefTypeFunc) {
+ bindlessImageModeCaller.erase(caller);
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ bool getBindlessMode() const
+ {
+ return getBindlessTextureMode() || getBindlessImageMode();
+ }
+
bool usingVariablePointers() const { return useVariablePointers; }
#ifdef ENABLE_HLSL
TSpirvRequirement* spirvRequirement;
TSpirvExecutionMode* spirvExecutionMode;
-
+ std::map<TString, AstRefType> bindlessTextureModeCaller;
+ std::map<TString, AstRefType> bindlessImageModeCaller;
std::unordered_map<std::string, int> uniformLocationOverrides;
int uniformLocationBase;
TNumericFeatures numericFeatures;
protected:
TMap<TString, TExtensionBehavior> extensionBehavior; // for each extension string, what its current behavior is
TMap<TString, unsigned int> extensionMinSpv; // for each extension string, store minimum spirv required
+ TVector<TString> spvUnsupportedExt; // for extensions reserved for spv usage.
EShMessages messages; // errors/warnings/rule-sets
int numErrors; // number of compile-time errors encountered
TInputScanner* currentScanner;
"GL_EXT_shader_integer_mix.vert",
"GL_ARB_draw_instanced.vert",
"GL_ARB_fragment_coord_conventions.vert",
+ "GL_ARB_bindless_texture.frag",
"BestMatchFunction.vert",
"EndStreamPrimitive.geom",
"floatBitsToInt.vert",