Don't generate TypeInfo objects as static objects within GetTypeInfo function

Generating static objects within a function results in multithread safe
code. This code generates the static objects upon the first execution of the
line which declares the object. This results in high runtime cost for
synchronization and a bigger code size.

Instead introduce a new function uint32_t GetPackedTypeInfo(GLenum type)
which returns a packed representation for the Type class. This
representation is usually returned in a register on the assembly level.
As a result we save constant storage for the TypeInfo object and one
indirection when reading any value from this object. The Type constructor
accepts the packed representation and unpacks it an inline function. For
fields which are not used the compiler also applies dead code
elimination which reduces the cost furthermore.

As a result of this change the cost of GetTypeInfo is reduced by a
factor of 4-5.

Bug: angleproject:2974
Change-Id: I8ed0bf2f09d087fa4cffa04f82e3b7f8c183fe30
Reviewed-on: https://chromium-review.googlesource.com/c/1340221
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/formatutils.cpp b/src/libANGLE/formatutils.cpp
index 5c32548..6fd1a9b 100644
--- a/src/libANGLE/formatutils.cpp
+++ b/src/libANGLE/formatutils.cpp
@@ -39,15 +39,24 @@
         return true;
     }
 }
+
+constexpr GLuint Log2(GLuint bytes)
+{
+    return bytes == 1 ? 0 : (1 + Log2(bytes / 2));
+}
+
+constexpr uint32_t PackTypeInfo(GLuint bytes, bool specialized)
+{
+    // static_assert within constexpr requires c++17
+    // static_assert(isPow2(bytes));
+    return bytes | (Log2(bytes) << 8) | (specialized << 16);
+}
+
 }  // anonymous namespace
 
-FormatType::FormatType() : format(GL_NONE), type(GL_NONE)
-{
-}
+FormatType::FormatType() : format(GL_NONE), type(GL_NONE) {}
 
-FormatType::FormatType(GLenum format_, GLenum type_) : format(format_), type(type_)
-{
-}
+FormatType::FormatType(GLenum format_, GLenum type_) : format(format_), type(type_) {}
 
 bool FormatType::operator<(const FormatType &other) const
 {
@@ -56,25 +65,6 @@
     return type < other.type;
 }
 
-Type::Type() : bytes(0), bytesShift(0), specialInterpretation(false)
-{
-}
-
-static Type GenTypeInfo(GLuint bytes, bool specialInterpretation)
-{
-    Type info;
-    info.bytes = bytes;
-    GLuint i   = 0;
-    while ((1u << i) < bytes)
-    {
-        ++i;
-    }
-    info.bytesShift = i;
-    ASSERT((1u << info.bytesShift) == bytes);
-    info.specialInterpretation = specialInterpretation;
-    return info;
-}
-
 bool operator<(const Type &a, const Type &b)
 {
     return memcmp(&a, &b, sizeof(Type)) < 0;
@@ -494,13 +484,9 @@
     }
 }
 
-Format::Format(GLenum internalFormat) : Format(GetSizedInternalFormatInfo(internalFormat))
-{
-}
+Format::Format(GLenum internalFormat) : Format(GetSizedInternalFormatInfo(internalFormat)) {}
 
-Format::Format(const InternalFormat &internalFormat) : info(&internalFormat)
-{
-}
+Format::Format(const InternalFormat &internalFormat) : info(&internalFormat) {}
 
 Format::Format(GLenum internalFormat, GLenum type)
     : info(&GetInternalFormatInfo(internalFormat, type))
@@ -1043,30 +1029,30 @@
     return result;
 }
 
-const Type &GetTypeInfo(GLenum type)
+uint32_t GetPackedTypeInfo(GLenum type)
 {
     switch (type)
     {
         case GL_UNSIGNED_BYTE:
         case GL_BYTE:
         {
-            static const Type info = GenTypeInfo(1, false);
-            return info;
+            static constexpr uint32_t kPacked = PackTypeInfo(1, false);
+            return kPacked;
         }
         case GL_UNSIGNED_SHORT:
         case GL_SHORT:
         case GL_HALF_FLOAT:
         case GL_HALF_FLOAT_OES:
         {
-            static const Type info = GenTypeInfo(2, false);
-            return info;
+            static constexpr uint32_t kPacked = PackTypeInfo(2, false);
+            return kPacked;
         }
         case GL_UNSIGNED_INT:
         case GL_INT:
         case GL_FLOAT:
         {
-            static const Type info = GenTypeInfo(4, false);
-            return info;
+            static constexpr uint32_t kPacked = PackTypeInfo(4, false);
+            return kPacked;
         }
         case GL_UNSIGNED_SHORT_5_6_5:
         case GL_UNSIGNED_SHORT_4_4_4_4:
@@ -1074,8 +1060,8 @@
         case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
         case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
         {
-            static const Type info = GenTypeInfo(2, true);
-            return info;
+            static constexpr uint32_t kPacked = PackTypeInfo(2, true);
+            return kPacked;
         }
         case GL_UNSIGNED_INT_2_10_10_10_REV:
         case GL_UNSIGNED_INT_24_8:
@@ -1083,18 +1069,17 @@
         case GL_UNSIGNED_INT_5_9_9_9_REV:
         {
             ASSERT(GL_UNSIGNED_INT_24_8_OES == GL_UNSIGNED_INT_24_8);
-            static const Type info = GenTypeInfo(4, true);
-            return info;
+            static constexpr uint32_t kPacked = PackTypeInfo(4, true);
+            return kPacked;
         }
         case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
         {
-            static const Type info = GenTypeInfo(8, true);
-            return info;
+            static constexpr uint32_t kPacked = PackTypeInfo(8, true);
+            return kPacked;
         }
         default:
         {
-            static const Type defaultInfo;
-            return defaultInfo;
+            return 0;
         }
     }
 }
@@ -2253,4 +2238,4 @@
     ASSERT(!(type == GL_FLOAT || type == GL_HALF_FLOAT || type == GL_FIXED) ||
            normalized == GL_FALSE);
 }
-}
+}  // namespace gl