Add high precision filtering extension

This lets users specify the level of sampling precision they want.
Chromium needs this to pass WebGL tests with SWANGLE.

Bug: b/146423360
Bug: b/154620295

Change-Id: I83575823b5909d836c3d4c02803ba7909ce08935
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/42268
Tested-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/include/vulkan/vk_google_filtering_precision.h b/include/vulkan/vk_google_filtering_precision.h
new file mode 100644
index 0000000..65e3bcf
--- /dev/null
+++ b/include/vulkan/vk_google_filtering_precision.h
@@ -0,0 +1,41 @@
+// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "vulkan_core.h"
+
+// THIS FILE SHOULD BE DELETED IF VK_GOOGLE_sampler_filtering_precision IS EVER ADDED TO THE VULKAN HEADERS
+#ifdef VK_GOOGLE_sampler_filtering_precision
+#error "VK_GOOGLE_sampler_filtering_precision is already defined in the Vulkan headers, you can delete this file"
+#endif
+
+static constexpr VkStructureType VK_STRUCTURE_TYPE_SAMPLER_FILTERING_PRECISION_GOOGLE = static_cast<VkStructureType>(1000264000);
+
+#define VK_GOOGLE_sampler_filtering_precisions 1
+#define VK_GOOGLE_SAMPLER_FILTERING_PRECISION_SPEC_VERSION 1
+#define VK_GOOGLE_SAMPLER_FILTERING_PRECISION_EXTENSION_NAME "VK_GOOGLE_sampler_filtering_precision"
+
+typedef enum VkSamplerFilteringPrecisionModeGOOGLE {
+    VK_SAMPLER_FILTERING_PRECISION_MODE_LOW_GOOGLE = 0,
+    VK_SAMPLER_FILTERING_PRECISION_MODE_HIGH_GOOGLE = 1,
+    VK_SAMPLER_FILTERING_PRECISION_MODE_BEGIN_RANGE_GOOGLE = VK_SAMPLER_FILTERING_PRECISION_MODE_LOW_GOOGLE,
+    VK_SAMPLER_FILTERING_PRECISION_MODE_END_RANGE_GOOGLE = VK_SAMPLER_FILTERING_PRECISION_MODE_HIGH_GOOGLE,
+    VK_SAMPLER_FILTERING_PRECISION_MODE_RANGE_SIZE_GOOGLE = (VK_SAMPLER_FILTERING_PRECISION_MODE_HIGH_GOOGLE - VK_SAMPLER_FILTERING_PRECISION_MODE_LOW_GOOGLE + 1),
+    VK_SAMPLER_FILTERING_PRECISION_MODE_MAX_ENUM_GOOGLE = 0x7FFFFFFF
+} VkSamplerFilteringPrecisionModeGOOGLE;
+
+typedef struct VkSamplerFilteringPrecisionGOOGLE {
+    VkStructureType                       sType;
+    const void*                           pNext;
+    VkSamplerFilteringPrecisionModeGOOGLE samplerFilteringPrecisionMode;
+} VkSamplerFilteringPrecisionGOOGLE;
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index 590fc11..d1d845c 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -56,7 +56,6 @@
 		samplerState.mipmapFilter = convertMipmapMode(sampler);
 		samplerState.swizzle = imageDescriptor->swizzle;
 		samplerState.gatherComponent = instruction.gatherComponent;
-		samplerState.highPrecisionFiltering = false;
 		samplerState.largeTexture = (imageDescriptor->extent.width > SHRT_MAX) ||
 		                            (imageDescriptor->extent.height > SHRT_MAX) ||
 		                            (imageDescriptor->extent.depth > SHRT_MAX);
@@ -67,6 +66,7 @@
 			samplerState.border = sampler->borderColor;
 
 			samplerState.mipmapFilter = convertMipmapMode(sampler);
+			samplerState.highPrecisionFiltering = (sampler->filteringPrecision == VK_SAMPLER_FILTERING_PRECISION_MODE_HIGH_GOOGLE);
 
 			samplerState.compareEnable = (sampler->compareEnable != VK_FALSE);
 			samplerState.compareOp = sampler->compareOp;
