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