Use a finite maxSamplerLodBias limit

We previously set this device limit to infinity to avoid having to
clamp the sum of the sampler and shader provided bias values to the
[-maxSamplerLodBias, maxSamplerLodBias] range. Unfortunately infinity
is not supported/allowed by JSON and the android.graphics.cts.VulkanFeaturesTest
tests which parse the output of the vkjson tool produce a failure.

This change works around it by setting maxSamplerLodBias to a finite
value (15, which is very common according to https://vulkan.gpuinfo.org/),
and performing the clamping required by Vulkan 1.1.117 section 15.6.7.
Fortunately this cost only has to be incurred when an optional Bias
operand is used in the SPIR-V image sampling instruction. When an Lod
operand is used, which is mutually exclusive with Bias because the
former is for explicit-lod instructions and the latter for implicit-lod,
no clamping is required because the explicit LOD is not part of this
clamping equation and the sampler LOD bias must already be clamped as
specified by the spec: "The absolute value of mipLodBias must be less
than or equal to VkPhysicalDeviceLimits::maxSamplerLodBias".

Bug: b/138670766
Change-Id: Iebd6a1fef1c993ec86ac8cc38f8d9a992ba9bc47
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/34510
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index 85c3783..d832bcb 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -92,14 +92,21 @@
 				computeLod3D(texture, sampler, lod, uuuu, vvvv, wwww, dsx, dsy, function);
 			}
 
+			Float bias = *Pointer<Float>(sampler + OFFSET(vk::Sampler, mipLodBias));
+
 			if(function == Bias)
 			{
-				lod += lodOrBias;
+				// Add SPIR-V Bias operand to the sampler provided bias and clamp to maxSamplerLodBias limit.
+				bias = Min(Max(bias + lodOrBias, -vk::MAX_SAMPLER_LOD_BIAS), vk::MAX_SAMPLER_LOD_BIAS);
 			}
+
+			lod += bias;
 		}
 		else if(function == Lod)
 		{
-			lod = lodOrBias;
+			// Vulkan 1.1: "The absolute value of mipLodBias must be less than or equal to VkPhysicalDeviceLimits::maxSamplerLodBias"
+			// Hence no explicit clamping to maxSamplerLodBias is required in this case.
+			lod = lodOrBias + *Pointer<Float>(sampler + OFFSET(vk::Sampler, mipLodBias));
 		}
 		else if(function == Fetch)
 		{
@@ -114,8 +121,6 @@
 
 		if(function != Base && function != Fetch && function != Gather)
 		{
-			lod += *Pointer<Float>(sampler + OFFSET(vk::Sampler, mipLodBias));
-
 			if(function == Query)
 			{
 				c.y = Float4(lod);  // Unclamped LOD.
diff --git a/src/Vulkan/VkConfig.h b/src/Vulkan/VkConfig.h
index 157f34e..8d0b57d 100644
--- a/src/Vulkan/VkConfig.h
+++ b/src/Vulkan/VkConfig.h
@@ -54,6 +54,7 @@
 	MAX_IMAGE_LEVELS_3D = 11,
 	MAX_IMAGE_LEVELS_CUBE = 14,
 	MAX_IMAGE_ARRAY_LAYERS = 2048,
+	MAX_SAMPLER_LOD_BIAS = 15,
 };
 
 enum
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 323d644..14476a5 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -205,7 +205,7 @@
 		4, // mipmapPrecisionBits
 		UINT32_MAX, // maxDrawIndexedIndexValue
 		UINT32_MAX, // maxDrawIndirectCount
-		std::numeric_limits<float>::infinity(), // maxSamplerLodBias (no clamping takes place)
+		vk::MAX_SAMPLER_LOD_BIAS, // maxSamplerLodBias
 		16, // maxSamplerAnisotropy
 		16, // maxViewports
 		{ 4096, 4096 }, // maxViewportDimensions[2]