Added support for EXT_frag_depth

This change also required that support be added for associating built-in
variables with an extension, similar to how functions could be associated with
extensions previously.

R=alokp@chromium.org

Review URL: https://codereview.appspot.com/9827044

git-svn-id: http://angleproject.googlecode.com/svn/trunk@2248 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
index b2b6e11..a0da456 100644
--- a/include/GLSLANG/ShaderLang.h
+++ b/include/GLSLANG/ShaderLang.h
@@ -215,6 +215,7 @@
     int OES_EGL_image_external;
     int ARB_texture_rectangle;
     int EXT_draw_buffers;
+    int EXT_frag_depth;
 
     // Set to 1 if highp precision is supported in the fragment language.
     // Default is 0.
diff --git a/src/compiler/BaseTypes.h b/src/compiler/BaseTypes.h
index 0a3adfd..1631f4f 100644
--- a/src/compiler/BaseTypes.h
+++ b/src/compiler/BaseTypes.h
@@ -108,6 +108,7 @@
     // built-ins written by fragment shader
     EvqFragColor,
     EvqFragData,
+    EvqFragDepth,
 
     // end of list
     EvqLast
@@ -139,6 +140,7 @@
     case EvqFrontFacing:    return "FrontFacing";    break;
     case EvqFragColor:      return "FragColor";      break;
     case EvqFragData:       return "FragData";      break;
+    case EvqFragDepth:      return "FragDepth";     break;
     default:                return "unknown qualifier";
     }
 }
diff --git a/src/compiler/Initialize.cpp b/src/compiler/Initialize.cpp
index 97b46f8..4aa36b2 100644
--- a/src/compiler/Initialize.cpp
+++ b/src/compiler/Initialize.cpp
@@ -539,6 +539,10 @@
         if (spec != SH_CSS_SHADERS_SPEC) {
             symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"),                   TType(EbtFloat, EbpMedium, EvqFragColor,   4)));
             symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData,    4)));
+            if (resources.EXT_frag_depth) {
+                symbolTable.insert(*new TVariable(NewPoolTString("gl_FragDepthEXT"),            TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1)));
+                symbolTable.relateToExtension("gl_FragDepthEXT", "GL_EXT_frag_depth");
+            }
         } else {
             symbolTable.insert(*new TVariable(NewPoolTString("css_MixColor"),                   TType(EbtFloat, EbpMedium, EvqGlobal,      4)));
             symbolTable.insert(*new TVariable(NewPoolTString("css_ColorMatrix"),                TType(EbtFloat, EbpMedium, EvqGlobal,      4, true)));
@@ -656,4 +660,6 @@
         extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
     if (resources.EXT_draw_buffers)
         extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
+    if (resources.EXT_frag_depth)
+        extBehavior["GL_EXT_frag_depth"] = EBhUndefined;
 }
diff --git a/src/compiler/OutputGLSL.cpp b/src/compiler/OutputGLSL.cpp
index 206f403..10a451c 100644
--- a/src/compiler/OutputGLSL.cpp
+++ b/src/compiler/OutputGLSL.cpp
@@ -19,3 +19,17 @@
 {
     return false;
 }
+
+void TOutputGLSL::visitSymbol(TIntermSymbol* node)
+{
+    TInfoSinkBase& out = objSink();
+
+    if (node->getSymbol() == "gl_FragDepthEXT")
+    {
+        out << "gl_FragDepth";
+    }
+    else
+    {
+        TOutputGLSLBase::visitSymbol(node);
+    }
+}
diff --git a/src/compiler/OutputGLSL.h b/src/compiler/OutputGLSL.h
index 199b6f3..fa68ac8 100644
--- a/src/compiler/OutputGLSL.h
+++ b/src/compiler/OutputGLSL.h
@@ -20,6 +20,7 @@
 
 protected:
     virtual bool writeVariablePrecision(TPrecision);
