Implement R5G6B5 framebuffer present.

Bug 20891368

Change-Id: If4b0b84d141eb16c96600b7ade98a552e5f2ad0e
Reviewed-on: https://swiftshader-review.googlesource.com/3251
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/Main/FrameBuffer.cpp b/src/Main/FrameBuffer.cpp
index 098184b..c807aba 100644
--- a/src/Main/FrameBuffer.cpp
+++ b/src/Main/FrameBuffer.cpp
@@ -320,6 +320,20 @@
 								d += 2 * dBytes;
 							}
 							break;
+						case FORMAT_R5G6B5:
+							For(, x < width, x++)
+							{
+								Int rgb = Int(*Pointer<Short>(s));
+
+								*Pointer<Int>(d) = 0xFF000000 |
+								                   ((rgb & 0xF800) << 8) | ((rgb & 0xE000) << 3) |
+								                   ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
+								                   ((rgb & 0x001F) << 3) | ((rgb & 0x001C) >> 2);
+
+								s += sBytes;
+								d += dBytes;
+							}
+							break;
 						default:
 							ASSERT(false);
 							break;
@@ -350,6 +364,16 @@
 									*Pointer<Int>(d) = Int(As<Int2>(Pack(c, c)));
 								}
 								break;
+							case FORMAT_R5G6B5:
+								{
+									Int rgb = Int(*Pointer<Short>(s));
+
+									*Pointer<Int>(d) = 0xFF000000 |
+									                   ((rgb & 0xF800) << 8) | ((rgb & 0xE000) << 3) |
+								                       ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
+								                       ((rgb & 0x001F) << 3) | ((rgb & 0x001C) >> 2);
+								}
+								break;
 							default:
 								ASSERT(false);
 								break;
@@ -403,6 +427,20 @@
 								d += 2 * dBytes;
 							}
 							break;
+						case FORMAT_R5G6B5:
+							For(, x < width, x++)
+							{
+								Int rgb = Int(*Pointer<Short>(s));
+
+								*Pointer<Int>(d) = 0xFF000000 |
+								                   ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
+								                   ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
+								                   ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
+
+								s += sBytes;
+								d += dBytes;
+							}
+							break;
 						default:
 							ASSERT(false);
 							break;
@@ -432,6 +470,16 @@
 									*Pointer<Int>(d) = Int(As<Int2>(Pack(c, c)));
 								}
 								break;
+							case FORMAT_R5G6B5:
+								{
+									Int rgb = Int(*Pointer<Short>(s));
+
+									*Pointer<Int>(d) = 0xFF000000 |
+									                   ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
+								                       ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
+								                       ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
+								}
+								break;
 							default:
 								ASSERT(false);
 								break;
@@ -464,6 +512,15 @@
 								*Pointer<Byte>(d + 1) = *Pointer<Byte>(s + 3);
 								*Pointer<Byte>(d + 2) = *Pointer<Byte>(s + 1);
 								break;
+							case FORMAT_R5G6B5:
+								{
+									Int rgb = Int(*Pointer<Short>(s));
+
+									*Pointer<Byte>(d + 0) = Byte(((rgb & 0x001F) << 3) | ((rgb & 0x001C) >> 2));
+									*Pointer<Byte>(d + 1) = Byte(((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1));
+									*Pointer<Byte>(d + 2) = Byte(((rgb & 0xF800) << 8) | ((rgb & 0xE000) << 3));
+								}
+								break;
 							default:
 								ASSERT(false);
 								break;
@@ -510,6 +567,9 @@
 									                           (c & 0x000000F8) << 8);
 								}
 								break;
+							case FORMAT_R5G6B5:
+								*Pointer<Short>(d) = *Pointer<Short>(s);
+								break;
 							default:
 								ASSERT(false);
 								break;
@@ -610,7 +670,17 @@
 			c2 = Swizzle(UnpackLow(As<Byte8>(c2), *Pointer<Byte8>(s)), 0xC6);
 			break;
 		case FORMAT_A16B16G16R16:
-			c2 = Swizzle(*Pointer<Short4>(s + 0), 0xC6);
+			c2 = Swizzle(*Pointer<Short4>(s), 0xC6);
+			break;
+		case FORMAT_R5G6B5:
+			{
+				Int rgb(*Pointer<Short>(s));
+				rgb = 0xFF000000 |
+				      ((rgb & 0x001F) << 19) | ((rgb & 0x001C) << 14) |
+				      ((rgb & 0x07E0) << 5) | ((rgb & 0x0600) >> 1) |
+				      ((rgb & 0xF800) >> 8) | ((rgb & 0xE000) >> 13);
+				c2 = Unpack(As<Byte4>(rgb));
+			}
 			break;
 		default:
 			ASSERT(false);