rework a bit how we manage EGL extensions

- don't advertise extensions that are not supported
  by any implementation

- remove EGL_ANDROID_swap_rectangle which is not
  implemented by anybody and confuses people

- add some comments about mandatory extensions

Bug: 5428001
Change-Id: Id8dc48116ac1d1eb79ec9ef55d03e29d4257c1f3
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 095f10c..2237eb6 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -49,22 +49,6 @@
 
 // ----------------------------------------------------------------------------
 
-static char const * const sVendorString     = "Android";
-static char const * const sVersionString    = "1.4 Android META-EGL";
-static char const * const sClientApiString  = "OpenGL ES";
-static char const * const sExtensionString  =
-        "EGL_KHR_image "
-        "EGL_KHR_image_base "
-        "EGL_KHR_image_pixmap "
-        "EGL_KHR_gl_texture_2D_image "
-        "EGL_KHR_gl_texture_cubemap_image "
-        "EGL_KHR_gl_renderbuffer_image "
-        "EGL_KHR_fence_sync "
-        "EGL_ANDROID_image_native_buffer "
-        "EGL_ANDROID_swap_rectangle "
-        "EGL_NV_system_time "
-        ;
-
 struct extention_map_t {
     const char* name;
     __eglMustCastToProperFunctionPointerType address;
@@ -79,8 +63,6 @@
             (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
     { "eglDestroyImageKHR",
             (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
-    { "eglSetSwapRectangleANDROID",
-            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
     { "eglGetSystemTimeFrequencyNV",
             (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
     { "eglGetSystemTimeNV",
@@ -978,13 +960,13 @@
 
     switch (name) {
         case EGL_VENDOR:
-            return sVendorString;
+            return dp->getVendorString();
         case EGL_VERSION:
-            return sVersionString;
+            return dp->getVersionString();
         case EGL_EXTENSIONS:
-            return sExtensionString;
+            return dp->getExtensionString();
         case EGL_CLIENT_APIS:
-            return sClientApiString;
+            return dp->getClientApiString();
     }
     return setError(EGL_BAD_PARAMETER, (const char *)0);
 }
@@ -1447,25 +1429,7 @@
 // ANDROID extensions
 // ----------------------------------------------------------------------------
 
-EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
-        EGLint left, EGLint top, EGLint width, EGLint height)
-{
-    clearError();
-
-    egl_display_t const * const dp = validate_display(dpy);
-    if (!dp) return EGL_FALSE;
-
-    SurfaceRef _s(dp, draw);
-    if (!_s.get())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
-    egl_surface_t const * const s = get_surface(draw);
-    if (s->cnx->egl.eglSetSwapRectangleANDROID) {
-        return s->cnx->egl.eglSetSwapRectangleANDROID(
-                dp->disp[s->impl].dpy, s->surface, left, top, width, height);
-    }
-    return setError(EGL_BAD_DISPLAY, NULL);
-}
+/* ANDROID extensions entry-point go here */
 
 // ----------------------------------------------------------------------------
 // NVIDIA extensions
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 2935832..862b48d2 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -14,6 +14,8 @@
  ** limitations under the License.
  */
 
+#include <string.h>
+
 #include "egl_cache.h"
 #include "egl_display.h"
 #include "egl_object.h"
@@ -25,6 +27,36 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+static char const * const sVendorString     = "Android";
+static char const * const sVersionString    = "1.4 Android META-EGL";
+static char const * const sClientApiString  = "OpenGL ES";
+
+// this is the list of EGL extensions that are exposed to applications
+// some of them are mandatory because used by the ANDROID system.
+//
+// mandatory extensions are required per the CDD and not explicitly
+// checked during EGL initialization. the system *assumes* these extensions
+// are present. the system may not function properly if some mandatory
+// extensions are missing.
+//
+// NOTE: sExtensionString MUST be have a single space as the last character.
+//
+static char const * const sExtensionString  =
+        "EGL_KHR_image "                        // mandatory
+        "EGL_KHR_image_base "                   // mandatory
+        "EGL_KHR_image_pixmap "
+        "EGL_KHR_gl_texture_2D_image "
+        "EGL_KHR_gl_texture_cubemap_image "
+        "EGL_KHR_gl_renderbuffer_image "
+        "EGL_KHR_fence_sync "
+        "EGL_NV_system_time "
+        "EGL_ANDROID_image_native_buffer "      // mandatory
+        ;
+
+// extensions not exposed to applications but used by the ANDROID system
+//      "EGL_ANDROID_recordable "               // mandatory
+//      "EGL_ANDROID_blob_cache "               // strongly recommended
+
 extern void initEglTraceLevel();
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 
@@ -174,6 +206,36 @@
         }
     }
 
+    // the query strings are per-display
+    mVendorString.setTo(sVendorString);
+    mVersionString.setTo(sVersionString);
+    mClientApiString.setTo(sClientApiString);
+
+    // we only add extensions that exist in at least one implementation
+    char const* start = sExtensionString;
+    char const* end;
+    do {
+        // find the space separating this extension for the next one
+        end = strchr(start, ' ');
+        if (end) {
+            // length of the extension string
+            const size_t len = end - start;
+            // NOTE: we could avoid the copy if we had strnstr.
+            const String8 ext(start, len);
+            // now go through all implementations and look for this extension
+            for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+                // if we find it, add this extension string to our list
+                // (and don't forget the space)
+                const char* match = strstr(disp[i].queryString.extensions, ext.string());
+                if (match && (match[len] == ' ' || match[len] == 0)) {
+                    mExtensionString.append(start, len+1);
+                }
+            }
+            // process the next extension string, and skip the space.
+            start = end + 1;
+        }
+    } while (end);
+
     egl_cache_t::get()->initialize(this);
 
     EGLBoolean res = EGL_FALSE;
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 94077be..042ae07 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -29,6 +29,7 @@
 
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
+#include <utils/String8.h>
 
 #include "egldefs.h"
 #include "hooks.h"
@@ -91,6 +92,11 @@
     inline bool isValid() const { return magic == '_dpy'; }
     inline bool isAlive() const { return isValid(); }
 
+    char const * getVendorString() const { return mVendorString.string(); }
+    char const * getVersionString() const { return mVersionString.string(); }
+    char const * getClientApiString() const { return mClientApiString.string(); }
+    char const * getExtensionString() const { return mExtensionString.string(); }
+
     inline uint32_t getRefsCount() const { return refs; }
 
     struct strings_t {
@@ -122,6 +128,10 @@
             uint32_t                    refs;
     mutable Mutex                       lock;
             SortedVector<egl_object_t*> objects;
+            String8 mVendorString;
+            String8 mVersionString;
+            String8 mClientApiString;
+            String8 mExtensionString;
 };
 
 // ----------------------------------------------------------------------------