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++)
diff --git a/src/compiler/translator/EmulatePrecision.h b/src/compiler/translator/EmulatePrecision.h
index 08177b3..c2b9857 100644
--- a/src/compiler/translator/EmulatePrecision.h
+++ b/src/compiler/translator/EmulatePrecision.h
@@ -28,7 +28,9 @@
     bool visitUnary(Visit visit, TIntermUnary *node) override;
     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
 
-    void writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage);
+    void writeEmulationHelpers(TInfoSinkBase &sink,
+                               const int shaderVersion,
+                               const ShShaderOutput outputLanguage);
 
   private:
     struct TypePair
diff --git a/src/compiler/translator/TranslatorESSL.cpp b/src/compiler/translator/TranslatorESSL.cpp
index 76d006f..412df5e 100644
--- a/src/compiler/translator/TranslatorESSL.cpp
+++ b/src/compiler/translator/TranslatorESSL.cpp
@@ -46,7 +46,7 @@
         EmulatePrecision emulatePrecision(getSymbolTable(), shaderVer);
         root->traverse(&emulatePrecision);
         emulatePrecision.updateTree();
-        emulatePrecision.writeEmulationHelpers(sink, SH_ESSL_OUTPUT);
+        emulatePrecision.writeEmulationHelpers(sink, shaderVer, SH_ESSL_OUTPUT);
     }
 
     RecordConstantPrecision(root, getTemporaryIndex());
diff --git a/src/compiler/translator/TranslatorGLSL.cpp b/src/compiler/translator/TranslatorGLSL.cpp
index a05802f..ddeffee 100644
--- a/src/compiler/translator/TranslatorGLSL.cpp
+++ b/src/compiler/translator/TranslatorGLSL.cpp
@@ -49,7 +49,7 @@
         EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion());
         root->traverse(&emulatePrecision);
         emulatePrecision.updateTree();
-        emulatePrecision.writeEmulationHelpers(sink, getOutputType());
+        emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType());
     }
 
     // Write emulated built-in functions if needed.