+    virtual void visitSymbol(TIntermSymbol* node);
 };
 
 #endif  // CROSSCOMPILERGLSL_OUTPUTGLSL_H_
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index c7ce5f2..3c4b8e1 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -52,6 +52,7 @@
     mUsesPointCoord = false;
     mUsesFrontFacing = false;
     mUsesPointSize = false;
+    mUsesFragDepth = false;
     mUsesXor = false;
     mUsesMod1 = false;
     mUsesMod2v = false;
@@ -189,6 +190,11 @@
         out << "\n"
                "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
 
+        if (mUsesFragDepth)
+        {
+            out << "static float gl_Depth = 0.0;\n";
+        }
+
         if (mUsesFragCoord)
         {
             out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
@@ -509,6 +515,11 @@
         out << "#define GL_USES_POINT_SIZE\n";
     }
 
+    if (mUsesFragDepth)
+    {
+        out << "#define GL_USES_FRAG_DEPTH\n";
+    }
+
     if (mUsesDepthRange)
     {
         out << "struct gl_DepthRangeParameters\n"
@@ -843,6 +854,11 @@
         mUsesPointSize = true;
         out << name;
     }
+    else if (name == "gl_FragDepthEXT")
+    {
+        mUsesFragDepth = true;
+        out << "gl_Depth";
+    }
     else
     {
         TQualifier qualifier = node->getQualifier();
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
index dc843fb..3a4c1da 100644
--- a/src/compiler/OutputHLSL.h
+++ b/src/compiler/OutputHLSL.h
@@ -97,6 +97,7 @@
     bool mUsesPointCoord;
     bool mUsesFrontFacing;
     bool mUsesPointSize;
+    bool mUsesFragDepth;
     bool mUsesXor;
     bool mUsesMod1;
     bool mUsesMod2v;
diff --git a/src/compiler/ParseHelper.cpp b/src/compiler/ParseHelper.cpp
index 040deb1..76855f1 100644
--- a/src/compiler/ParseHelper.cpp
+++ b/src/compiler/ParseHelper.cpp
@@ -925,6 +925,27 @@
     return static_cast<const TFunction*>(symbol);
 }
 
+bool TParseContext::isVariableBuiltIn(const TVariable* var)
+{
+    bool builtIn = false;
+    // First find by unmangled name to check whether the function name has been
+    // hidden by a variable name or struct typename.
+    const TSymbol* symbol = symbolTable.find(var->getName(), &builtIn);
+    if (symbol == 0) {
+        symbol = symbolTable.find(var->getMangledName(), &builtIn);
+    }
+
+    if (symbol == 0) {
+        return false;
+    }
+
+    if (!symbol->isVariable()) {
+        return false;
+    }
+
+    return builtIn;
+}
+
 //
 // Initializers show up in several places in the grammar.  Have one set of
 // code to handle them here.
diff --git a/src/compiler/ParseHelper.h b/src/compiler/ParseHelper.h
index b938b7d..289ec2f 100644
--- a/src/compiler/ParseHelper.h
+++ b/src/compiler/ParseHelper.h
@@ -105,6 +105,7 @@
     bool containsSampler(TType& type);
     bool areAllChildConst(TIntermAggregate* aggrNode);
     const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, bool *builtIn = 0);
