VK_KHR_spirv_1_4 enables SPIR-V 1.4 modules

In Vulkan 1.1, VK_KHR_spirv_1_4 enables SPIR-V 1.4 modules for assembly
and validation.  This is true even if the underlying Vulkan version doesn't
natively support SPIR-V 1.4.

Deprecates vk::getMaxSpirvVersionForGlsl and vk::getMaxSpirvVersionForAsm
in favour of unified vk::getMaxSpirvVersionForVulkan.

Components: Vulkan

VK-GL-CTS issue: 1712, 1711

Change-Id: I850ab4ec3a0d88485e838d4263d751b2d6e18c08
diff --git a/external/vulkancts/framework/vulkan/vkPrograms.cpp b/external/vulkancts/framework/vulkan/vkPrograms.cpp
index 3561596..06a97b8 100644
--- a/external/vulkancts/framework/vulkan/vkPrograms.cpp
+++ b/external/vulkancts/framework/vulkan/vkPrograms.cpp
@@ -948,8 +948,8 @@
 	return vk::SPIRV_VERSION_1_0;
 }
 
-// Max supported versions for each vulkan version, without requiring a Vulkan extension.
-vk::SpirvVersion getMaxSpirvVersionForAsm (const deUint32 vulkanVersion)
+// Max supported versions for each Vulkan version, without requiring a Vulkan extension.
+vk::SpirvVersion getMaxSpirvVersionForVulkan (const deUint32 vulkanVersion)
 {
 	vk::SpirvVersion	result			= vk::SPIRV_VERSION_LAST;
 
@@ -964,19 +964,14 @@
 	return result;
 }
 
+vk::SpirvVersion getMaxSpirvVersionForAsm (const deUint32 vulkanVersion)
+{
+	return getMaxSpirvVersionForVulkan(vulkanVersion);
+}
+
 vk::SpirvVersion getMaxSpirvVersionForGlsl (const deUint32 vulkanVersion)
 {
-	vk::SpirvVersion	result			= vk::SPIRV_VERSION_LAST;
-
-	deUint32 vulkanVersionMajorMinor = VK_MAKE_VERSION(VK_VERSION_MAJOR(vulkanVersion), VK_VERSION_MINOR(vulkanVersion), 0);
-	if (vulkanVersionMajorMinor == VK_API_VERSION_1_0)
-		result = vk::SPIRV_VERSION_1_0;
-	else if (vulkanVersionMajorMinor >= VK_API_VERSION_1_1)
-		result = vk::SPIRV_VERSION_1_3;
-
-	DE_ASSERT(result < vk::SPIRV_VERSION_LAST);
-
-	return result;
+	return getMaxSpirvVersionForVulkan(vulkanVersion);
 }
 
 SpirvVersion extractSpirvVersion (const ProgramBinary& binary)
diff --git a/external/vulkancts/framework/vulkan/vkPrograms.hpp b/external/vulkancts/framework/vulkan/vkPrograms.hpp
index cca650d..fe43469 100644
--- a/external/vulkancts/framework/vulkan/vkPrograms.hpp
+++ b/external/vulkancts/framework/vulkan/vkPrograms.hpp
@@ -218,7 +218,11 @@
 glu::ShaderType			getGluShaderType	(VkShaderStageFlagBits shaderStage);
 VkShaderStageFlagBits	getVkShaderStage	(glu::ShaderType shaderType);
 
+// Returns the max SPIR-V version usable with a given Vulkan version, without requiring an extension.
+vk::SpirvVersion		getMaxSpirvVersionForVulkan	(const deUint32 vulkanVersion);
+// Deprecated. Use getMaxSpirvVersionForVulkan instead.
 vk::SpirvVersion		getMaxSpirvVersionForAsm	(const deUint32 vulkanVersion);
+// Deprecated. Use getMaxSpirvVersionForVulkan instead.
 vk::SpirvVersion		getMaxSpirvVersionForGlsl	(const deUint32 vulkanVersion);
 vk::SpirvVersion		getBaselineSpirvVersion		(const deUint32 vulkanVersion);
 SpirvVersion			extractSpirvVersion			(const ProgramBinary& binary);
diff --git a/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp b/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp
index 332072b..1b36568 100644
--- a/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp
+++ b/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp
@@ -39,13 +39,16 @@
 
 #if defined(DEQP_HAVE_SPIRV_TOOLS)
 
