Add option to support EXT_draw_buffers with NV_draw_buffers

After this patch, it is possible to set a flag to change
EXT_draw_buffers extension directives to NV_draw_buffers in ESSL.
This enables users of ANGLE to emulate EXT_draw_buffers by using
NV_draw_buffers in combination with GLES3.0.

Change-Id: I5dacdbd6cd0d0362424ea3791557342c42efd4bd
Reviewed-on: https://chromium-review.googlesource.com/219941
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Tested-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
index b7989f5..10a89dc 100644
--- a/include/GLSLANG/ShaderLang.h
+++ b/include/GLSLANG/ShaderLang.h
@@ -246,6 +246,12 @@
     int EXT_frag_depth;
     int EXT_shader_texture_lod;
 
+    // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
+    // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
+    // EXT_draw_buffers by using it in combination with GLES3.0 glDrawBuffers
+    // function. This applies to Tegra K1 devices.
+    int NV_draw_buffers;
+
     // Set to 1 if highp precision is supported in the fragment language.
     // Default is 0.
     int FragmentPrecisionHigh;
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 368cd2a..8e1743d 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -360,7 +360,8 @@
               << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
               << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
               << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
-              << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset;
+              << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
+              << ":NV_draw_buffers:" << compileResources.NV_draw_buffers;
 
     builtInResourcesString = strstream.str();
 }
diff --git a/src/compiler/translator/ShaderLang.cpp b/src/compiler/translator/ShaderLang.cpp
index 20ce716..e0ed5f5 100644
--- a/src/compiler/translator/ShaderLang.cpp
+++ b/src/compiler/translator/ShaderLang.cpp
@@ -201,6 +201,8 @@
     resources->EXT_frag_depth = 0;
     resources->EXT_shader_texture_lod = 0;
 
+    resources->NV_draw_buffers = 0;
+
     // Disable highp precision in fragment shader by default.
     resources->FragmentPrecisionHigh = 0;
 
diff --git a/src/compiler/translator/TranslatorESSL.cpp b/src/compiler/translator/TranslatorESSL.cpp
index 5b99fea..df6266b 100644
--- a/src/compiler/translator/TranslatorESSL.cpp
+++ b/src/compiler/translator/TranslatorESSL.cpp
@@ -37,8 +37,13 @@
     for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
          iter != extensionBehavior.end(); ++iter) {
         if (iter->second != EBhUndefined) {
-            sink << "#extension " << iter->first << " : "
-                 << getBehaviorString(iter->second) << "\n";
+            if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") {
+                sink << "#extension GL_NV_draw_buffers : "
+                     << getBehaviorString(iter->second) << "\n";
+            } else {
+                sink << "#extension " << iter->first << " : "
+                     << getBehaviorString(iter->second) << "\n";
+            }
         }
     }
 }
diff --git a/tests/compiler_tests/NV_draw_buffers_test.cpp b/tests/compiler_tests/NV_draw_buffers_test.cpp
new file mode 100644
index 0000000..68ef5ea
--- /dev/null
+++ b/tests/compiler_tests/NV_draw_buffers_test.cpp
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2014 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.
+//
+// NV_draw_buffers_test.cpp:
+//   Test for NV_draw_buffers setting
+//
+
+#include "angle_gl.h"
+#include "gtest/gtest.h"
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/translator/TranslatorESSL.h"
+
+class NVDrawBuffersTest : public testing::Test
+{
+  public:
+    NVDrawBuffersTest() {}
+
+  protected:
+    virtual void SetUp()
+    {
+        ShBuiltInResources resources;
+        ShInitBuiltInResources(&resources);
+        resources.MaxDrawBuffers = 8;
+        resources.EXT_draw_buffers = 1;
+        resources.NV_draw_buffers = 1;
+
+        mTranslator = new TranslatorESSL(GL_FRAGMENT_SHADER, SH_GLES2_SPEC);
+        ASSERT_TRUE(mTranslator->Init(resources));
+    }
+
+    virtual void TearDown()
+    {
+        delete mTranslator;
+    }
+
+    TranslatorESSL *mTranslator;
+};
+
+TEST_F(NVDrawBuffersTest, NVDrawBuffers)
+{
+    const std::string &shaderString =
+        "#extension GL_EXT_draw_buffers : require\n"
+        "precision mediump float;\n"
+        "void main() {\n"
+        "   gl_FragData[0] = vec4(1.0);\n"
+        "   gl_FragData[1] = vec4(0.0);\n"
+        "}\n";
+
+    const char *shaderStrings[] = { shaderString.c_str() };
+    ASSERT_TRUE(mTranslator->compile(shaderStrings, 1, SH_OBJECT_CODE));
+
+    TInfoSink& infoSink = mTranslator->getInfoSink();
+    std::string objCode(infoSink.obj.c_str());
+    size_t nv_draw_buffers_ind = objCode.find("GL_NV_draw_buffers");
+    EXPECT_NE(std::string::npos, nv_draw_buffers_ind);
+    size_t ext_draw_buffers_ind = objCode.find("GL_EXT_draw_buffers");
+    EXPECT_EQ(std::string::npos, ext_draw_buffers_ind);
+};