+    bool isVariableBuiltIn(const TVariable* pVar);
     bool executeInitializer(const TSourceLoc& line, TString& identifier, TPublicType& pType,
                             TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
 
diff --git a/src/compiler/ShaderLang.cpp b/src/compiler/ShaderLang.cpp
index dcf8b96..a67a627 100644
--- a/src/compiler/ShaderLang.cpp
+++ b/src/compiler/ShaderLang.cpp
@@ -126,6 +126,7 @@
     resources->OES_EGL_image_external = 0;
     resources->ARB_texture_rectangle = 0;
     resources->EXT_draw_buffers = 0;
+    resources->EXT_frag_depth = 0;
 
     // Disable highp precision in fragment shader by default.
     resources->FragmentPrecisionHigh = 0;
diff --git a/src/compiler/SymbolTable.cpp b/src/compiler/SymbolTable.cpp
index 1e34f1a..f6b6ab6 100644
--- a/src/compiler/SymbolTable.cpp
+++ b/src/compiler/SymbolTable.cpp
@@ -223,10 +223,8 @@
 void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext)
 {
     for (tLevel::iterator it = level.begin(); it != level.end(); ++it) {
-        if (it->second->isFunction()) {
-            TFunction* function = static_cast<TFunction*>(it->second);
-            if (function->getName() == name)
-                function->relateToExtension(ext);
-        }
+        TSymbol* symbol = it->second;
+        if (symbol->getName() == name)
+            symbol->relateToExtension(ext);
     }
 }
diff --git a/src/compiler/SymbolTable.h b/src/compiler/SymbolTable.h
index 5006973..f6e1959 100644
--- a/src/compiler/SymbolTable.h
+++ b/src/compiler/SymbolTable.h
@@ -50,13 +50,16 @@
     virtual bool isVariable() const { return false; }
     void setUniqueId(int id) { uniqueId = id; }
     int getUniqueId() const { return uniqueId; }
-    virtual void dump(TInfoSink &infoSink) const = 0;	
+    virtual void dump(TInfoSink &infoSink) const = 0;
+    void relateToExtension(const TString& ext) { extension = ext; }
+    const TString& getExtension() const { return extension; }
 
 private:
     DISALLOW_COPY_AND_ASSIGN(TSymbol);
 
     const TString *name;
     unsigned int uniqueId;      // For real comparing during code generation
+    TString extension;
 };
 
 //
@@ -156,9 +159,6 @@
     void relateToOperator(TOperator o) { op = o; }
     TOperator getBuiltInOp() const { return op; }
 
-    void relateToExtension(const TString& ext) { extension = ext; }
-    const TString& getExtension() const { return extension; }
-
     void setDefined() { defined = true; }
     bool isDefined() { return defined; }
 
@@ -175,7 +175,6 @@
     TType returnType;
     TString mangledName;
     TOperator op;
-    TString extension;
     bool defined;
 };
 
diff --git a/src/compiler/glslang.y b/src/compiler/glslang.y
index f85a745..8836378 100644
--- a/src/compiler/glslang.y
+++ b/src/compiler/glslang.y
@@ -197,7 +197,14 @@
                 context->error(@1, "variable expected", $1.string->c_str());
                 context->recover();
             }
+
             variable = static_cast<const TVariable*>(symbol);
+
+            if (context->isVariableBuiltIn(variable) && 
+                !variable->getExtension().empty() &&
+                context->extensionErrorCheck(@1, variable->getExtension())) {
+                context->recover();
+            }
         }
 
         // don't delete $1.string, it's used by error recovery, and the pool
diff --git a/src/compiler/glslang_tab.cpp b/src/compiler/glslang_tab.cpp
index cd401a9..3cc96a0 100644
--- a/src/compiler/glslang_tab.cpp
+++ b/src/compiler/glslang_tab.cpp
@@ -325,6 +325,14 @@
       }                                                      \
   } while (0)
 