-// Convert a Vulkan version number to a SPIRV-Tools target environment enum.
-static spv_target_env mapVulkanVersionToSpirvToolsEnv(deUint32 vulkanVersion)
+// Returns the SPIRV-Tools target environment enum for the given dEQP Spirv validator options object.
+// Do this here instead of as a method on SpirvValidatorOptions because only this file has access to
+// the SPIRV-Tools headers.
+static spv_target_env getSpirvToolsEnvForValidatorOptions(SpirvValidatorOptions opts)
 {
-	switch (vulkanVersion)
+	const bool allow_1_4 = opts.supports_VK_KHR_spirv_1_4;
+	switch (opts.vulkanVersion)
 	{
 		case VK_MAKE_VERSION(1, 0, 0): return SPV_ENV_VULKAN_1_0;
-		case VK_MAKE_VERSION(1, 1, 0): return SPV_ENV_VULKAN_1_1;
+		case VK_MAKE_VERSION(1, 1, 0): return allow_1_4 ? SPV_ENV_VULKAN_1_1_SPIRV_1_4 : SPV_ENV_VULKAN_1_1;
 		default:
 			break;
 	}
@@ -63,6 +66,7 @@
 		case SPIRV_VERSION_1_1: result = SPV_ENV_UNIVERSAL_1_1; break;	//!< SPIR-V 1.1
 		case SPIRV_VERSION_1_2: result = SPV_ENV_UNIVERSAL_1_2; break;	//!< SPIR-V 1.2
 		case SPIRV_VERSION_1_3: result = SPV_ENV_UNIVERSAL_1_3; break;	//!< SPIR-V 1.3
+		case SPIRV_VERSION_1_4: result = SPV_ENV_UNIVERSAL_1_4; break;	//!< SPIR-V 1.4
 		default:				TCU_THROW(InternalError, "Unknown SPIR-V version");
 	}
 
@@ -147,7 +151,7 @@
 
 bool validateSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog, const SpirvValidatorOptions &val_options)
 {
-	const spv_context	context		= spvContextCreate(mapVulkanVersionToSpirvToolsEnv(val_options.vulkanVersion));
+	const spv_context	context		= spvContextCreate(getSpirvToolsEnvForValidatorOptions(val_options));
 	spv_diagnostic		diagnostic	= DE_NULL;
 
 	try
diff --git a/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp b/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp
index 6f9d449..63c145c 100644
--- a/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp
+++ b/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp
@@ -39,22 +39,27 @@
 
 struct SpirVAsmBuildOptions
 {
-	deUint32	vulkanVersion;
+	deUint32		vulkanVersion;
 	SpirvVersion	targetVersion;
+	bool			supports_VK_KHR_spirv_1_4;
 
 	SpirVAsmBuildOptions (deUint32 vulkanVersion_, SpirvVersion targetVersion_)
-		: vulkanVersion	(vulkanVersion_)
-		, targetVersion	(targetVersion_)
+		: vulkanVersion				(vulkanVersion_)
+		, targetVersion				(targetVersion_)
+		, supports_VK_KHR_spirv_1_4	(false)
 	{}
 
 	SpirVAsmBuildOptions (void)
-		: vulkanVersion	(VK_MAKE_VERSION(1, 0, 0))
-		, targetVersion	(SPIRV_VERSION_1_0)
+		: vulkanVersion				(VK_MAKE_VERSION(1, 0, 0))
+		, targetVersion				(SPIRV_VERSION_1_0)
+		, supports_VK_KHR_spirv_1_4	(false)
 	{}
 
 	SpirvValidatorOptions getSpirvValidatorOptions() const
 	{
-		return SpirvValidatorOptions(vulkanVersion);
+		SpirvValidatorOptions result(vulkanVersion);
+		result.supports_VK_KHR_spirv_1_4 = supports_VK_KHR_spirv_1_4;
+		return result;
 	}
 };
 
diff --git a/external/vulkancts/framework/vulkan/vkValidatorOptions.hpp b/external/vulkancts/framework/vulkan/vkValidatorOptions.hpp
index 5364946..e14b4c7 100644
--- a/external/vulkancts/framework/vulkan/vkValidatorOptions.hpp
+++ b/external/vulkancts/framework/vulkan/vkValidatorOptions.hpp
@@ -45,7 +45,7 @@
 	};
 
 	SpirvValidatorOptions(deUint32 the_vulkan_version = VK_MAKE_VERSION(1, 0, 0), BlockLayoutRules the_layout = kDefaultBlockLayout)
