1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <dlfcn.h>
5
6 #include <EGL/egl.h>
7 #include <GLES2/gl2.h>
8
9
10 #define COUNT_OF(x) (sizeof(x) / sizeof(0[x]))
11
12
13 struct egl_enum_item {
14 EGLint id;
15 const char* name;
16 };
17
18 struct egl_enum_item egl_enum_boolean[] = {
19 {
20 .id = EGL_TRUE,
21 .name = "EGL_TRUE",
22 },
23 {
24 .id = EGL_FALSE,
25 .name = "EGL_FALSE",
26 },
27 };
28
29 struct egl_enum_item egl_enum_caveat[] = {
30 {
31 .id = EGL_NONE,
32 .name = "EGL_NONE",
33 },
34 {
35 .id = EGL_SLOW_CONFIG,
36 .name = "EGL_SLOW_CONFIG",
37 },
38 {
39 .id = EGL_NON_CONFORMANT_CONFIG,
40 .name = "EGL_NON_CONFORMANT_CONFIG",
41 },
42 };
43
44 struct egl_enum_item egl_enum_transparency[] = {
45 {
46 .id = EGL_NONE,
47 .name = "EGL_NONE",
48 },
49 {
50 .id = EGL_TRANSPARENT_RGB,
51 .name = "EGL_TRANSPARENT_RGB",
52 },
53 };
54
55 struct egl_enum_item egl_enum_color_buffer[] = {
56 {
57 .id = EGL_RGB_BUFFER,
58 .name = "EGL_RGB_BUFFER",
59 },
60 {
61 .id = EGL_LUMINANCE_BUFFER,
62 .name = "EGL_LUMINANCE_BUFFER",
63 },
64 };
65
66 #ifndef EGL_OPENGL_ES3_BIT
67 #define EGL_OPENGL_ES3_BIT 0x40
68 #endif
69
70 struct egl_enum_item egl_enum_conformant[] = {
71 {
72 .id = EGL_OPENGL_BIT,
73 .name = "EGL_OPENGL_BIT",
74 },
75 {
76 .id = EGL_OPENGL_ES_BIT,
77 .name = "EGL_OPENGL_ES_BIT",
78 },
79 {
80 .id = EGL_OPENGL_ES2_BIT,
81 .name = "EGL_OPENGL_ES2_BIT",
82 },
83 {
84 .id = EGL_OPENGL_ES3_BIT,
85 .name = "EGL_OPENGL_ES3_BIT",
86 },
87 {
88 .id = EGL_OPENVG_BIT,
89 .name = "EGL_OPENVG_BIT",
90 },
91 };
92
93 struct egl_enum_item egl_enum_surface_type[] = {
94 {
95 .id = EGL_PBUFFER_BIT,
96 .name = "EGL_PBUFFER_BIT",
97 },
98 {
99 .id = EGL_PIXMAP_BIT,
100 .name = "EGL_PIXMAP_BIT",
101 },
102 {
103 .id = EGL_WINDOW_BIT,
104 .name = "EGL_WINDOW_BIT",
105 },
106 {
107 .id = EGL_VG_COLORSPACE_LINEAR_BIT,
108 .name = "EGL_VG_COLORSPACE_LINEAR_BIT",
109 },
110 {
111 .id = EGL_VG_ALPHA_FORMAT_PRE_BIT,
112 .name = "EGL_VG_ALPHA_FORMAT_PRE_BIT",
113 },
114 {
115 .id = EGL_MULTISAMPLE_RESOLVE_BOX_BIT,
116 .name = "EGL_MULTISAMPLE_RESOLVE_BOX_BIT",
117 },
118 {
119 .id = EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
120 .name = "EGL_SWAP_BEHAVIOR_PRESERVED_BIT",
121 },
122 };
123
124 struct egl_enum_item egl_enum_renderable_type[] = {
125 {
126 .id = EGL_OPENGL_ES_BIT,
127 .name = "EGL_OPENGL_ES_BIT",
128 },
129 {
130 .id = EGL_OPENVG_BIT,
131 .name = "EGL_OPENVG_BIT",
132 },
133 {
134 .id = EGL_OPENGL_ES2_BIT,
135 .name = "EGL_OPENGL_ES2_BIT",
136 },
137 {
138 .id = EGL_OPENGL_BIT,
139 .name = "EGL_OPENGL_BIT",
140 },
141 {
142 .id = EGL_OPENGL_ES3_BIT,
143 .name = "EGL_OPENGL_ES3_BIT",
144 },
145 };
146
147 struct egl_config_attribute {
148 EGLint id;
149 const char* name;
150 int32_t cardinality;
151 const struct egl_enum_item* values;
152 };
153
154 struct egl_config_attribute egl_config_attributes[] = {
155 {
156 .id = EGL_CONFIG_ID,
157 .name = "EGL_CONFIG_ID",
158 },
159 {
160 .id = EGL_CONFIG_CAVEAT,
161 .name = "EGL_CONFIG_CAVEAT",
162 .cardinality = COUNT_OF(egl_enum_caveat),
163 .values = egl_enum_caveat,
164 },
165 {
166 .id = EGL_LUMINANCE_SIZE,
167 .name = "EGL_LUMINANCE_SIZE",
168 },
169 {
170 .id = EGL_RED_SIZE,
171 .name = "EGL_RED_SIZE",
172 },
173 {
174 .id = EGL_GREEN_SIZE,
175 .name = "EGL_GREEN_SIZE",
176 },
177 {
178 .id = EGL_BLUE_SIZE,
179 .name = "EGL_BLUE_SIZE",
180 },
181 {
182 .id = EGL_ALPHA_SIZE,
183 .name = "EGL_ALPHA_SIZE",
184 },
185 {
186 .id = EGL_DEPTH_SIZE,
187 .name = "EGL_DEPTH_SIZE",
188 },
189 {
190 .id = EGL_STENCIL_SIZE,
191 .name = "EGL_STENCIL_SIZE",
192 },
193 {
194 .id = EGL_ALPHA_MASK_SIZE,
195 .name = "EGL_ALPHA_MASK_SIZE",
196 },
197 {
198 .id = EGL_BIND_TO_TEXTURE_RGB,
199 .name = "EGL_BIND_TO_TEXTURE_RGB",
200 .cardinality = COUNT_OF(egl_enum_boolean),
201 .values = egl_enum_boolean,
202 },
203 {
204 .id = EGL_BIND_TO_TEXTURE_RGBA,
205 .name = "EGL_BIND_TO_TEXTURE_RGBA",
206 .cardinality = COUNT_OF(egl_enum_boolean),
207 .values = egl_enum_boolean,
208 },
209 {
210 .id = EGL_MAX_PBUFFER_WIDTH,
211 .name = "EGL_MAX_PBUFFER_WIDTH",
212 },
213 {
214 .id = EGL_MAX_PBUFFER_HEIGHT,
215 .name = "EGL_MAX_PBUFFER_HEIGHT",
216 },
217 {
218 .id = EGL_MAX_PBUFFER_PIXELS,
219 .name = "EGL_MAX_PBUFFER_PIXELS",
220 },
221 {
222 .id = EGL_TRANSPARENT_RED_VALUE,
223 .name = "EGL_TRANSPARENT_RED_VALUE",
224 },
225 {
226 .id = EGL_TRANSPARENT_GREEN_VALUE,
227 .name = "EGL_TRANSPARENT_GREEN_VALUE",
228 },
229 {
230 .id = EGL_TRANSPARENT_BLUE_VALUE,
231 .name = "EGL_TRANSPARENT_BLUE_VALUE",
232 },
233 {
234 .id = EGL_SAMPLE_BUFFERS,
235 .name = "EGL_SAMPLE_BUFFERS",
236 },
237 {
238 .id = EGL_SAMPLES,
239 .name = "EGL_SAMPLES",
240 },
241 {
242 .id = EGL_LEVEL,
243 .name = "EGL_LEVEL",
244 },
245 {
246 .id = EGL_MAX_SWAP_INTERVAL,
247 .name = "EGL_MAX_SWAP_INTERVAL",
248 },
249 {
250 .id = EGL_MIN_SWAP_INTERVAL,
251 .name = "EGL_MIN_SWAP_INTERVAL",
252 },
253 {
254 .id = EGL_SURFACE_TYPE,
255 .name = "EGL_SURFACE_TYPE",
256 .cardinality = -(int32_t) COUNT_OF(egl_enum_surface_type),
257 .values = egl_enum_surface_type,
258 },
259 {
260 .id = EGL_RENDERABLE_TYPE,
261 .name = "EGL_RENDERABLE_TYPE",
262 .cardinality = -(int32_t) COUNT_OF(egl_enum_renderable_type),
263 .values = egl_enum_renderable_type,
264 },
265 {
266 .id = EGL_CONFORMANT,
267 .name = "EGL_CONFORMANT",
268 .cardinality = -(int32_t) COUNT_OF(egl_enum_conformant),
269 .values = egl_enum_conformant,
270 },
271 {
272 .id = EGL_TRANSPARENT_TYPE,
273 .name = "EGL_TRANSPARENT_TYPE",
274 .cardinality = COUNT_OF(egl_enum_transparency),
275 .values = egl_enum_transparency,
276 },
277 {
278 .id = EGL_COLOR_BUFFER_TYPE,
279 .name = "EGL_COLOR_BUFFER_TYPE",
280 .cardinality = COUNT_OF(egl_enum_color_buffer),
281 .values = egl_enum_color_buffer,
282 },
283 };
284
report_gles_attributes(void)285 void report_gles_attributes(void) {
286 void* libEGL = NULL;
287 EGLConfig* configs = NULL;
288 EGLDisplay display = EGL_NO_DISPLAY;
289 EGLSurface surface = EGL_NO_SURFACE;
290 EGLContext context = EGL_NO_CONTEXT;
291 EGLBoolean egl_init_status = EGL_FALSE;
292 EGLBoolean egl_make_current_status = EGL_FALSE;
293 EGLBoolean egl_status;
294
295 libEGL = dlopen("libEGL.so", RTLD_LAZY | RTLD_LOCAL);
296
297 display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
298 if (display == EGL_NO_DISPLAY) {
299 fprintf(stderr, "failed to get default EGL display\n");
300 goto cleanup;
301 }
302
303 EGLint egl_major = 0, egl_minor = 0;
304 egl_init_status = eglInitialize(display, &egl_major, &egl_minor);
305 if (egl_init_status != EGL_TRUE) {
306 fprintf(stderr, "failed to initialize EGL display connection\n");
307 goto cleanup;
308 }
309 printf("initialized display connection with EGL %d.%d\n", (int) egl_major, (int) egl_minor);
310
311 EGLint configs_count = 0;
312 egl_status = eglGetConfigs(display, NULL, 0, &configs_count);
313 if (egl_status != EGL_TRUE) {
314 fprintf(stderr, "failed to get the number of EGL frame buffer configurations\n");
315 goto cleanup;
316 }
317
318 configs = (EGLConfig*) malloc(configs_count * sizeof(EGLConfig));
319 if (configs == NULL) {
320 fprintf(stderr, "failed to allocate %zu bytes for %d frame buffer configurations\n",
321 configs_count * sizeof(EGLConfig), configs_count);
322 goto cleanup;
323 }
324
325 egl_status = eglGetConfigs(display, configs, configs_count, &configs_count);
326 if (egl_status != EGL_TRUE || configs_count == 0) {
327 fprintf(stderr, "failed to get EGL frame buffer configurations\n");
328 goto cleanup;
329 }
330
331 printf("EGL framebuffer configurations:\n");
332 for (EGLint i = 0; i < configs_count; i++) {
333 printf("\tConfiguration #%d:\n", (int) i);
334 for (size_t n = 0; n < COUNT_OF(egl_config_attributes); n++) {
335 EGLint value = 0;
336 egl_status = eglGetConfigAttrib(display, configs[i], egl_config_attributes[n].id, &value);
337 if (egl_config_attributes[n].cardinality == 0) {
338 printf("\t\t%s: %d\n", egl_config_attributes[n].name, (int) value);
339 } else if (egl_config_attributes[n].cardinality > 0) {
340 /* Enumeration */
341 bool known_value = false;
342 for (size_t k = 0; k < (size_t) egl_config_attributes[n].cardinality; k++) {
343 if (egl_config_attributes[n].values[k].id == value) {
344 printf("\t\t%s: %s\n", egl_config_attributes[n].name, egl_config_attributes[n].values[k].name);
345 known_value = true;
346 break;
347 }
348 }
349 if (!known_value) {
350 printf("\t\t%s: unknown (%d)\n", egl_config_attributes[n].name, value);
351 }
352 } else {
353 /* Bitfield */
354 printf("\t\t%s: ", egl_config_attributes[n].name);
355 if (value == 0) {
356 printf("none\n");
357 } else {
358 for (size_t k = 0; k < (size_t) -egl_config_attributes[n].cardinality; k++) {
359 if (egl_config_attributes[n].values[k].id & value) {
360 value &= ~egl_config_attributes[n].values[k].id;
361 if (value != 0) {
362 printf("%s | ", egl_config_attributes[n].values[k].name);
363 } else {
364 printf("%s\n", egl_config_attributes[n].values[k].name);
365 }
366 }
367 }
368 if (value != 0) {
369 printf("0x%08X\n", (int) value);
370 }
371 }
372 }
373 }
374 }
375
376 EGLint const config_attributes[] = {
377 EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
378 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
379 EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,
380 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
381 EGL_NONE,
382 };
383 EGLConfig config = NULL;
384 EGLint config_count = 0;
385 egl_status = eglChooseConfig(display, config_attributes, &config, 1, &config_count);
386 if (egl_status != EGL_TRUE || config_count == 0 || config == NULL) {
387 fprintf(stderr, "failed to find EGL frame buffer configuration that match required attributes\n");
388 goto cleanup;
389 }
390
391 EGLint const surface_attributes[] = {
392 EGL_HEIGHT, 1,
393 EGL_WIDTH, 1,
394 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
395 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
396 EGL_NONE,
397 };
398 surface = eglCreatePbufferSurface(display, config, surface_attributes);
399 if (surface == EGL_NO_SURFACE) {
400 fprintf(stderr, "failed to create PBuffer surface\n");
401 goto cleanup;
402 }
403
404 EGLint const context_attributes[] = {
405 EGL_CONTEXT_CLIENT_VERSION, 2,
406 EGL_NONE,
407 };
408 context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
409 if (context == EGL_NO_CONTEXT) {
410 fprintf(stderr, "failed to create OpenGL ES context\n");
411 goto cleanup;
412 }
413
414 egl_make_current_status = eglMakeCurrent(display, surface, surface, context);
415 if (egl_make_current_status != EGL_TRUE) {
416 fprintf(stderr, "failed to attach OpenGL ES rendering context\n");
417 goto cleanup;
418 }
419
420 printf("OpenGL ES Attributes:\n");
421 printf("\t%s: \"%s\"\n", "GL_VENDOR", glGetString(GL_VENDOR));
422 printf("\t%s: \"%s\"\n", "GL_RENDERER", glGetString(GL_RENDERER));
423 printf("\t%s: \"%s\"\n", "GL_VERSION", glGetString(GL_VERSION));
424 printf("\t%s: \"%s\"\n", "GL_SHADING_LANGUAGE_VERSION", glGetString(GL_SHADING_LANGUAGE_VERSION));
425 printf("\t%s: \"%s\"\n", "GL_EXTENSIONS", glGetString(GL_EXTENSIONS));
426
427 cleanup:
428 if (egl_make_current_status == EGL_TRUE) {
429 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
430 }
431 if (context != EGL_NO_CONTEXT) {
432 eglDestroyContext(display, context);
433 }
434 if (surface != EGL_NO_SURFACE) {
435 eglDestroySurface(display, surface);
436 }
437 if (egl_init_status == EGL_TRUE) {
438 eglTerminate(display);
439 }
440 free(configs);
441
442 if (libEGL != NULL) {
443 dlclose(libEGL);
444 }
445 }
446
main(int argc,char ** argv)447 int main(int argc, char** argv) {
448 report_gles_attributes();
449 return 0;
450 }
451