Implement writing B10G11R11 in the Blitter

This does not yet handle rounding correctly, nor are Inf and NaN
input values dealt with.

Note that the Vulkan 1.1.117 spec refers to
https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#11bitfp
for the specification on the interpretation of 11- and 10-bit floating-
point formats, while that spec itself states that:
"Note that in general conversion from a real number to any
representation may require rounding, truncation and special value
management rules which are beyond the scope of a data format
specification and may be documented in APIs which generate these
formats."

The Vulkan spec however does not document any specific conversion
requirement (in contrast, it does for the shared exponent format).

Bug: b/138944025
Change-Id: If59adfb02f2793f69a028d379a03c05f9a12bd89
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/34828
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp
index b4ca5f3..06425db 100644
--- a/src/Device/Blitter.cpp
+++ b/src/Device/Blitter.cpp
@@ -604,6 +604,28 @@
 		case VK_FORMAT_R16_SFLOAT:
 			if(writeR) { *Pointer<Half>(element) = Half(c.x); }
 			break;
+		case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+			{
+				// 10 (or 11) bit float formats are unsigned formats with a 5 bit exponent and a 5 (or 6) bit mantissa.
+				// Since the 16-bit half-precision float format also has a 5 bit exponent, we can extract these minifloats from them.
+
+				// FIXME(b/138944025): Handle negative values, Inf, and NaN.
+				// FIXME(b/138944025): Perform rounding before truncating the mantissa.
+				UInt r = (UInt(As<UShort>(Half(c.x))) & 0x00007FF0) >> 4;
+				UInt g = (UInt(As<UShort>(Half(c.y))) & 0x00007FF0) << 7;
+				UInt b = (UInt(As<UShort>(Half(c.z))) & 0x00007FE0) << 17;
+
+				UInt rgb = r | g | b;
+
+				UInt old = *Pointer<UInt>(element);
+
+				unsigned int mask = (writeR ? 0x000007FF : 0) |
+				                    (writeG ? 0x003FF800 : 0) |
+				                    (writeB ? 0xFFC00000 : 0);
+
+				*Pointer<UInt>(element) = (rgb & mask) | (old & ~mask);
+			}
+			break;
 		case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
 			{
 				ASSERT(writeRGBA);  // Can't sensibly write just part of this format.