Add an EGL extension to disable GL extensions by default.

BUG=angleproject:2404

Change-Id: I2667ddc92d5c9ef6e0ef115f2fdf0c3d3643d945
Reviewed-on: https://chromium-review.googlesource.com/962702
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index 7fa6bf6..1bf0b35 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -1173,7 +1173,8 @@
       createContextClientArrays(false),
       programCacheControl(false),
       robustResourceInitialization(false),
-      iosurfaceClientBuffer(false)
+      iosurfaceClientBuffer(false),
+      createContextExtensionsEnabled(false)
 {
 }
 
@@ -1219,6 +1220,7 @@
     InsertExtensionString("EGL_ANGLE_program_cache_control",                     programCacheControl,                &extensionStrings);
     InsertExtensionString("EGL_ANGLE_robust_resource_initialization",            robustResourceInitialization,       &extensionStrings);
     InsertExtensionString("EGL_ANGLE_iosurface_client_buffer",                   iosurfaceClientBuffer,              &extensionStrings);
+    InsertExtensionString("EGL_ANGLE_create_context_extensions_enabled",         createContextExtensionsEnabled,     &extensionStrings);
     // TODO(jmadill): Enable this when complete.
     //InsertExtensionString("KHR_create_context_no_error",                       createContextNoError,               &extensionStrings);
     // clang-format on
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index e8f0a93..9e61953 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -725,6 +725,9 @@
 
     // EGL_ANGLE_iosurface_client_buffer
     bool iosurfaceClientBuffer;
+
+    // EGL_ANGLE_create_context_extensions_enabled
+    bool createContextExtensionsEnabled;
 };
 
 struct DeviceExtensions
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 01e58f6..15a2a79 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -201,6 +201,13 @@
     return (attribs.get(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE, EGL_FALSE) == EGL_TRUE);
 }
 
+bool GetExtensionsEnabled(const egl::AttributeMap &attribs, bool webGLContext)
+{
+    // If the context is WebGL, extensions are disabled by default
+    EGLAttrib defaultValue = webGLContext ? EGL_FALSE : EGL_TRUE;
+    return (attribs.get(EGL_EXTENSIONS_ENABLED_ANGLE, defaultValue) == EGL_TRUE);
+}
+
 bool GetBindGeneratesResource(const egl::AttributeMap &attribs)
 {
     return (attribs.get(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE) == EGL_TRUE);
@@ -290,6 +297,7 @@
       mCurrentDisplay(static_cast<egl::Display *>(EGL_NO_DISPLAY)),
       mSurfacelessFramebuffer(nullptr),
       mWebGLContext(GetWebGLContext(attribs)),
+      mExtensionsEnabled(GetExtensionsEnabled(attribs, mWebGLContext)),
       mMemoryProgramCache(memoryProgramCache),
       mScratchBuffer(1000u),
       mZeroFilledBuffer(1000u)
@@ -2774,8 +2782,9 @@
     mExtensions.webglCompatibility = mWebGLContext;
     for (const auto &extensionInfo : GetExtensionInfoMap())
     {
-        // If this context is for WebGL, disable all enableable extensions
-        if (mWebGLContext && extensionInfo.second.Requestable)
+        // If the user has requested that extensions start disabled and they are requestable,
+        // disable them.
+        if (!mExtensionsEnabled && extensionInfo.second.Requestable)
         {
             mExtensions.*(extensionInfo.second.ExtensionsMember) = false;
         }
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index 6a0ff2e..6f9ead7 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -1306,6 +1306,7 @@
     egl::Display *mCurrentDisplay;
     Framebuffer *mSurfacelessFramebuffer;
     bool mWebGLContext;
+    bool mExtensionsEnabled;
     MemoryProgramCache *mMemoryProgramCache;
 
     State::DirtyBits mTexImageDirtyBits;
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index 5c0f4f1..7feca74 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -1049,6 +1049,9 @@
     // Enable program cache control since it is not back-end dependent.
     mDisplayExtensions.programCacheControl = true;
 
+    // Request extension is implemented in the ANGLE frontend
+    mDisplayExtensions.createContextExtensionsEnabled = true;
+
     mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
 }
 
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index 283e53d..cf024b8 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -738,6 +738,20 @@
               }
               break;
 
