--- include/GLSLANG/ShaderLang.h.orig
+++ include/GLSLANG/ShaderLang.h
@@ -50,6 +50,10 @@
     SH_ESSL_OUTPUT,
 
     // GLSL output only supported in some configurations.
+    SH_GLSL_COMPATIBILITY_OUTPUT,
+    // Note: GL introduced core profiles in 1.5.
+    SH_GLSL_130_OUTPUT,
+    SH_GLSL_140_OUTPUT,
     SH_GLSL_150_CORE_OUTPUT,
     SH_GLSL_330_CORE_OUTPUT,
     SH_GLSL_400_CORE_OUTPUT,
--- samples/shader_translator/shader_translator.cpp.orig
+++ samples/shader_translator/shader_translator.cpp
@@ -441,8 +441,9 @@
         "       -s=w     : use WebGL 1.0 spec\n"
         "       -s=w2    : use WebGL 2.0 spec\n"
         "       -b=e     : output GLSL ES code (this is by default)\n"
-        "       -b=g     : output GLSL code (version 150)\n"
-        "       -b=g[NUM]: output GLSL code (NUM can be 150, 330, 400, 410, 420, 430, 440, 450)\n"
+        "       -b=g     : output GLSL code (compatibility profile)\n"
+        "       -b=g[NUM]: output GLSL code (NUM can be 130, 140, 150, 330, 400, 410, 420, 430, "
+        "440, 450)\n"
         "       -b=v     : output Vulkan SPIR-V code\n"
         "       -b=h11   : output HLSL11 code\n"
         "       -b=m     : output MSL code\n"
@@ -834,7 +835,7 @@
 {
     if (num.length() == 0)
     {
-        *outResult = SH_GLSL_150_CORE_OUTPUT;
+        *outResult = SH_GLSL_COMPATIBILITY_OUTPUT;
         return true;
     }
     std::istringstream input(num);
@@ -846,6 +847,12 @@
 
     switch (value)
     {
+        case 130:
+            *outResult = SH_GLSL_130_OUTPUT;
+            return true;
+        case 140:
+            *outResult = SH_GLSL_140_OUTPUT;
+            return true;
         case 150:
             *outResult = SH_GLSL_150_CORE_OUTPUT;
             return true;
--- src/compiler/fuzz/translator_fuzzer.cpp.orig
+++ src/compiler/fuzz/translator_fuzzer.cpp
@@ -159,6 +159,9 @@
 
     std::vector<uint32_t> validOutputs;
     validOutputs.push_back(SH_ESSL_OUTPUT);
+    validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT);
+    validOutputs.push_back(SH_GLSL_130_OUTPUT);
+    validOutputs.push_back(SH_GLSL_140_OUTPUT);
     validOutputs.push_back(SH_GLSL_150_CORE_OUTPUT);
     validOutputs.push_back(SH_GLSL_330_CORE_OUTPUT);
     validOutputs.push_back(SH_GLSL_400_CORE_OUTPUT);
--- src/compiler/translator/Compiler.cpp.orig
+++ src/compiler/translator/Compiler.cpp
@@ -299,9 +299,10 @@
 
 }  // anonymous namespace
 
