Fix border color when sampling normalized texture formats

Border color replacement was using same 16-bit scale for all normalized
texture formats. This change uses proper scale values and also takes
packed formats into account.

Bug: b/191101048
Change-Id: I4c55a64dc914bc58c0650b700741a992e39263fd
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/58628
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index 40e9bb5..ab00880 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -197,6 +197,15 @@
 				c.z *= Float4(1.0f / 0xFF00u);
 				c.w *= Float4(1.0f / 0xFF00u);
 				break;
+			//TODO(b/205576016)
+			case VK_FORMAT_R16_UNORM:
+			case VK_FORMAT_R16G16_UNORM:
+			case VK_FORMAT_R16G16B16A16_UNORM:
+				c.x *= Float4(1.0f / 0xFFFF);
+				c.y *= Float4(1.0f / 0xFFFF);
+				c.z *= Float4(1.0f / 0xFFFF);
+				c.w *= Float4(1.0f / 0xFFFF);
+				break;
 			case VK_FORMAT_R16_SNORM:
 			case VK_FORMAT_R16G16_SNORM:
 			case VK_FORMAT_R16G16B16A16_SNORM:
@@ -2169,10 +2178,20 @@
 {
 	Vector4i border;
 
-	bool scaled = !hasFloatTexture() && !hasUnnormalizedIntegerTexture() && !state.compareEnable;
-	bool sign = !hasUnsignedTextureComponent(0);
-	float scale = scaled ? static_cast<float>(sign ? 0x7FFF : 0xFFFF) : 1.0f;
-	Int4 float_one = As<Int4>(Float4(scale));
+	const bool scaled = !hasFloatTexture() && !hasUnnormalizedIntegerTexture() && !state.compareEnable;
+	const sw::float4 scale = state.textureFormat.getScale();
+	const sw::int4 bits = state.textureFormat.bitsPerComponent();
+	const sw::int4 shift = sw::int4(std::max(16 - bits.x, 0), std::max(16 - bits.y, 0), std::max(16 - bits.z, 0), std::max(16 - bits.w, 0));
+	sw::float4 scaleComp = scaled ? sw::float4(static_cast<uint16_t>(scale.x) << shift.x, static_cast<uint16_t>(scale.y) << shift.y,
+	                                           static_cast<uint16_t>(scale.z) << shift.z, static_cast<uint16_t>(scale.w) << shift.w)
+	                              : sw::float4(1.0, 1.0, 1.0, 1.0);
+	// TODO(b/204709464): Unlike other formats, the fixed point presentation of the formats below are handled with bit extension.
+	// This special handling of such formats should be removed later.
+	const VkFormat format = static_cast<VkFormat>(state.textureFormat);
+	if(format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 || format == VK_FORMAT_A2R10G10B10_UNORM_PACK32)
+		scaleComp = sw::float4(0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+	else if(format == VK_FORMAT_A2B10G10R10_SNORM_PACK32 || format == VK_FORMAT_A2R10G10B10_SNORM_PACK32)
+		scaleComp = sw::float4(0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF);
 
 	switch(state.border)
 	{
@@ -2187,7 +2206,7 @@
 		border.x = Int4(0);
 		border.y = Int4(0);
 		border.z = Int4(0);
-		border.w = float_one;
+		border.w = Int4(bit_cast<int>(scaleComp.w));
 		break;
 	case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
 		border.x = Int4(0);
@@ -2196,10 +2215,10 @@
 		border.w = Int4(1);
 		break;
 	case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
-		border.x = float_one;
-		border.y = float_one;
-		border.z = float_one;
-		border.w = float_one;
+		border.x = Int4(bit_cast<int>(scaleComp.x));
+		border.y = Int4(bit_cast<int>(scaleComp.y));
+		border.z = Int4(bit_cast<int>(scaleComp.z));
+		border.w = Int4(bit_cast<int>(scaleComp.w));
 		break;
 	case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
 		border.x = Int4(1);
@@ -2210,10 +2229,10 @@
 	case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:
 		// This bit-casts from float to int in C++ code instead of Reactor code
 		// because Reactor does not guarantee preserving infinity (b/140302841).
-		border.x = Int4(bit_cast<int>(scale * state.customBorder.float32[0]));
-		border.y = Int4(bit_cast<int>(scale * state.customBorder.float32[1]));
-		border.z = Int4(bit_cast<int>(scale * state.customBorder.float32[2]));
-		border.w = Int4(bit_cast<int>(scale * state.customBorder.float32[3]));
+		border.x = Int4(bit_cast<int>(scaleComp.x * state.customBorder.float32[0]));
+		border.y = Int4(bit_cast<int>(scaleComp.y * state.customBorder.float32[1]));
+		border.z = Int4(bit_cast<int>(scaleComp.z * state.customBorder.float32[2]));
+		border.w = Int4(bit_cast<int>(scaleComp.w * state.customBorder.float32[3]));
 		break;
 	case VK_BORDER_COLOR_INT_CUSTOM_EXT:
 		border.x = Int4(state.customBorder.int32[0]);