Support writing interface blocks in OutputGLSL.

BUG=angleproject:882
BUG=angleproject:1149

Change-Id: Iea0b1d0bc586ec9517a06793386c91890b7a5115
Reviewed-on: https://chromium-review.googlesource.com/297086
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 63b2813..56d3275 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -96,6 +96,11 @@
     {
         out << "invariant ";
     }
+    if (type.getBasicType() == EbtInterfaceBlock)
+    {
+        TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+        declareInterfaceBlockLayout(interfaceBlock);
+    }
     TQualifier qualifier = type.getQualifier();
     if (qualifier != EvqTemporary && qualifier != EvqGlobal)
     {
@@ -134,6 +139,11 @@
             mDeclaredStructs.insert(structure->uniqueId());
         }
     }
+    else if (type.getBasicType() == EbtInterfaceBlock)
+    {
+        TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
+        declareInterfaceBlock(interfaceBlock);
+    }
     else
     {
         if (writeVariablePrecision(type.getPrecision()))
@@ -1287,3 +1297,70 @@
     out << "}";
 }
 
+void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
+{
+    TInfoSinkBase &out = objSink();
+
+    out << "layout(";
+
+    switch (interfaceBlock->blockStorage())
+    {
+        case EbsUnspecified:
+        case EbsShared:
+            // Default block storage is shared.
+            out << "shared";
+            break;
+
+        case EbsPacked:
+            out << "packed";
+            break;
+
+        case EbsStd140:
+            out << "std140";
+            break;
+
+        default:
+            UNREACHABLE();
+            break;
+    }
+
+    out << ", ";
+
+    switch (interfaceBlock->matrixPacking())
+    {
+        case EmpUnspecified:
+        case EmpColumnMajor:
+            // Default matrix packing is column major.
+            out << "column_major";
+            break;
+
+        case EmpRowMajor:
+            out << "row_major";
+            break;
+
+        default:
+            UNREACHABLE();
+            break;
+    }
+
+    out << ") ";
+}
+
+void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
+{
+    TInfoSinkBase &out = objSink();
+
+    out << hashName(interfaceBlock->name()) << "{\n";
+    const TFieldList &fields = interfaceBlock->fields();
+    for (size_t i = 0; i < fields.size(); ++i)
+    {
+        const TField *field = fields[i];
+        if (writeVariablePrecision(field->type()->getPrecision()))
+            out << " ";
+        out << getTypeName(*field->type()) << " " << hashName(field->name());
+        if (field->type()->isArray())
+            out << arrayBrackets(*field->type());
+        out << ";\n";
+    }
+    out << "}";
+}