Implement getPlatformDisplay with ANGLE support

Apps that care can request a specific ANGLE backend.
That would allow them to choose the native GL backend if
that was preferred (if available.)
Test: TODO

Bug: 80239516
Change-Id: I7bfdf7094749f15f8436c266d12c1191994e27ac
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 3a7979c..619297f 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -52,6 +52,21 @@
     return cnx->platform.eglGetDisplay(display);
 }
 
+EGLDisplay eglGetPlatformDisplay(EGLenum platform, EGLNativeDisplayType display,
+                                 const EGLAttrib* attrib_list) {
+    ATRACE_CALL();
+    clearError();
+
+    if (egl_init_drivers() == EGL_FALSE) {
+        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+    }
+
+    // Call down the chain, which usually points directly to the impl
+    // but may also be routed through layers
+    egl_connection_t* const cnx = &gEGLImpl;
+    return cnx->platform.eglGetPlatformDisplay(platform, display, attrib_list);
+}
+
 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
     clearError();
 
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 893cf0b..476b304 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -120,14 +120,15 @@
     return false;
 }
 
-EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
+EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp,
+                                               const EGLAttrib* attrib_list) {
     if (uintptr_t(disp) >= NUM_DISPLAYS)
         return nullptr;
 
-    return sDisplay[uintptr_t(disp)].getDisplay(disp);
+    return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
 }
 
-static void addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
+static bool addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
                                        std::vector<EGLAttrib>& attrs) {
     intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
 
@@ -154,24 +155,29 @@
         }
     }
 
-    cnx->angleBackend = angleBackendDefault;
-
     // Allow debug property to override application's
     char prop[PROPERTY_VALUE_MAX];
     property_get("debug.angle.backend", prop, "0");
     switch (atoi(prop)) {
         case 1:
             ALOGV("addAnglePlatformAttributes: Requesting OpenGLES back-end");
-            cnx->angleBackend = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
+            angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
             break;
         case 2:
             ALOGV("addAnglePlatformAttributes: Requesting Vulkan back-end");
-            cnx->angleBackend = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+            angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
             break;
         default:
             break;
     }
 
+    if (cnx->angleBackend == 0) {
+        // Haven't been initialized yet, so set it.
+        cnx->angleBackend = angleBackendDefault;
+    } else if (cnx->angleBackend != angleBackendDefault) {
+        return false;
+    }
+
     attrs.reserve(4 * 2);
 
     attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
@@ -199,6 +205,8 @@
     }
     attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
     attrs.push_back(EGL_FALSE);
+
+    return true;
 }
 
 // Initialize function ptrs for ANGLE PlatformMethods struct, used for systrace
@@ -238,24 +246,30 @@
     return true;
 }
 
-static EGLDisplay getDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx) {
+static EGLDisplay getPlatformDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx,
+                                          const EGLAttrib* attrib_list, EGLint* error) {
     EGLDisplay dpy = EGL_NO_DISPLAY;
+    *error = EGL_NONE;
 
-    // Locally define this until EGL 1.5 is supported
-    typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, void* native_display,
-                                                       const EGLAttrib* attrib_list);
-
-    PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplay =
-            reinterpret_cast<PFNEGLGETPLATFORMDISPLAYPROC>(
-                    cnx->egl.eglGetProcAddress("eglGetPlatformDisplay"));
-
-    if (eglGetPlatformDisplay) {
+    if (cnx->egl.eglGetPlatformDisplay) {
         std::vector<EGLAttrib> attrs;
-        addAnglePlatformAttributes(cnx, nullptr, attrs);
+        if (attrib_list) {
+            for (const EGLAttrib* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
+                attrs.push_back(attr[0]);
+                attrs.push_back(attr[1]);
+            }
+        }
+
+        if (!addAnglePlatformAttributes(cnx, attrib_list, attrs)) {
+            ALOGE("eglGetDisplay(%p) failed: Mismatch display request", display);
+            *error = EGL_BAD_PARAMETER;
+            return EGL_NO_DISPLAY;
+        }
         attrs.push_back(EGL_NONE);
 
-        dpy = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
-                                    reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY), attrs.data());
+        dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
+                                             reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY),
+                                             attrs.data());
         if (dpy == EGL_NO_DISPLAY) {
             ALOGE("eglGetPlatformDisplay failed!");
         } else {
@@ -271,8 +285,8 @@
     return dpy;
 }
 
-EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
-
+EGLDisplay egl_display_t::getPlatformDisplay(EGLNativeDisplayType display,
+                                             const EGLAttrib* attrib_list) {
     std::lock_guard<std::mutex> _l(lock);
     ATRACE_CALL();
 
@@ -284,10 +298,24 @@
         EGLDisplay dpy = EGL_NO_DISPLAY;
 
         if (cnx->useAngle) {
-            dpy = getDisplayAngle(display, cnx);
+            EGLint error;
+            dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error);
+            if (error != EGL_NONE) {
+                return setError(error, dpy);
+            }
         }
         if (dpy == EGL_NO_DISPLAY) {
-            dpy = cnx->egl.eglGetDisplay(display);
+            // NOTE: eglGetPlatformDisplay with a empty attribute list
+            // behaves the same as eglGetDisplay
+            if (cnx->egl.eglGetPlatformDisplay) {
+                dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANDROID_KHR, display,
+                                                     attrib_list);
+            } else {
+                if (attrib_list) {
+                    ALOGW("getPlatformDisplay: unexpected attribute list, attributes ignored");
+                }
+                dpy = cnx->egl.eglGetDisplay(display);
+            }
         }
 
         disp.dpy = dpy;
@@ -306,13 +334,20 @@
         std::unique_lock<std::mutex> _l(refLock);
         refs++;
         if (refs > 1) {
-            if (major != nullptr)
-                *major = VERSION_MAJOR;
-            if (minor != nullptr)
-                *minor = VERSION_MINOR;
+            // We don't know what to report until we know what the
+            // driver supports. Make sure we are initialized before
+            // returning the version info.
             while(!eglIsInitialized) {
                 refCond.wait(_l);
             }
+            egl_connection_t* const cnx = &gEGLImpl;
+
+            // TODO: If device doesn't provide 1.4 or 1.5 then we'll be
+            // changing the behavior from the past where we always advertise
+            // version 1.4. May need to check that revision is valid
+            // before using cnx->major & cnx->minor
+            if (major != nullptr) *major = cnx->major;
+            if (minor != nullptr) *minor = cnx->minor;
             return EGL_TRUE;
         }
         while(eglIsInitialized) {
@@ -465,10 +500,12 @@
             traceGpuCompletion = true;
         }
 
