[RenderEngine] Make use of EGL_KHR_surfaceless_context.

Per
https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_surfaceless_context.txt,
when EGL_KHR_surfaceless_context is present, we can make the context current
without specifying draw and read surface, thus we no longer need to create a
1x1 buffer surface.

BUG: 35315015
Test: Build, flash, boot.
Change-Id: Ia5f19cf0f9561bb660708b5a2ae0187593422210
diff --git a/libs/renderengine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLES20RenderEngine.cpp
index d35762d..b10b52b 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.cpp
+++ b/libs/renderengine/gl/GLES20RenderEngine.cpp
@@ -240,60 +240,29 @@
         config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
 
-    EGLint renderableType = 0;
-    if (config == EGL_NO_CONFIG) {
-        renderableType = EGL_OPENGL_ES2_BIT;
-    } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
-        LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
-    }
-    EGLint contextClientVersion = 0;
-    if (renderableType & EGL_OPENGL_ES2_BIT) {
-        contextClientVersion = 2;
-    } else if (renderableType & EGL_OPENGL_ES_BIT) {
-        contextClientVersion = 1;
-    } else {
-        LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
-    }
-
-    std::vector<EGLint> contextAttributes;
-    contextAttributes.reserve(6);
-    contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
-    contextAttributes.push_back(contextClientVersion);
     bool useContextPriority = extensions.hasContextPriority() &&
             (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
-    if (useContextPriority) {
-        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
-        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
-    }
-    contextAttributes.push_back(EGL_NONE);
-
-    EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
+    EGLContext ctxt = createEglContext(display, config, EGL_NO_CONTEXT, useContextPriority);
 
     // if can't create a GL context, we can only abort.
     LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
 
-    // now figure out what version of GL did we actually get
-    // NOTE: a dummy surface is not needed if KHR_create_context is supported
-    // TODO(alecmouri): don't create this surface if EGL_KHR_surfaceless_context
-    // is supported.
-
-    EGLConfig dummyConfig = config;
-    if (dummyConfig == EGL_NO_CONFIG) {
-        dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+    EGLSurface dummy = EGL_NO_SURFACE;
+    if (!extensions.hasSurfacelessContext()) {
+        dummy = createDummyEglPbufferSurface(display, config, hwcFormat);
+        LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
     }
-    EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
-    EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
-    LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
+
     EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
     LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
 
     extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
                                  glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
 
+    // now figure out what version of GL did we actually get
     GlesVersion version = parseGlesVersion(extensions.getVersion());
 
     // initialize the renderer while GL is current
-
     std::unique_ptr<GLES20RenderEngine> engine;
     switch (version) {
         case GLES_VERSION_1_0:
@@ -908,6 +877,53 @@
     return GLES_VERSION_1_0;
 }
 
+EGLContext GLES20RenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
+                                                EGLContext shareContext, bool useContextPriority) {
+    EGLint renderableType = 0;
+    if (config == EGL_NO_CONFIG) {
+        renderableType = EGL_OPENGL_ES2_BIT;
+    } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
+        LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
+    }
+    EGLint contextClientVersion = 0;
+    if (renderableType & EGL_OPENGL_ES2_BIT) {
+        contextClientVersion = 2;
+    } else if (renderableType & EGL_OPENGL_ES_BIT) {
+        contextClientVersion = 1;
+    } else {
+        LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
+    }
+
+    std::vector<EGLint> contextAttributes;
+    contextAttributes.reserve(5);
+    contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+    contextAttributes.push_back(contextClientVersion);
+    if (useContextPriority) {
+        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
+        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+    }
+    contextAttributes.push_back(EGL_NONE);
+
+    return eglCreateContext(display, config, shareContext, contextAttributes.data());
+}
+
+EGLSurface GLES20RenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
+                                                            int hwcFormat) {
+    EGLConfig dummyConfig = config;
+    if (dummyConfig == EGL_NO_CONFIG) {
+        dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+    }
+    std::vector<EGLint> attributes;
+    attributes.reserve(5);
+    attributes.push_back(EGL_WIDTH);
+    attributes.push_back(1);
+    attributes.push_back(EGL_HEIGHT);
+    attributes.push_back(1);
+    attributes.push_back(EGL_NONE);
+
+    return eglCreatePbufferSurface(display, dummyConfig, attributes.data());
+}
+
 bool GLES20RenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
     const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
     const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
