Add ANGLE support to getDisplay

If ANGLE is enabled for this application construct the necessary
attributes to configure ANGLE and call ANGLE's eglGetPlatformDisplay
to initialize.

Test: manual - enable ANGLE for app and verify
Bug: 80239516
Change-Id: I9bbd40c660cd3bed72989fb4529e50eb608d71ea
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index c361ab0..1ed9850 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -25,6 +25,7 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
+#include <EGL/eglext_angle.h>
 
 #include <android/hardware_buffer.h>
 #include <private/android/AHardwareBufferHelpers.h>
@@ -711,12 +712,16 @@
             return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
         }
 
-        int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
-        if (result < 0) {
-            ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
-                    "failed (%#x) (already connected to another API?)",
-                    window, result);
-            return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+        // NOTE: When using Vulkan backend, the Vulkan runtime makes all the
+        // native_window_* calls, so don't do them here.
+        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+            int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+            if (result < 0) {
+                ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
+                      "failed (%#x) (already connected to another API?)",
+                      window, result);
+                return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            }
         }
 
         EGLDisplay iDpy = dp->disp.dpy;
@@ -733,7 +738,7 @@
         }
         attrib_list = strippedAttribList.data();
 
-        {
+        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
             int err = native_window_set_buffers_format(window, format);
             if (err != 0) {
                 ALOGE("error setting native window pixel format: %s (%d)",
@@ -741,16 +746,16 @@
                 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
                 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
             }
-        }
 
-        android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
-        if (dataSpace != HAL_DATASPACE_UNKNOWN) {
-            int err = native_window_set_buffers_data_space(window, dataSpace);
-            if (err != 0) {
-                ALOGE("error setting native window pixel dataSpace: %s (%d)",
-                      strerror(-err), err);
-                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+            android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
+            if (dataSpace != HAL_DATASPACE_UNKNOWN) {
+                err = native_window_set_buffers_data_space(window, dataSpace);
+                if (err != 0) {
+                    ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err),
+                          err);
+                    native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+                    return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+                }
             }
         }
 
@@ -769,8 +774,10 @@
         }
 
         // EGLSurface creation failed
-        native_window_set_buffers_format(window, 0);
-        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+        if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+            native_window_set_buffers_format(window, 0);
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+        }
     }
     return EGL_NO_SURFACE;
 }
@@ -1362,9 +1369,11 @@
         }
     }
 
-    if (!sendSurfaceMetadata(s)) {
-        native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
-        return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
+    if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+        if (!sendSurfaceMetadata(s)) {
+            native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
+            return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
+        }
     }
 
     if (n_rects == 0) {
@@ -1385,7 +1394,10 @@
         androidRect.bottom = y;
         androidRects.push_back(androidRect);
     }
-    native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), androidRects.size());
+    if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+        native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(),
+                                         androidRects.size());
+    }
 
     if (s->cnx->egl.eglSwapBuffersWithDamageKHR) {
         return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface,
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 10a097a..d1635b7 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -122,7 +122,81 @@
     return sDisplay[uintptr_t(disp)].getDisplay(disp);
 }
 
-EGLDisplay getDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx) {
+static void addAnglePlatformAttributes(egl_connection_t* const cnx, const EGLAttrib* attrib_list,
+                                       std::vector<EGLAttrib>& attrs) {
+    intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
+
+    EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+    if (attrib_list) {
+        while (*attrib_list != EGL_NONE) {
+            EGLAttrib attr = *attrib_list++;
+            EGLAttrib value = *attrib_list++;
+            if (attr == EGL_PLATFORM_ANGLE_TYPE_ANGLE) {
+                switch (value) {
+                    case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
+                        angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+                        break;
+                    case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
+                    case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
+                        angleBackendDefault = value;
+                        break;
+                    default:
+                        ALOGW("Invalid EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute: 0x%" PRIxPTR,
+                              value);
+                        break;
+                }
+            }
+        }
+    }
+
+    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;
+            break;
+        case 2:
+            ALOGV("addAnglePlatformAttributes: Requesting Vulkan back-end");
+            cnx->angleBackend = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
+            break;
+        default:
+            break;
+    }
+
+    attrs.reserve(4 * 2);
+
+    attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
+    attrs.push_back(cnx->angleBackend);
+
+    switch (cnx->angleBackend) {
+        case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
+            ALOGV("%s: Requesting Vulkan ANGLE back-end", __FUNCTION__);
+            property_get("debug.angle.validation", prop, "0");
+            attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
+            attrs.push_back(atoi(prop));
+            break;
+        case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
+            ALOGV("%s: Requesting Default ANGLE back-end", __FUNCTION__);
+            break;
+        case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
+            ALOGV("%s: Requesting OpenGL ES ANGLE back-end", __FUNCTION__);
+            // NOTE: This is only valid if the backend is OpenGL
+            attrs.push_back(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE);
+            attrs.push_back(vendorEGL);
+            break;
+        default:
+            ALOGV("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
+            break;
+    }
+    attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
+    attrs.push_back(EGL_FALSE);
+}
+
+static EGLDisplay getDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx) {
     EGLDisplay dpy = EGL_NO_DISPLAY;
 
     // Locally define this until EGL 1.5 is supported
@@ -134,18 +208,15 @@
                     cnx->egl.eglGetProcAddress("eglGetPlatformDisplay"));
 
     if (eglGetPlatformDisplay) {
-        intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
+        std::vector<EGLAttrib> attrs;
+        addAnglePlatformAttributes(cnx, nullptr, attrs);
+        attrs.push_back(EGL_NONE);
 
-        EGLAttrib attrs[] = {
-                EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE,
-                EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, vendorEGL,
-                EGL_NONE // list terminator
-        };
-
-        // Initially, request the default display type
         dpy = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
-                                    reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY), attrs);
-
+                                    reinterpret_cast<void*>(EGL_DEFAULT_DISPLAY), attrs.data());
+        if (dpy == EGL_NO_DISPLAY) {
+            ALOGE("eglGetPlatformDisplay failed!");
+        }
     } else {
         ALOGE("eglGetDisplay(%p) failed: Unable to look up eglGetPlatformDisplay from ANGLE",
               display);
@@ -168,7 +239,8 @@
 
         if (cnx->useAngle) {
             dpy = getDisplayAngle(display, cnx);
-        } else {
+        }
+        if (dpy == EGL_NO_DISPLAY) {
             dpy = cnx->egl.eglGetDisplay(display);
         }
 
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 2600eb0..4990af6 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -49,6 +49,7 @@
     void*               libGles2;
 
     bool                useAngle;
+    EGLint              angleBackend;
     void*               vendorEGL;
 };