1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "Egl.h"
18 
19 #include <GLES/gl.h>
20 
21 namespace gfxstream {
22 namespace {
23 
24 constexpr const char kEglLib[] = "libEGL.so";
25 constexpr const char kEglLibAlt[] = "libEGL.so.1";
26 
LoadEglLib()27 gfxstream::expected<Lib, std::string> LoadEglLib() {
28     for (const auto* possible_name : {kEglLib, kEglLibAlt}) {
29         auto result = Lib::Load(possible_name);
30         if (result.ok()) {
31             return std::move(result.value());
32         }
33     }
34     return gfxstream::unexpected("Failed to load libEGL.");
35 }
36 
37 }  // namespace
38 
39 /*static*/
Load()40 gfxstream::expected<Egl, std::string> Egl::Load() {
41     Egl egl;
42     egl.mLib = GFXSTREAM_EXPECT(LoadEglLib());
43 
44 #define LOAD_EGL_FUNCTION_POINTER(return_type, function_name, signature)           \
45     egl.function_name = reinterpret_cast<return_type(GL_APIENTRY*) signature>(     \
46         egl.mLib.GetSymbol(#function_name));                                       \
47     if (egl.function_name == nullptr) {                                            \
48         egl.function_name = reinterpret_cast<return_type(GL_APIENTRY*) signature>( \
49             egl.eglGetProcAddress(#function_name));                                \
50     }
51 
52     FOR_EACH_EGL_FUNCTION(LOAD_EGL_FUNCTION_POINTER);
53 
54     GFXSTREAM_EXPECT(egl.Init());
55 
56     return std::move(egl);
57 }
58 
Init()59 gfxstream::expected<Ok, std::string> Egl::Init() {
60     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
61     if (display == EGL_NO_DISPLAY) {
62         return gfxstream::unexpected("Failed to get default display");
63     }
64 
65     EGLint clientVersionMajor = 0;
66     EGLint clientVersionMinor = 0;
67     if (eglInitialize(display, &clientVersionMajor, &clientVersionMinor) != EGL_TRUE) {
68         return gfxstream::unexpected("Failed to initialize display.");
69     }
70 
71     const std::string vendorString = eglQueryString(display, EGL_VENDOR);
72     if (vendorString.empty()) {
73         return gfxstream::unexpected("Failed to query vendor.");
74     }
75 
76     const std::string extensionsString = eglQueryString(display, EGL_EXTENSIONS);
77     if (extensionsString.empty()) {
78         return gfxstream::unexpected("Failed to query extensions.");
79     }
80 
81     if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
82         return gfxstream::unexpected("Failed to bind GLES API.");
83     }
84 
85     const EGLint attribs[] = {
86         // clang-format off
87         EGL_SURFACE_TYPE,     EGL_PBUFFER_BIT,
88         EGL_RENDERABLE_TYPE,  EGL_OPENGL_ES3_BIT,
89         EGL_RED_SIZE,         8,
90         EGL_GREEN_SIZE,       8,
91         EGL_BLUE_SIZE,        8,
92         EGL_ALPHA_SIZE,       8,
93         EGL_NONE,
94         // clang-format on
95     };
96 
97     EGLConfig config;
98     EGLint numConfigs = 0;
99     if (eglChooseConfig(display, attribs, &config, 1, &numConfigs) != EGL_TRUE) {
100         return gfxstream::unexpected("Failed to find matching framebuffer config.");
101     }
102 
103     const EGLint pbufferAttribs[] = {
104         // clang-format off
105         EGL_WIDTH,  720,
106         EGL_HEIGHT, 720,
107         EGL_NONE,
108         // clang-format on
109     };
110 
111     EGLSurface primarySurface = eglCreatePbufferSurface(display, config, pbufferAttribs);
112     if (primarySurface == EGL_NO_SURFACE) {
113         return gfxstream::unexpected("Failed to create EGL surface.");
114     }
115 
116     const EGLint contextAttribs[] = {
117         // clang-format off
118         EGL_CONTEXT_CLIENT_VERSION, 3,
119         EGL_NONE
120         // clang-format on
121     };
122 
123     EGLContext primaryContext = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
124     if (primaryContext == EGL_NO_CONTEXT) {
125       return gfxstream::unexpected("Failed to create EGL context.");
126     }
127 
128     if (eglMakeCurrent(display, primarySurface, primarySurface, primaryContext) == EGL_FALSE) {
129       return gfxstream::unexpected("Failed to make primary EGL context/surface current.");
130     }
131 
132     return {};
133 }
134 
135 }  // namespace gfxstream