+          case EGL_EXTENSIONS_ENABLED_ANGLE:
+              if (!display->getExtensions().createContextExtensionsEnabled)
+              {
+                  return EglBadAttribute()
+                         << "Attribute EGL_EXTENSIONS_ENABLED_ANGLE "
+                            "requires EGL_ANGLE_create_context_extensions_enabled.";
+              }
+              if (value != EGL_TRUE && value != EGL_FALSE)
+              {
+                  return EglBadAttribute() << "EGL_EXTENSIONS_ENABLED_ANGLE must be "
+                                              "either EGL_TRUE or EGL_FALSE.";
+              }
+              break;
+
           default:
               return EglBadAttribute() << "Unknown attribute.";
         }
diff --git a/src/tests/angle_end2end_tests.gypi b/src/tests/angle_end2end_tests.gypi
index 199a429..62a3b66 100644
--- a/src/tests/angle_end2end_tests.gypi
+++ b/src/tests/angle_end2end_tests.gypi
@@ -75,6 +75,7 @@
             '<(angle_path)/src/tests/gl_tests/ReadPixelsTest.cpp',
             '<(angle_path)/src/tests/gl_tests/RenderbufferMultisampleTest.cpp',
             '<(angle_path)/src/tests/gl_tests/RendererTest.cpp',
+            '<(angle_path)/src/tests/gl_tests/RequestExtensionTest.cpp',
             '<(angle_path)/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp',
             '<(angle_path)/src/tests/gl_tests/RobustClientMemoryTest.cpp',
             '<(angle_path)/src/tests/gl_tests/RobustResourceInitTest.cpp',
diff --git a/src/tests/gl_tests/RequestExtensionTest.cpp b/src/tests/gl_tests/RequestExtensionTest.cpp
new file mode 100644
index 0000000..6fa20fb
--- /dev/null
+++ b/src/tests/gl_tests/RequestExtensionTest.cpp
@@ -0,0 +1,45 @@
+//
+// Copyright 2018 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.
+//
+// RequestExtensionTest:
+//   Tests that extensions can be requested and are disabled by default when using
+//   EGL_ANGLE_request_extension
+//
+
+#include "test_utils/ANGLETest.h"
+
+namespace angle
+{
+
+class RequestExtensionTest : public ANGLETest
+{
+  protected:
+    RequestExtensionTest() { setExtensionsEnabled(false); }
+};
+
+// Test that a known requestable extension is disabled by default and make sure it can be requested
+// if possible
+TEST_P(RequestExtensionTest, ExtensionsDisabledByDefault)
+{
+    EXPECT_TRUE(eglDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
+                                           "EGL_ANGLE_create_context_extensions_enabled"));
+    EXPECT_FALSE(extensionEnabled("GL_OES_rgb8_rgba8"));
+
+    if (extensionRequestable("GL_OES_rgb8_rgba8"))
+    {
+        glRequestExtensionANGLE("GL_OES_rgb8_rgba8");
+        EXPECT_TRUE(extensionEnabled("GL_OES_rgb8_rgba8"));
+    }
+}
+
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these
+// tests should be run against.
+ANGLE_INSTANTIATE_TEST(RequestExtensionTest,
+                       ES2_D3D11(),
+                       ES2_OPENGL(),
+                       ES2_OPENGLES(),
+                       ES2_VULKAN());
+
+}  // namespace angle
diff --git a/src/tests/test_utils/ANGLETest.cpp b/src/tests/test_utils/ANGLETest.cpp
index 6a64882..3e87c4b 100644
--- a/src/tests/test_utils/ANGLETest.cpp
+++ b/src/tests/test_utils/ANGLETest.cpp
@@ -847,6 +847,11 @@
     mEGLWindow->setWebGLCompatibilityEnabled(webglCompatibility);
 }
 
+void ANGLETestBase::setExtensionsEnabled(bool extensionsEnabled)
+{
+    mEGLWindow->setExtensionsEnabled(extensionsEnabled);
+}
+
 void ANGLETestBase::setRobustAccess(bool enabled)
 {
     mEGLWindow->setRobustAccess(enabled);
diff --git a/src/tests/test_utils/ANGLETest.h b/src/tests/test_utils/ANGLETest.h
index 9e6d308..82b85fc 100644
--- a/src/tests/test_utils/ANGLETest.h
+++ b/src/tests/test_utils/ANGLETest.h
@@ -319,6 +319,7 @@
     void setDebugEnabled(bool enabled);
     void setNoErrorEnabled(bool enabled);
     void setWebGLCompatibilityEnabled(bool webglCompatibility);
+    void setExtensionsEnabled(bool extensionsEnabled);
     void setRobustAccess(bool enabled);
     void setBindGeneratesResource(bool bindGeneratesResource);
     void setDebugLayersEnabled(bool enabled);