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 "Gles.h"
18
19 #include <iostream>
20 #include <vector>
21
22 namespace gfxstream {
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 std::cout << "GlDebugCallback message: " << message << std::endl;
30 }
31
32 } // namespace
33
Load()34 /*static*/ gfxstream::expected<Gles, std::string> Gles::Load() {
35 Gles gles;
36 gles.lib_ = GFXSTREAM_EXPECT(Lib::Load(kGles2Lib));
37
38 #define LOAD_GLES_FUNCTION_POINTER(return_type, function_name, signature, \
39 args) \
40 gles.function_name = reinterpret_cast<return_type(*) signature>( \
41 gles.lib_.GetSymbol(#function_name)); \
42 if (gles.function_name == nullptr) { \
43 gles.function_name = reinterpret_cast<return_type(*) signature>( \
44 gles.lib_.GetSymbol(#function_name)); \
45 } \
46 if (gles.function_name == nullptr) { \
47 gles.function_name = reinterpret_cast<return_type(*) signature>( \
48 gles.lib_.GetSymbol(#function_name "OES")); \
49 } \
50 if (gles.function_name == nullptr) { \
51 gles.function_name = reinterpret_cast<return_type(*) signature>( \
52 gles.lib_.GetSymbol(#function_name "EXT")); \
53 } \
54 if (gles.function_name == nullptr) { \
55 gles.function_name = reinterpret_cast<return_type(*) signature>( \
56 gles.lib_.GetSymbol(#function_name "ARB")); \
57 }
58
59 FOR_EACH_GLES_FUNCTION(LOAD_GLES_FUNCTION_POINTER);
60
61 gles.Init();
62
63 return std::move(gles);
64 }
65
LoadFromEgl(Egl * egl)66 /*static*/ gfxstream::expected<Gles, std::string> Gles::LoadFromEgl(Egl* egl) {
67 Gles gles;
68
69 #define LOAD_GLES_FUNCTION_POINTER_FROM_EGL(return_type, function_name, \
70 signature, args) \
71 gles.function_name = reinterpret_cast<return_type(*) signature>( \
72 egl->eglGetProcAddress(#function_name));
73
74 FOR_EACH_GLES_FUNCTION(LOAD_GLES_FUNCTION_POINTER_FROM_EGL);
75
76 gles.Init();
77
78 return std::move(gles);
79 }
80
Init()81 void Gles::Init() {
82 const GLubyte* glesVendor = glGetString(GL_VENDOR);
83 if (glesVendor == nullptr) {
84 return;
85 }
86
87 const std::string glesExtensionsStr = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
88 if (glesExtensionsStr.empty()) {
89 return;
90 }
91
92 glEnable(GL_DEBUG_OUTPUT);
93 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
94 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0,
95 nullptr, GL_TRUE);
96 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0,
97 nullptr, GL_TRUE);
98 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0,
99 nullptr, GL_TRUE);
100 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE,
101 GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE);
102 glDebugMessageCallback(&GlDebugCallback, nullptr);
103 }
104
CreateShader(GLenum shader_type,const std::string & shader_source)105 std::optional<GLuint> Gles::CreateShader(GLenum shader_type,
106 const std::string& shader_source) {
107 GLuint shader = glCreateShader(shader_type);
108
109 const char* const shader_source_cstr = shader_source.c_str();
110 glShaderSource(shader, 1, &shader_source_cstr, nullptr);
111 glCompileShader(shader);
112
113 GLint status;
114 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
115
116 if (status != GL_TRUE) {
117 GLsizei log_length = 0;
118 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
119
120 std::vector<char> log(log_length + 1, 0);
121 glGetShaderInfoLog(shader, log_length, nullptr, log.data());
122
123 glDeleteShader(shader);
124 return std::nullopt;
125 }
126
127 return shader;
128 }
129
CreateProgram(const std::string & vert_shader_source,const std::string & frag_shader_source)130 std::optional<GLuint> Gles::CreateProgram(
131 const std::string& vert_shader_source,
132 const std::string& frag_shader_source) {
133 auto vert_shader_opt = CreateShader(GL_VERTEX_SHADER, vert_shader_source);
134 if (!vert_shader_opt) {
135 return std::nullopt;
136 }
137 auto vert_shader = *vert_shader_opt;
138
139 auto frag_shader_opt = CreateShader(GL_FRAGMENT_SHADER, frag_shader_source);
140 if (!frag_shader_opt) {
141 return std::nullopt;
142 }
143 auto frag_shader = *frag_shader_opt;
144
145 GLuint program = glCreateProgram();
146 glAttachShader(program, vert_shader);
147 glAttachShader(program, frag_shader);
148 glLinkProgram(program);
149
150 GLint status;
151 glGetProgramiv(program, GL_LINK_STATUS, &status);
152
153 if (status != GL_TRUE) {
154 GLsizei log_length = 0;
155 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
156
157 std::vector<char> log(log_length + 1, 0);
158 glGetProgramInfoLog(program, log_length, nullptr, log.data());
159
160 glDeleteProgram(program);
161 return std::nullopt;
162 }
163
164 glDeleteShader(vert_shader);
165 glDeleteShader(frag_shader);
166
167 return program;
168 }
169
170 } // namespace gfxstream
171