Initial support of 'EGL_EXT_platform_wayland' extension

Change-Id: I90fff2dd2c5f3984f113a6d42acaa56e8ebee2de
Signed-off-by: Eugene Mutavchi <Ievgen_Mutavchi@comcast.com>
diff --git a/src/third_party/starboard/rdk/shared/system/system_egl.cc b/src/third_party/starboard/rdk/shared/system/system_egl.cc
index 7eeb8ce..5149cd2 100644
--- a/src/third_party/starboard/rdk/shared/system/system_egl.cc
+++ b/src/third_party/starboard/rdk/shared/system/system_egl.cc
@@ -34,9 +34,13 @@
 #include "starboard/egl.h"
 
 #include "third_party/starboard/rdk/shared/application_rdk.h"
+#include "third_party/starboard/rdk/shared/log_override.h"
 
+#include <mutex>
 #include <essos-app.h>
 
+EssAppPlatformDisplayType EssContextGetAppPlatformDisplayType( EssCtx *ctx ) __attribute__((weak));
+
 #if !defined(EGL_VERSION_1_0) || !defined(EGL_VERSION_1_1) || \
     !defined(EGL_VERSION_1_2) || !defined(EGL_VERSION_1_3) || \
     !defined(EGL_VERSION_1_4)
@@ -45,6 +49,47 @@
 
 namespace {
 
+#ifdef EGL_PLATFORM_WAYLAND_EXT
+static PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC gEglCreatePlatformWindowSurfaceEXT;
+static PFNEGLGETPLATFORMDISPLAYEXTPROC gEglGetPlatformDisplayEXT;
+
+bool isExtensionSupported(const char* extension_list, const char* extension) {
+  int len = strlen(extension);
+  const char* ptr = extension_list;
+  while ((ptr = strstr(ptr, extension))) {
+    if (ptr[len] == ' ' || ptr[len] == '\0')
+      return true;
+    ptr += len;
+  }
+  return false;
+}
+
+bool resolveEglPlatfromExtFns() {
+  static std::once_flag flag;
+  std::call_once(flag, [] {
+    const char* extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+    if (!isExtensionSupported(extensions, "EGL_EXT_platform_wayland")) {
+      SB_LOG(INFO) << "Wayland EGL platform extension is not supported. Supported extensions: " << extensions;
+    }
+    else {
+      gEglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
+      gEglCreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
+      if (!gEglGetPlatformDisplayEXT || !gEglCreatePlatformWindowSurfaceEXT) {
+        if (!gEglGetPlatformDisplayEXT)
+          SB_LOG(INFO) << "eglGetPlatformDisplayEXT is not available";
+        if (!gEglCreatePlatformWindowSurfaceEXT)
+          SB_LOG(INFO) << "eglCreatePlatformWindowSurfaceEXT is not available";
+        gEglGetPlatformDisplayEXT = nullptr;
+        gEglCreatePlatformWindowSurfaceEXT = nullptr;
+      } else {
+        SB_LOG(INFO) << "Successfully resolved EGL platform display extension functions.";
+      }
+    }
+  });
+  return gEglGetPlatformDisplayEXT && gEglCreatePlatformWindowSurfaceEXT;
+}
+#endif
+
 // Convenience functions that redirect to the intended function but "cast" the
 // type of the SbEglNative*Type parameter into the desired type. Depending on
 // the platform, the type of cast to use is different so either C-style casts or
@@ -69,16 +114,64 @@
                                       SbEglConfig config,
                                       SbEglNativeWindowType win,
                                       const SbEglInt32* attrib_list) {
-  return eglCreateWindowSurface(dpy, config, (EGLNativeWindowType)win,
-                                attrib_list);
+  SbEglSurface result = EGL_NO_SURFACE;
+
+#ifdef EGL_PLATFORM_WAYLAND_EXT
+  if (gEglCreatePlatformWindowSurfaceEXT) {
+    result = gEglCreatePlatformWindowSurfaceEXT(dpy, config, (EGLNativeWindowType)win,
+                                                attrib_list);
+    if (result == EGL_NO_SURFACE)
+      SB_LOG(WARNING) << "eglCreatePlatformWindowSurfaceEXT failed, err: " << eglGetError();
+  }
+#endif
+
+  if (result == EGL_NO_SURFACE) {
+    result = eglCreateWindowSurface(dpy, config, (EGLNativeWindowType)win,
+                                    attrib_list);
+    if (result == EGL_NO_SURFACE)
+      SB_LOG(ERROR) << "eglCreateWindowSurface failed, err: " << eglGetError();
+  }
+
+  return result;
 }
 
 SbEglDisplay SbEglGetDisplay(SbEglNativeDisplayType display_id) {
   NativeDisplayType display_type;
   EssCtx *ctx = third_party::starboard::rdk::shared::Application::Get()->GetEssCtx();
-  if (EssContextGetEGLDisplayType(ctx, &display_type))
-    return eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(display_type));
-  return eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(display_id));
+
+  if (EssContextGetEGLDisplayType(ctx, &display_type) == false) {
+    SB_LOG(ERROR) << "EssContextGetEGLDisplayType failed! Going to try display_id=" << display_id << '.';
+    display_type = reinterpret_cast<NativeDisplayType>(display_id);
+  }
+
+#ifdef EGL_PLATFORM_WAYLAND_EXT
+  if (EssContextGetAppPlatformDisplayType == nullptr) {
+    SB_LOG(INFO) << "'EssContextGetAppPlatformDisplayType' is not available. Fallback to eglGetDisplay.";
+  }
+  else if (EssContextGetAppPlatformDisplayType(ctx) != EssAppPlatformDisplayType_waylandExtension) {
+    SB_LOG(INFO) << "Essos app platform display type is not 'WaylandExtension' ("
+                 << EssContextGetAppPlatformDisplayType(ctx)
+                 << " != "
+                 << EssAppPlatformDisplayType_waylandExtension << ")."
+                 << " Fallback to eglGetDisplay.";
+  }
+  else if (!resolveEglPlatfromExtFns()) {
+    SB_LOG(INFO) << "eglGetPlatformDisplayEXT is not available or failed. Fallback to eglGetDisplay.";
+  }
+  else {
+    SbEglDisplay result = gEglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, reinterpret_cast<EGLNativeDisplayType>(display_type), nullptr);
+    if (result == EGL_NO_DISPLAY) {
+      SB_LOG(ERROR) << "eglGetPlatformDisplayEXT returned EGL_NO_DISPLAY. Fallback to eglGetDisplay.";
+      gEglGetPlatformDisplayEXT = nullptr;
+      gEglCreatePlatformWindowSurfaceEXT = nullptr;
+    } else {
+      SB_LOG(INFO) << "Using display=" << result << ", returned by eglGetPlatformDisplayEXT.";
+      return result;
+    }
+  }
+#endif
+
+  return eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(display_type));
 }
 
 const SbEglInterface g_sb_egl_interface = {