-bool IsGLSL150OrNewer(ShShaderOutput output)
+bool IsGLSL130OrNewer(ShShaderOutput output)
 {
-    return (output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
+    return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
+            output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
             output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT ||
             output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
             output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
@@ -315,7 +316,8 @@
 
 bool IsGLSL410OrOlder(ShShaderOutput output)
 {
-    return (output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
+    return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
+            output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
             output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT);
 }
 
@@ -1193,6 +1195,12 @@
         compileOptions.expandFragmentOutputsToVec4   = false;
     }
 
+    // gl_Position should always be written in GLSL compatibility output mode.
+    if (mOutputType == SH_GLSL_COMPATIBILITY_OUTPUT && mShaderType == GL_VERTEX_SHADER)
+    {
+        compileOptions.initGLPosition = true;
+    }
+
 #if !defined(ANGLE_IR)
     compileOptions.useIR = false;
 #endif
--- src/compiler/translator/Compiler.h.orig
+++ src/compiler/translator/Compiler.h
@@ -44,7 +44,7 @@
 //
 // Helper function to check if the shader type is GLSL.
 //
-bool IsGLSL150OrNewer(ShShaderOutput output);
+bool IsGLSL130OrNewer(ShShaderOutput output);
 bool IsGLSL420OrNewer(ShShaderOutput output);
 bool IsGLSL410OrOlder(ShShaderOutput output);
 
--- src/compiler/translator/glsl/ExtensionGLSL.cpp.orig
+++ src/compiler/translator/glsl/ExtensionGLSL.cpp
@@ -43,6 +43,11 @@
 
 void TExtensionGLSL::checkOperator(TIntermOperator *node)
 {
+    if (mTargetVersion < GLSL_VERSION_130)
+    {
+        return;
+    }
+
     switch (node->getOp())
     {
         case EOpAbs:
--- src/compiler/translator/glsl/OutputGLSL.cpp.orig
+++ src/compiler/translator/glsl/OutputGLSL.cpp
@@ -49,19 +49,17 @@
         return;
     }
 
-    ASSERT(sh::IsGLSL150OrNewer(getShaderOutput()));
-
     // Some built-ins get a special translation.
     const ImmutableString &name = node->getName();
     if (name == "gl_FragDepthEXT")
     {
         out << "gl_FragDepth";
     }
-    else if (name == "gl_FragColor")
+    else if (name == "gl_FragColor" && sh::IsGLSL130OrNewer(getShaderOutput()))
     {
         out << "webgl_FragColor";
     }
-    else if (name == "gl_FragData")
+    else if (name == "gl_FragData" && sh::IsGLSL130OrNewer(getShaderOutput()))
     {
         out << "webgl_FragData";
     }
@@ -82,7 +80,20 @@
 ImmutableString TOutputGLSL::translateTextureFunction(const ImmutableString &name,
                                                       const ShCompileOptions &option)
 {
-    ASSERT(sh::IsGLSL150OrNewer(getShaderOutput()));
+    static const char *simpleRename[]       = {"texture2DLodEXT",
+                                               "texture2DLod",
+                                               "texture2DProjLodEXT",
+                                               "texture2DProjLod",
+                                               "textureCubeLodEXT",
+                                               "textureCubeLod",
+                                               "texture2DGradEXT",
+                                               "texture2DGradARB",
+                                               "texture2DProjGradEXT",
+                                               "texture2DProjGradARB",
+                                               "textureCubeGradEXT",
+                                               "textureCubeGradARB",
+                                               nullptr,
+                                               nullptr};
     static const char *legacyToCoreRename[] = {
         "texture2D", "texture", "texture2DProj", "textureProj", "texture2DLod", "textureLod",
         "texture2DProjLod", "textureProjLod", "texture2DRect", "texture", "texture2DRectProj",
@@ -94,12 +105,14 @@
         "texture", "texture3DProj", "textureProj", "texture3DLod", "textureLod", "texture3DProjLod",
         "textureProjLod", "shadow2DEXT", "texture", "shadow2DProjEXT", "textureProj", nullptr,
         nullptr};
+    const char **mapping =
+        (sh::IsGLSL130OrNewer(getShaderOutput())) ? legacyToCoreRename : simpleRename;
 
-    for (int i = 0; ANGLE_UNSAFE_TODO(legacyToCoreRename[i]) != nullptr; i += 2)
+    for (int i = 0; ANGLE_UNSAFE_TODO(mapping[i]) != nullptr; i += 2)
     {
-        if (name == ANGLE_UNSAFE_TODO(legacyToCoreRename[i]))
+        if (name == ANGLE_UNSAFE_TODO(mapping[i]))
         {
-            return ImmutableString(ANGLE_UNSAFE_TODO(legacyToCoreRename[i + 1]));
+            return ImmutableString(ANGLE_UNSAFE_TODO(mapping[i + 1]));
         }
     }
 
--- src/compiler/translator/glsl/OutputGLSLBase.cpp.orig
+++ src/compiler/translator/glsl/OutputGLSLBase.cpp
@@ -384,7 +384,7 @@
                 break;
         }
     }
-    if (sh::IsGLSL150OrNewer(mOutput))
+    if (sh::IsGLSL130OrNewer(mOutput))
     {
         switch (qualifier)
         {
@@ -408,7 +408,7 @@
         // gl_ClipDistance / gl_CullDistance require different qualifiers based on shader type.
         case EvqClipDistance:
         case EvqCullDistance:
-            return (sh::IsGLSL150OrNewer(mOutput) || mShaderVersion > 100)
+            return (sh::IsGLSL130OrNewer(mOutput) || mShaderVersion > 100)
                        ? (mShaderType == GL_FRAGMENT_SHADER ? "in" : "out")
                        : "varying";
 
--- src/compiler/translator/glsl/TranslatorGLSL.cpp.orig
+++ src/compiler/translator/glsl/TranslatorGLSL.cpp
@@ -32,8 +32,6 @@
                                const ShCompileOptions &compileOptions,
                                PerformanceDiagnostics * /*perfDiagnostics*/)
 {
-    ASSERT(sh::IsGLSL150OrNewer(getOutputType()));
-
     TInfoSinkBase &sink = getInfoSink().obj;
 
     // Write GLSL version.
@@ -176,6 +174,7 @@
         const bool mayHaveESSL1SecondaryOutputs =
             IsExtensionEnabled(getExtensionBehavior(), TExtension::EXT_blend_func_extended) &&
             getShaderVersion() == 100;
+        const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType());
 
         bool hasGLFragColor          = false;
         bool hasGLFragData           = false;
@@ -184,17 +183,20 @@
 
         for (const auto &outputVar : mOutputVariables)
         {
-            if (outputVar.name == "gl_FragColor")
-            {
-                ASSERT(!hasGLFragColor);
-                hasGLFragColor = true;
-                continue;
-            }
-            else if (outputVar.name == "gl_FragData")
+            if (declareGLFragmentOutputs)
             {
-                ASSERT(!hasGLFragData);
-                hasGLFragData = true;
-                continue;
+                if (outputVar.name == "gl_FragColor")
+                {
+                    ASSERT(!hasGLFragColor);
+                    hasGLFragColor = true;
+                    continue;
+                }
+                else if (outputVar.name == "gl_FragData")
+                {
+                    ASSERT(!hasGLFragData);
+                    hasGLFragData = true;
+                    continue;
+                }
             }
             if (mayHaveESSL1SecondaryOutputs)
             {
@@ -261,18 +263,23 @@
 
 bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll()
 {
-    // Required when outputting to any GLSL version greater than 1.20, but since ANGLE always
-    // translates to at least version 1.50, return true.
-    return true;
+    // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't
+    // translate to that version, return true for the next higher version.
+    return IsGLSL130OrNewer(getOutputType());
 }
 
 void TranslatorGLSL::writeVersion(TIntermNode *root)
 {
-    int version = ShaderOutputTypeToGLSLVersion(getOutputType());
-    ASSERT(version >= GLSL_VERSION_150);
-
-    TInfoSinkBase &sink = getInfoSink().obj;
-    sink << "#version " << version << "\n";
+    TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType());
+    root->traverse(&versionGLSL);
+    int version = versionGLSL.getVersion();
+    // We need to write version directive only if it is greater than 110.
+    // If there is no version directive in the shader, 110 is implied.
+    if (version > 110)
+    {
+        TInfoSinkBase &sink = getInfoSink().obj;
+        sink << "#version " << version << "\n";
+    }
 }
 
 void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root,
@@ -291,6 +298,30 @@
             continue;
         }
 
+        if (getOutputType() == SH_GLSL_COMPATIBILITY_OUTPUT)
+        {
+            // For GLSL output, we don't need to emit most extensions explicitly,
+            // but some we need to translate in GL compatibility profile.
+            if (iter.first == TExtension::EXT_shader_texture_lod)
+            {
+                sink << "#extension GL_ARB_shader_texture_lod : " << GetBehaviorString(iter.second)
+                     << "\n";
+            }
+
+            if (iter.first == TExtension::EXT_draw_buffers)
+            {
+                sink << "#extension GL_ARB_draw_buffers : " << GetBehaviorString(iter.second)
+                     << "\n";
+            }
+
+            if (iter.first == TExtension::EXT_geometry_shader ||
+                iter.first == TExtension::OES_geometry_shader)
+            {
+                sink << "#extension GL_ARB_geometry_shader4 : " << GetBehaviorString(iter.second)
+                     << "\n";
+            }
+        }
+
         const bool isMultiview =
             (iter.first == TExtension::OVR_multiview) || (iter.first == TExtension::OVR_multiview2);
         if (isMultiview)
@@ -380,7 +411,7 @@
     // Need to enable gpu_shader5 to have index constant sampler array indexing
     if (usesGPUShader5)
     {
-        if (getOutputType() >= SH_GLSL_150_CORE_OUTPUT &&
+        if (getOutputType() >= SH_GLSL_COMPATIBILITY_OUTPUT &&
             getOutputType() < SH_GLSL_400_CORE_OUTPUT && getShaderVersion() == 100)
         {
             // Don't use "require" on to avoid breaking WebGL 1 on drivers that silently
@@ -400,7 +431,8 @@
 
     if (usesTextureCubeMapArray)
     {
-        if (getOutputType() >= SH_GLSL_150_CORE_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT)
+        if (getOutputType() >= SH_GLSL_COMPATIBILITY_OUTPUT &&
+            getOutputType() < SH_GLSL_400_CORE_OUTPUT)
         {
             sink << "#extension GL_ARB_texture_cube_map_array : enable\n";
         }
@@ -413,7 +445,8 @@
 
     if (usesTextureBuffer)
     {
-        if (getOutputType() >= SH_GLSL_150_CORE_OUTPUT && getOutputType() < SH_GLSL_400_CORE_OUTPUT)
+        if (getOutputType() >= SH_GLSL_COMPATIBILITY_OUTPUT &&
+            getOutputType() < SH_GLSL_400_CORE_OUTPUT)
         {
             sink << "#extension GL_ARB_texture_buffer_objects : enable\n";
         }
--- src/compiler/translator/glsl/VersionGLSL.cpp.orig
+++ src/compiler/translator/glsl/VersionGLSL.cpp
@@ -6,13 +6,25 @@
 
 #include "compiler/translator/glsl/VersionGLSL.h"
 
+#include "angle_gl.h"
+#include "compiler/translator/Symbol.h"
+
 namespace sh
 {
 
+namespace
+{
+constexpr const ImmutableString kGlPointCoordString("gl_PointCoord");
+}  // anonymous namespace
+
 int ShaderOutputTypeToGLSLVersion(ShShaderOutput output)
 {
     switch (output)
     {
+        case SH_GLSL_130_OUTPUT:
+            return GLSL_VERSION_130;
+        case SH_GLSL_140_OUTPUT:
+            return GLSL_VERSION_140;
         case SH_GLSL_150_CORE_OUTPUT:
             return GLSL_VERSION_150;
         case SH_GLSL_330_CORE_OUTPUT:
@@ -29,10 +41,116 @@
             return GLSL_VERSION_440;
         case SH_GLSL_450_CORE_OUTPUT:
             return GLSL_VERSION_450;
+        case SH_GLSL_COMPATIBILITY_OUTPUT:
+            return GLSL_VERSION_110;
         default:
             UNREACHABLE();
             return 0;
     }
 }
 
+// We need to scan for the following:
+// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
+//    but only at the global scope.
+// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader
+//    but inside any scope.
+// 3. Call to a matrix constructor with another matrix as argument.
+//    (These constructors were reserved in GLSL version 1.10.)
+// 4. Arrays as "out" function parameters.
+//    GLSL spec section 6.1.1: "When calling a function, expressions that do
+//    not evaluate to l-values cannot be passed to parameters declared as
+//    out or inout."
+//    GLSL 1.1 section 5.8: "Other binary or unary expressions,
+//    non-dereferenced arrays, function names, swizzles with repeated fields,
+//    and constants cannot be l-values."
+//    GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that
+//    are built-in types, entire structures or arrays... are all l-values."
+//
+TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output)
+    : TIntermTraverser(true, false, false)
+{
+    mVersion = ShaderOutputTypeToGLSLVersion(output);
+    if (pragma.stdgl.invariantAll)
+    {
+        ensureVersionIsAtLeast(GLSL_VERSION_120);
+    }
+    if (type == GL_COMPUTE_SHADER)
+    {
+        ensureVersionIsAtLeast(GLSL_VERSION_430);
+    }
+}
+
+void TVersionGLSL::visitSymbol(TIntermSymbol *node)
+{
+    if (node->variable().symbolType() == SymbolType::BuiltIn &&
+        node->getName() == kGlPointCoordString)
+    {
+        ensureVersionIsAtLeast(GLSL_VERSION_120);
+    }
+}
+
+bool TVersionGLSL::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+    const TIntermSequence &sequence = *(node->getSequence());
+    if (sequence.front()->getAsTyped()->getType().isInvariant())
+    {
+        ensureVersionIsAtLeast(GLSL_VERSION_120);
+    }
+    return true;
+}
+
+bool TVersionGLSL::visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *node)
+{
+    if (node->isPrecise())
+    {
+        ensureVersionIsAtLeast(GLSL_VERSION_420);
+    }
+    else
+    {
+        ensureVersionIsAtLeast(GLSL_VERSION_120);
+    }
+    return true;
+}
+
+void TVersionGLSL::visitFunctionPrototype(TIntermFunctionPrototype *node)
+{
+    size_t paramCount = node->getFunction()->getParamCount();
+    for (size_t i = 0; i < paramCount; ++i)
+    {
+        const TVariable *param = node->getFunction()->getParam(i);
+        const TType &type      = param->getType();
+        if (type.isArray())
+        {
+            TQualifier qualifier = type.getQualifier();
+            if ((qualifier == EvqParamOut) || (qualifier == EvqParamInOut))
+            {
+                ensureVersionIsAtLeast(GLSL_VERSION_120);
+                break;
+            }
+        }
+    }
+}
+
+bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate *node)
+{
+    if (node->getOp() == EOpConstruct && node->getType().isMatrix())
+    {
+        const TIntermSequence &sequence = *(node->getSequence());
+        if (sequence.size() == 1)
+        {
+            TIntermTyped *typed = sequence.front()->getAsTyped();
+            if (typed && typed->isMatrix())
+            {
+                ensureVersionIsAtLeast(GLSL_VERSION_120);
+            }
+        }
+    }
+    return true;
+}
+
+void TVersionGLSL::ensureVersionIsAtLeast(int version)
+{
+    mVersion = std::max(version, mVersion);
+}
+
 }  // namespace sh
--- src/compiler/translator/glsl/VersionGLSL.h.orig
+++ src/compiler/translator/glsl/VersionGLSL.h
@@ -9,9 +9,15 @@
 
 #include "compiler/translator/tree_util/IntermTraverse.h"
 
+#include "compiler/translator/Pragma.h"
+
 namespace sh
 {
 
+static const int GLSL_VERSION_110 = 110;
+static const int GLSL_VERSION_120 = 120;
+static const int GLSL_VERSION_130 = 130;
+static const int GLSL_VERSION_140 = 140;
 static const int GLSL_VERSION_150 = 150;
 static const int GLSL_VERSION_330 = 330;
 static const int GLSL_VERSION_400 = 400;
@@ -23,6 +29,48 @@
 
 int ShaderOutputTypeToGLSLVersion(ShShaderOutput output);
 
+// Traverses the intermediate tree to return the minimum GLSL version
+// required to legally access all built-in features used in the shader.
+// GLSL 1.1 which is mandated by OpenGL 2.0 provides:
+//   - #version and #extension to declare version and extensions.
+//   - built-in functions refract, exp, and log.
+//   - updated step() to compare x < edge instead of x <= edge.
+// GLSL 1.2 which is mandated by OpenGL 2.1 provides:
+//   - many changes to reduce differences when compared to the ES specification.
+//   - invariant keyword and its support.
+//   - c++ style name hiding rules.
+//   - built-in variable gl_PointCoord for fragment shaders.
+//   - matrix constructors taking matrix as argument.
+//   - array as "out" function parameters
+//
+// TODO: ES3 equivalent versions of GLSL
+class TVersionGLSL : public TIntermTraverser
+{
+  public:
+    TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output);
+
+    // If output is core profile, returns 150.
+    // If output is legacy profile,
+    //   Returns 120 if the following is used the shader:
+    //   - "invariant",
+    //   - "gl_PointCoord",
+    //   - matrix/matrix constructors
+    //   - array "out" parameters
+    //   Else 110 is returned.
+    int getVersion() const { return mVersion; }
+
+    void visitSymbol(TIntermSymbol *node) override;
+    bool visitAggregate(Visit, TIntermAggregate *node) override;
+    bool visitGlobalQualifierDeclaration(Visit, TIntermGlobalQualifierDeclaration *node) override;
+    void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
+    bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+
+  private:
+    void ensureVersionIsAtLeast(int version);
+
+    int mVersion;
+};
+
 }  // namespace sh
 
 #endif  // COMPILER_TRANSLATOR_GLSL_VERSIONGLSL_H_
--- src/compiler/translator/ir/src/compile.rs.orig
+++ src/compiler/translator/ir/src/compile.rs
@@ -18,6 +18,9 @@
     enum OutputLanguage {
         Null,
         Essl,
+        GlslCompatibility,
+        Glsl130,
+        Glsl140,
         Glsl150Core,
         Glsl330Core,
         Glsl400Core,
@@ -418,7 +421,10 @@
             #[cfg(not(angle_enable_essl))]
             panic!("Internal error: ESSL generator is not built");
         }
-        OutputLanguage::Glsl150Core
+        OutputLanguage::GlslCompatibility
+        | OutputLanguage::Glsl130
+        | OutputLanguage::Glsl140
+        | OutputLanguage::Glsl150Core
         | OutputLanguage::Glsl330Core
         | OutputLanguage::Glsl400Core
         | OutputLanguage::Glsl410Core
--- src/compiler/translator/util.cpp.orig
+++ src/compiler/translator/util.cpp
@@ -838,6 +838,8 @@
 {
     switch (output)
     {
+        case SH_GLSL_130_OUTPUT:
+        case SH_GLSL_140_OUTPUT:
         case SH_GLSL_150_CORE_OUTPUT:
         case SH_GLSL_330_CORE_OUTPUT:
         case SH_GLSL_400_CORE_OUTPUT:
@@ -846,6 +848,7 @@
         case SH_GLSL_430_CORE_OUTPUT:
         case SH_GLSL_440_CORE_OUTPUT:
         case SH_GLSL_450_CORE_OUTPUT:
+        case SH_GLSL_COMPATIBILITY_OUTPUT:
             return true;
         default:
             break;
--- src/libANGLE/renderer/gl/FenceNVGL.cpp.orig
+++ src/libANGLE/renderer/gl/FenceNVGL.cpp
@@ -103,10 +103,8 @@
 // static
 bool FenceNVSyncGL::Supported(const FunctionsGL *functions)
 {
-    // GL 3.2 is required for desktop GL
-    ASSERT(functions->standard != STANDARD_GL_DESKTOP || functions->isAtLeastGL(gl::Version(3, 2)));
-    return functions->standard == STANDARD_GL_DESKTOP ||
-           functions->isAtLeastGLES(gl::Version(3, 0));
+    return functions->isAtLeastGL(gl::Version(3, 2)) ||
+           functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLExtension("GL_ARB_sync");
 }
 
 }  // namespace rx
--- src/libANGLE/renderer/gl/renderergl_utils.cpp.orig
+++ src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -382,8 +382,19 @@
         {
             return SH_GLSL_330_CORE_OUTPUT;
         }
-        ASSERT(functions->isAtLeastGL(gl::Version(3, 2)));
-        return SH_GLSL_150_CORE_OUTPUT;
+        if (functions->isAtLeastGL(gl::Version(3, 2)))
+        {
+            return SH_GLSL_150_CORE_OUTPUT;
+        }
+        if (functions->isAtLeastGL(gl::Version(3, 1)))
+        {
+            return SH_GLSL_140_OUTPUT;
+        }
+        if (functions->isAtLeastGL(gl::Version(3, 0)))
+        {
+            return SH_GLSL_130_OUTPUT;
+        }
+        return SH_GLSL_COMPATIBILITY_OUTPUT;
     }
     if (functions->standard == STANDARD_GL_ES)
     {
@@ -801,12 +812,6 @@
     // Start by assuming ES3.1 support and work down
     *maxSupportedESVersion = gl::Version(3, 1);
 
-    // Desktop GL below 3.2 is not supported
-    if (functions->standard == STANDARD_GL_DESKTOP && !functions->isAtLeastGL(gl::Version(3, 2)))
-    {
-        LimitVersion(maxSupportedESVersion, gl::Version(0, 0));
-    }
-
     // Texture format support checks
     const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
     for (GLenum internalFormat : allFormats)
@@ -3010,8 +3015,7 @@
 }
 bool SupportsSeparateFramebufferBindings(const FunctionsGL *functions)
 {
-    // Note: GL 3.2 is required for desktop GL
-    return functions->standard == STANDARD_GL_DESKTOP ||
+    return functions->isAtLeastGL(gl::Version(3, 0)) ||
            functions->isAtLeastGLES(gl::Version(3, 0));
 }
 
--- src/tests/angle_unittests.gni.orig
+++ src/tests/angle_unittests.gni
@@ -93,6 +93,7 @@
   "compiler_tests/CollectVariables_test.cpp",
   "compiler_tests/ConstructCompiler_test.cpp",
   "compiler_tests/FloatLex_test.cpp",
+  "compiler_tests/GLSLCompatibilityOutput_test.cpp",
   "compiler_tests/GeometryShader_test.cpp",
   "compiler_tests/GlFragDataNotModified_test.cpp",
   "compiler_tests/HashNames_test.cpp",
--- src/tests/compiler_tests/CollectVariables_test.cpp.orig
+++ src/tests/compiler_tests/CollectVariables_test.cpp
@@ -54,7 +54,8 @@
 
     virtual void initTranslator(const ShBuiltInResources &resources)
     {
-        mTranslator.reset(new TranslatorGLSL(mShaderType, SH_GLES3_SPEC, SH_GLSL_150_CORE_OUTPUT));
+        mTranslator.reset(
+            new TranslatorGLSL(mShaderType, SH_GLES3_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));
         ASSERT_TRUE(mTranslator->Init(resources));
     }
 
@@ -175,7 +176,7 @@
     void initTranslator(const ShBuiltInResources &resources) override
     {
         mTranslator.reset(
-            new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_150_CORE_OUTPUT));
+            new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));
         ASSERT_TRUE(mTranslator->Init(resources));
     }
 };
