Unnormalized texture coordinates

Unnormalized texture coordinates are pretty much the same
as rectangle texture coordinates, with a few extra addressing
modes to support. ADDRESSING_CLAMP and ADDRESSING_BORDER
work properly. Other modes can't used with unnormalized
texture coordinates, according to the Vulkan spec:
"If unnormalizedCoordinates is VK_TRUE,
 addressModeU and addressModeV must each be either
 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE or
 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER"

Bug b/129523279

Change-Id: I3e39c16172bc5825ec48c6395f52e9b177df1304
Tests: dEQP-VK.texture.filtering.unnormal.*
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31648
Tested-by: Alexis Hétu <sugoi@google.com>
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Device/Sampler.hpp b/src/Device/Sampler.hpp
index d02c723..8768a19 100644
--- a/src/Device/Sampler.hpp
+++ b/src/Device/Sampler.hpp
@@ -68,7 +68,6 @@
 		TEXTURE_1D,
 		TEXTURE_2D,
 		TEXTURE_3D,
-		TEXTURE_RECTANGLE,  // TODO(b/129523279): Eliminate
 		TEXTURE_CUBE,
 		TEXTURE_1D_ARRAY,   // Treated as 2D texture with second coordinate 0.
 		TEXTURE_2D_ARRAY,
@@ -154,6 +153,7 @@
 		bool compareEnable;
 		VkCompareOp compareOp;
 		VkBorderColor border;
+		bool unnormalizedCoordinates;
 
 		#if PERF_PROFILE
 		bool compressedFormat;
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index fa4a711..5af0357 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -128,9 +128,8 @@
 
 		bool force32BitFiltering = state.highPrecisionFiltering && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
 		bool seamlessCube = (state.addressingModeU == ADDRESSING_SEAMLESS);
-		bool rectangleTexture = (state.textureType == TEXTURE_RECTANGLE);
 		bool use32BitFiltering = hasFloatTexture() || hasUnnormalizedIntegerTexture() || force32BitFiltering ||
-		                         seamlessCube || rectangleTexture || state.compareEnable || borderModeActive();
+		                         seamlessCube || state.unnormalizedCoordinates || state.compareEnable || borderModeActive();
 
 		if(use32BitFiltering)
 		{
@@ -2006,14 +2005,22 @@
 
 			Float4 coord = uvw;
 
-			if(state.textureType == TEXTURE_RECTANGLE)
+			if(state.unnormalizedCoordinates)
 			{
-				// According to https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_rectangle.txt
-				// "CLAMP_TO_EDGE causes the s coordinate to be clamped to the range[0.5, wt - 0.5].
-				//  CLAMP_TO_EDGE causes the t coordinate to be clamped to the range[0.5, ht - 0.5]."
-				// Unless SwiftShader implements support for ADDRESSING_BORDER, other modes should be equivalent
-				// to CLAMP_TO_EDGE. Rectangle textures have no support for any MIRROR or REPEAT modes.
-				coord = Min(Max(coord, Float4(0.5f)), Float4(dim) - Float4(0.5f));
+				switch(addressingMode)
+				{
+				case ADDRESSING_CLAMP:
+					coord = Min(Max(coord, Float4(0.0f)), Float4(dim) * As<Float4>(Int4(oneBits)));
+					break;
+				case ADDRESSING_BORDER:
+					// Don't map to a valid range here.
+					break;
+				default:
+					// If unnormalizedCoordinates is VK_TRUE, addressModeU and addressModeV must each be
+					// either VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE or VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
+					UNREACHABLE("addressingMode %d", int(addressingMode));
+					break;
+				}
 			}
 			else
 			{
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index 5f31d94..43b34c5 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -65,14 +65,13 @@
 	samplerState.highPrecisionFiltering = false;
 	samplerState.compareEnable = (sampler->compareEnable == VK_TRUE);
 	samplerState.compareOp = sampler->compareOp;
+	samplerState.unnormalizedCoordinates = (sampler->unnormalizedCoordinates == VK_TRUE);
 
 	if(sampler->anisotropyEnable != VK_FALSE)
 	{
 		UNSUPPORTED("anisotropyEnable");
 	}
 
-	ASSERT(sampler->unnormalizedCoordinates == VK_FALSE);  // TODO(b/129523279)
-
 	auto fptr = emitSamplerFunction(instruction, samplerState);
 
 	cache.emplace(key, fptr);