diff --git a/src/Vulkan/VkSampler.cpp b/src/Vulkan/VkSampler.cpp
index 11cb00e..d64a4d5 100644
--- a/src/Vulkan/VkSampler.cpp
+++ b/src/Vulkan/VkSampler.cpp
@@ -16,7 +16,7 @@
 
 namespace vk {
 
-SamplerState::SamplerState(const VkSamplerCreateInfo *pCreateInfo, const vk::SamplerYcbcrConversion *ycbcrConversion)
+SamplerState::SamplerState(const VkSamplerCreateInfo *pCreateInfo, const vk::SamplerYcbcrConversion *ycbcrConversion, VkSamplerFilteringPrecisionModeGOOGLE filteringPrecision)
     : Memset(this, 0)
     , magFilter(pCreateInfo->magFilter)
     , minFilter(pCreateInfo->minFilter)
@@ -33,6 +33,7 @@
     , maxLod(ClampLod(pCreateInfo->maxLod))
     , borderColor(pCreateInfo->borderColor)
     , unnormalizedCoordinates(pCreateInfo->unnormalizedCoordinates)
+    , filteringPrecision(filteringPrecision)
 {
 	if(ycbcrConversion)
 	{
diff --git a/src/Vulkan/VkSampler.hpp b/src/Vulkan/VkSampler.hpp
index d2f51ac..f713ed2 100644
--- a/src/Vulkan/VkSampler.hpp
+++ b/src/Vulkan/VkSampler.hpp
@@ -26,7 +26,7 @@
 
 struct SamplerState : sw::Memset<SamplerState>
 {
-	SamplerState(const VkSamplerCreateInfo *pCreateInfo, const vk::SamplerYcbcrConversion *ycbcrConversion);
+	SamplerState(const VkSamplerCreateInfo *pCreateInfo, const vk::SamplerYcbcrConversion *ycbcrConversion, VkSamplerFilteringPrecisionModeGOOGLE filteringPrecision);
 
 	// Prevents accessing mipmap levels out of range.
 	static float ClampLod(float lod)
@@ -51,6 +51,7 @@
 	const VkBool32 unnormalizedCoordinates = VK_FALSE;
 
 	VkSamplerYcbcrModelConversion ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+	const VkSamplerFilteringPrecisionModeGOOGLE filteringPrecision = VK_SAMPLER_FILTERING_PRECISION_MODE_LOW_GOOGLE;
 	bool studioSwing = false;    // Narrow range
 	bool swappedChroma = false;  // Cb/Cr components in reverse order
 };
diff --git a/src/Vulkan/VkStringify.cpp b/src/Vulkan/VkStringify.cpp
index a8247f3..6551b76 100644
--- a/src/Vulkan/VkStringify.cpp
+++ b/src/Vulkan/VkStringify.cpp
@@ -17,6 +17,7 @@
 #include "System/Debug.hpp"
 
 #include "vulkan/vk_ext_provoking_vertex.h"
+#include "vulkan/vk_google_filtering_precision.h"
 
 #include <iostream>
 #include <map>
@@ -452,6 +453,7 @@
 		INSERT_ELEMENT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT),
 		INSERT_ELEMENT(VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT),
 		INSERT_ELEMENT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT),
+		INSERT_ELEMENT(VK_STRUCTURE_TYPE_SAMPLER_FILTERING_PRECISION_GOOGLE),
 		INSERT_ELEMENT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT),
 		INSERT_ELEMENT(VK_STRUCTURE_TYPE_MAX_ENUM)
 #	undef INSERT_ELEMENT
diff --git a/src/Vulkan/VulkanPlatform.hpp b/src/Vulkan/VulkanPlatform.hpp
index a220865..317cf14 100644
--- a/src/Vulkan/VulkanPlatform.hpp
+++ b/src/Vulkan/VulkanPlatform.hpp
@@ -50,6 +50,7 @@
 	template class VkNonDispatchableHandle<object##Ptr>;
 
 #include <vulkan/vk_ext_provoking_vertex.h>
+#include <vulkan/vk_google_filtering_precision.h>
 #include <vulkan/vulkan.h>
 
 #ifdef Bool
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 07e9b0a..c911ef4 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -379,6 +379,7 @@
 	{ VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME, VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION },
 #endif
 	{ VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, VK_EXT_PROVOKING_VERTEX_SPEC_VERSION },
+	{ VK_GOOGLE_SAMPLER_FILTERING_PRECISION_EXTENSION_NAME, VK_GOOGLE_SAMPLER_FILTERING_PRECISION_SPEC_VERSION },
 };
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance)
@@ -1922,10 +1923,11 @@
 
 	const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
 	const vk::SamplerYcbcrConversion *ycbcrConversion = nullptr;
+	VkSamplerFilteringPrecisionModeGOOGLE filteringPrecision = VK_SAMPLER_FILTERING_PRECISION_MODE_LOW_GOOGLE;
 
 	while(extensionCreateInfo)
 	{
-		switch(extensionCreateInfo->sType)
+		switch(static_cast<long>(extensionCreateInfo->sType))
 		{
 			case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO:
 			{
@@ -1933,6 +1935,13 @@
 				ycbcrConversion = vk::Cast(samplerYcbcrConversionInfo->conversion);
 			}
 			break;
+			case VK_STRUCTURE_TYPE_SAMPLER_FILTERING_PRECISION_GOOGLE:
+			{
+				const VkSamplerFilteringPrecisionGOOGLE *filteringInfo =
+				    reinterpret_cast<const VkSamplerFilteringPrecisionGOOGLE *>(extensionCreateInfo);
+				filteringPrecision = filteringInfo->samplerFilteringPrecisionMode;
+			}
+			break;
 			default:
 				LOG_TRAP("pCreateInfo->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str());
 				break;
@@ -1941,7 +1950,7 @@
 		extensionCreateInfo = extensionCreateInfo->pNext;
 	}
 
-	vk::SamplerState samplerState(pCreateInfo, ycbcrConversion);
+	vk::SamplerState samplerState(pCreateInfo, ycbcrConversion, filteringPrecision);
 	uint32_t samplerID = vk::Cast(device)->indexSampler(samplerState);
 
 	VkResult result = vk::Sampler::Create(pAllocator, pCreateInfo, pSampler, samplerState, samplerID);