diff --git a/libs/renderengine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLES20RenderEngine.h
index 6c50938..77dba62 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.h
+++ b/libs/renderengine/gl/GLES20RenderEngine.h
@@ -112,6 +112,10 @@
     };
 
     static GlesVersion parseGlesVersion(const char* str);
+    static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
+                                       EGLContext shareContext, bool useContextPriority);
+    static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
+                                                   int hwcFormat);
 
     // A data space is considered HDR data space if it has BT2020 color space
     // with PQ or HLG transfer function.
diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp
index 784693b..ce83dd5 100644
--- a/libs/renderengine/gl/GLExtensions.cpp
+++ b/libs/renderengine/gl/GLExtensions.cpp
@@ -112,6 +112,9 @@
     if (extensionSet.hasExtension("EGL_IMG_context_priority")) {
         mHasContextPriority = true;
     }
+    if (extensionSet.hasExtension("EGL_KHR_surfaceless_context")) {
+        mHasSurfacelessContext = true;
+    }
 }
 
 char const* GLExtensions::getEGLVersion() const {
diff --git a/libs/renderengine/gl/GLExtensions.h b/libs/renderengine/gl/GLExtensions.h
index 382c23a..2a654d5 100644
--- a/libs/renderengine/gl/GLExtensions.h
+++ b/libs/renderengine/gl/GLExtensions.h
@@ -32,29 +32,6 @@
 namespace gl {
 
 class GLExtensions : public Singleton<GLExtensions> {
-    friend class Singleton<GLExtensions>;
-
-    bool mHasNoConfigContext = false;
-    bool mHasNativeFenceSync = false;
-    bool mHasFenceSync = false;
-    bool mHasWaitSync = false;
-    bool mHasProtectedContent = false;
-    bool mHasContextPriority = false;
-
-    String8 mVendor;
-    String8 mRenderer;
-    String8 mVersion;
-    String8 mExtensions;
-
-    String8 mEGLVersion;
-    String8 mEGLExtensions;
-
-    GLExtensions(const GLExtensions&);
-    GLExtensions& operator=(const GLExtensions&);
-
-protected:
-    GLExtensions() = default;
-
 public:
     bool hasNoConfigContext() const { return mHasNoConfigContext; }
     bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
@@ -62,6 +39,7 @@
     bool hasWaitSync() const { return mHasWaitSync; }
     bool hasProtectedContent() const { return mHasProtectedContent; }
     bool hasContextPriority() const { return mHasContextPriority; }
+    bool hasSurfacelessContext() const { return mHasSurfacelessContext; }
 
     void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
                            GLubyte const* extensions);
@@ -73,6 +51,31 @@
     void initWithEGLStrings(char const* eglVersion, char const* eglExtensions);
     char const* getEGLVersion() const;
     char const* getEGLExtensions() const;
+
+protected:
+    GLExtensions() = default;
+
+private:
+    friend class Singleton<GLExtensions>;
+
+    bool mHasNoConfigContext = false;
+    bool mHasNativeFenceSync = false;
+    bool mHasFenceSync = false;
+    bool mHasWaitSync = false;
+    bool mHasProtectedContent = false;
+    bool mHasContextPriority = false;
+    bool mHasSurfacelessContext = false;
+
+    String8 mVendor;
+    String8 mRenderer;
+    String8 mVersion;
+    String8 mExtensions;
+
+    String8 mEGLVersion;
+    String8 mEGLExtensions;
+
+    GLExtensions(const GLExtensions&);
+    GLExtensions& operator=(const GLExtensions&);
 };
 
 } // namespace gl