+#define FRAG_VERT_ONLY(S, L) {  \
+    if (context->shaderType != SH_FRAGMENT_SHADER &&  \
+        context->shaderType != SH_VERTEX_SHADER) {  \
+        context->error(L, " supported in vertex/fragment shaders only ", S);  \
+        context->recover();  \
+    }  \
+}
+
 #define VERTEX_ONLY(S, L) {  \
     if (context->shaderType != SH_VERTEX_SHADER) {  \
         context->error(L, " supported in vertex shaders only ", S);  \
@@ -713,27 +721,27 @@
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   179,   179,   180,   183,   219,   222,   235,   240,   245,
-     251,   254,   329,   332,   433,   443,   456,   464,   564,   567,
-     575,   578,   584,   588,   595,   601,   610,   618,   673,   683,
-     686,   696,   706,   727,   728,   729,   734,   735,   743,   754,
-     755,   763,   774,   778,   779,   789,   799,   809,   822,   823,
-     833,   846,   850,   854,   858,   859,   872,   873,   886,   887,
-     900,   901,   918,   919,   932,   933,   934,   935,   936,   940,
-     943,   954,   962,   989,   994,  1008,  1045,  1048,  1055,  1063,
-    1084,  1105,  1115,  1143,  1148,  1158,  1163,  1173,  1176,  1179,
-    1182,  1188,  1195,  1198,  1220,  1238,  1262,  1285,  1289,  1307,
-    1315,  1347,  1367,  1388,  1397,  1420,  1423,  1429,  1437,  1445,
-    1453,  1463,  1470,  1473,  1476,  1482,  1485,  1500,  1504,  1508,
-    1512,  1516,  1521,  1526,  1531,  1536,  1541,  1546,  1551,  1556,
-    1561,  1566,  1571,  1576,  1580,  1584,  1592,  1600,  1604,  1617,
-    1617,  1631,  1631,  1640,  1643,  1659,  1695,  1699,  1705,  1712,
-    1727,  1731,  1735,  1736,  1742,  1743,  1744,  1745,  1746,  1750,
-    1751,  1751,  1751,  1761,  1762,  1766,  1766,  1767,  1767,  1772,
-    1775,  1785,  1788,  1794,  1795,  1799,  1807,  1811,  1821,  1826,
-    1843,  1843,  1848,  1848,  1855,  1855,  1863,  1866,  1872,  1875,
-    1881,  1885,  1892,  1899,  1906,  1913,  1924,  1933,  1937,  1944,
-    1947,  1953,  1953
+       0,   187,   187,   188,   191,   234,   237,   250,   255,   260,
+     266,   269,   356,   359,   460,   470,   483,   491,   591,   594,
+     602,   605,   611,   615,   622,   628,   637,   645,   700,   710,
+     713,   723,   733,   754,   755,   756,   761,   762,   771,   783,
+     784,   792,   803,   807,   808,   818,   828,   838,   851,   852,
+     862,   875,   879,   883,   887,   888,   901,   902,   915,   916,
+     929,   930,   947,   948,   961,   962,   963,   964,   965,   969,
+     972,   983,   991,  1018,  1023,  1037,  1074,  1077,  1084,  1092,
+    1113,  1134,  1144,  1172,  1177,  1187,  1192,  1202,  1205,  1208,
+    1211,  1217,  1224,  1227,  1249,  1267,  1291,  1314,  1318,  1336,
+    1344,  1376,  1396,  1485,  1494,  1517,  1520,  1526,  1534,  1542,
+    1550,  1560,  1567,  1570,  1573,  1579,  1582,  1597,  1601,  1605,
+    1609,  1618,  1623,  1628,  1633,  1638,  1643,  1648,  1653,  1658,
+    1663,  1669,  1675,  1681,  1686,  1691,  1700,  1709,  1714,  1727,
+    1727,  1741,  1741,  1750,  1753,  1769,  1805,  1809,  1815,  1822,
+    1837,  1841,  1845,  1846,  1852,  1853,  1854,  1855,  1856,  1860,
+    1861,  1861,  1861,  1871,  1872,  1876,  1876,  1877,  1877,  1882,
+    1885,  1895,  1898,  1904,  1905,  1909,  1917,  1921,  1931,  1936,
+    1953,  1953,  1958,  1958,  1965,  1965,  1973,  1976,  1982,  1985,
+    1991,  1995,  2002,  2009,  2016,  2023,  2034,  2043,  2047,  2054,
+    2057,  2063,  2063
 };
 #endif
 
