diff --git a/Test/baseResults/samplerlessTextureFunctions.frag.out b/Test/baseResults/samplerlessTextureFunctions.frag.out
new file mode 100644
index 0000000000000000000000000000000000000000..8ac8d4deb071bcd1739e0db7d82c8558ce24af42
--- /dev/null
+++ b/Test/baseResults/samplerlessTextureFunctions.frag.out
@@ -0,0 +1,13 @@
+samplerlessTextureFunctions.frag
+ERROR: 0:9: 'texelFetch' : required extension not requested: GL_EXT_samplerless_texture_functions
+ERROR: 0:10: 'texelFetch' : required extension not requested: GL_EXT_samplerless_texture_functions
+ERROR: 0:16: 'texelFetchOffset' : required extension not requested: GL_EXT_samplerless_texture_functions
+ERROR: 0:18: 'textureSize' : required extension not requested: GL_EXT_samplerless_texture_functions
+ERROR: 0:19: 'textureSize' : required extension not requested: GL_EXT_samplerless_texture_functions
+ERROR: 0:20: 'textureSize' : required extension not requested: GL_EXT_samplerless_texture_functions
+ERROR: 0:22: 'textureQueryLevels' : required extension not requested: GL_EXT_samplerless_texture_functions
+ERROR: 0:24: 'textureSamples' : required extension not requested: GL_EXT_samplerless_texture_functions
+ERROR: 8 compilation errors.  No code generated.
+
+
+SPIR-V is not generated for failed compile or link
diff --git a/Test/baseResults/spv.samplerlessTextureFunctions.frag.out b/Test/baseResults/spv.samplerlessTextureFunctions.frag.out
new file mode 100644
index 0000000000000000000000000000000000000000..0f09b43e765565d7db9de43303504824e8f1046f
--- /dev/null
+++ b/Test/baseResults/spv.samplerlessTextureFunctions.frag.out
@@ -0,0 +1,93 @@
+spv.samplerlessTextureFunctions.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 51
+
+                              Capability Shader
+                              Capability SampledBuffer
+                              Capability ImageQuery
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main"
+                              ExecutionMode 4 OriginUpperLeft
+                              Source GLSL 450
+                              SourceExtension  "GL_EXT_samplerless_texture_functions"
+                              Name 4  "main"
+                              Name 9  "tex2DFetch"
+                              Name 12  "tex2D"
+                              Name 19  "texMSFetch"
+                              Name 22  "texMS"
+                              Name 25  "bufFetch"
+                              Name 28  "buf"
+                              Name 31  "tex2DFetchOffset"
+                              Name 35  "tex2DSize"
+                              Name 38  "texMSSize"
+                              Name 42  "bufSize"
+                              Name 45  "tex2DLevels"
+                              Name 48  "texMSSamples"
+                              Decorate 12(tex2D) DescriptorSet 0
+                              Decorate 12(tex2D) Binding 1
+                              Decorate 22(texMS) DescriptorSet 0
+                              Decorate 22(texMS) Binding 1
+                              Decorate 28(buf) DescriptorSet 0
+                              Decorate 28(buf) Binding 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 4
+               8:             TypePointer Function 7(fvec4)
+              10:             TypeImage 6(float) 2D sampled format:Unknown
+              11:             TypePointer UniformConstant 10
+       12(tex2D):     11(ptr) Variable UniformConstant
+              14:             TypeInt 32 1
+              15:             TypeVector 14(int) 2
+              16:     14(int) Constant 0
+              17:   15(ivec2) ConstantComposite 16 16
+              20:             TypeImage 6(float) 2D multi-sampled sampled format:Unknown
+              21:             TypePointer UniformConstant 20
+       22(texMS):     21(ptr) Variable UniformConstant
+              26:             TypeImage 6(float) Buffer sampled format:Unknown
+              27:             TypePointer UniformConstant 26
+         28(buf):     27(ptr) Variable UniformConstant
+              34:             TypePointer Function 15(ivec2)
+              41:             TypePointer Function 14(int)
+         4(main):           2 Function None 3
+               5:             Label
+   9(tex2DFetch):      8(ptr) Variable Function
+  19(texMSFetch):      8(ptr) Variable Function
+    25(bufFetch):      8(ptr) Variable Function
+31(tex2DFetchOffset):      8(ptr) Variable Function
+   35(tex2DSize):     34(ptr) Variable Function
+   38(texMSSize):     34(ptr) Variable Function
+     42(bufSize):     41(ptr) Variable Function
+ 45(tex2DLevels):     41(ptr) Variable Function
+48(texMSSamples):     41(ptr) Variable Function
+              13:          10 Load 12(tex2D)
+              18:    7(fvec4) ImageFetch 13 17 Lod 16
+                              Store 9(tex2DFetch) 18
+              23:          20 Load 22(texMS)
+              24:    7(fvec4) ImageFetch 23 17 Sample 16
+                              Store 19(texMSFetch) 24
+              29:          26 Load 28(buf)
+              30:    7(fvec4) ImageFetch 29 16
+                              Store 25(bufFetch) 30
+              32:          10 Load 12(tex2D)
+              33:    7(fvec4) ImageFetch 32 17 Lod ConstOffset 16 17
+                              Store 31(tex2DFetchOffset) 33
+              36:          10 Load 12(tex2D)
+              37:   15(ivec2) ImageQuerySizeLod 36 16
+                              Store 35(tex2DSize) 37
+              39:          20 Load 22(texMS)
+              40:   15(ivec2) ImageQuerySize 39
+                              Store 38(texMSSize) 40
+              43:          26 Load 28(buf)
+              44:     14(int) ImageQuerySize 43
+                              Store 42(bufSize) 44
+              46:          10 Load 12(tex2D)
+              47:     14(int) ImageQueryLevels 46
+                              Store 45(tex2DLevels) 47
+              49:          20 Load 22(texMS)
+              50:     14(int) ImageQuerySamples 49
+                              Store 48(texMSSamples) 50
+                              Return
+                              FunctionEnd
diff --git a/Test/baseResults/spv.specConstant.vert.out b/Test/baseResults/spv.specConstant.vert.out
index ab70471e822e2211798988e6380b559d54642751..beda9e033b5fd882bb5de0094f67f0d2c9673d83 100644
--- a/Test/baseResults/spv.specConstant.vert.out
+++ b/Test/baseResults/spv.specConstant.vert.out
@@ -11,7 +11,7 @@ spv.specConstant.vert
                               Source GLSL 400
                               Name 4  "main"
                               Name 9  "arraySize"