-	: vulkanVersion(the_vulkan_version), blockLayout(the_layout) {}
+	: vulkanVersion(the_vulkan_version), blockLayout(the_layout), supports_VK_KHR_spirv_1_4(false) {}
 
 	// The target Vulkan version.  This determines the SPIR-V environment rules to
 	// be checked. The bit pattern is as produced by VK_MAKE_VERSION.
@@ -53,6 +53,10 @@
 
 	// The block layout rules to enforce.
 	BlockLayoutRules blockLayout;
+
+	// Does the device support VK_KHR_spirv_1_4?
+	// (Camelcase would just be wrong here.)
+	bool supports_VK_KHR_spirv_1_4;
 };
 
 }  // namespace vk
diff --git a/external/vulkancts/modules/vulkan/vktTestPackage.cpp b/external/vulkancts/modules/vulkan/vktTestPackage.cpp
index b3ba3f0..61b0365 100644
--- a/external/vulkancts/modules/vulkan/vktTestPackage.cpp
+++ b/external/vulkancts/modules/vulkan/vktTestPackage.cpp
@@ -196,6 +196,7 @@
 	virtual tcu::TestNode::IterateResult		iterate				(tcu::TestCase* testCase);
 
 private:
+	bool										spirvVersionSupported(vk::SpirvVersion);
 	vk::BinaryCollection						m_progCollection;
 	vk::BinaryRegistryReader					m_prebuiltBinRegistry;
 
@@ -259,7 +260,7 @@
 
 	for (vk::GlslSourceCollection::Iterator progIter = sourceProgs.glslSources.begin(); progIter != sourceProgs.glslSources.end(); ++progIter)
 	{
-		if (progIter.getProgram().buildOptions.targetVersion > vk::getMaxSpirvVersionForGlsl(m_context.getUsedApiVersion()))
+		if (!spirvVersionSupported(progIter.getProgram().buildOptions.targetVersion))
 			TCU_THROW(NotSupportedError, "Shader requires SPIR-V higher than available");
 
 		const vk::ProgramBinary* const binProg = buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, progIter, m_prebuiltBinRegistry, log, &m_progCollection, commandLine);
@@ -283,7 +284,7 @@
 
 	for (vk::HlslSourceCollection::Iterator progIter = sourceProgs.hlslSources.begin(); progIter != sourceProgs.hlslSources.end(); ++progIter)
 	{
-		if (progIter.getProgram().buildOptions.targetVersion > vk::getMaxSpirvVersionForGlsl(m_context.getUsedApiVersion()))
+		if (!spirvVersionSupported(progIter.getProgram().buildOptions.targetVersion))
 			TCU_THROW(NotSupportedError, "Shader requires SPIR-V higher than available");
 
 		const vk::ProgramBinary* const binProg = buildProgram<glu::ShaderProgramInfo, vk::HlslSourceCollection::Iterator>(casePath, progIter, m_prebuiltBinRegistry, log, &m_progCollection, commandLine);
@@ -307,7 +308,7 @@
 
 	for (vk::SpirVAsmCollection::Iterator asmIterator = sourceProgs.spirvAsmSources.begin(); asmIterator != sourceProgs.spirvAsmSources.end(); ++asmIterator)
 	{
-		if (asmIterator.getProgram().buildOptions.targetVersion > vk::getMaxSpirvVersionForAsm(m_context.getUsedApiVersion()))
+		if (!spirvVersionSupported(asmIterator.getProgram().buildOptions.targetVersion))
 			TCU_THROW(NotSupportedError, "Shader requires SPIR-V higher than available");
 
 		buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, asmIterator, m_prebuiltBinRegistry, log, &m_progCollection, commandLine);
@@ -379,6 +380,17 @@
 		return tcu::TestNode::CONTINUE;
 }
 
+bool TestCaseExecutor::spirvVersionSupported (vk::SpirvVersion spirvVersion)
+{
+	if (spirvVersion <= vk::getMaxSpirvVersionForVulkan(m_context.getUsedApiVersion()))
+		return true;
+
+	if (spirvVersion <= vk::SPIRV_VERSION_1_4)
+		return vk::isDeviceExtensionSupported(m_context.getUsedApiVersion(), m_context.getDeviceExtensions(), "VK_KHR_spirv_1_4");
+
+	return false;
+}
+
 // GLSL shader tests
 
 void createGlslTests (tcu::TestCaseGroup* glslTests)