EGL: Fix binding EGL_NO_SURFACE without surfaceless support.

It was possible for ANGLE to call eglMakeCurrent with EGL_NO_SURFACE and
a valid context when the client called eglMakeCurrent with
EGL_NO_SURFACE and EGL_NO_CONTEXT.  Fix this by always binding a surface
when the driver has no native surfaceless support.

Don't expose the surfaceless extension when it's not possible to support
it (unvirtualized contexts and no native surfaceless support).

BUG=860800
BUG=angleproject:2464

Change-Id: Id8af9638d4356dbd710c453c9f196b9f25a2bbf9
Reviewed-on: https://chromium-review.googlesource.com/1131555
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
index 1fc32fe..e33728d 100644
--- a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
+++ b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
@@ -109,9 +109,6 @@
     // Contexts are virtualized so textures can be shared globally
     outExtensions->displayTextureShareGroup = true;
 
-    // Surfaceless contexts are emulated even if there is no native support.
-    outExtensions->surfacelessContext = true;
-
     // We will fallback to regular swap if swapBuffersWithDamage isn't
     // supported, so indicate support here to keep validation happy.
     outExtensions->swapBuffersWithDamage = true;
diff --git a/src/libANGLE/renderer/gl/egl/DisplayEGL.h b/src/libANGLE/renderer/gl/egl/DisplayEGL.h
index 7533fc5..af64961 100644
--- a/src/libANGLE/renderer/gl/egl/DisplayEGL.h
+++ b/src/libANGLE/renderer/gl/egl/DisplayEGL.h
@@ -30,11 +30,12 @@
                                  const egl::AttributeMap &eglAttributes,
                                  EGLContext *outContext) const;
 
+    void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
+
     FunctionsEGL *mEGL;
     EGLConfig mConfig;
 
   private:
-    void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
     void generateCaps(egl::Caps *outCaps) const override;
 };
 
diff --git a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
index 64ce9f3..b188ba8 100644
--- a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
+++ b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
@@ -42,6 +42,7 @@
 DisplayAndroid::DisplayAndroid(const egl::DisplayState &state)
     : DisplayEGL(state),
       mVirtualizedContexts(kDefaultEGLVirtualizedContexts),
+      mSupportsSurfaceless(false),
       mDummyPbuffer(EGL_NO_SURFACE)
 {
 }
@@ -126,7 +127,8 @@
     }
 
     // A dummy pbuffer is only needed if surfaceless contexts are not supported.
-    if (!mEGL->hasExtension("EGL_KHR_surfaceless_context"))
+    mSupportsSurfaceless = mEGL->hasExtension("EGL_KHR_surfaceless_context");
+    if (!mSupportsSurfaceless)
     {
         int dummyPbufferAttribs[] = {
             EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE,
@@ -499,6 +501,22 @@
                newContext == currentContext.context);
 
         newContext = mRenderer->getContext();
+
+        // If we know that we're only running on one thread (mVirtualizedContexts == true) and
+        // EGL_NO_SURFACE is going to be bound, we can optimize this case by not changing the
+        // surface binding and emulate the surfaceless extension in the frontend.
+        if (newSurface == EGL_NO_SURFACE)
+        {
+            newSurface = currentContext.surface;
+        }
+
+        // It's possible that no surface has been created yet and the driver doesn't support
+        // surfaceless, bind the dummy pbuffer.
+        if (newSurface == EGL_NO_SURFACE && !mSupportsSurfaceless)
+        {
+            newSurface = mDummyPbuffer;
+            ASSERT(newSurface != EGL_NO_SURFACE);
+        }
     }
 
     if (newSurface != currentContext.surface || newContext != currentContext.context)
@@ -535,6 +553,15 @@
     }
 }
 
+void DisplayAndroid::generateExtensions(egl::DisplayExtensions *outExtensions) const
+{
+    // Surfaceless can be support if the native driver supports it or we know that we are running on
+    // a single thread (mVirtualizedContexts == true)
+    outExtensions->surfacelessContext = mSupportsSurfaceless || mVirtualizedContexts;
+
+    DisplayEGL::generateExtensions(outExtensions);
+}
+
 egl::Error DisplayAndroid::makeCurrentSurfaceless(gl::Context *context)
 {
     // Nothing to do because EGL always uses the same context and the previous surface can be left
diff --git a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
index 604cad4..fc99a34 100644
--- a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
+++ b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
@@ -73,6 +73,8 @@
     void destroyNativeContext(EGLContext context) override;
 
   private:
+    void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
+
     egl::Error createRenderer(EGLContext shareContext,
                               bool makeNewContextCurrent,
                               std::shared_ptr<RendererEGL> *outRenderer);
@@ -94,6 +96,8 @@
 
     egl::AttributeMap mDisplayAttributes;
 
+    bool mSupportsSurfaceless;
+
     std::vector<EGLint> mConfigAttribList;
     std::map<EGLint, EGLint> mConfigIds;
     EGLSurface mDummyPbuffer;
diff --git a/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp b/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp
index 0c59700..51f5426 100644
--- a/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp
+++ b/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.cpp
@@ -1009,6 +1009,14 @@
     ASSERT(data != nullptr);
 }
 
+void DisplayOzone::generateExtensions(egl::DisplayExtensions *outExtensions) const
+{
+    // Surfaceless contexts are emulated even if there is no native support.
+    outExtensions->surfacelessContext = true;
+
+    DisplayEGL::generateExtensions(outExtensions);
+}
+
 egl::Error DisplayOzone::makeCurrentSurfaceless(gl::Context *context)
 {
     // Nothing to do, handled in the GL layers
diff --git a/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h b/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h
index 0200503..b71c990 100644
--- a/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h
+++ b/src/libANGLE/renderer/gl/egl/ozone/DisplayOzone.h
@@ -156,6 +156,8 @@
     void setSwapInterval(EGLSurface drawable, SwapControlData *data);
 
   private:
+    void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
+
     egl::Error makeCurrentSurfaceless(gl::Context *context) override;
 
     GLuint makeShader(GLuint type, const char *src);