-        if (major != nullptr)
-            *major = VERSION_MAJOR;
-        if (minor != nullptr)
-            *minor = VERSION_MINOR;
+        // TODO: If device doesn't provide 1.4 or 1.5 then we'll be
+        // changing the behavior from the past where we always advertise
+        // version 1.4. May need to check that revision is valid
+        // before using cnx->major & cnx->minor
+        if (major != nullptr) *major = cnx->major;
+        if (minor != nullptr) *minor = cnx->minor;
     }
 
     { // scope for refLock
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index f764028..36856b7 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -49,6 +49,7 @@
 class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
     static egl_display_t sDisplay[NUM_DISPLAYS];
     EGLDisplay getDisplay(EGLNativeDisplayType display);
+    EGLDisplay getPlatformDisplay(EGLNativeDisplayType display, const EGLAttrib* attrib_list);
     void loseCurrentImpl(egl_context_t * cur_c);
 
 public:
@@ -72,7 +73,7 @@
     bool getObject(egl_object_t* object) const;
 
     static egl_display_t* get(EGLDisplay dpy);
-    static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
+    static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp, const EGLAttrib* attrib_list);
 
     EGLBoolean makeCurrent(egl_context_t* c, egl_context_t* cur_c,
             EGLSurface draw, EGLSurface read, EGLContext ctx,
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 35c2ecb..177c154 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -47,6 +47,7 @@
 /* EGL 1.5 */
 EGL_ENTRY(EGLImage, eglCreateImage, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLAttrib *)
 EGL_ENTRY(EGLBoolean, eglDestroyImage, EGLDisplay, EGLImage)
+EGL_ENTRY(EGLDisplay, eglGetPlatformDisplay, EGLenum, void *, const EGLAttrib *)
 
 /* EGL_EGLEXT_VERSION 3 */
 
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 6ef0082..e6aa24d 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -135,6 +135,11 @@
         "EGL_IMG_context_priority "
         "EGL_KHR_no_config_context "
         ;
+
+char const * const gClientExtensionString =
+        "EGL_EXT_client_extensions "
+        "EGL_KHR_platform_android "
+        "EGL_ANGLE_platform_angle";
 // clang-format on
 
 // extensions not exposed to applications but used by the ANDROID system
@@ -279,17 +284,31 @@
 
 // ----------------------------------------------------------------------------
 
-EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display)
-{
+static EGLDisplay eglGetPlatformDisplayTmpl(EGLenum platform, EGLNativeDisplayType display,
+                                            const EGLAttrib* attrib_list) {
+    if (platform != EGL_PLATFORM_ANDROID_KHR) {
+        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+    }
+
     uintptr_t index = reinterpret_cast<uintptr_t>(display);
     if (index >= NUM_DISPLAYS) {
         return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
     }
 
-    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
+    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display, attrib_list);
     return dpy;
 }
 
+EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display) {
+    return eglGetPlatformDisplayTmpl(EGL_PLATFORM_ANDROID_KHR, display, nullptr);
+}
+
+EGLDisplay eglGetPlatformDisplayImpl(EGLenum platform, void* native_display,
+                                     const EGLAttrib* attrib_list) {
+    return eglGetPlatformDisplayTmpl(platform, static_cast<EGLNativeDisplayType>(native_display),
+                                     attrib_list);
+}
+
 // ----------------------------------------------------------------------------
 // Initialization
 // ----------------------------------------------------------------------------
@@ -1402,15 +1421,10 @@
 
 const char* eglQueryStringImpl(EGLDisplay dpy, EGLint name)
 {
-    // Generate an error quietly when client extensions (as defined by
-    // EGL_EXT_client_extensions) are queried.  We do not want to rely on
-    // validate_display to generate the error as validate_display would log
-    // the error, which can be misleading.
-    //
-    // If we want to support EGL_EXT_client_extensions later, we can return
-    // the client extension string here instead.
-    if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
-        return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)nullptr);
+    if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) {
+        // Return list of client extensions
+        return gClientExtensionString;
+    }
 
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) return (const char *) nullptr;
@@ -2434,6 +2448,7 @@
 static const implementation_map_t sPlatformImplMap[] = {
         // clang-format off
     { "eglGetDisplay", (EGLFuncPointer)&eglGetDisplayImpl },
+    { "eglGetPlatformDisplay", (EGLFuncPointer)&eglGetPlatformDisplayImpl },
     { "eglInitialize", (EGLFuncPointer)&eglInitializeImpl },
     { "eglTerminate", (EGLFuncPointer)&eglTerminateImpl },
     { "eglGetConfigs", (EGLFuncPointer)&eglGetConfigsImpl },
diff --git a/opengl/libs/platform_entries.in b/opengl/libs/platform_entries.in
index 6f087fd..95fa32d 100644
--- a/opengl/libs/platform_entries.in
+++ b/opengl/libs/platform_entries.in
@@ -1,4 +1,5 @@
 EGL_ENTRY(EGLDisplay, eglGetDisplay, EGLNativeDisplayType)
+EGL_ENTRY(EGLDisplay, eglGetPlatformDisplay, EGLenum, EGLNativeDisplayType, const EGLAttrib*)
 EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
 EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
 EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)