Add new ESSL 3.10 pack/unpack builtins

This adds new built-ins found in ESSL 3.10 section 8.4 Floating-Point
Pack and Unpack Functions.

This includes constant folding support and support for both GLSL and
HLSL output. In HLSL all of these functions need to be emulated.

BUG=angleproject:1730
TEST=angle_unittests
TEST=dEQP-GLES31.functional.shaders.*pack*norm4x8*

Change-Id: Ibed60286a366cd35c4faafd405e79af562a02a06
Reviewed-on: https://chromium-review.googlesource.com/434170
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
index d0f4dfa..3f8acde 100644
--- a/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -297,23 +297,23 @@
         "}\n");
 
     emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
-                             "int webgl_toSnorm(in float x) {\n"
+                             "int webgl_toSnorm16(in float x) {\n"
                              "    return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n"
                              "}\n"
                              "\n"
                              "uint webgl_packSnorm2x16_emu(in float2 v) {\n"
-                             "    int x = webgl_toSnorm(v.x);\n"
-                             "    int y = webgl_toSnorm(v.y);\n"
+                             "    int x = webgl_toSnorm16(v.x);\n"
+                             "    int y = webgl_toSnorm16(v.y);\n"
                              "    return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n"
                              "}\n");
     emu->addEmulatedFunction(EOpPackUnorm2x16, float2,
-                             "uint webgl_toUnorm(in float x) {\n"
+                             "uint webgl_toUnorm16(in float x) {\n"
                              "    return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n"
                              "}\n"
                              "\n"
                              "uint webgl_packUnorm2x16_emu(in float2 v) {\n"
-                             "    uint x = webgl_toUnorm(v.x);\n"
-                             "    uint y = webgl_toUnorm(v.y);\n"
+                             "    uint x = webgl_toUnorm16(v.x);\n"
+                             "    uint y = webgl_toUnorm16(v.y);\n"
                              "    return (y << 16) | x;\n"
                              "}\n");
     emu->addEmulatedFunction(EOpPackHalf2x16, float2,
@@ -324,7 +324,7 @@
                              "}\n");
 
     emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
-                             "float webgl_fromSnorm(in uint x) {\n"
+                             "float webgl_fromSnorm16(in uint x) {\n"
                              "    int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n"
                              "    return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
                              "}\n"
@@ -332,17 +332,17 @@
                              "float2 webgl_unpackSnorm2x16_emu(in uint u) {\n"
                              "    uint y = (u >> 16);\n"
                              "    uint x = u;\n"
-                             "    return float2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n"
+                             "    return float2(webgl_fromSnorm16(x), webgl_fromSnorm16(y));\n"
                              "}\n");
     emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1,
-                             "float webgl_fromUnorm(in uint x) {\n"
+                             "float webgl_fromUnorm16(in uint x) {\n"
                              "    return float(x) / 65535.0;\n"
                              "}\n"
                              "\n"
                              "float2 webgl_unpackUnorm2x16_emu(in uint u) {\n"
                              "    uint y = (u >> 16);\n"
                              "    uint x = u & 0xffffu;\n"
-                             "    return float2(webgl_fromUnorm(x), webgl_fromUnorm(y));\n"
+                             "    return float2(webgl_fromUnorm16(x), webgl_fromUnorm16(y));\n"
                              "}\n");
     emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
                              "float2 webgl_unpackHalf2x16_emu(in uint u) {\n"
@@ -351,6 +351,60 @@
                              "    return float2(f16tof32(x), f16tof32(y));\n"
                              "}\n");
 
