1 /*
2  * Copyright (C) 2009 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 
18 #ifndef ANDROID_UI_EGLUTILS_H
19 #define ANDROID_UI_EGLUTILS_H
20 
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <vector>
24 
25 #include <EGL/egl.h>
26 #include <EGL/eglext.h>
27 #include <GLES2/gl2.h>
28 #include <system/window.h>
29 #include <utils/Errors.h>
30 #include <utils/String8.h>
31 
32 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
33 
34 // ----------------------------------------------------------------------------
35 namespace android {
36 // ----------------------------------------------------------------------------
37 
38 class EGLUtils
39 {
40 public:
41 
42     static inline const char *strerror(EGLint err);
43 
44     static inline status_t selectConfigForPixelFormat(
45             EGLDisplay dpy,
46             EGLint const* attrs,
47             int32_t format,
48             EGLConfig* outConfig);
49 
50     static inline status_t selectConfigForNativeWindow(
51             EGLDisplay dpy,
52             EGLint const* attrs,
53             EGLNativeWindowType window,
54             EGLConfig* outConfig);
55 
56     static inline String8 printGLString(const char* name, GLenum s);
57     static inline String8 printEGLString(EGLDisplay dpy, const char* name, GLenum s);
58     static inline String8 checkEglError(const char* op, EGLBoolean returnVal);
59     static inline String8 checkGlError(const char* op);
60     static inline String8 printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
61     static inline bool printEGLConfigurations(EGLDisplay dpy, String8& msg);
62     static inline bool printEGLConfigurations(FILE* output, EGLDisplay dpy);
63     static inline String8 decodeColorSpace(EGLint colorSpace);
64     static inline bool hasEglExtension(EGLDisplay dpy, const char* name);
65     static inline bool hasExtension(const char* exts, const char* name);
66 };
67 
68 // ----------------------------------------------------------------------------
69 
strerror(EGLint err)70 const char *EGLUtils::strerror(EGLint err)
71 {
72     switch (err){
73         case EGL_SUCCESS:           return "EGL_SUCCESS";
74         case EGL_NOT_INITIALIZED:   return "EGL_NOT_INITIALIZED";
75         case EGL_BAD_ACCESS:        return "EGL_BAD_ACCESS";
76         case EGL_BAD_ALLOC:         return "EGL_BAD_ALLOC";
77         case EGL_BAD_ATTRIBUTE:     return "EGL_BAD_ATTRIBUTE";
78         case EGL_BAD_CONFIG:        return "EGL_BAD_CONFIG";
79         case EGL_BAD_CONTEXT:       return "EGL_BAD_CONTEXT";
80         case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
81         case EGL_BAD_DISPLAY:       return "EGL_BAD_DISPLAY";
82         case EGL_BAD_MATCH:         return "EGL_BAD_MATCH";
83         case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
84         case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
85         case EGL_BAD_PARAMETER:     return "EGL_BAD_PARAMETER";
86         case EGL_BAD_SURFACE:       return "EGL_BAD_SURFACE";
87         case EGL_CONTEXT_LOST:      return "EGL_CONTEXT_LOST";
88         default: return "UNKNOWN";
89     }
90 }
91 
selectConfigForPixelFormat(EGLDisplay dpy,EGLint const * attrs,int32_t format,EGLConfig * outConfig)92 status_t EGLUtils::selectConfigForPixelFormat(
93         EGLDisplay dpy,
94         EGLint const* attrs,
95         int32_t format,
96         EGLConfig* outConfig)
97 {
98     EGLint numConfigs = -1, n=0;
99 
100     if (!attrs)
101         return BAD_VALUE;
102 
103     if (outConfig == nullptr)
104         return BAD_VALUE;
105 
106     // Get all the "potential match" configs...
107     if (eglGetConfigs(dpy, nullptr, 0, &numConfigs) == EGL_FALSE)
108         return BAD_VALUE;
109 
110     std::vector<EGLConfig> configs(numConfigs);
111     if (eglChooseConfig(dpy, attrs, configs.data(), numConfigs, &n) == EGL_FALSE) {
112         return BAD_VALUE;
113     }
114 
115     int i;
116     EGLConfig config = nullptr;
117     for (i=0 ; i<n ; i++) {
118         EGLint nativeVisualId = 0;
119         eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
120         if (nativeVisualId>0 && format == nativeVisualId) {
121             config = configs[i];
122             break;
123         }
124     }
125 
126     if (i<n) {
127         *outConfig = config;
128         return NO_ERROR;
129     }
130 
131     return NAME_NOT_FOUND;
132 }
133 
selectConfigForNativeWindow(EGLDisplay dpy,EGLint const * attrs,EGLNativeWindowType window,EGLConfig * outConfig)134 status_t EGLUtils::selectConfigForNativeWindow(
135         EGLDisplay dpy,
136         EGLint const* attrs,
137         EGLNativeWindowType window,
138         EGLConfig* outConfig)
139 {
140     int err;
141     int format;
142 
143     if (!window)
144         return BAD_VALUE;
145 
146     if ((err = window->query(window, NATIVE_WINDOW_FORMAT, &format)) < 0) {
147         return err;
148     }
149 
150     return selectConfigForPixelFormat(dpy, attrs, format, outConfig);
151 }
152 
printGLString(const char * name,GLenum s)153 String8 EGLUtils::printGLString(const char* name, GLenum s) {
154     String8 msg;
155     const char* v = reinterpret_cast<const char*>(glGetString(s));
156     msg.appendFormat("GL %s = %s\n", name, v);
157     return msg;
158 }
159 
printEGLString(EGLDisplay dpy,const char * name,GLenum s)160 String8 EGLUtils::printEGLString(EGLDisplay dpy, const char* name, GLenum s) {
161     String8 msg;
162     const char* v = static_cast<const char*>(eglQueryString(dpy, s));
163     msg.appendFormat("GL %s = %s\n", name, v);
164     const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s);
165     msg.appendFormat("ImplementationANDROID: %s = %s\n", name, va);
166     return msg;
167 }
168 
169 String8 EGLUtils::checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
170     String8 msg;
171     if (returnVal != EGL_TRUE) {
172         msg.appendFormat("%s() returned %d\n", op, returnVal);
173     }
174 
175     for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) {
176         msg.appendFormat("after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), error);
177     }
178     return msg;
179 }
180 
checkGlError(const char * op)181 String8 EGLUtils::checkGlError(const char* op) {
182     String8 msg;
183     for (GLint error = glGetError(); error != GL_NO_ERROR; error = glGetError()) {
184         msg.appendFormat("after %s() glError (0x%x)\n", op, error);
185     }
186     return msg;
187 }
188 
printEGLConfiguration(EGLDisplay dpy,EGLConfig config)189 String8 EGLUtils::printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
190 #define X(VAL) \
191     { VAL, #VAL }
192     struct {
193         EGLint attribute;
194         const char* name;
195     } names[] = {
196             X(EGL_BUFFER_SIZE),
197             X(EGL_ALPHA_SIZE),
198             X(EGL_BLUE_SIZE),
199             X(EGL_GREEN_SIZE),
200             X(EGL_RED_SIZE),
201             X(EGL_DEPTH_SIZE),
202             X(EGL_STENCIL_SIZE),
203             X(EGL_CONFIG_CAVEAT),
204             X(EGL_CONFIG_ID),
205             X(EGL_LEVEL),
206             X(EGL_MAX_PBUFFER_HEIGHT),
207             X(EGL_MAX_PBUFFER_PIXELS),
208             X(EGL_MAX_PBUFFER_WIDTH),
209             X(EGL_NATIVE_RENDERABLE),
210             X(EGL_NATIVE_VISUAL_ID),
211             X(EGL_NATIVE_VISUAL_TYPE),
212             X(EGL_SAMPLES),
213             X(EGL_SAMPLE_BUFFERS),
214             X(EGL_SURFACE_TYPE),
215             X(EGL_TRANSPARENT_TYPE),
216             X(EGL_TRANSPARENT_RED_VALUE),
217             X(EGL_TRANSPARENT_GREEN_VALUE),
218             X(EGL_TRANSPARENT_BLUE_VALUE),
219             X(EGL_BIND_TO_TEXTURE_RGB),
220             X(EGL_BIND_TO_TEXTURE_RGBA),
221             X(EGL_MIN_SWAP_INTERVAL),
222             X(EGL_MAX_SWAP_INTERVAL),
223             X(EGL_LUMINANCE_SIZE),
224             X(EGL_ALPHA_MASK_SIZE),
225             X(EGL_COLOR_BUFFER_TYPE),
226             X(EGL_RENDERABLE_TYPE),
227             X(EGL_CONFORMANT),
228     };
229 #undef X
230 
231     String8 msg;
232     for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
233         EGLint value = -1;
234         EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
235         EGLint error = eglGetError();
236         if (returnVal && error == EGL_SUCCESS) {
237             msg.appendFormat(" %s: %d (0x%x)", names[j].name, value, value);
238         }
239     }
240     msg.append("\n");
241     return msg;
242 }
243 
printEGLConfigurations(EGLDisplay dpy,String8 & msg)244 bool EGLUtils::printEGLConfigurations(EGLDisplay dpy, String8& msg) {
245     EGLint numConfig = 0;
246     EGLint returnVal = eglGetConfigs(dpy, nullptr, 0, &numConfig);
247     msg.append(checkEglError("eglGetConfigs", returnVal));
248     if (!returnVal) {
249         return false;
250     }
251 
252     msg.appendFormat("Number of EGL configuration: %d\n", numConfig);
253 
254     std::vector<EGLConfig> configs(numConfig);
255 
256     returnVal = eglGetConfigs(dpy, configs.data(), numConfig, &numConfig);
257     msg.append(checkEglError("eglGetConfigs", returnVal));
258     if (!returnVal) {
259         return false;
260     }
261 
262     for (int i = 0; i < numConfig; i++) {
263         msg.appendFormat("Configuration %d\n", i);
264         msg.append(printEGLConfiguration(dpy, configs[i]));
265     }
266 
267     return true;
268 }
269 
printEGLConfigurations(FILE * output,EGLDisplay dpy)270 bool EGLUtils::printEGLConfigurations(FILE* output, EGLDisplay dpy) {
271     String8 msg;
272     bool status = printEGLConfigurations(dpy, msg);
273     fprintf(output, "%s", msg.c_str());
274     return status;
275 }
276 
decodeColorSpace(EGLint colorSpace)277 String8 EGLUtils::decodeColorSpace(EGLint colorSpace) {
278     switch (colorSpace) {
279         case EGL_GL_COLORSPACE_SRGB_KHR:
280             return String8("EGL_GL_COLORSPACE_SRGB_KHR");
281         case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
282             return String8("EGL_GL_COLORSPACE_DISPLAY_P3_EXT");
283         case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
284             return String8("EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT");
285         case  EGL_GL_COLORSPACE_LINEAR_KHR:
286             return String8("EGL_GL_COLORSPACE_LINEAR_KHR");
287         default:
288             return String8::format("UNKNOWN ColorSpace %d", colorSpace);
289     }
290 }
291 
hasExtension(const char * exts,const char * name)292 bool EGLUtils::hasExtension(const char* exts, const char* name) {
293     size_t nameLen = strlen(name);
294     if (exts) {
295         for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) {
296             if (match[nameLen] == '\0' || match[nameLen] == ' ') {
297                 return true;
298             }
299         }
300     }
301     return false;
302 }
303 
hasEglExtension(EGLDisplay dpy,const char * name)304 bool EGLUtils::hasEglExtension(EGLDisplay dpy, const char* name) {
305     return hasExtension(eglQueryString(dpy, EGL_EXTENSIONS), name);
306 }
307 
308 // ----------------------------------------------------------------------------
309 }; // namespace android
310 // ----------------------------------------------------------------------------
311 
312 #endif /* ANDROID_UI_EGLUTILS_H */
313