@@ -231,7 +232,7 @@
     void initTranslator(const ShBuiltInResources &resources)
     {
         mTranslator.reset(
-            new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_150_CORE_OUTPUT));
+            new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));
         ASSERT_TRUE(mTranslator->Init(resources));
     }
 };
--- src/tests/compiler_tests/ConstructCompiler_test.cpp.orig
+++ src/tests/compiler_tests/ConstructCompiler_test.cpp
@@ -17,7 +17,7 @@
     ShBuiltInResources resources;
     sh::InitBuiltInResources(&resources);
     ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL_SPEC,
-                                              SH_GLSL_150_CORE_OUTPUT, &resources);
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     ASSERT_NE(nullptr, compiler);
     sh::Destruct(compiler);
 }
@@ -29,7 +29,7 @@
     sh::InitBuiltInResources(&resources);
     resources.MaxDrawBuffers = 0;
     ShHandle compiler        = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL_SPEC,
-                                                     SH_GLSL_150_CORE_OUTPUT, &resources);
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     ASSERT_EQ(nullptr, compiler);
 }
 
@@ -41,6 +41,6 @@
     resources.EXT_blend_func_extended  = 1;
     resources.MaxDualSourceDrawBuffers = 0;
     ShHandle compiler                  = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL_SPEC,