+    emu->addEmulatedFunction(EOpPackSnorm4x8, float4,
+                             "int webgl_toSnorm8(in float x) {\n"
+                             "    return int(round(clamp(x, -1.0, 1.0) * 127.0));\n"
+                             "}\n"
+                             "\n"
+                             "uint webgl_packSnorm4x8_emu(in float4 v) {\n"
+                             "    int x = webgl_toSnorm8(v.x);\n"
+                             "    int y = webgl_toSnorm8(v.y);\n"
+                             "    int z = webgl_toSnorm8(v.z);\n"
+                             "    int w = webgl_toSnorm8(v.w);\n"
+                             "    return ((asuint(w) & 0xffu) << 24) | ((asuint(z) & 0xffu) << 16) "
+                             "| ((asuint(y) & 0xffu) << 8) | (asuint(x) & 0xffu);\n"
+                             "}\n");
+    emu->addEmulatedFunction(EOpPackUnorm4x8, float4,
+                             "uint webgl_toUnorm8(in float x) {\n"
+                             "    return uint(round(clamp(x, 0.0, 1.0) * 255.0));\n"
+                             "}\n"
+                             "\n"
+                             "uint webgl_packUnorm4x8_emu(in float4 v) {\n"
+                             "    uint x = webgl_toUnorm8(v.x);\n"
+                             "    uint y = webgl_toUnorm8(v.y);\n"
+                             "    uint z = webgl_toUnorm8(v.z);\n"
+                             "    uint w = webgl_toUnorm8(v.w);\n"
+                             "    return (w << 24) | (z << 16) | (y << 8) | x;\n"
+                             "}\n");
+
+    emu->addEmulatedFunction(EOpUnpackSnorm4x8, uint1,
+                             "float webgl_fromSnorm8(in uint x) {\n"
+                             "    int xi = asint(x & 0x7fu) - asint(x & 0x80u);\n"
+                             "    return clamp(float(xi) / 127.0, -1.0, 1.0);\n"
+                             "}\n"
+                             "\n"
+                             "float4 webgl_unpackSnorm4x8_emu(in uint u) {\n"
+                             "    uint w = (u >> 24);\n"
+                             "    uint z = (u >> 16);\n"
+                             "    uint y = (u >> 8);\n"
+                             "    uint x = u;\n"
+                             "    return float4(webgl_fromSnorm8(x), webgl_fromSnorm8(y), "
+                             "webgl_fromSnorm8(z), webgl_fromSnorm8(w));\n"
+                             "}\n");
+    emu->addEmulatedFunction(EOpUnpackUnorm4x8, uint1,
+                             "float webgl_fromUnorm8(in uint x) {\n"
+                             "    return float(x) / 255.0;\n"
+                             "}\n"
+                             "\n"
+                             "float4 webgl_unpackUnorm4x8_emu(in uint u) {\n"
+                             "    uint w = (u >> 24) & 0xffu;\n"
+                             "    uint z = (u >> 16) & 0xffu;\n"
+                             "    uint y = (u >> 8) & 0xffu;\n"
+                             "    uint x = u & 0xffu;\n"
+                             "    return float4(webgl_fromUnorm8(x), webgl_fromUnorm8(y), "
+                             "webgl_fromUnorm8(z), webgl_fromUnorm8(w));\n"
+                             "}\n");
+
     // The matrix resulting from outer product needs to be transposed
     // (matrices are stored as transposed to simplify element access in HLSL).
     // So the function should return transpose(c * r) where c is a column vector
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index e016a10..8a6a63a 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -128,6 +128,11 @@
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpUnpackUnorm2x16, float2, uint1);
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpUnpackHalf2x16, float2, uint1);
 
+    symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpPackUnorm4x8, uint1, float4);
+    symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpPackSnorm4x8, uint1, float4);
+    symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpUnpackUnorm4x8, float4, uint1);
+    symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpUnpackSnorm4x8, float4, uint1);
+
     //
     // Geometric Functions.
     //
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 276b653..4039305 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -821,6 +821,8 @@
         case EOpPackSnorm2x16:
         case EOpPackUnorm2x16:
         case EOpPackHalf2x16:
+        case EOpPackUnorm4x8:
+        case EOpPackSnorm4x8:
             setType(TType(EbtUInt, EbpHigh, resultQualifier));
             break;
         case EOpUnpackSnorm2x16:
@@ -830,6 +832,10 @@
         case EOpUnpackHalf2x16:
             setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
             break;
+        case EOpUnpackUnorm4x8:
+        case EOpUnpackSnorm4x8:
+            setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
+            break;
         case EOpAny:
         case EOpAll:
             setType(TType(EbtBool, EbpUndefined, resultQualifier));
@@ -1315,6 +1321,10 @@
         case EOpUnpackUnorm2x16:
         case EOpPackHalf2x16:
         case EOpUnpackHalf2x16:
+        case EOpPackUnorm4x8:
+        case EOpPackSnorm4x8:
+        case EOpUnpackUnorm4x8:
+        case EOpUnpackSnorm4x8:
             constArray = operandConstant->foldUnaryNonComponentWise(mOp);
             break;
         default:
@@ -1868,6 +1878,49 @@
             break;
         }
 
+        case EOpPackUnorm4x8:
+        {
+            ASSERT(getType().getBasicType() == EbtFloat);
+            resultArray = new TConstantUnion();
+            resultArray->setUConst(
+                gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
+                                 operandArray[2].getFConst(), operandArray[3].getFConst()));
+            break;
+        }
+        case EOpPackSnorm4x8:
+        {
+            ASSERT(getType().getBasicType() == EbtFloat);
+            resultArray = new TConstantUnion();
+            resultArray->setUConst(
+                gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
+                                 operandArray[2].getFConst(), operandArray[3].getFConst()));
+            break;
+        }
+        case EOpUnpackUnorm4x8:
+        {
+            ASSERT(getType().getBasicType() == EbtUInt);
+            resultArray = new TConstantUnion[4];
+            float f[4];
+            gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
+            for (size_t i = 0; i < 4; ++i)
+            {
+                resultArray[i].setFConst(f[i]);
+            }
+            break;
+        }
+        case EOpUnpackSnorm4x8:
+        {
+            ASSERT(getType().getBasicType() == EbtUInt);
+            resultArray = new TConstantUnion[4];
+            float f[4];
+            gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
+            for (size_t i = 0; i < 4; ++i)
+            {
+                resultArray[i].setFConst(f[i]);
+            }
+            break;
+        }
+
         default:
             UNREACHABLE();
             break;
diff --git a/src/compiler/translator/Operator.cpp b/src/compiler/translator/Operator.cpp
index 12ae1a9..64e8052 100644
--- a/src/compiler/translator/Operator.cpp
+++ b/src/compiler/translator/Operator.cpp
@@ -210,6 +210,15 @@
         case EOpUnpackHalf2x16:
             return "unpackHalf2x16";
 
+        case EOpPackUnorm4x8:
+            return "packUnorm4x8";
+        case EOpPackSnorm4x8:
+            return "packSnorm4x8";
+        case EOpUnpackUnorm4x8:
+            return "unpackUnorm4x8";
+        case EOpUnpackSnorm4x8:
+            return "unpackSnorm4x8";
+
         case EOpLength:
             return "length";
         case EOpDistance:
diff --git a/src/compiler/translator/Operator.h b/src/compiler/translator/Operator.h
index 968dbac..18e7ca5 100644
--- a/src/compiler/translator/Operator.h
+++ b/src/compiler/translator/Operator.h
@@ -150,6 +150,11 @@
     EOpUnpackUnorm2x16,
     EOpUnpackHalf2x16,
 
+    EOpPackUnorm4x8,
+    EOpPackSnorm4x8,
+    EOpUnpackUnorm4x8,
+    EOpUnpackSnorm4x8,
+
     EOpLength,
     EOpDistance,
     EOpDot,
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 3a2a757..4ae8651 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -714,6 +714,10 @@
         case EOpUnpackSnorm2x16:
         case EOpUnpackUnorm2x16:
         case EOpUnpackHalf2x16:
+        case EOpPackUnorm4x8:
+        case EOpPackSnorm4x8:
+        case EOpUnpackUnorm4x8:
+        case EOpUnpackSnorm4x8:
         case EOpLength:
         case EOpNormalize:
         case EOpDFdx:
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 8a3794d..df0fa9f 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1414,6 +1414,10 @@
         case EOpUnpackSnorm2x16:
         case EOpUnpackUnorm2x16:
         case EOpUnpackHalf2x16:
+        case EOpPackUnorm4x8:
+        case EOpPackSnorm4x8:
+        case EOpUnpackUnorm4x8:
+        case EOpUnpackSnorm4x8:
             ASSERT(node->getUseEmulatedFunction());
             writeEmulatedFunctionTriplet(out, visit, node->getOp());
             break;