@@ -2262,7 +2270,14 @@
                 context->error((yylsp[(1) - (1)]), "variable expected", (yyvsp[(1) - (1)].lex).string->c_str());
                 context->recover();
             }
+
             variable = static_cast<const TVariable*>(symbol);
+
+            if (context->isVariableBuiltIn(variable) && 
+                !variable->getExtension().empty() &&
+                context->extensionErrorCheck((yylsp[(1) - (1)]), variable->getExtension())) {
+                context->recover();
+            }
         }
 
         // don't delete $1.string, it's used by error recovery, and the pool
@@ -2369,7 +2384,15 @@
                 }
             } else {
                 if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray()) {
-                    if (index >= (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize()) {
+                    if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize() == 0) {
+                        if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getMaxArraySize() <= index) {
+                            if (context->arraySetMaxSize((yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getTypePointer(), index, true, (yylsp[(2) - (4)])))
+                                context->recover();
+                        } else {
+                            if (context->arraySetMaxSize((yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getTypePointer(), 0, false, (yylsp[(2) - (4)])))
+                                context->recover();
+                        }
+                    } else if (index >= (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize()) {
                         std::stringstream extraInfoStream;
                         extraInfoStream << "array index out of range '" << index << "'";
                         std::string extraInfo = extraInfoStream.str();
@@ -2389,6 +2412,10 @@
                 (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(3) - (4)].interm.intermTypedNode), (yylsp[(2) - (4)]));
             }
         } else {
+            if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray() && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize() == 0) {
+                context->error((yylsp[(2) - (4)]), "", "[", "array must be redeclared with a size before being indexed with a variable");
+                context->recover();
+            }
             (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexIndirect, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(3) - (4)].interm.intermTypedNode), (yylsp[(2) - (4)]));
         }
         if ((yyval.interm.intermTypedNode) == 0) {
@@ -2752,33 +2779,33 @@
             case EbtFloat:
                 if ((yyvsp[(1) - (1)].interm.type).matrix) {
                     switch((yyvsp[(1) - (1)].interm.type).size) {
-                    case 2: op = EOpConstructMat2;  break;
-                    case 3: op = EOpConstructMat3;  break;
-                    case 4: op = EOpConstructMat4;  break;
+                    case 2:                                     op = EOpConstructMat2;  break;
+                    case 3:                                     op = EOpConstructMat3;  break;
+                    case 4:                                     op = EOpConstructMat4;  break;
                     }
                 } else {
                     switch((yyvsp[(1) - (1)].interm.type).size) {
-                    case 1: op = EOpConstructFloat; break;
-                    case 2: op = EOpConstructVec2;  break;
-                    case 3: op = EOpConstructVec3;  break;
-                    case 4: op = EOpConstructVec4;  break;
+                    case 1:                                     op = EOpConstructFloat; break;
+                    case 2:                                     op = EOpConstructVec2;  break;
+                    case 3:                                     op = EOpConstructVec3;  break;
+                    case 4:                                     op = EOpConstructVec4;  break;
                     }
                 }
                 break;
             case EbtInt:
                 switch((yyvsp[(1) - (1)].interm.type).size) {
-                case 1: op = EOpConstructInt;   break;
-                case 2: op = EOpConstructIVec2; break;
-                case 3: op = EOpConstructIVec3; break;
-                case 4: op = EOpConstructIVec4; break;
+                case 1:                                         op = EOpConstructInt;   break;
+                case 2:       FRAG_VERT_ONLY("ivec2", (yylsp[(1) - (1)])); op = EOpConstructIVec2; break;
+                case 3:       FRAG_VERT_ONLY("ivec3", (yylsp[(1) - (1)])); op = EOpConstructIVec3; break;
+                case 4:       FRAG_VERT_ONLY("ivec4", (yylsp[(1) - (1)])); op = EOpConstructIVec4; break;
                 }
                 break;
             case EbtBool:
                 switch((yyvsp[(1) - (1)].interm.type).size) {
-                case 1: op = EOpConstructBool;  break;
-                case 2: op = EOpConstructBVec2; break;
-                case 3: op = EOpConstructBVec3; break;
-                case 4: op = EOpConstructBVec4; break;
+                case 1:                                         op = EOpConstructBool;  break;
+                case 2:       FRAG_VERT_ONLY("bvec2", (yylsp[(1) - (1)])); op = EOpConstructBVec2; break;
+                case 3:       FRAG_VERT_ONLY("bvec3", (yylsp[(1) - (1)])); op = EOpConstructBVec3; break;
+                case 4:       FRAG_VERT_ONLY("bvec4", (yylsp[(1) - (1)])); op = EOpConstructBVec4; break;
                 }
                 break;
             default: break;
@@ -2887,6 +2914,7 @@
   case 37:
 
     {
+        FRAG_VERT_ONLY("*", (yylsp[(2) - (3)]));
         (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpMul, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
         if ((yyval.interm.intermTypedNode) == 0) {
             context->binaryOpError((yylsp[(2) - (3)]), "*", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
@@ -2899,6 +2927,7 @@
   case 38:
 
     {
+        FRAG_VERT_ONLY("/", (yylsp[(2) - (3)]));
         (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpDiv, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
         if ((yyval.interm.intermTypedNode) == 0) {
             context->binaryOpError((yylsp[(2) - (3)]), "/", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
@@ -3152,27 +3181,27 @@
 
   case 64:
 
-    { (yyval.interm).op = EOpAssign; }
+    {                            (yyval.interm).op = EOpAssign; }
     break;
 
   case 65:
 
-    { (yyval.interm).op = EOpMulAssign; }
+    { FRAG_VERT_ONLY("*=", (yylsp[(1) - (1)]));  (yyval.interm).op = EOpMulAssign; }
     break;
 
   case 66:
 
-    { (yyval.interm).op = EOpDivAssign; }
+    { FRAG_VERT_ONLY("/=", (yylsp[(1) - (1)]));  (yyval.interm).op = EOpDivAssign; }
     break;
 
   case 67:
 
-    { (yyval.interm).op = EOpAddAssign; }
+    {                            (yyval.interm).op = EOpAddAssign; }
     break;
 
   case 68:
 
-    { (yyval.interm).op = EOpSubAssign; }
+    {                            (yyval.interm).op = EOpSubAssign; }
     break;
 
   case 69:
@@ -3976,6 +4005,7 @@
   case 130:
 
     {
+        FRAG_VERT_ONLY("mat2", (yylsp[(1) - (1)]));
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
         (yyval.interm.type).setAggregate(2, true);
@@ -3985,6 +4015,7 @@
   case 131:
 
     {
+        FRAG_VERT_ONLY("mat3", (yylsp[(1) - (1)]));
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
         (yyval.interm.type).setAggregate(3, true);
@@ -3994,6 +4025,7 @@
   case 132:
 
     {
+        FRAG_VERT_ONLY("mat4", (yylsp[(1) - (1)]));
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
         (yyval.interm.type).setAggregate(4, true);
@@ -4003,6 +4035,7 @@
   case 133:
 
     {
+        FRAG_VERT_ONLY("sampler2D", (yylsp[(1) - (1)]));
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtSampler2D, qual, (yylsp[(1) - (1)]));
     }
@@ -4011,6 +4044,7 @@
   case 134:
 
     {
+        FRAG_VERT_ONLY("samplerCube", (yylsp[(1) - (1)]));
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtSamplerCube, qual, (yylsp[(1) - (1)]));
     }
@@ -4023,6 +4057,7 @@
             context->error((yylsp[(1) - (1)]), "unsupported type", "samplerExternalOES");
             context->recover();
         }
+        FRAG_VERT_ONLY("samplerExternalOES", (yylsp[(1) - (1)]));
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtSamplerExternalOES, qual, (yylsp[(1) - (1)]));
     }
@@ -4035,6 +4070,7 @@
             context->error((yylsp[(1) - (1)]), "unsupported type", "sampler2DRect");
             context->recover();
         }
+        FRAG_VERT_ONLY("sampler2DRect", (yylsp[(1) - (1)]));
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtSampler2DRect, qual, (yylsp[(1) - (1)]));
     }
@@ -4043,6 +4079,7 @@
   case 137:
 
     {
+        FRAG_VERT_ONLY("struct", (yylsp[(1) - (1)]));
         (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
         (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
     }
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index 3dd2cd8..f6ce667 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -3964,6 +3964,7 @@
 
     extensionString += "GL_EXT_texture_format_BGRA8888 ";
     extensionString += "GL_EXT_texture_storage ";
+    extensionString += "GL_EXT_frag_depth ";
 
     // ANGLE-specific extensions
     if (supportsDepthTextures())
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index 2c57c62..f68f6e5 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -1549,8 +1549,14 @@
                   "\n"
                   "struct PS_OUTPUT\n"
                   "{\n"
-                  "    float4 gl_Color[1] : COLOR;\n"
-                  "};\n"
+                  "    float4 gl_Color[1] : COLOR;\n";
+
+    if (fragmentShader->mUsesFragDepth)
+    {
+        pixelHLSL += "    float gl_Depth : DEPTH;\n";
+    }
+
+    pixelHLSL +=  "};\n"
                   "\n"
                   "PS_OUTPUT main(PS_INPUT input)\n"
                   "{\n";
@@ -1625,9 +1631,15 @@
     pixelHLSL += "\n"
                   "    gl_main();\n"
                   "\n"
-                  "    PS_OUTPUT output;\n"                 
-                  "    output.gl_Color[0] = gl_Color[0];\n"
-                  "\n"
+                  "    PS_OUTPUT output;\n"
+                  "    output.gl_Color[0] = gl_Color[0];\n";
+
+    if (fragmentShader->mUsesFragDepth)
+    {
+        pixelHLSL += "    output.gl_Depth = gl_Depth;\n";
+    }
+
+    pixelHLSL += "\n"
                   "    return output;\n"
                   "}\n";
 
diff --git a/src/libGLESv2/Shader.cpp b/src/libGLESv2/Shader.cpp
index e3e02d5..c3ee644 100644
--- a/src/libGLESv2/Shader.cpp
+++ b/src/libGLESv2/Shader.cpp
@@ -238,6 +238,7 @@
             resources.OES_standard_derivatives = context->supportsDerivativeInstructions() ? 1 : 0;
             // resources.OES_EGL_image_external = getDisplay()->isD3d9ExDevice() ? 1 : 0; // TODO: commented out until the extension is actually supported.
             resources.FragmentPrecisionHigh = 1;   // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp
+            resources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output
 
             mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
             mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
@@ -292,6 +293,7 @@
         mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
         mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
         mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
+        mUsesFragDepth = strstr(mHlsl, "GL_USES_FRAG_DEPTH") != NULL;
     }
 }
 
@@ -311,6 +313,7 @@
     mUsesFrontFacing = false;
     mUsesPointSize = false;
     mUsesPointCoord = false;
+    mUsesFragDepth = false;
 }
 
 void Shader::compileToHLSL(void *compiler)
diff --git a/src/libGLESv2/Shader.h b/src/libGLESv2/Shader.h
index b73fc28..e6ca03d 100644
--- a/src/libGLESv2/Shader.h
+++ b/src/libGLESv2/Shader.h
@@ -90,6 +90,7 @@
     bool mUsesFrontFacing;
     bool mUsesPointSize;
     bool mUsesPointCoord;
+    bool mUsesFragDepth;
 
     static void *mFragmentCompiler;
     static void *mVertexCompiler;