src/video/SDL_egl.c
changeset 7659 ac4ce59c40e7
child 7679 b1fe132bc6a4
equal deleted inserted replaced
7658:4033ba4fcc31 7659:ac4ce59c40e7
       
     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     if (!_this->egl_data) {
       
   309         return SDL_SetError("OpenGL not initialized");
       
   310     }
       
   311     
       
   312     EGLContext egl_context = (EGLContext) context;
       
   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     if (_this->egl_data) {
       
   334         return SDL_SetError("OpenGL ES context not active");
       
   335     }
       
   336     
       
   337     EGLBoolean status;
       
   338     status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval);
       
   339     if (status == EGL_TRUE) {
       
   340         _this->egl_data->egl_swapinterval = interval;
       
   341         return 0;
       
   342     }
       
   343     
       
   344     return SDL_SetError("Unable to set the EGL swap interval");
       
   345 }
       
   346 
       
   347 int
       
   348 SDL_EGL_GetSwapInterval(_THIS)
       
   349 {
       
   350     if (_this->egl_data) {
       
   351         return SDL_SetError("OpenGL ES context not active");
       
   352     }
       
   353     
       
   354     return _this->egl_data->egl_swapinterval;
       
   355 }
       
   356 
       
   357 void
       
   358 SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface)
       
   359 {
       
   360     _this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface);
       
   361 }
       
   362 
       
   363 void
       
   364 SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
       
   365 {
       
   366     /* Clean up GLES and EGL */
       
   367     if (!_this->egl_data) {
       
   368         return;
       
   369     }
       
   370     
       
   371     EGLContext egl_context = (EGLContext) context;
       
   372     
       
   373     if (!egl_context && egl_context != EGL_NO_CONTEXT) {
       
   374         SDL_EGL_MakeCurrent(_this, NULL, NULL);
       
   375         _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context);
       
   376     }
       
   377         
       
   378     /* FIXME: This "crappy fix" comes from the X11 code, 
       
   379      * it's required so you can create a GLX context, destroy it and create a EGL one */
       
   380     SDL_EGL_UnloadLibrary(_this);
       
   381 }
       
   382 
       
   383 EGLSurface *
       
   384 SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) 
       
   385 {
       
   386     return _this->egl_data->eglCreateWindowSurface(
       
   387             _this->egl_data->egl_display,
       
   388             _this->egl_data->egl_config,
       
   389             nw, NULL);
       
   390 }
       
   391 
       
   392 void
       
   393 SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) 
       
   394 {
       
   395     if (!_this->egl_data) {
       
   396         return;
       
   397     }
       
   398     
       
   399     if (egl_surface != EGL_NO_SURFACE) {
       
   400         _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface);
       
   401     }
       
   402 }
       
   403 
       
   404 #endif /* SDL_VIDEO_OPENGL_EGL */
       
   405 
       
   406 /* vi: set ts=4 sw=4 expandtab: */
       
   407