From c07c30399906aed27bfdcb156cf0c21b13c8f50f Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 27 Sep 2018 13:36:38 +0200 Subject: [PATCH] Use GL_EXT_samplerless_texture_functions in Vulkan GLSL. --- main.cpp | 3 +- .../image-fetch-no-sampler.asm.vk.frag.vk | 4 +- .../image-fetch-no-sampler.asm.vk.frag.vk | 6 +-- .../image-query-no-sampler.vk.asm.frag.vk | 10 ++--- spirv_cross.cpp | 4 +- spirv_glsl.cpp | 37 ++++++++++--------- spirv_glsl.hpp | 2 +- spirv_msl.cpp | 7 ++-- 8 files changed, 37 insertions(+), 36 deletions(-) diff --git a/main.cpp b/main.cpp index 1596e095..bb89f319 100644 --- a/main.cpp +++ b/main.cpp @@ -832,7 +832,8 @@ static int main_inner(int argc, char *argv[]) else { combined_image_samplers = !args.vulkan_semantics; - build_dummy_sampler = true; + if (!args.vulkan_semantics) + build_dummy_sampler = true; compiler = unique_ptr(new CompilerGLSL(read_spirv_file(args.input))); } diff --git a/reference/opt/shaders/asm/frag/image-fetch-no-sampler.asm.vk.frag.vk b/reference/opt/shaders/asm/frag/image-fetch-no-sampler.asm.vk.frag.vk index 23acab0b..55e2c2da 100644 --- a/reference/opt/shaders/asm/frag/image-fetch-no-sampler.asm.vk.frag.vk +++ b/reference/opt/shaders/asm/frag/image-fetch-no-sampler.asm.vk.frag.vk @@ -1,14 +1,14 @@ #version 450 +#extension GL_EXT_samplerless_texture_functions : require layout(set = 0, binding = 0) uniform sampler Sampler; layout(set = 0, binding = 0) uniform texture2D SampledImage; -layout(set = 0, binding = 0) uniform sampler SPIRV_Cross_DummySampler; layout(location = 0) out vec4 _entryPointOutput; void main() { ivec2 _152 = ivec3(int(gl_FragCoord.x * 1280.0), int(gl_FragCoord.y * 720.0), 0).xy; - _entryPointOutput = ((texelFetch(sampler2D(SampledImage, SPIRV_Cross_DummySampler), _152, 0) + texelFetch(sampler2D(SampledImage, SPIRV_Cross_DummySampler), _152, 0)) + texture(sampler2D(SampledImage, Sampler), gl_FragCoord.xy)) + texture(sampler2D(SampledImage, Sampler), gl_FragCoord.xy); + _entryPointOutput = ((texelFetch(SampledImage, _152, 0) + texelFetch(SampledImage, _152, 0)) + texture(sampler2D(SampledImage, Sampler), gl_FragCoord.xy)) + texture(sampler2D(SampledImage, Sampler), gl_FragCoord.xy); } diff --git a/reference/shaders/asm/frag/image-fetch-no-sampler.asm.vk.frag.vk b/reference/shaders/asm/frag/image-fetch-no-sampler.asm.vk.frag.vk index e4d9fc45..2dab6640 100644 --- a/reference/shaders/asm/frag/image-fetch-no-sampler.asm.vk.frag.vk +++ b/reference/shaders/asm/frag/image-fetch-no-sampler.asm.vk.frag.vk @@ -1,14 +1,14 @@ #version 450 +#extension GL_EXT_samplerless_texture_functions : require layout(set = 0, binding = 0) uniform sampler Sampler; layout(set = 0, binding = 0) uniform texture2D SampledImage; -layout(set = 0, binding = 0) uniform sampler SPIRV_Cross_DummySampler; layout(location = 0) out vec4 _entryPointOutput; vec4 sample_fetch(texture2D tex, ivec3 UV) { - return texelFetch(sampler2D(tex, SPIRV_Cross_DummySampler), UV.xy, UV.z); + return texelFetch(tex, UV.xy, UV.z); } vec4 sample_sampler(texture2D tex, vec2 UV) @@ -21,7 +21,7 @@ vec4 _main(vec4 xIn) ivec3 coord = ivec3(int(xIn.x * 1280.0), int(xIn.y * 720.0), 0); ivec3 param = coord; vec4 value = sample_fetch(SampledImage, param); - value += texelFetch(sampler2D(SampledImage, SPIRV_Cross_DummySampler), coord.xy, coord.z); + value += texelFetch(SampledImage, coord.xy, coord.z); vec2 param_1 = xIn.xy; value += sample_sampler(SampledImage, param_1); value += texture(sampler2D(SampledImage, Sampler), xIn.xy); diff --git a/reference/shaders/asm/frag/image-query-no-sampler.vk.asm.frag.vk b/reference/shaders/asm/frag/image-query-no-sampler.vk.asm.frag.vk index 828d2a87..021d3a60 100644 --- a/reference/shaders/asm/frag/image-query-no-sampler.vk.asm.frag.vk +++ b/reference/shaders/asm/frag/image-query-no-sampler.vk.asm.frag.vk @@ -1,14 +1,14 @@ #version 450 +#extension GL_EXT_samplerless_texture_functions : require layout(set = 0, binding = 0) uniform texture2D uSampler2D; layout(set = 0, binding = 0) uniform texture2DMS uSampler2DMS; -layout(set = 0, binding = 0) uniform sampler SPIRV_Cross_DummySampler; void main() { - ivec2 b = textureSize(sampler2D(uSampler2D, SPIRV_Cross_DummySampler), 0); - ivec2 c = textureSize(sampler2DMS(uSampler2DMS, SPIRV_Cross_DummySampler)); - int l1 = textureQueryLevels(sampler2D(uSampler2D, SPIRV_Cross_DummySampler)); - int s0 = textureSamples(sampler2DMS(uSampler2DMS, SPIRV_Cross_DummySampler)); + ivec2 b = textureSize(uSampler2D, 0); + ivec2 c = textureSize(uSampler2DMS); + int l1 = textureQueryLevels(uSampler2D); + int s0 = textureSamples(uSampler2DMS); } diff --git a/spirv_cross.cpp b/spirv_cross.cpp index 4cb6ab92..4082957c 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -1098,8 +1098,8 @@ const SPIRType &Compiler::get_non_pointer_type(uint32_t type_id) const bool Compiler::is_sampled_image_type(const SPIRType &type) { - return (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage) && - type.image.sampled == 1 && type.image.dim != DimBuffer; + return (type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage) && type.image.sampled == 1 && + type.image.dim != DimBuffer; } void Compiler::set_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration, diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index c8d63042..320020fd 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -4083,30 +4083,32 @@ string CompilerGLSL::to_function_name(uint32_t tex, const SPIRType &imgtype, boo return is_legacy() ? legacy_tex_op(fname, imgtype, lod, tex) : fname; } -std::string CompilerGLSL::convert_separate_image_to_combined(uint32_t id) +std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id) { - auto &imgtype = expression_type(id); auto *var = maybe_get_backing_variable(id); - // If we are fetching from a plain OpTypeImage, we must combine with a dummy sampler. + // If we are fetching from a plain OpTypeImage, we must combine with a dummy sampler in GLSL. + // In Vulkan GLSL, we can make use of the newer GL_EXT_samplerless_texture_functions. if (var) { auto &type = get(var->basetype); if (type.basetype == SPIRType::Image && type.image.sampled == 1 && type.image.dim != DimBuffer) { - if (!dummy_sampler_id) - SPIRV_CROSS_THROW( - "Cannot find dummy sampler ID. Was build_dummy_sampler_for_combined_images() called?"); - if (options.vulkan_semantics) { - auto sampled_type = imgtype; - sampled_type.basetype = SPIRType::SampledImage; - return join(type_to_glsl(sampled_type), "(", to_expression(id), ", ", to_expression(dummy_sampler_id), - ")"); + // Newer glslang supports this extension to deal with texture2D as argument to texture functions. + if (dummy_sampler_id) + SPIRV_CROSS_THROW("Vulkan GLSL should not have a dummy sampler for combining."); + require_extension_internal("GL_EXT_samplerless_texture_functions"); } else + { + if (!dummy_sampler_id) + SPIRV_CROSS_THROW( + "Cannot find dummy sampler ID. Was build_dummy_sampler_for_combined_images() called?"); + return to_combined_image_sampler(id, dummy_sampler_id); + } } } @@ -4121,7 +4123,7 @@ string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &imgtype, boo { string farg_str; if (is_fetch) - farg_str = convert_separate_image_to_combined(img); + farg_str = convert_separate_image_to_expression(img); else farg_str = to_expression(img); @@ -7526,7 +7528,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (options.es) SPIRV_CROSS_THROW("textureQueryLevels not supported in ES profile."); - auto expr = join("textureQueryLevels(", convert_separate_image_to_combined(ops[2]), ")"); + auto expr = join("textureQueryLevels(", convert_separate_image_to_expression(ops[2]), ")"); auto &restype = get(ops[0]); expr = bitcast_expression(restype, SPIRType::Int, expr); emit_op(result_type, id, expr, true); @@ -7543,7 +7545,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (type.image.sampled == 2) expr = join("imageSamples(", to_expression(ops[2]), ")"); else - expr = join("textureSamples(", convert_separate_image_to_combined(ops[2]), ")"); + expr = join("textureSamples(", convert_separate_image_to_expression(ops[2]), ")"); auto &restype = get(ops[0]); expr = bitcast_expression(restype, SPIRType::Int, expr); @@ -7564,7 +7566,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) uint32_t result_type = ops[0]; uint32_t id = ops[1]; - auto expr = join("textureSize(", convert_separate_image_to_combined(ops[2]), ", ", + auto expr = join("textureSize(", convert_separate_image_to_expression(ops[2]), ", ", bitcast_expression(SPIRType::Int, ops[3]), ")"); auto &restype = get(ops[0]); expr = bitcast_expression(restype, SPIRType::Int, expr); @@ -7783,7 +7785,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) else { // This path is hit for samplerBuffers and multisampled images which do not have LOD. - expr = join("textureSize(", convert_separate_image_to_combined(ops[2]), ")"); + expr = join("textureSize(", convert_separate_image_to_expression(ops[2]), ")"); } auto &restype = get(ops[0]); @@ -9282,8 +9284,7 @@ void CompilerGLSL::branch(uint32_t from, uint32_t to) // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block, // write to the ladder here, and defer the break. // The loop we're breaking out of must dominate the switch block, or there is no ladder breaking case. - if (current_emitting_switch && is_loop_break(to) && - current_emitting_switch->loop_dominator != -1u && + if (current_emitting_switch && is_loop_break(to) && current_emitting_switch->loop_dominator != -1u && get(current_emitting_switch->loop_dominator).merge_block == to) { if (!current_emitting_switch->need_ladder_break) diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index fc9ca038..fe445adc 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -574,7 +574,7 @@ protected: std::string convert_float_to_string(const SPIRConstant &value, uint32_t col, uint32_t row); std::string convert_double_to_string(const SPIRConstant &value, uint32_t col, uint32_t row); - std::string convert_separate_image_to_combined(uint32_t id); + std::string convert_separate_image_to_expression(uint32_t id); // Builtins in GLSL are always specific signedness, but the SPIR-V can declare them // as either unsigned or signed. diff --git a/spirv_msl.cpp b/spirv_msl.cpp index e8c0c64b..fc9d43e1 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -3161,8 +3161,7 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool farg_str += to_expression(sample); } - if (msl_options.swizzle_texture_samples && is_sampled_image_type(imgtype) && - (!is_gather || !imgtype.image.depth)) + if (msl_options.swizzle_texture_samples && is_sampled_image_type(imgtype) && (!is_gather || !imgtype.image.depth)) { // Add the swizzle constant from the swizzle buffer. if (!is_gather) @@ -4687,8 +4686,8 @@ bool CompilerMSL::SampledImageScanner::handle(spv::Op opcode, const uint32_t *ar case OpImageSampleProjDrefImplicitLod: case OpImageFetch: case OpImageGather: - compiler.has_sampled_images = compiler.has_sampled_images || - compiler.is_sampled_image_type(compiler.expression_type(args[2])); + compiler.has_sampled_images = + compiler.has_sampled_images || compiler.is_sampled_image_type(compiler.expression_type(args[2])); break; default: break;