1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <stdlib.h>
  27 #include <assert.h>
  28 #include <stdio.h>
  29 #include <string.h>
  30 #include <fcntl.h>
  31 #include <unistd.h>
  32 #include <linux/fb.h>
  33 #include <sys/ioctl.h>
  34 
  35 #include "../PrismES2Defs.h"
  36 
  37 #include "eglUtils.h"
  38 
  39 #include "eglfb/wrapped_egl.h"
  40 
  41 #ifdef EGL_X11_FB_CONTAINER
  42 #include "X11/Xlib.h"
  43 #endif
  44 
  45 #define WARN_MISSING_SYMBOLS 0
  46 
  47 void *get_dlsym(void *handle, const char *symbol, int warn) {
  48     void *ret = dlsym(handle, symbol);
  49     if (!ret && warn) {
  50         fprintf(stderr, "ERROR: could not find symbol for %s\n", symbol);
  51     }
  52     return ret;
  53 }
  54 
  55 #define GET_DLSYM(handle,symbol) get_dlsym(handle,symbol, WARN_MISSING_SYMBOLS);
  56 
  57 EGLSurface sharedWindowSurface = NULL;
  58 #ifdef ANDROID_NDK
  59 EGLNativeWindowType currentNativeWindow = NULL;
  60 #endif
  61 #ifdef EGL_X11_FB_CONTAINER
  62 EGLSurface dummySurface = NULL;
  63 #endif
  64 
  65 EGLSurface getDummyWindowSurface(EGLDisplay dpy, EGLConfig cfg) {
  66 #ifdef EGL_X11_FB_CONTAINER
  67     if (dummySurface == NULL) {
  68         Display *display;
  69         Window window;
  70 
  71         display = XOpenDisplay(0);
  72         if (display == NULL) {
  73             fprintf(stderr, "XOpenDisplay failed\n");
  74             return 0;
  75         }
  76         window = XCreateWindow(display,
  77                                RootWindow(display, DefaultScreen(display)),
  78                                0, 0, 1, 1, 0,
  79                                CopyFromParent, InputOutput, CopyFromParent, 0,
  80                                (XSetWindowAttributes *) 0);
  81         XSync(display, False);
  82         dummySurface = eglCreateWindowSurface(dpy, cfg, window, NULL);
  83         XSync(display, False);
  84     }
  85     return dummySurface;
  86 #else
  87     return getSharedWindowSurface(dpy, cfg, NULL);
  88 #endif
  89 }
  90 
  91 EGLSurface getSharedWindowSurface(EGLDisplay dpy,
  92                                   EGLConfig cfg,
  93                                   void *nativeWindow) {
  94     if (sharedWindowSurface == NULL) {
  95         EGLNativeWindowType window = 0;
  96 #if EGL_X11_FB_CONTAINER
  97         window = (EGLNativeWindowType)nativeWindow;
  98 #else
  99         if (nativeWindow == NULL) {
 100             window = getNativeWindowType();
 101         }
 102 #endif
 103         sharedWindowSurface = eglCreateWindowSurface(dpy, cfg, window, NULL);
 104         if (sharedWindowSurface == EGL_NO_SURFACE) {
 105             fprintf(stderr, "eglCreateWindowSurface failed! eglGetError %d\n", eglGetError());
 106             return 0;
 107         }
 108 #ifdef ANDROID_NDK
 109         currentNativeWindow = window;
 110 #endif
 111         return sharedWindowSurface;
 112     }
 113 #ifdef ANDROID_NDK
 114     EGLNativeWindowType wnd = getNativeWindowType();
 115     if (currentNativeWindow != wnd) {
 116        sharedWindowSurface = eglCreateWindowSurface(dpy, cfg, wnd, NULL);
 117        if (sharedWindowSurface == EGL_NO_SURFACE) {
 118            fprintf(stderr, "Recreating eglSurface: eglCreateWindowSurface failed! eglGetError %d\n", eglGetError());
 119            return 0;
 120        }
 121        currentNativeWindow = wnd;
 122     }
 123 #endif
 124     return sharedWindowSurface;
 125 }
 126 
 127 void setEGLAttrs(jint *attrs, int *eglAttrs) {
 128     int index = 0;
 129 
 130     eglAttrs[index++] = EGL_SURFACE_TYPE;
 131     if (attrs[ONSCREEN] != 0) {
 132         eglAttrs[index++] = (EGL_WINDOW_BIT);
 133     } else {
 134         eglAttrs[index++] = EGL_PBUFFER_BIT;
 135     }
 136 
 137     // NOTE: EGL_TRANSPARENT_TYPE ?
 138 
 139     if (attrs[RED_SIZE] == 5 && attrs[GREEN_SIZE] == 6
 140             && attrs[BLUE_SIZE] == 5 && attrs[ALPHA_SIZE] == 0) {
 141         // Optimization for Raspberry Pi model B. Even though the result
 142         // of setting EGL_BUFFER_SIZE to 16 should be the same as setting
 143         // component sizes separately, we get less per-frame overhead if we
 144         // only set EGL_BUFFER_SIZE.
 145         eglAttrs[index++] = EGL_BUFFER_SIZE;
 146         eglAttrs[index++] = 16;
 147     } else {
 148         eglAttrs[index++] = EGL_RED_SIZE;
 149         eglAttrs[index++] = attrs[RED_SIZE];
 150         eglAttrs[index++] = EGL_GREEN_SIZE;
 151         eglAttrs[index++] = attrs[GREEN_SIZE];
 152         eglAttrs[index++] = EGL_BLUE_SIZE;
 153         eglAttrs[index++] = attrs[BLUE_SIZE];
 154         eglAttrs[index++] = EGL_ALPHA_SIZE;
 155         eglAttrs[index++] = attrs[ALPHA_SIZE];
 156     }
 157 
 158     eglAttrs[index++] = EGL_DEPTH_SIZE;
 159     eglAttrs[index++] = attrs[DEPTH_SIZE];
 160     eglAttrs[index++] = EGL_RENDERABLE_TYPE;
 161     eglAttrs[index++] = EGL_OPENGL_ES2_BIT;
 162     eglAttrs[index] = EGL_NONE;
 163 }
 164 
 165 ContextInfo *eglContextFromConfig(EGLDisplay *dpy, EGLConfig config) {
 166 
 167     EGLSurface surface = getDummyWindowSurface(dpy, config);
 168 
 169     EGLint contextAttrs[] = {
 170         EGL_CONTEXT_CLIENT_VERSION, 2,
 171         EGL_NONE
 172     };
 173 
 174     EGLContext context = eglCreateContext(dpy, config, NULL, contextAttrs);
 175     if (context == EGL_NO_CONTEXT) {
 176         fprintf(stderr, "eglCreateContext() failed - %d\n", eglGetError());
 177         return 0;
 178     }
 179 
 180     if (!eglMakeCurrent(dpy, surface, surface, context)) {
 181         fprintf(stderr, "eglMakeCurrent failed - %d\n", eglGetError());
 182         return 0;
 183     }
 184     ContextInfo *ctxInfo = NULL;
 185 
 186     /* Note: We are only storing the string information of a driver.
 187      Assuming a system with a single or homogeneous GPUs. For the case
 188      of heterogeneous GPUs system the string information will need to move to
 189      GLContext class. */
 190     /* allocate the structure */
 191     ctxInfo = (ContextInfo *) malloc(sizeof(ContextInfo));
 192     if (ctxInfo == NULL) {
 193         fprintf(stderr, "nInitialize: Failed in malloc\n");
 194         return 0;
 195     }
 196     /* initialize the structure */
 197     initializeCtxInfo(ctxInfo);
 198 
 199     const char *glVersion = (char *)glGetString(GL_VERSION);
 200     const char *glVendor = (char *)glGetString(GL_VENDOR);
 201     const char *glRenderer = (char *)glGetString(GL_RENDERER);
 202     // Make a copy, at least one platform does not preserve the string beyond the call.
 203     char *glExtensions = strdup((char *)glGetString(GL_EXTENSIONS));
 204     char *eglExtensions = strdup((char *)eglQueryString(dpy, EGL_EXTENSIONS));
 205 
 206     /* find out the version, major and minor version number */
 207     char *tmpVersionStr = strdup(glVersion);
 208     int versionNumbers[2];
 209     extractVersionInfo(tmpVersionStr, versionNumbers);
 210     free(tmpVersionStr);
 211 
 212     ctxInfo->versionStr = strdup(glVersion);
 213     ctxInfo->vendorStr = strdup(glVendor);
 214     ctxInfo->rendererStr = strdup(glRenderer);
 215     ctxInfo->glExtensionStr = strdup(glExtensions);
 216     ctxInfo->glxExtensionStr = strdup(eglExtensions);
 217     ctxInfo->versionNumbers[0] = versionNumbers[0];
 218     ctxInfo->versionNumbers[1] = versionNumbers[1];
 219 
 220     ctxInfo->display = getNativeDisplayType();
 221     ctxInfo->context = context;
 222     ctxInfo->egldisplay = dpy;
 223 
 224     // cleanup
 225     free(glExtensions);
 226     free(eglExtensions);
 227 
 228     // from the wrapped_egl.c
 229     void *handle = getLibGLEShandle();
 230 
 231     /* set function pointers */
 232     ctxInfo->glActiveTexture = (PFNGLACTIVETEXTUREPROC)
 233                                GET_DLSYM(handle, "glActiveTexture");
 234     ctxInfo->glAttachShader = (PFNGLATTACHSHADERPROC)
 235                               GET_DLSYM(handle, "glAttachShader");
 236     ctxInfo->glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)
 237                                     GET_DLSYM(handle, "glBindAttribLocation");
 238     ctxInfo->glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)
 239                                  GET_DLSYM(handle, "glBindFramebuffer");
 240     ctxInfo->glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)
 241                                   GET_DLSYM(handle, "glBindRenderbuffer");
 242     ctxInfo->glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)
 243                                         GET_DLSYM(handle, "glCheckFramebufferStatus");
 244     ctxInfo->glCreateProgram = (PFNGLCREATEPROGRAMPROC)
 245                                GET_DLSYM(handle, "glCreateProgram");
 246     ctxInfo->glCreateShader = (PFNGLCREATESHADERPROC)
 247                               GET_DLSYM(handle, "glCreateShader");
 248     ctxInfo->glCompileShader = (PFNGLCOMPILESHADERPROC)
 249                                GET_DLSYM(handle, "glCompileShader");
 250     ctxInfo->glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)
 251                                GET_DLSYM(handle, "glDeleteBuffers");
 252     ctxInfo->glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)
 253                                     GET_DLSYM(handle, "glDeleteFramebuffers");
 254     ctxInfo->glDeleteProgram = (PFNGLDELETEPROGRAMPROC)
 255                                GET_DLSYM(handle, "glDeleteProgram");
 256     ctxInfo->glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)
 257                                      GET_DLSYM(handle, "glDeleteRenderbuffers");
 258     ctxInfo->glDeleteShader = (PFNGLDELETESHADERPROC)
 259                               GET_DLSYM(handle, "glDeleteShader");
 260     ctxInfo->glDetachShader = (PFNGLDETACHSHADERPROC)
 261                               GET_DLSYM(handle, "glDetachShader");
 262     ctxInfo->glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)
 263                                          GET_DLSYM(handle, "glDisableVertexAttribArray");
 264     ctxInfo->glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)
 265                                          GET_DLSYM(handle, "glEnableVertexAttribArray");
 266     ctxInfo->glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)
 267                                          GET_DLSYM(handle, "glFramebufferRenderbuffer");
 268     ctxInfo->glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)
 269                                       GET_DLSYM(handle, "glFramebufferTexture2D");
 270     ctxInfo->glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)
 271                                  GET_DLSYM(handle, "glGenFramebuffers");
 272     ctxInfo->glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)
 273                                   GET_DLSYM(handle, "glGenRenderbuffers");
 274     ctxInfo->glGetProgramiv = (PFNGLGETPROGRAMIVPROC)
 275                               GET_DLSYM(handle, "glGetProgramiv");
 276     ctxInfo->glGetShaderiv = (PFNGLGETSHADERIVPROC)
 277                              GET_DLSYM(handle, "glGetShaderiv");
 278     ctxInfo->glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)
 279                                     GET_DLSYM(handle, "glGetUniformLocation");
 280     ctxInfo->glLinkProgram = (PFNGLLINKPROGRAMPROC)
 281                              GET_DLSYM(handle, "glLinkProgram");
 282     ctxInfo->glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)
 283                                      GET_DLSYM(handle, "glRenderbufferStorage");
 284     ctxInfo->glShaderSource = (PFNGLSHADERSOURCEPROC)
 285                               GET_DLSYM(handle, "glShaderSource");
 286     ctxInfo->glUniform1f = (PFNGLUNIFORM1FPROC)
 287                            GET_DLSYM(handle, "glUniform1f");
 288     ctxInfo->glUniform2f = (PFNGLUNIFORM2FPROC)
 289                            GET_DLSYM(handle, "glUniform2f");
 290     ctxInfo->glUniform3f = (PFNGLUNIFORM3FPROC)
 291                            GET_DLSYM(handle, "glUniform3f");
 292     ctxInfo->glUniform4f = (PFNGLUNIFORM4FPROC)
 293                            GET_DLSYM(handle, "glUniform4f");
 294     ctxInfo->glUniform4fv = (PFNGLUNIFORM4FVPROC)
 295                             GET_DLSYM(handle, "glUniform4fv");
 296     ctxInfo->glUniform1i = (PFNGLUNIFORM1IPROC)
 297                            GET_DLSYM(handle, "glUniform1i");
 298     ctxInfo->glUniform2i = (PFNGLUNIFORM2IPROC)
 299                            GET_DLSYM(handle, "glUniform2i");
 300     ctxInfo->glUniform3i = (PFNGLUNIFORM3IPROC)
 301                            GET_DLSYM(handle, "glUniform3i");
 302     ctxInfo->glUniform4i = (PFNGLUNIFORM4IPROC)
 303                            GET_DLSYM(handle, "glUniform4i");
 304     ctxInfo->glUniform4iv = (PFNGLUNIFORM4IVPROC)
 305                             GET_DLSYM(handle, "glUniform4iv");
 306     ctxInfo->glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)
 307                                   GET_DLSYM(handle, "glUniformMatrix4fv");
 308     ctxInfo->glUseProgram = (PFNGLUSEPROGRAMPROC)
 309                             GET_DLSYM(handle, "glUseProgram");
 310     ctxInfo->glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)
 311                                  GET_DLSYM(handle, "glValidateProgram");
 312     ctxInfo->glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)
 313                                      GET_DLSYM(handle, "glVertexAttribPointer");
 314     ctxInfo->glGenBuffers = (PFNGLGENBUFFERSPROC)
 315                             GET_DLSYM(handle, "glGenBuffers");
 316     ctxInfo->glBindBuffer = (PFNGLBINDBUFFERPROC)
 317                             GET_DLSYM(handle, "glBindBuffer");
 318     ctxInfo->glBufferData = (PFNGLBUFFERDATAPROC)
 319                             GET_DLSYM(handle, "glBufferData");
 320     ctxInfo->glBufferSubData = (PFNGLBUFFERSUBDATAPROC)
 321                               GET_DLSYM(handle, "glBufferSubData");
 322     ctxInfo->glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)
 323                                   GET_DLSYM(handle, "glGetShaderInfoLog");
 324     ctxInfo->glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)
 325                                    GET_DLSYM(handle, "glGetProgramInfoLog");
 326     ctxInfo->glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)
 327                             GET_DLSYM(handle, "glTexImage2DMultisample");
 328     ctxInfo->glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)
 329                             GET_DLSYM(handle, "glRenderbufferStorageMultisample");
 330     ctxInfo->glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)
 331                             GET_DLSYM(handle, "glBlitFramebuffer");
 332 
 333     initState(ctxInfo);
 334     /* Releasing native resources */
 335     eglMakeCurrent(ctxInfo->egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 336     //eglDestroySurface(ctxInfo->egldisplay, surface);
 337     return ctxInfo;
 338 }
 339 
 340 
 341 
 342 //#ifdef DEBUG
 343 
 344 const char *eglErrorMsg(int err) {
 345     const char *ret;
 346     if (err == EGL_SUCCESS) {
 347         ret = "The last function succeeded without error.";
 348     } else if (err == EGL_NOT_INITIALIZED) {
 349         ret = "EGL is not initialized, or could not be initialized, for the specified EGL display connection.";
 350     } else if (err == EGL_BAD_ACCESS) {
 351         ret = "EGL cannot access a requested resource (for example a context is bound in another thread).";
 352     } else if (err == EGL_BAD_ALLOC) {
 353         ret = "EGL failed to allocate resources for the requested operation.";
 354     } else if (err == EGL_BAD_ATTRIBUTE) {
 355         ret = "An unrecognized attribute or attribute value was passed in the attribute list.";
 356     } else if (err == EGL_BAD_CONTEXT) {
 357         ret = "An EGLContext argument does not name a valid EGL rendering context.";
 358     } else if (err == EGL_BAD_CONFIG) {
 359         ret = "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
 360     } else if (err == EGL_BAD_CURRENT_SURFACE) {
 361         ret = "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid.";
 362     } else if (err == EGL_BAD_DISPLAY) {
 363         ret = "An EGLDisplay argument does not name a valid EGL display connection.";
 364     } else if (err == EGL_BAD_SURFACE) {
 365         ret = "An EGLSurface argument does not name a valid surface (window, pixel buffer or pixmap) configured for GL rendering.";
 366     } else if (err == EGL_BAD_MATCH) {
 367         ret = "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface).";
 368     } else if (err == EGL_BAD_PARAMETER) {
 369         ret = "One or more argument values are invalid.";
 370     } else if (err == EGL_BAD_NATIVE_PIXMAP) {
 371         ret = "A NativePixmapType argument does not refer to a valid native pixmap.";
 372     } else if (err == EGL_BAD_NATIVE_WINDOW) {
 373         ret = "A NativeWindowType argument does not refer to a valid native window.";
 374     } else {
 375         ret = "Unknown EGL error";
 376     }
 377     return ret;
 378 }
 379 
 380 char *printErrorExit(char *message) {
 381     EGLint err = eglGetError();
 382     char buffer[80];
 383     char *ret;
 384     if (err == EGL_SUCCESS) {
 385         ret = "The last function succeeded without error.";
 386     } else if (err == EGL_NOT_INITIALIZED) {
 387         ret = "EGL is not initialized, or could not be initialized, for the specified EGL display connection.";
 388     } else if (err == EGL_BAD_ACCESS) {
 389         ret = "EGL cannot access a requested resource (for example a context is bound in another thread).";
 390     } else if (err == EGL_BAD_ALLOC) {
 391         ret = "EGL failed to allocate resources for the requested operation.";
 392     } else if (err == EGL_BAD_ATTRIBUTE) {
 393         ret = "An unrecognized attribute or attribute value was passed in the attribute list.";
 394     } else if (err == EGL_BAD_CONTEXT) {
 395         ret = "An EGLContext argument does not name a valid EGL rendering context.";
 396     } else if (err == EGL_BAD_CONFIG) {
 397         ret = "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
 398     } else if (err == EGL_BAD_CURRENT_SURFACE) {
 399         ret = "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid.";
 400     } else if (err == EGL_BAD_DISPLAY) {
 401         ret = "An EGLDisplay argument does not name a valid EGL display connection.";
 402     } else if (err == EGL_BAD_SURFACE) {
 403         ret = "An EGLSurface argument does not name a valid surface (window, pixel buffer or pixmap) configured for GL rendering.";
 404     } else if (err == EGL_BAD_MATCH) {
 405         ret = "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface).";
 406     } else if (err == EGL_BAD_PARAMETER) {
 407         ret = "One or more argument values are invalid.";
 408     } else if (err == EGL_BAD_NATIVE_PIXMAP) {
 409         ret = "A NativePixmapType argument does not refer to a valid native pixmap.";
 410     } else if (err == EGL_BAD_NATIVE_WINDOW) {
 411         ret = "A NativeWindowType argument does not refer to a valid native window.";
 412     } else {
 413         sprintf(buffer, "unknown error code 0x%0x", err);
 414         ret = buffer;
 415     }
 416     if (message) {
 417         printf("%s\n", message);
 418     }
 419     printf("EGL ERROR: %s\n", ret);
 420     exit(1);
 421 }
 422 
 423 int printConfigAttrs(EGLint *config) {
 424     int cnt = 0;
 425     while ((*config != EGL_NONE) && (cnt < 25)) {
 426         EGLint arg = *config++;
 427         EGLint val = *config++;
 428         cnt++;
 429         printf("    ");
 430         switch (arg) {
 431             case EGL_SURFACE_TYPE:
 432                 if (val == (EGL_PBUFFER_BIT | EGL_WINDOW_BIT)) {
 433                     printf("EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT,\n");
 434                 } else if (val == (EGL_WINDOW_BIT)) {
 435                     printf("EGL_SURFACE_TYPE: EGL_WINDOW_BIT,\n");
 436                 } else if (val == (EGL_PBUFFER_BIT)) {
 437                     printf("EGL_SURFACE_TYPE: EGL_PBUFFER_BIT,\n");
 438                 } else {
 439                     printf("EGL_SURFACE_TYPE, %d,\n", val);
 440                 }
 441                 break;
 442             case EGL_BUFFER_SIZE:
 443                 printf("EGL_BUFFER_SIZE, %d,\n", val);
 444                 break;
 445             case EGL_SAMPLE_BUFFERS:
 446                 printf("EGL_SAMPLE_BUFFERS, %d,\n", val);
 447                 break;
 448             case EGL_SAMPLES:
 449                 printf("EGL_SAMPLES, %d,\n", val);
 450                 break;
 451             case EGL_DEPTH_SIZE:
 452                 printf("EGL_DEPTH_SIZE, %d,\n", val);
 453                 break;
 454             case EGL_RED_SIZE:
 455                 printf("EGL_RED_SIZE, %d,\n", val);
 456                 break;
 457             case EGL_GREEN_SIZE:
 458                 printf("EGL_GREEN_SIZE, %d,\n", val);
 459                 break;
 460             case EGL_BLUE_SIZE:
 461                 printf("EGL_BLUE_SIZE, %d,\n", val);
 462                 break;
 463             case EGL_ALPHA_SIZE:
 464                 printf("EGL_ALPHA_SIZE, %d,\n", val);
 465                 break;
 466             case EGL_LEVEL:
 467                 printf("EGL_LEVEL, %d,\n", val);
 468                 break;
 469             case EGL_NATIVE_RENDERABLE:
 470                 printf("EGL_NATIVE_RENDERABLE, %d,\n", val);
 471                 break;
 472             case EGL_STENCIL_SIZE:
 473                 printf("EGL_STENCIL_SIZE, %d,\n", val);
 474                 break;
 475             case EGL_TRANSPARENT_TYPE:
 476                 if (val == EGL_TRANSPARENT_RGB) {
 477                     printf("EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RGB,\n");
 478                 } else if (val == EGL_NONE) {
 479                     printf("EGL_TRANSPARENT_TYPE, EGL_NONE,\n");
 480                 } else {
 481                     printf("EGL_TRANSPARENT_TYPE, bad val %d\n", val);
 482                 }
 483                 break;
 484             case EGL_TRANSPARENT_RED_VALUE:
 485                 printf("EGL_TRANSPARENT_RED_VALUE, %d,\n", val);
 486                 break;
 487             case EGL_TRANSPARENT_GREEN_VALUE:
 488                 printf("EGL_TRANSPARENT_GREEN_VALUE, %d,\n", val);
 489                 break;
 490             case EGL_TRANSPARENT_BLUE_VALUE:
 491                 printf("EGL_TRANSPARENT_BLUE_VALUE, %d,\n", val);
 492                 break;
 493             case EGL_NATIVE_VISUAL_TYPE:
 494                 printf("EGL_NATIVE_VISUAL_TYPE, %d,\n", val);
 495                 break;
 496             case EGL_RENDERABLE_TYPE:
 497                 printf("EGL_RENDERABLE_TYPE, %s,\n", val == EGL_OPENGL_ES2_BIT ? "EGL_OPENGL_ES2_BIT," : "EGL_OPENGL_ES_BIT");
 498                 break;
 499             default:
 500                 printf("UNRECOGNIZED, %d, %d\n", arg, val);
 501         }
 502     }
 503     if (*config == EGL_NONE) {
 504         printf("    EGL_NONE\n");
 505     } else {
 506         printf("    *** ERROR exceeded arg limit *** \n");
 507     }
 508     return 1;
 509 }
 510 
 511 int printConfig(EGLDisplay display, EGLConfig config) {
 512 
 513     int id;
 514     eglGetConfigAttrib(display, config, EGL_CONFIG_ID, &id);
 515 
 516     int red, green, blue, alpha, depth;
 517     eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red);
 518     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green);
 519     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue);
 520     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha);
 521     eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth);
 522 
 523     int pwidth, phgt, psize;
 524     pwidth = phgt = psize =  0;
 525     eglGetConfigAttrib(display, config, EGL_MAX_PBUFFER_WIDTH, &pwidth);
 526     eglGetConfigAttrib(display, config, EGL_MAX_PBUFFER_HEIGHT, &phgt);
 527     eglGetConfigAttrib(display, config, EGL_MAX_PBUFFER_PIXELS, &psize);
 528 
 529     int sbuffers, samples;
 530     eglGetConfigAttrib(display, config, EGL_SAMPLE_BUFFERS, &sbuffers);
 531     eglGetConfigAttrib(display, config, EGL_SAMPLES, &samples);
 532 
 533     int stencil;
 534     eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencil);
 535 
 536     int surface;
 537     eglGetConfigAttrib(display, config, EGL_SURFACE_TYPE, &surface);
 538 
 539     int transparent;
 540     eglGetConfigAttrib(display, config, EGL_TRANSPARENT_TYPE, &transparent);
 541 
 542     int caveat;
 543     eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &caveat);
 544     char *strcaveat = "Normal";
 545     if (caveat == EGL_SLOW_CONFIG) {
 546         strcaveat = "Slow";
 547     } else if (caveat == EGL_NON_CONFORMANT_CONFIG) {
 548         strcaveat = "NonConf";
 549     }
 550 
 551     // humm, not documented as a supported element, but there all the same ?
 552     int rtype = -1;
 553     if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &rtype)) {
 554         printf("failed to get EGL_RENDERABLE_TYPE\n");
 555     }
 556     char rstr[5];
 557     char *rstrptr = rstr;
 558     if ((rtype & EGL_OPENGL_ES_BIT) == EGL_OPENGL_ES_BIT) {
 559         *(rstrptr++) = '1';
 560     }
 561     if ((rtype & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT) {
 562         *(rstrptr++) = '2';
 563     }
 564     if ((rtype & EGL_OPENVG_BIT) == EGL_OPENVG_BIT) {
 565         *(rstrptr++) = 'V';
 566     }
 567     if ((rtype & EGL_OPENGL_BIT) == EGL_OPENGL_BIT) {
 568         *(rstrptr++) = 'G';
 569     }
 570     *rstrptr = 0;
 571 
 572     printf("  %02d: %d%d%d%d %02d %04dx%04d %d %d,%d %d %s%s%s %s %s %s\n", id,
 573            red, green, blue, alpha, depth,
 574            pwidth, phgt, psize,
 575            sbuffers, samples,
 576            stencil,
 577            ((surface & EGL_WINDOW_BIT) == EGL_WINDOW_BIT) ? "W" : "_",
 578            ((surface & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT) ? "P" : "_",
 579            ((surface & EGL_PIXMAP_BIT) == EGL_PIXMAP_BIT) ? "X" : "_",
 580            (transparent == EGL_TRANSPARENT_RGB) ? "Trans" : "Opaqe",
 581            strcaveat,
 582            rstr
 583           );
 584 
 585     return 1;
 586 }
 587 
 588 //#endif // DEBUG