diff --git a/Test/baseResults/samplerlessTextureFunctions.frag.out b/Test/baseResults/samplerlessTextureFunctions.frag.out new file mode 100644 index 000000000..8ac8d4deb --- /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 000000000..0f09b43e7 --- /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 ab70471e8..beda9e033 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 000000000..092685030 --- /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 000000000..3043b39df --- /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 34341b0ea..27bd9ac91 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 828e49651..92c6f53f5 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 51b643085..5d83081a5 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 b297d27b5..0e11a8fdd 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 4b1ff462c..0e5f26122 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 );