-                                                               SH_GLSL_150_CORE_OUTPUT, &resources);
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     ASSERT_EQ(nullptr, compiler);
 }
--- /dev/null
+++ src/tests/compiler_tests/GLSLCompatibilityOutput_test.cpp
@@ -0,0 +1,34 @@
+//
+// Copyright 2016 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// GLSLCompatibilityOutputTest.cpp
+//   Test compiler output for glsl compatibility mode
+//
+
+#include "GLSLANG/ShaderLang.h"
+#include "angle_gl.h"
+#include "gtest/gtest.h"
+#include "tests/test_utils/compiler_test.h"
+
+using namespace sh;
+
+class GLSLCompatibilityOutputTest : public MatchOutputCodeTest
+{
+  public:
+    GLSLCompatibilityOutputTest()
+        : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_GLSL_COMPATIBILITY_OUTPUT)
+    {}
+};
+
+// Verify gl_Position is written when compiling in compatibility mode
+TEST_F(GLSLCompatibilityOutputTest, GLPositionWrittenTest)
+{
+    const std::string &shaderString =
+        "precision mediump float;\n"
+        "void main() {\n"
+        "}";
+    compile(shaderString);
+    EXPECT_TRUE(foundInCode("gl_Position"));
+}
--- src/tests/compiler_tests/PruneEmptyCases_test.cpp.orig
+++ src/tests/compiler_tests/PruneEmptyCases_test.cpp
@@ -21,7 +21,7 @@
 class PruneEmptyCasesTest : public MatchOutputCodeTest
 {
   public:
-    PruneEmptyCasesTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_GLSL_150_CORE_OUTPUT) {}
+    PruneEmptyCasesTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_GLSL_COMPATIBILITY_OUTPUT) {}
 };
 
 // Test that a switch statement that only contains no-ops is pruned entirely.
