Support non-square matrices in precision emulation

In case the shader version is greater than ESSL 1.00, the precision
emulation needs to output rounding functions for non-square matrix
types.

Writing emulated compound assignment functions for non-square matrices
already had most of the code in place before this change.

New compound assignment operators like >>= don't need floating point
precision emulation in ESSL 3.00, since all of them only operate on
integers.

BUG=angleproject:1434
TEST=angle_unittests

Change-Id: I4678f511edf4f9f744fe23bb8d7dab4387f07f20
Reviewed-on: https://chromium-review.googlesource.com/358472
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index 4931c59..7b22686 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -9,8 +9,9 @@
 namespace
 {
 
-static void writeVectorPrecisionEmulationHelpers(
-    TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size)
+static void writeVectorPrecisionEmulationHelpers(TInfoSinkBase &sink,
+                                                 const ShShaderOutput outputLanguage,
+                                                 const unsigned int size)
 {
     std::stringstream vecTypeStrStr;
     if (outputLanguage == SH_ESSL_OUTPUT)
@@ -37,19 +38,27 @@
     "}\n";
 }
 
-static void writeMatrixPrecisionEmulationHelper(
-    TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size, const char *functionName)
+static void writeMatrixPrecisionEmulationHelper(TInfoSinkBase &sink,
+                                                const ShShaderOutput outputLanguage,
+                                                const unsigned int columns,
+                                                const unsigned int rows,
+                                                const char *functionName)
 {
     std::stringstream matTypeStrStr;
     if (outputLanguage == SH_ESSL_OUTPUT)
         matTypeStrStr << "highp ";
-    matTypeStrStr << "mat" << size;
+    matTypeStrStr << "mat" << columns;
+    if (rows != columns)
+    {
+        matTypeStrStr << "x" << rows;
+    }
+
     std::string matType = matTypeStrStr.str();
 
     sink << matType << " " << functionName << "(in " << matType << " m) {\n"
             "    " << matType << " rounded;\n";
 
-    for (unsigned int i = 0; i < size; ++i)
+    for (unsigned int i = 0; i < columns; ++i)
     {
         sink << "    rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n";
     }
@@ -58,7 +67,9 @@
             "}\n";
 }
 
-static void writeCommonPrecisionEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage)
+static void writeCommonPrecisionEmulationHelpers(TInfoSinkBase &sink,
+                                                 const int shaderVersion,
+                                                 const ShShaderOutput outputLanguage)
 {
     // Write the angle_frm functions that round floating point numbers to
     // half precision, and angle_frl functions that round them to minimum lowp
@@ -134,10 +145,26 @@
     writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 2);
     writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 3);
     writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 4);
-    for (unsigned int size = 2; size <= 4; ++size)
+    if (shaderVersion > 100)
     {
-        writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frm");
-        writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frl");
+        for (unsigned int columns = 2; columns <= 4; ++columns)
+        {
+            for (unsigned int rows = 2; rows <= 4; ++rows)
+            {
+                writeMatrixPrecisionEmulationHelper(sink, outputLanguage, columns, rows,
+                                                    "angle_frm");
+                writeMatrixPrecisionEmulationHelper(sink, outputLanguage, columns, rows,
+                                                    "angle_frl");
+            }
+        }
+    }
+    else
+    {
+        for (unsigned int size = 2; size <= 4; ++size)
+        {
+            writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, size, "angle_frm");
+            writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, size, "angle_frl");
+        }
     }
 }
 
@@ -174,8 +201,8 @@
 
 bool canRoundFloat(const TType &type)
 {
-    return type.getBasicType() == EbtFloat && !type.isNonSquareMatrix() && !type.isArray() &&
-        (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium);
+    return type.getBasicType() == EbtFloat && !type.isArray() &&
+           (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium);
 }
 
 TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child)
@@ -443,13 +470,15 @@
     return true;
 }
 
-void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage)
+void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase &sink,
+                                             const int shaderVersion,
+                                             const ShShaderOutput outputLanguage)
 {
     // Other languages not yet supported
     ASSERT(outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT ||
            IsGLSL130OrNewer(outputLanguage) ||
            outputLanguage == SH_ESSL_OUTPUT);
-    writeCommonPrecisionEmulationHelpers(sink, outputLanguage);
+    writeCommonPrecisionEmulationHelpers(sink, shaderVersion, outputLanguage);
 
     EmulationSet::const_iterator it;
     for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++)