[glslang][EXT] Support extension ARB_bindless_texture.
authorZhou <shaozhou@amd.com>
Tue, 15 Nov 2022 16:04:55 +0000 (00:04 +0800)
committerShchchowAMD <laddoc@outlook.com>
Wed, 7 Dec 2022 05:32:39 +0000 (13:32 +0800)
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.

19 files changed:
SPIRV/GlslangToSpv.cpp
Test/GL_ARB_bindless_texture.frag [new file with mode: 0644]
Test/baseResults/GL_ARB_bindless_texture.frag.out [new file with mode: 0644]
Test/baseResults/vulkan.frag.out
glslang/Include/Types.h
glslang/MachineIndependent/Intermediate.cpp
glslang/MachineIndependent/ParseContextBase.cpp
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/ParseHelper.h
glslang/MachineIndependent/SymbolTable.h
glslang/MachineIndependent/Versions.cpp
glslang/MachineIndependent/Versions.h
glslang/MachineIndependent/glslang.m4
glslang/MachineIndependent/glslang.y
glslang/MachineIndependent/glslang_tab.cpp
glslang/MachineIndependent/linkValidate.cpp
glslang/MachineIndependent/localintermediate.h
glslang/MachineIndependent/parseVersions.h
gtests/AST.FromFile.cpp

index 842221c..baed22c 100644 (file)
@@ -1293,7 +1293,7 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T
             type.getQualifier().storage == glslang::EvqUniform) {
         if (type.isAtomic())
             return spv::StorageClassAtomicCounter;
-        if (type.containsOpaque())
+        if (type.containsOpaque() && !glslangIntermediate->getBindlessMode())
             return spv::StorageClassUniformConstant;
     }
 
@@ -5083,7 +5083,7 @@ bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier,
         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
diff --git a/Test/GL_ARB_bindless_texture.frag b/Test/GL_ARB_bindless_texture.frag
new file mode 100644 (file)
index 0000000..58c8359
--- /dev/null
@@ -0,0 +1,50 @@
+#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
diff --git a/Test/baseResults/GL_ARB_bindless_texture.frag.out b/Test/baseResults/GL_ARB_bindless_texture.frag.out
new file mode 100644 (file)
index 0000000..3f902c9
--- /dev/null
@@ -0,0 +1,205 @@
+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)
+
index 78aea82..8e6bfcc 100644 (file)
@@ -6,7 +6,7 @@ ERROR: 0:6: 'binding' : sampler/texture/image requires layout(binding=X)
 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 
index a6f47e8..ee9b79a 100644 (file)
@@ -429,6 +429,12 @@ enum TLayoutFormat {
     ElfR16ui,
     ElfR8ui,
     ElfR64ui,
+    ElfExtSizeGuard,   // to help with comparisons
+    ElfSize1x8,
+    ElfSize1x16,
+    ElfSize1x32,
+    ElfSize2x32,
+    ElfSize4x32,
 
     ElfCount
 };
@@ -898,6 +904,8 @@ public:
         // -2048 as the default value indicating layoutSecondaryViewportRelative is not set
         layoutSecondaryViewportRelativeOffset = -2048;
         layoutShaderRecord = false;
+        layoutBindlessSampler = false;
+        layoutBindlessImage = false;
         layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd;
         layoutFormat = ElfNone;
 #endif
@@ -1001,6 +1009,9 @@ public:
     // GL_EXT_spirv_intrinsics
     int spirvStorageClass;
     TSpirvDecorate* spirvDecorate;
+
+    bool layoutBindlessSampler;
+    bool layoutBindlessImage;
 #endif
 
     bool hasUniformLayout() const
@@ -1132,6 +1143,14 @@ public:
     {
         return nonUniform;
     }
+    bool isBindlessSampler() const
+    {
+        return layoutBindlessSampler;
+    }
+    bool isBindlessImage() const
+    {
+        return layoutBindlessImage;
+    }
 
     // GL_EXT_spirv_intrinsics
     bool hasSprivDecorate() const { return spirvDecorate != nullptr; }
@@ -1241,6 +1260,11 @@ public:
         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";
         }
     }
@@ -1898,6 +1922,8 @@ public:
     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; }