--- src/tests/compiler_tests/PruneEmptyDeclarations_test.cpp.orig
+++ src/tests/compiler_tests/PruneEmptyDeclarations_test.cpp
@@ -20,7 +20,9 @@
 class PruneEmptyDeclarationsTest : public MatchOutputCodeTest
 {
   public:
-    PruneEmptyDeclarationsTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_GLSL_150_CORE_OUTPUT) {}
+    PruneEmptyDeclarationsTest()
+        : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_GLSL_COMPATIBILITY_OUTPUT)
+    {}
 };
 
 TEST_F(PruneEmptyDeclarationsTest, EmptyDeclarationStartsDeclaratorList)
--- src/tests/compiler_tests/PruneNoOps_test.cpp.orig
+++ src/tests/compiler_tests/PruneNoOps_test.cpp
@@ -20,7 +20,7 @@
 class PruneNoOpsTest : public MatchOutputCodeTest
 {
   public:
-    PruneNoOpsTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_GLSL_150_CORE_OUTPUT) {}
+    PruneNoOpsTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_GLSL_COMPATIBILITY_OUTPUT) {}
 };
 
 // Test that a switch statement with a constant expression without a matching case is pruned.
--- src/tests/compiler_tests/ShCompile_test.cpp.orig
+++ src/tests/compiler_tests/ShCompile_test.cpp
@@ -24,7 +24,7 @@
     {
         sh::InitBuiltInResources(&mResources);
         mCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL_SPEC,
-                                          SH_GLSL_150_CORE_OUTPUT, &mResources);
+                                          SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
         ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
     }
 
