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