• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "host/libs/graphics_detector/gles.h"
18 
19 #include <android-base/logging.h>
20 #include <android-base/strings.h>
21 
22 namespace cuttlefish {
23 namespace {
24 
25 constexpr const char kGles2Lib[] = "libGLESv2.so";
26 
GlDebugCallback(GLenum,GLenum,GLuint,GLenum,GLsizei,const GLchar * message,const void *)27 static void GL_APIENTRY GlDebugCallback(GLenum, GLenum, GLuint, GLenum, GLsizei,
28                                         const GLchar* message, const void*) {
29   LOG(VERBOSE) << "GlDebugCallback message: " << message;
30 }
31 
32 }  // namespace
33 
Load()34 /*static*/ std::optional<Gles> Gles::Load() {
35   auto lib_opt = Lib::Load(kGles2Lib);
36   if (!lib_opt) {
37     return std::nullopt;
38   }
39 
40   Gles gles;
41   gles.lib_ = std::move(*lib_opt);
42 
43 #define LOAD_GLES_FUNCTION_POINTER(return_type, function_name, signature, \
44                                    args)                                  \
45   gles.function_name = reinterpret_cast<return_type(*) signature>(        \
46       gles.lib_.GetSymbol(#function_name));                               \
47   if (gles.function_name == nullptr) {                                    \
48     gles.function_name = reinterpret_cast<return_type(*) signature>(      \
49         gles.lib_.GetSymbol(#function_name));                             \
50   }                                                                       \
51   if (gles.function_name == nullptr) {                                    \
52     gles.function_name = reinterpret_cast<return_type(*) signature>(      \
53         gles.lib_.GetSymbol(#function_name "OES"));                       \
54   }                                                                       \
55   if (gles.function_name == nullptr) {                                    \
56     gles.function_name = reinterpret_cast<return_type(*) signature>(      \
57         gles.lib_.GetSymbol(#function_name "EXT"));                       \
58   }                                                                       \
59   if (gles.function_name == nullptr) {                                    \
60     gles.function_name = reinterpret_cast<return_type(*) signature>(      \
61         gles.lib_.GetSymbol(#function_name "ARB"));                       \
62   }                                                                       \
63   if (gles.function_name == nullptr) {                                    \
64     LOG(VERBOSE) << "Failed to load GLES function: " << #function_name;   \
65   } else {                                                                \
66     LOG(VERBOSE) << "Loaded GLES function: " << #function_name;           \
67   }
68 
69   FOR_EACH_GLES_FUNCTION(LOAD_GLES_FUNCTION_POINTER);
70 
71   gles.Init();
72 
73   return std::move(gles);
74 }
75 
LoadFromEgl(Egl * egl)76 /*static*/ std::optional<Gles> Gles::LoadFromEgl(Egl* egl) {
77   auto lib_opt = Lib::Load(kGles2Lib);
78   if (!lib_opt) {
79     return std::nullopt;
80   }
81 
82   Gles gles;
83 
84 #define LOAD_GLES_FUNCTION_POINTER_FROM_EGL(return_type, function_name, \
85                                             signature, args)            \
86   gles.function_name = reinterpret_cast<return_type(*) signature>(      \
87       egl->eglGetProcAddress(#function_name));                          \
88   if (gles.function_name == nullptr) {                                  \
89     LOG(VERBOSE) << "Failed to load GLES function: " << #function_name; \
90   } else {                                                              \
91     LOG(VERBOSE) << "Loaded GLES function: " << #function_name;         \
92   }
93 
94   FOR_EACH_GLES_FUNCTION(LOAD_GLES_FUNCTION_POINTER_FROM_EGL);
95 
96   gles.Init();
97 
98   return std::move(gles);
99 }
100 
Init()101 void Gles::Init() {
102   const GLubyte* gles_vendor = glGetString(GL_VENDOR);
103   if (gles_vendor == nullptr) {
104     LOG(FATAL) << "Failed to get GLES vendor";
105     return;
106   }
107   LOG(VERBOSE) << "Found GLES vendor: " << gles_vendor;
108 
109   const std::string gles_extensions_str =
110       reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
111   if (gles_extensions_str.empty()) {
112     LOG(FATAL) << "Failed to get GLES extensions";
113     return;
114   }
115   std::vector<std::string> gles_extensions =
116       android::base::Split(gles_extensions_str, " ");
117   std::sort(gles_extensions.begin(), gles_extensions.end());
118   LOG(VERBOSE) << "Found GLES extensions:";
119   for (const std::string& gles_extension : gles_extensions) {
120     LOG(VERBOSE) << gles_extension;
121   }
122   LOG(VERBOSE) << "";
123 
124   glEnable(GL_DEBUG_OUTPUT);
125   glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
126   glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0,
127                         nullptr, GL_TRUE);
128   glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0,
129                         nullptr, GL_TRUE);
130   glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
131                         nullptr, GL_TRUE);
132   glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
133                         GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE);
134   glDebugMessageCallback(&GlDebugCallback, nullptr);
135 }
136 
CreateShader(GLenum shader_type,const std::string & shader_source)137 std::optional<GLuint> Gles::CreateShader(GLenum shader_type,
138                                          const std::string& shader_source) {
139   GLuint shader = glCreateShader(shader_type);
140 
141   const char* const shader_source_cstr = shader_source.c_str();
142   glShaderSource(shader, 1, &shader_source_cstr, nullptr);
143   glCompileShader(shader);
144 
145   GLint status;
146   glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
147 
148   if (status != GL_TRUE) {
149     GLsizei log_length = 0;
150     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
151 
152     std::vector<char> log(log_length + 1, 0);
153     glGetShaderInfoLog(shader, log_length, nullptr, log.data());
154     LOG(ERROR) << "Failed to compile shader: " << log.data();
155 
156     glDeleteShader(shader);
157     return std::nullopt;
158   }
159 
160   return shader;
161 }
162 
CreateProgram(const std::string & vert_shader_source,const std::string & frag_shader_source)163 std::optional<GLuint> Gles::CreateProgram(
164     const std::string& vert_shader_source,
165     const std::string& frag_shader_source) {
166   auto vert_shader_opt = CreateShader(GL_VERTEX_SHADER, vert_shader_source);
167   if (!vert_shader_opt) {
168     LOG(ERROR) << "Failed to create vert shader.";
169     return std::nullopt;
170   }
171   auto vert_shader = *vert_shader_opt;
172 
173   auto frag_shader_opt = CreateShader(GL_FRAGMENT_SHADER, frag_shader_source);
174   if (!frag_shader_opt) {
175     LOG(ERROR) << "Failed to create frag shader.";
176     return std::nullopt;
177   }
178   auto frag_shader = *frag_shader_opt;
179 
180   GLuint program = glCreateProgram();
181   glAttachShader(program, vert_shader);
182   glAttachShader(program, frag_shader);
183   glLinkProgram(program);
184 
185   GLint status;
186   glGetProgramiv(program, GL_LINK_STATUS, &status);
187 
188   if (status != GL_TRUE) {
189     GLsizei log_length = 0;
190     glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
191 
192     std::vector<char> log(log_length + 1, 0);
193     glGetProgramInfoLog(program, log_length, nullptr, log.data());
194     LOG(ERROR) << "Failed to link program: " << log.data();
195 
196     glDeleteProgram(program);
197     return std::nullopt;
198   }
199 
200   glDeleteShader(vert_shader);
201   glDeleteShader(frag_shader);
202 
203   return program;
204 }
205 
206 }  // namespace cuttlefish
207