-                              Name 14  "foo(vf4[s2468];"
+                              Name 14  "foo(vf4[s2543];"
                               Name 13  "p"
                               Name 17  "builtin_spec_constant("
                               Name 20  "color"
@@ -102,10 +102,10 @@ spv.specConstant.vert
                               Store 20(color) 46
               48:          10 Load 22(ucol)
                               Store 47(param) 48
-              49:           2 FunctionCall 14(foo(vf4[s2468];) 47(param)
+              49:           2 FunctionCall 14(foo(vf4[s2543];) 47(param)
                               Return
                               FunctionEnd
-14(foo(vf4[s2468];):           2 Function None 12
+14(foo(vf4[s2543];):           2 Function None 12
            13(p):     11(ptr) FunctionParameter
               15:             Label
               54:     24(ptr) AccessChain 53(dupUcol) 23
diff --git a/Test/samplerlessTextureFunctions.frag b/Test/samplerlessTextureFunctions.frag
new file mode 100644
index 0000000000000000000000000000000000000000..0926850309dd55f74145cdd7bc7a9b54898ab434
--- /dev/null
+++ b/Test/samplerlessTextureFunctions.frag
@@ -0,0 +1,46 @@
+#version 450 core
+
+layout(binding = 1) uniform texture2D tex2D;
+layout(binding = 1) uniform texture2DMS texMS;
+layout(binding = 0) uniform textureBuffer buf;
+
+void testBad()
+{
+    vec4 tex2DFetch = texelFetch(tex2D, ivec2(0, 0), 0);
+    vec4 texMSFetch = texelFetch(texMS, ivec2(0, 0), 0);
+
+    // Allowed by KHR_vulkan_glsl without the extension. All others should
+    // error.
+    vec4 bufFetch = texelFetch(buf, 0);
+
+    vec4 tex2DFetchOffset = texelFetchOffset(tex2D, ivec2(0, 0), 0, ivec2(0, 0));
+
+    ivec2 tex2DSize = textureSize(tex2D, 0);
+    ivec2 texMSSize = textureSize(texMS);
+    int bufSize = textureSize(buf);
+
+    int tex2DLevels = textureQueryLevels(tex2D);
+
+    int texMSSamples = textureSamples(texMS);
+}
+
+#extension GL_EXT_samplerless_texture_functions : enable
+
+void main()
+{
+    // These should all succeed.
+
+    vec4 tex2DFetch = texelFetch(tex2D, ivec2(0, 0), 0);
+    vec4 texMSFetch = texelFetch(texMS, ivec2(0, 0), 0);
+    vec4 bufFetch = texelFetch(buf, 0);
+
+    vec4 tex2DFetchOffset = texelFetchOffset(tex2D, ivec2(0, 0), 0, ivec2(0, 0));
+
+    ivec2 tex2DSize = textureSize(tex2D, 0);
+    ivec2 texMSSize = textureSize(texMS);
+    int bufSize = textureSize(buf);
+
+    int tex2DLevels = textureQueryLevels(tex2D);
+
+    int texMSSamples = textureSamples(texMS);
+}
diff --git a/Test/spv.samplerlessTextureFunctions.frag b/Test/spv.samplerlessTextureFunctions.frag
new file mode 100644
index 0000000000000000000000000000000000000000..3043b39df21993af6c18a6e15b6e0cc05e7367cf
--- /dev/null
+++ b/Test/spv.samplerlessTextureFunctions.frag
@@ -0,0 +1,23 @@
+#version 450 core
+#extension GL_EXT_samplerless_texture_functions : enable
+
+layout(binding = 1) uniform texture2D tex2D;
+layout(binding = 1) uniform texture2DMS texMS;
+layout(binding = 0) uniform textureBuffer buf;
+
+void main()
+{
+    vec4 tex2DFetch = texelFetch(tex2D, ivec2(0, 0), 0);
+    vec4 texMSFetch = texelFetch(texMS, ivec2(0, 0), 0);
+    vec4 bufFetch = texelFetch(buf, 0);
+
+    vec4 tex2DFetchOffset = texelFetchOffset(tex2D, ivec2(0, 0), 0, ivec2(0, 0));
+
+    ivec2 tex2DSize = textureSize(tex2D, 0);
+    ivec2 texMSSize = textureSize(texMS);
+    int bufSize = textureSize(buf);
+
+    int tex2DLevels = textureQueryLevels(tex2D);
+
+    int texMSSamples = textureSamples(texMS);
+}
diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp
index 34341b0ea12b7c7a2aa953b5fb7b1bfb87c448dc..27bd9ac91184ee5ce728fae649722b88495658fd 100755
--- a/glslang/MachineIndependent/Initialize.cpp
+++ b/glslang/MachineIndependent/Initialize.cpp
@@ -5914,15 +5914,19 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c
                                 addSamplingFunctions(sampler, typeName, version, profile);
                                 addGatherFunctions(sampler, typeName, version, profile);
 
-                                if (spvVersion.vulkan > 0 && sampler.dim == EsdBuffer && sampler.isCombined()) {
-                                    // Vulkan wants a textureBuffer to allow texelFetch() --
-                                    // a sampled image with no sampler.
-                                    // So, add sampling functions for both the
-                                    // samplerBuffer and textureBuffer types.
+                                if (spvVersion.vulkan > 0 && sampler.isCombined() && !sampler.shadow) {
+                                    // Base Vulkan allows texelFetch() for
+                                    // textureBuffer (i.e. without sampler).
+                                    //
+                                    // GL_EXT_samplerless_texture_functions
+                                    // allows texelFetch() and query functions
+                                    // (other than textureQueryLod()) for all
+                                    // texture types.
                                     sampler.setTexture(sampler.type, sampler.dim, sampler.arrayed, sampler.shadow,
                                                        sampler.ms);
                                     TString textureTypeName = sampler.getString();
                                     addSamplingFunctions(sampler, textureTypeName, version, profile);
+                                    addQueryFunctions(sampler, textureTypeName, version, profile);
                                 }
                             }
                         }
@@ -5995,7 +5999,7 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, const TString& typeName, int
     // textureQueryLod(), fragment stage only
     //
 
-    if (profile != EEsProfile && version >= 400 && ! sampler.image && sampler.dim != EsdRect && ! sampler.ms && sampler.dim != EsdBuffer) {
+    if (profile != EEsProfile && version >= 400 && sampler.combined && sampler.dim != EsdRect && ! sampler.ms && sampler.dim != EsdBuffer) {
 #ifdef AMD_EXTENSIONS
         for (int f16TexAddr = 0; f16TexAddr < 2; ++f16TexAddr) {
             if (f16TexAddr && sampler.type != EbtFloat16)
@@ -6200,12 +6204,12 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName,
     //
     for (int proj = 0; proj <= 1; ++proj) { // loop over "bool" projective or not
 
-        if (proj && (sampler.dim == EsdCube || sampler.dim == EsdBuffer || sampler.arrayed || sampler.ms))
+        if (proj && (sampler.dim == EsdCube || sampler.dim == EsdBuffer || sampler.arrayed || sampler.ms || !sampler.combined))
             continue;
 
         for (int lod = 0; lod <= 1; ++lod) {
 
-            if (lod && (sampler.dim == EsdBuffer || sampler.dim == EsdRect || sampler.ms))
+            if (lod && (sampler.dim == EsdBuffer || sampler.dim == EsdRect || sampler.ms || !sampler.combined))
                 continue;
             if (lod && sampler.dim == Esd2D && sampler.arrayed && sampler.shadow)
                 continue;
@@ -6214,7 +6218,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName,
 
             for (int bias = 0; bias <= 1; ++bias) {
 
-                if (bias && (lod || sampler.ms))
+                if (bias && (lod || sampler.ms || !sampler.combined))
                     continue;
                 if (bias && (sampler.dim == Esd2D || sampler.dim == EsdCube) && sampler.shadow && sampler.arrayed)
                     continue;
@@ -6236,12 +6240,12 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName,
                             continue;
                         if (fetch && (sampler.shadow || sampler.dim == EsdCube))
                             continue;
-                        if (fetch == 0 && (sampler.ms || sampler.dim == EsdBuffer))
+                        if (fetch == 0 && (sampler.ms || sampler.dim == EsdBuffer || !sampler.combined))
                             continue;
 
                         for (int grad = 0; grad <= 1; ++grad) { // loop over "bool" grad or not
 
-                            if (grad && (lod || bias || sampler.ms))
+                            if (grad && (lod || bias || sampler.ms || !sampler.combined))
                                 continue;
                             if (grad && sampler.dim == EsdBuffer)
                                 continue;
@@ -6263,7 +6267,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName,
 
                                 if (extraProj && ! proj)
                                     continue;
-                                if (extraProj && (sampler.dim == Esd3D || sampler.shadow))
+                                if (extraProj && (sampler.dim == Esd3D || sampler.shadow || !sampler.combined))
                                     continue;
 #ifdef AMD_EXTENSIONS
                                 for (int f16TexAddr = 0; f16TexAddr <= 1; ++f16TexAddr) { // loop over 16-bit floating-point texel addressing
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 828e49651f056893a66d91dc65ed6a680bfcb21d..92c6f53f5486babedfbadbe176bd9efd14a2f1d8 100755
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -1705,6 +1705,31 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
         break;
     }
 
+    // Texture operations on texture objects (aside from texelFetch on a
+    // textureBuffer) require EXT_samplerless_texture_functions.
+    switch (callNode.getOp()) {
+    case EOpTextureQuerySize:
+    case EOpTextureQueryLevels:
+    case EOpTextureQuerySamples:
+    case EOpTextureFetch:
+    case EOpTextureFetchOffset:
+    {
+        const TSampler& sampler = fnCandidate[0].type->getSampler();
+
+        const bool isTexture = sampler.isTexture() && !sampler.isCombined();
+        const bool isBuffer = sampler.dim == EsdBuffer;
+        const bool isFetch = callNode.getOp() == EOpTextureFetch || callNode.getOp() == EOpTextureFetchOffset;
+
+        if (isTexture && (!isBuffer || !isFetch))
+            requireExtensions(loc, 1, &E_GL_EXT_samplerless_texture_functions, fnCandidate.getName().c_str());
+
+        break;
+    }
+
+    default:
+        break;
+    }
+
     if (callNode.getOp() > EOpSubgroupGuardStart && callNode.getOp() < EOpSubgroupGuardStop) {
         // these require SPIR-V 1.3
         if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_3)
diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp
index 51b643085392fe266e022882bb2024cec6897f78..5d83081a50d88f4a280800dbd496ef2dcb3f5821 100755
--- a/glslang/MachineIndependent/Versions.cpp
+++ b/glslang/MachineIndependent/Versions.cpp
@@ -200,6 +200,7 @@ void TParseVersions::initializeExtensionBehavior()
     extensionBehavior[E_GL_EXT_post_depth_coverage]                     = EBhDisable;
     extensionBehavior[E_GL_EXT_control_flow_attributes]                 = EBhDisable;
     extensionBehavior[E_GL_EXT_nonuniform_qualifier]                    = EBhDisable;
+    extensionBehavior[E_GL_EXT_samplerless_texture_functions]           = EBhDisable;
 
     // #line and #include
     extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive]          = EBhDisable;
@@ -362,6 +363,7 @@ void TParseVersions::getPreamble(std::string& preamble)
             "#define GL_EXT_post_depth_coverage 1\n"
             "#define GL_EXT_control_flow_attributes 1\n"
             "#define GL_EXT_nonuniform_qualifier 1\n"
+            "#define GL_EXT_samplerless_texture_functions 1\n"
 
             // GL_KHR_shader_subgroup
             "#define GL_KHR_shader_subgroup_basic 1\n"
diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h
index b297d27b5c783b7776d71b2fa1530e3ca64db0e7..0e11a8fdd747208da4a331810d7823d592599f03 100755
--- a/glslang/MachineIndependent/Versions.h
+++ b/glslang/MachineIndependent/Versions.h
@@ -153,11 +153,12 @@ const char* const E_GL_EXT_shader_non_constant_global_initializers = "GL_EXT_sha
 const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_load_formatted";
 
 // EXT extensions
-const char* const E_GL_EXT_device_group                 = "GL_EXT_device_group";
-const char* const E_GL_EXT_multiview                    = "GL_EXT_multiview";
-const char* const E_GL_EXT_post_depth_coverage          = "GL_EXT_post_depth_coverage";
-const char* const E_GL_EXT_control_flow_attributes      = "GL_EXT_control_flow_attributes";
-const char* const E_GL_EXT_nonuniform_qualifier         = "GL_EXT_nonuniform_qualifier";
+const char* const E_GL_EXT_device_group                     = "GL_EXT_device_group";
+const char* const E_GL_EXT_multiview                        = "GL_EXT_multiview";
+const char* const E_GL_EXT_post_depth_coverage              = "GL_EXT_post_depth_coverage";
+const char* const E_GL_EXT_control_flow_attributes          = "GL_EXT_control_flow_attributes";
+const char* const E_GL_EXT_nonuniform_qualifier             = "GL_EXT_nonuniform_qualifier";
+const char* const E_GL_EXT_samplerless_texture_functions    = "GL_EXT_samplerless_texture_functions";
 
 // Arrays of extensions for the above viewportEXTs duplications
 
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index 4b1ff462cc782c209f0cc5e7dbf9b3c1a0e3f392..0e5f26122b91cbc77f06e355faa608e20cda084a 100755
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -344,6 +344,7 @@ INSTANTIATE_TEST_CASE_P(
         "spv.xfb.vert",
         "spv.xfb2.vert",
         "spv.xfb3.vert",
+        "spv.samplerlessTextureFunctions.frag",
     })),
     FileNameAsCustomTestSuffix
 );
@@ -433,6 +434,7 @@ INSTANTIATE_TEST_CASE_P(
         "vulkan.frag",
         "vulkan.vert",
         "vulkan.comp",
+        "samplerlessTextureFunctions.frag",
     })),
     FileNameAsCustomTestSuffix
 );