blob: 20f9c66eca6773e2942b19e10cd4c722f9a765b7 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* 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.h"
#include <GLES/gl.h>
namespace gfxstream {
namespace {
constexpr const char kEglLib[] = "libEGL.so";
constexpr const char kEglLibAlt[] = "libEGL.so.1";
gfxstream::expected<Lib, std::string> LoadEglLib() {
for (const auto* possible_name : {kEglLib, kEglLibAlt}) {
auto result = Lib::Load(possible_name);
if (result.ok()) {
return std::move(result.value());
}
}
return gfxstream::unexpected("Failed to load libEGL.");
}
} // namespace
/*static*/
gfxstream::expected<Egl, std::string> Egl::Load() {
Egl egl;
egl.mLib = GFXSTREAM_EXPECT(LoadEglLib());
#define LOAD_EGL_FUNCTION_POINTER(return_type, function_name, signature) \
egl.function_name = reinterpret_cast<return_type(GL_APIENTRY*) signature>( \
egl.mLib.GetSymbol(#function_name)); \
if (egl.function_name == nullptr) { \
egl.function_name = reinterpret_cast<return_type(GL_APIENTRY*) signature>( \
egl.eglGetProcAddress(#function_name)); \
}
FOR_EACH_EGL_FUNCTION(LOAD_EGL_FUNCTION_POINTER);
GFXSTREAM_EXPECT(egl.Init());
return std::move(egl);
}
gfxstream::expected<Ok, std::string> Egl::Init() {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY) {
return gfxstream::unexpected("Failed to get default display");
}
EGLint clientVersionMajor = 0;
EGLint clientVersionMinor = 0;
if (eglInitialize(display, &clientVersionMajor, &clientVersionMinor) != EGL_TRUE) {
return gfxstream::unexpected("Failed to initialize display.");
}
const std::string vendorString = eglQueryString(display, EGL_VENDOR);
if (vendorString.empty()) {
return gfxstream::unexpected("Failed to query vendor.");
}
const std::string extensionsString = eglQueryString(display, EGL_EXTENSIONS);
if (extensionsString.empty()) {
return gfxstream::unexpected("Failed to query extensions.");
}
if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
return gfxstream::unexpected("Failed to bind GLES API.");
}
const EGLint attribs[] = {
// clang-format off
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_NONE,
// clang-format on
};
EGLConfig config;
EGLint numConfigs = 0;
if (eglChooseConfig(display, attribs, &config, 1, &numConfigs) != EGL_TRUE) {
return gfxstream::unexpected("Failed to find matching framebuffer config.");
}
const EGLint pbufferAttribs[] = {
// clang-format off
EGL_WIDTH, 720,
EGL_HEIGHT, 720,
EGL_NONE,
// clang-format on
};
EGLSurface primarySurface = eglCreatePbufferSurface(display, config, pbufferAttribs);
if (primarySurface == EGL_NO_SURFACE) {
return gfxstream::unexpected("Failed to create EGL surface.");
}
const EGLint contextAttribs[] = {
// clang-format off
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE
// clang-format on
};
EGLContext primaryContext = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (primaryContext == EGL_NO_CONTEXT) {
return gfxstream::unexpected("Failed to create EGL context.");
}
if (eglMakeCurrent(display, primarySurface, primarySurface, primaryContext) == EGL_FALSE) {
return gfxstream::unexpected("Failed to make primary EGL context/surface current.");
}
return {};
}
} // namespace gfxstream