blob: 5149cd2abd289fb23e2192c870459ba95cc6f269 [file]
//
// Copyright 2020 Comcast Cable Communications Management, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
// Copyright 2019 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <EGL/egl.h>
#include <EGL/eglext.h>
#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)
#error "EGL version must be >= 1.4"
#endif
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
// constructor-style casts are needed to work across platforms (or provide
// implementations for these functions for each platform).
SbEglBoolean SbEglCopyBuffers(SbEglDisplay dpy,
SbEglSurface surface,
SbEglNativePixmapType target) {
return eglCopyBuffers(dpy, surface, (EGLNativePixmapType)target);
}
SbEglSurface SbEglCreatePixmapSurface(SbEglDisplay dpy,
SbEglConfig config,
SbEglNativePixmapType pixmap,
const SbEglInt32* attrib_list) {
return eglCreatePixmapSurface(dpy, config, (EGLNativePixmapType)pixmap,
attrib_list);
}
SbEglSurface SbEglCreateWindowSurface(SbEglDisplay dpy,
SbEglConfig config,
SbEglNativeWindowType win,
const SbEglInt32* 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) == 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 = {
&eglChooseConfig,
&SbEglCopyBuffers,
&eglCreateContext,
&eglCreatePbufferSurface,
&SbEglCreatePixmapSurface,
&SbEglCreateWindowSurface,
&eglDestroyContext,
&eglDestroySurface,
&eglGetConfigAttrib,
&eglGetConfigs,
&eglGetCurrentDisplay,
&eglGetCurrentSurface,
&SbEglGetDisplay,
&eglGetError,
&eglGetProcAddress,
&eglInitialize,
&eglMakeCurrent,
&eglQueryContext,
&eglQueryString,
&eglQuerySurface,
&eglSwapBuffers,
&eglTerminate,
&eglWaitGL,
&eglWaitNative,
&eglBindTexImage,
&eglReleaseTexImage,
&eglSurfaceAttrib,
&eglSwapInterval,
&eglBindAPI,
&eglQueryAPI,
&eglCreatePbufferFromClientBuffer,
&eglReleaseThread,
&eglWaitClient,
&eglGetCurrentContext,
nullptr, // eglCreateSync
nullptr, // eglDestroySync
nullptr, // eglClientWaitSync
nullptr, // eglGetSyncAttrib
nullptr, // eglCreateImage
nullptr, // eglDestroyImage
nullptr, // eglGetPlatformDisplay
nullptr, // eglCreatePlatformWindowSurface
nullptr, // eglCreatePlatformPixmapSurface
nullptr, // eglWaitSync
};
} // namespace
const SbEglInterface* SbGetEglInterface() {
return &g_sb_egl_interface;
}