@@ -1954,6 +1980,11 @@ public:
         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
     {
@@ -2285,7 +2316,10 @@ public:
               }
               if (qualifier.layoutShaderRecord)
                 appendStr(" shaderRecordNV");
-
+              if (qualifier.layoutBindlessSampler)
+                  appendStr(" layoutBindlessSampler");
+              if (qualifier.layoutBindlessImage)
+                  appendStr(" layoutBindlessImage");
               appendStr(")");
             }
           }
@@ -2544,6 +2578,7 @@ public:
     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
     {
index 6a43ef3..e038e45 100644 (file)
@@ -751,6 +751,11 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne
         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;
         }
index 616580f..ab06be4 100644 (file)
@@ -159,7 +159,8 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
         //
         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";
index 41afbc0..68fcfea 100644 (file)
@@ -1389,7 +1389,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)
@@ -1675,9 +1676,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;
 }
@@ -1928,6 +1933,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);
 }
 
@@ -2811,6 +2819,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) {
@@ -3544,8 +3560,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(), "");
@@ -3565,6 +3586,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) {
@@ -3660,13 +3701,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());
+        }
     }
 }
 
@@ -3732,7 +3792,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;
 
@@ -3768,6 +3828,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;
@@ -4172,7 +4237,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");
@@ -5105,7 +5170,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, "");
 }
 
@@ -5480,6 +5545,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;
@@ -6137,6 +6224,10 @@ 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)
@@ -6418,7 +6509,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)
@@ -6437,7 +6528,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);
@@ -7745,12 +7836,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;
@@ -7885,6 +7978,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:
@@ -7898,7 +8001,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:
@@ -8246,6 +8357,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,
@@ -8297,8 +8432,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(), "");
@@ -9472,4 +9612,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
index 885fd90..37f4d0b 100644 (file)
@@ -393,7 +393,7 @@ public:
     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);
@@ -456,9 +456,11 @@ public:
     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;
index 0d45e48..179135c 100644 (file)
@@ -319,6 +319,7 @@ public:
 
     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)
index a5fd107..044a6bd 100644 (file)
@@ -227,6 +227,7 @@ void TParseVersions::initializeExtensionBehavior()
     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;
 
 
@@ -370,6 +371,9 @@ void TParseVersions::initializeExtensionBehavior()
     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
@@ -437,7 +441,6 @@ void TParseVersions::getPreamble(std::string& preamble)
 
     } 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"
@@ -477,6 +480,7 @@ void TParseVersions::getPreamble(std::string& preamble)
             "#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"
@@ -576,6 +580,10 @@ void TParseVersions::getPreamble(std::string& preamble)
             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
     }
 
@@ -1099,6 +1107,13 @@ void TParseVersions::extensionRequires(const TSourceLoc &loc, const char * const
             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.
index f06abdd..831da9f 100644 (file)
@@ -163,6 +163,7 @@ const char* const E_GL_ARB_texture_query_lod            = "GL_ARB_texture_query_
 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";
index a59da44..f8b0397 100644 (file)
@@ -1218,7 +1218,7 @@ fully_specified_type
         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) {
index 35242f2..344a1c1 100644 (file)
@@ -1218,7 +1218,7 @@ fully_specified_type
         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) {
index 7ca3e71..1458c5f 100644 (file)
@@ -6551,7 +6551,7 @@ yyreduce:
   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) {
index fab65a7..aa0f295 100644 (file)
@@ -1517,7 +1517,10 @@ void TIntermediate::checkCallGraphBodies(TInfoSink& infoSink, bool keepUncalled)
     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());
     }
@@ -2012,6 +2015,15 @@ int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size)
     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;
     }
 }
index 1bb4e97..87c4c91 100644 (file)
@@ -225,6 +225,16 @@ enum ComputeDerivativeMode {
     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]; }
@@ -744,6 +754,65 @@ public:
         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
@@ -1188,7 +1257,8 @@ protected:
 
     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;
index 3c52ff1..6663e88 100644 (file)
@@ -226,6 +226,7 @@ public:
 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;
index 1d97546..81633f9 100644 (file)
@@ -291,6 +291,7 @@ INSTANTIATE_TEST_SUITE_P(
         "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",