@@ -84,7 +84,7 @@
     {
         sh::InitBuiltInResources(&mResources);
         mCompiler = sh::ConstructCompiler(GL_COMPUTE_SHADER, SH_GLES3_1_SPEC,
-                                          SH_GLSL_150_CORE_OUTPUT, &mResources);
+                                          SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
         ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
     }
 };
--- src/tests/compiler_tests/ShaderVariable_test.cpp.orig
+++ src/tests/compiler_tests/ShaderVariable_test.cpp
@@ -230,8 +230,8 @@
     ShBuiltInResources resources;
     sh::InitBuiltInResources(&resources);
 
-    ShHandle compiler =
-        sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC, SH_GLSL_150_CORE_OUTPUT, &resources);
+    ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     EXPECT_NE(static_cast<ShHandle>(0), compiler);
 
     const char *program[] = {
@@ -253,8 +253,8 @@
     ShBuiltInResources resources;
     sh::InitBuiltInResources(&resources);
 
-    ShHandle compiler =
-        sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC, SH_GLSL_150_CORE_OUTPUT, &resources);
+    ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     EXPECT_NE(static_cast<ShHandle>(0), compiler);
 
     const char *program1[] = {
@@ -288,8 +288,8 @@
     ShBuiltInResources resources;
     sh::InitBuiltInResources(&resources);
 
-    ShHandle compiler =
-        sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC, SH_GLSL_150_CORE_OUTPUT, &resources);
+    ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     EXPECT_NE(static_cast<ShHandle>(0), compiler);
 
     const char *program1[] = {
@@ -330,8 +330,8 @@
     ShBuiltInResources resources;
     sh::InitBuiltInResources(&resources);
 
-    ShHandle compiler =
-        sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC, SH_GLSL_150_CORE_OUTPUT, &resources);
+    ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     EXPECT_NE(static_cast<ShHandle>(0), compiler);
 
     const char *program1[] = {
@@ -372,8 +372,8 @@
     ShBuiltInResources resources;
     sh::InitBuiltInResources(&resources);
 
-    ShHandle compiler =
-        sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC, SH_GLSL_150_CORE_OUTPUT, &resources);
+    ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     EXPECT_NE(static_cast<ShHandle>(0), compiler);
 
     const char *program1[] = {
@@ -466,8 +466,8 @@
     ShBuiltInResources resources;
     sh::InitBuiltInResources(&resources);
 
-    ShHandle compiler =
-        sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES3_SPEC, SH_GLSL_150_CORE_OUTPUT, &resources);
+    ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES3_SPEC,
+                                              SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
     EXPECT_NE(static_cast<ShHandle>(0), compiler);
 
     const char *front_underscores[] = {
--- src/tests/test_utils/compiler_test.h.orig
+++ src/tests/test_utils/compiler_test.h
@@ -61,7 +61,7 @@
 
     bool foundInGLSLCode(const char *stringToFind) const
     {
-        return foundInCode(SH_GLSL_150_CORE_OUTPUT, stringToFind);
+        return foundInCode(SH_GLSL_COMPATIBILITY_OUTPUT, stringToFind);
     }
 
     bool foundInCode(ShShaderOutput output, const char *stringToFind) const;
