src/video/SDL_egl.c
author Gabriel Jacobo
Mon, 26 Aug 2013 14:23:18 -0300
changeset 7702 83878644c8e6
parent 7679 b1fe132bc6a4
child 7753 e4c38f17bfad
permissions -rw-r--r--
Fixes typo in EGL code (thanks jmcfarlane!)
     1 /*
     2  *  Simple DirectMedia Layer
     3  *  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4  * 
     5  *  This software is provided 'as-is', without any express or implied
     6  *  warranty.  In no event will the authors be held liable for any damages
     7  *  arising from the use of this software.
     8  * 
     9  *  Permission is granted to anyone to use this software for any purpose,
    10  *  including commercial applications, and to alter it and redistribute it
    11  *  freely, subject to the following restrictions:
    12  * 
    13  *  1. The origin of this software must not be misrepresented; you must not
    14  *     claim that you wrote the original software. If you use this software
    15  *     in a product, an acknowledgment in the product documentation would be
    16  *     appreciated but is not required.
    17  *  2. Altered source versions must be plainly marked as such, and must not be
    18  *     misrepresented as being the original software.
    19  *  3. This notice may not be removed or altered from any source distribution.
    20  */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_OPENGL_EGL
    24 
    25 #include "SDL_sysvideo.h"
    26 #include "SDL_egl.h"
    27 
    28 #define DEFAULT_EGL "libEGL.so"
    29 #define DEFAULT_OGL_ES2 "libGLESv2.so"
    30 #define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
    31 #define DEFAULT_OGL_ES "libGLESv1_CM.so"
    32 
    33 #define LOAD_FUNC(NAME) \
    34 *((void**)&_this->egl_data->NAME) = dlsym(handle, #NAME); \
    35 if (!_this->egl_data->NAME) \
    36 { \
    37     return SDL_SetError("Could not retrieve EGL function " #NAME); \
    38 }
    39     
    40 /* EGL implementation of SDL OpenGL ES support */
    41 
    42 void *
    43 SDL_EGL_GetProcAddress(_THIS, const char *proc)
    44 {
    45     static char procname[1024];
    46     void *handle;
    47     void *retval;
    48     
    49     /* eglGetProcAddress is busted on Android http://code.google.com/p/android/issues/detail?id=7681 */
    50 #if !defined(SDL_VIDEO_DRIVER_ANDROID)
    51     handle = _this->egl_data->egl_dll_handle;
    52     if (_this->egl_data->eglGetProcAddress) {
    53         retval = _this->egl_data->eglGetProcAddress(proc);
    54         if (retval) {
    55             return retval;
    56         }
    57     }
    58 #endif
    59     
    60     handle = _this->gl_config.dll_handle;
    61     #if defined(__OpenBSD__) && !defined(__ELF__)
    62     #undef dlsym(x,y);
    63     #endif
    64     retval = dlsym(handle, proc);
    65     if (!retval && strlen(proc) <= 1022) {
    66         procname[0] = '_';
    67         strcpy(procname + 1, proc);
    68         retval = dlsym(handle, procname);
    69     }
    70     return retval;
    71 }
    72 
    73 void
    74 SDL_EGL_UnloadLibrary(_THIS)
    75 {
    76     if ((_this->egl_data) && (_this->gl_config.driver_loaded)) {
    77         _this->egl_data->eglTerminate(_this->egl_data->egl_display);
    78         
    79         dlclose(_this->gl_config.dll_handle);
    80         dlclose(_this->egl_data->egl_dll_handle);
    81         
    82         SDL_free(_this->egl_data);
    83         _this->egl_data = NULL;
    84         
    85         _this->gl_config.dll_handle = NULL;
    86         _this->gl_config.driver_loaded = 0;
    87     }
    88 }
    89 
    90 int
    91 SDL_EGL_LoadLibrary(_THIS, const char *path, NativeDisplayType native_display)
    92 {
    93     void *handle;
    94     int dlopen_flags;
    95     
    96     if (_this->egl_data) {
    97         return SDL_SetError("OpenGL ES context already created");
    98     }
    99     
   100     /* Unload the old driver and reset the pointers */
   101     SDL_EGL_UnloadLibrary(_this);
   102     
   103     #ifdef RTLD_GLOBAL
   104     dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
   105     #else
   106     dlopen_flags = RTLD_LAZY;
   107     #endif
   108     handle = dlopen(path, dlopen_flags);
   109     /* Catch the case where the application isn't linked with EGL */
   110     if ((dlsym(handle, "eglChooseConfig") == NULL) && (path == NULL)) {
   111         
   112         dlclose(handle);
   113         path = getenv("SDL_VIDEO_EGL_DRIVER");
   114         if (path == NULL) {
   115             path = DEFAULT_EGL;
   116         }
   117         handle = dlopen(path, dlopen_flags);
   118     }
   119 
   120     if (handle == NULL) {
   121         return SDL_SetError("Could not load OpenGL ES/EGL library");
   122     }
   123     
   124     _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
   125     if (!_this->egl_data) {
   126         return SDL_OutOfMemory();
   127     }
   128     
   129     /* Load new function pointers */
   130     LOAD_FUNC(eglGetDisplay);
   131     LOAD_FUNC(eglInitialize);
   132     LOAD_FUNC(eglTerminate);
   133     LOAD_FUNC(eglGetProcAddress);
   134     LOAD_FUNC(eglChooseConfig);
   135     LOAD_FUNC(eglGetConfigAttrib);
   136     LOAD_FUNC(eglCreateContext);
   137     LOAD_FUNC(eglDestroyContext);
   138     LOAD_FUNC(eglCreateWindowSurface);
   139     LOAD_FUNC(eglDestroySurface);
   140     LOAD_FUNC(eglMakeCurrent);
   141     LOAD_FUNC(eglSwapBuffers);
   142     LOAD_FUNC(eglSwapInterval);
   143     LOAD_FUNC(eglWaitNative);
   144     LOAD_FUNC(eglWaitGL);
   145     
   146     _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
   147     
   148     if (!_this->egl_data->egl_display) {
   149         return SDL_SetError("Could not get EGL display");
   150     }
   151     
   152     if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
   153         return SDL_SetError("Could not initialize EGL");
   154     }
   155 
   156     _this->egl_data->egl_dll_handle = handle;
   157 
   158     path = getenv("SDL_VIDEO_GL_DRIVER");
   159     handle = dlopen(path, dlopen_flags);
   160     if ((path == NULL) | (handle == NULL)) {
   161       if (_this->gl_config.major_version > 1) {
   162           path = DEFAULT_OGL_ES2;
   163           handle = dlopen(path, dlopen_flags);
   164       } else {
   165           path = DEFAULT_OGL_ES;
   166           handle = dlopen(path, dlopen_flags);
   167           if (handle == NULL) {
   168               path = DEFAULT_OGL_ES_PVR;
   169               handle = dlopen(path, dlopen_flags);
   170           }
   171       }
   172     }
   173 
   174     if (handle == NULL) {
   175       return SDL_SetError("Could not initialize OpenGL ES library");
   176     }
   177 
   178     _this->gl_config.dll_handle = handle;
   179     _this->gl_config.driver_loaded = 1;
   180 
   181     if (path) {
   182       strncpy(_this->gl_config.driver_path, path,
   183               sizeof(_this->gl_config.driver_path) - 1);
   184     } else {
   185       strcpy(_this->gl_config.driver_path, "");
   186     }
   187     
   188     /* We need to select a config here to satisfy some video backends such as X11 */
   189     SDL_EGL_ChooseConfig(_this);
   190     
   191     return 0;
   192 }
   193 
   194 int
   195 SDL_EGL_ChooseConfig(_THIS) 
   196 {
   197     /* 64 seems nice. */
   198     EGLint attribs[64];
   199     EGLint found_configs = 0;
   200     int i;
   201     
   202     if (!_this->egl_data) {
   203         /* The EGL library wasn't loaded, SDL_GetError() should have info */
   204         return -1;
   205     }
   206   
   207     /* Get a valid EGL configuration */
   208     i = 0;
   209     attribs[i++] = EGL_RED_SIZE;
   210     attribs[i++] = _this->gl_config.red_size;
   211     attribs[i++] = EGL_GREEN_SIZE;
   212     attribs[i++] = _this->gl_config.green_size;
   213     attribs[i++] = EGL_BLUE_SIZE;
   214     attribs[i++] = _this->gl_config.blue_size;
   215     
   216     if (_this->gl_config.alpha_size) {
   217         attribs[i++] = EGL_ALPHA_SIZE;
   218         attribs[i++] = _this->gl_config.alpha_size;
   219     }
   220     
   221     if (_this->gl_config.buffer_size) {
   222         attribs[i++] = EGL_BUFFER_SIZE;
   223         attribs[i++] = _this->gl_config.buffer_size;
   224     }
   225     
   226     attribs[i++] = EGL_DEPTH_SIZE;
   227     attribs[i++] = _this->gl_config.depth_size;
   228     
   229     if (_this->gl_config.stencil_size) {
   230         attribs[i++] = EGL_STENCIL_SIZE;
   231         attribs[i++] = _this->gl_config.stencil_size;
   232     }
   233     
   234     if (_this->gl_config.multisamplebuffers) {
   235         attribs[i++] = EGL_SAMPLE_BUFFERS;
   236         attribs[i++] = _this->gl_config.multisamplebuffers;
   237     }
   238     
   239     if (_this->gl_config.multisamplesamples) {
   240         attribs[i++] = EGL_SAMPLES;
   241         attribs[i++] = _this->gl_config.multisamplesamples;
   242     }
   243     
   244     attribs[i++] = EGL_RENDERABLE_TYPE;
   245     if (_this->gl_config.major_version == 2) {
   246         attribs[i++] = EGL_OPENGL_ES2_BIT;
   247     } else {
   248         attribs[i++] = EGL_OPENGL_ES_BIT;
   249     }
   250     
   251     attribs[i++] = EGL_NONE;
   252     
   253     if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display,
   254         attribs,
   255         &_this->egl_data->egl_config, 1,
   256         &found_configs) == EGL_FALSE ||
   257         found_configs == 0) {
   258         return SDL_SetError("Couldn't find matching EGL config");
   259     }
   260     
   261     return 0;
   262 }
   263 
   264 SDL_GLContext
   265 SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
   266 {
   267     EGLint context_attrib_list[] = {
   268         EGL_CONTEXT_CLIENT_VERSION,
   269         1,
   270         EGL_NONE
   271     };
   272     
   273     EGLContext egl_context;
   274     
   275     if (!_this->egl_data) {
   276         /* The EGL library wasn't loaded, SDL_GetError() should have info */
   277         return NULL;
   278     }
   279     
   280     if (_this->gl_config.major_version) {
   281         context_attrib_list[1] = _this->gl_config.major_version;
   282     }
   283 
   284     egl_context =
   285     _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
   286                                       _this->egl_data->egl_config,
   287                                       EGL_NO_CONTEXT, context_attrib_list);
   288     
   289     if (egl_context == EGL_NO_CONTEXT) {
   290         SDL_SetError("Could not create EGL context");
   291         return NULL;
   292     }
   293     
   294     _this->egl_data->egl_swapinterval = 0;
   295     
   296     if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
   297         SDL_EGL_DeleteContext(_this, egl_context);
   298         SDL_SetError("Could not make EGL context current");
   299         return NULL;
   300     }
   301   
   302     return (SDL_GLContext) egl_context;
   303 }
   304 
   305 int
   306 SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
   307 {
   308     EGLContext egl_context = (EGLContext) context;
   309 
   310     if (!_this->egl_data) {
   311         return SDL_SetError("OpenGL not initialized");
   312     }
   313     
   314     /* The android emulator crashes badly if you try to eglMakeCurrent 
   315      * with a valid context and invalid surface, so we have to check for both here.
   316      */
   317     if (!egl_context || !egl_surface) {
   318          _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   319     }
   320     else {
   321         if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
   322             egl_surface, egl_surface, egl_context)) {
   323             return SDL_SetError("Unable to make EGL context current");
   324         }
   325     }
   326       
   327     return 0;
   328 }
   329 
   330 int
   331 SDL_EGL_SetSwapInterval(_THIS, int interval)
   332 {
   333     EGLBoolean status;
   334     
   335     if (!_this->egl_data) {
   336         return SDL_SetError("EGL not initialized");
   337     }
   338     
   339     status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval);
   340     if (status == EGL_TRUE) {
   341         _this->egl_data->egl_swapinterval = interval;
   342         return 0;
   343     }
   344     
   345     return SDL_SetError("Unable to set the EGL swap interval");
   346 }
   347 
   348 int
   349 SDL_EGL_GetSwapInterval(_THIS)
   350 {
   351     if (!_this->egl_data) {
   352         return SDL_SetError("EGL not initialized");
   353     }
   354     
   355     return _this->egl_data->egl_swapinterval;
   356 }
   357 
   358 void
   359 SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface)
   360 {
   361     _this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface);
   362 }
   363 
   364 void
   365 SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
   366 {
   367     EGLContext egl_context = (EGLContext) context;
   368 
   369     /* Clean up GLES and EGL */
   370     if (!_this->egl_data) {
   371         return;
   372     }
   373     
   374     if (!egl_context && egl_context != EGL_NO_CONTEXT) {
   375         SDL_EGL_MakeCurrent(_this, NULL, NULL);
   376         _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context);
   377     }
   378         
   379     /* FIXME: This "crappy fix" comes from the X11 code, 
   380      * it's required so you can create a GLX context, destroy it and create a EGL one */
   381     SDL_EGL_UnloadLibrary(_this);
   382 }
   383 
   384 EGLSurface *
   385 SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) 
   386 {
   387     return _this->egl_data->eglCreateWindowSurface(
   388             _this->egl_data->egl_display,
   389             _this->egl_data->egl_config,
   390             nw, NULL);
   391 }
   392 
   393 void
   394 SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) 
   395 {
   396     if (!_this->egl_data) {
   397         return;
   398     }
   399     
   400     if (egl_surface != EGL_NO_SURFACE) {
   401         _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface);
   402     }
   403 }
   404 
   405 #endif /* SDL_VIDEO_OPENGL_EGL */
   406 
   407 /* vi: set ts=4 sw=4 expandtab: */
   408