src/video/x11/SDL_x11opengles.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 09 Apr 2012 23:55:43 -0400
changeset 6305 601b0e251822
parent 6188 e82023802002
child 6368 fcbbd0e2da5e
permissions -rwxr-xr-x
SDL_ExitProcess() was ignoring exit code parameter.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_DRIVER_X11 && SDL_VIDEO_OPENGL_ES
    24 
    25 #include "SDL_x11video.h"
    26 #include "SDL_x11opengles.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->gles_data->NAME) = dlsym(handle, #NAME); \
    35 	if (!_this->gles_data->NAME) \
    36 	{ \
    37 		SDL_SetError("Could not retrieve EGL function " #NAME); \
    38 		return -1; \
    39 	}
    40 
    41 /* GLES implementation of SDL OpenGL support */
    42 
    43 void *
    44 X11_GLES_GetProcAddress(_THIS, const char *proc)
    45 {
    46     static char procname[1024];
    47     void *handle;
    48     void *retval;
    49 
    50     handle = _this->gles_data->egl_dll_handle;
    51     if (_this->gles_data->eglGetProcAddress) {
    52         retval = _this->gles_data->eglGetProcAddress(proc);
    53         if (retval) {
    54             return retval;
    55         }
    56     }
    57     
    58     handle = _this->gl_config.dll_handle;
    59 #if defined(__OpenBSD__) && !defined(__ELF__)
    60 #undef dlsym(x,y);
    61 #endif
    62     retval = dlsym(handle, proc);
    63     if (!retval && strlen(proc) <= 1022) {
    64         procname[0] = '_';
    65         strcpy(procname + 1, proc);
    66         retval = dlsym(handle, procname);
    67     }
    68     return retval;
    69 }
    70 
    71 void
    72 X11_GLES_UnloadLibrary(_THIS)
    73 {
    74     if (_this->gl_config.driver_loaded) {
    75         _this->gles_data->eglTerminate(_this->gles_data->egl_display);
    76 
    77         dlclose(_this->gl_config.dll_handle);
    78         dlclose(_this->gles_data->egl_dll_handle);
    79 
    80         _this->gles_data->eglGetProcAddress = NULL;
    81         _this->gles_data->eglChooseConfig = NULL;
    82         _this->gles_data->eglCreateContext = NULL;
    83         _this->gles_data->eglCreateWindowSurface = NULL;
    84         _this->gles_data->eglDestroyContext = NULL;
    85         _this->gles_data->eglDestroySurface = NULL;
    86         _this->gles_data->eglMakeCurrent = NULL;
    87         _this->gles_data->eglSwapBuffers = NULL;
    88         _this->gles_data->eglGetDisplay = NULL;
    89         _this->gles_data->eglTerminate = NULL;
    90 
    91         _this->gl_config.dll_handle = NULL;
    92         _this->gl_config.driver_loaded = 0;
    93     }
    94 }
    95 
    96 int
    97 X11_GLES_LoadLibrary(_THIS, const char *path)
    98 {
    99     void *handle;
   100     int dlopen_flags;
   101 
   102     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   103 
   104     if (_this->gles_data->egl_active) {
   105         SDL_SetError("OpenGL ES context already created");
   106         return -1;
   107     }
   108 #ifdef RTLD_GLOBAL
   109     dlopen_flags = RTLD_LAZY | RTLD_GLOBAL;
   110 #else
   111     dlopen_flags = RTLD_LAZY;
   112 #endif
   113     handle = dlopen(path, dlopen_flags);
   114     /* Catch the case where the application isn't linked with EGL */
   115     if ((dlsym(handle, "eglChooseConfig") == NULL) && (path == NULL)) {
   116 
   117         dlclose(handle);
   118         path = getenv("SDL_VIDEO_GL_DRIVER");
   119         if (path == NULL) {
   120             path = DEFAULT_EGL;
   121         }
   122         handle = dlopen(path, dlopen_flags);
   123     }
   124 
   125     if (handle == NULL) {
   126         SDL_SetError("Could not load OpenGL ES/EGL library");
   127         return -1;
   128     }
   129 
   130     /* Unload the old driver and reset the pointers */
   131     X11_GLES_UnloadLibrary(_this);
   132 
   133     /* Load new function pointers */
   134     LOAD_FUNC(eglGetDisplay);
   135     LOAD_FUNC(eglInitialize);
   136     LOAD_FUNC(eglTerminate);
   137     LOAD_FUNC(eglGetProcAddress);
   138     LOAD_FUNC(eglChooseConfig);
   139     LOAD_FUNC(eglGetConfigAttrib);
   140     LOAD_FUNC(eglCreateContext);
   141     LOAD_FUNC(eglDestroyContext);
   142     LOAD_FUNC(eglCreateWindowSurface);
   143     LOAD_FUNC(eglDestroySurface);
   144     LOAD_FUNC(eglMakeCurrent);
   145     LOAD_FUNC(eglSwapBuffers);
   146     LOAD_FUNC(eglSwapInterval);
   147 
   148     _this->gles_data->egl_display =
   149         _this->gles_data->eglGetDisplay((NativeDisplayType) data->display);
   150 
   151     if (!_this->gles_data->egl_display) {
   152         SDL_SetError("Could not get EGL display");
   153         return -1;
   154     }
   155 
   156     if (_this->gles_data->
   157         eglInitialize(_this->gles_data->egl_display, NULL,
   158                       NULL) != EGL_TRUE) {
   159         SDL_SetError("Could not initialize EGL");
   160         return -1;
   161     }
   162 
   163     _this->gles_data->egl_dll_handle = handle;
   164 
   165     path = getenv("SDL_VIDEO_GL_DRIVER");
   166     handle = dlopen(path, dlopen_flags);
   167     if ((path == NULL) | (handle == NULL)) {
   168         if (_this->gl_config.major_version > 1) {
   169             path = DEFAULT_OGL_ES2;
   170             handle = dlopen(path, dlopen_flags);
   171         } else {
   172             path = DEFAULT_OGL_ES;
   173             handle = dlopen(path, dlopen_flags);
   174             if (handle == NULL) {
   175                 path = DEFAULT_OGL_ES_PVR;
   176                 handle = dlopen(path, dlopen_flags);
   177             }
   178         }
   179     }
   180 
   181     if (handle == NULL) {
   182         SDL_SetError("Could not initialize OpenGL ES library");
   183         return -1;
   184     }
   185 
   186     _this->gl_config.dll_handle = handle;
   187     _this->gl_config.driver_loaded = 1;
   188 
   189     if (path) {
   190         strncpy(_this->gl_config.driver_path, path,
   191                 sizeof(_this->gl_config.driver_path) - 1);
   192     } else {
   193         strcpy(_this->gl_config.driver_path, "");
   194     }
   195     return 0;
   196 }
   197 
   198 XVisualInfo *
   199 X11_GLES_GetVisual(_THIS, Display * display, int screen)
   200 {
   201     /* 64 seems nice. */
   202     EGLint attribs[64];
   203     EGLint found_configs = 0;
   204     VisualID visual_id;
   205     int i;
   206 
   207     /* load the gl driver from a default path */
   208     if (!_this->gl_config.driver_loaded) {
   209         /* no driver has been loaded, use default (ourselves) */
   210         if (X11_GLES_LoadLibrary(_this, NULL) < 0) {
   211             return NULL;
   212         }
   213     }
   214 
   215     i = 0;
   216     attribs[i++] = EGL_RED_SIZE;
   217     attribs[i++] = _this->gl_config.red_size;
   218     attribs[i++] = EGL_GREEN_SIZE;
   219     attribs[i++] = _this->gl_config.green_size;
   220     attribs[i++] = EGL_BLUE_SIZE;
   221     attribs[i++] = _this->gl_config.blue_size;
   222 
   223     if (_this->gl_config.alpha_size) {
   224         attribs[i++] = EGL_ALPHA_SIZE;
   225         attribs[i++] = _this->gl_config.alpha_size;
   226     }
   227 
   228     if (_this->gl_config.buffer_size) {
   229         attribs[i++] = EGL_BUFFER_SIZE;
   230         attribs[i++] = _this->gl_config.buffer_size;
   231     }
   232 
   233     attribs[i++] = EGL_DEPTH_SIZE;
   234     attribs[i++] = _this->gl_config.depth_size;
   235 
   236     if (_this->gl_config.stencil_size) {
   237         attribs[i++] = EGL_STENCIL_SIZE;
   238         attribs[i++] = _this->gl_config.stencil_size;
   239     }
   240 
   241     if (_this->gl_config.multisamplebuffers) {
   242         attribs[i++] = EGL_SAMPLE_BUFFERS;
   243         attribs[i++] = _this->gl_config.multisamplebuffers;
   244     }
   245 
   246     if (_this->gl_config.multisamplesamples) {
   247         attribs[i++] = EGL_SAMPLES;
   248         attribs[i++] = _this->gl_config.multisamplesamples;
   249     }
   250 
   251     attribs[i++] = EGL_RENDERABLE_TYPE;
   252     if (_this->gl_config.major_version == 2) {
   253         attribs[i++] = EGL_OPENGL_ES2_BIT;
   254     } else {
   255         attribs[i++] = EGL_OPENGL_ES_BIT;
   256     }
   257 
   258     attribs[i++] = EGL_NONE;
   259 
   260     if (_this->gles_data->eglChooseConfig(_this->gles_data->egl_display,
   261                                           attribs,
   262                                           &_this->gles_data->egl_config, 1,
   263                                           &found_configs) == EGL_FALSE ||
   264         found_configs == 0) {
   265         SDL_SetError("Couldn't find matching EGL config");
   266         return NULL;
   267     }
   268 
   269     if (_this->gles_data->eglGetConfigAttrib(_this->gles_data->egl_display,
   270                                              _this->gles_data->egl_config,
   271                                              EGL_NATIVE_VISUAL_ID,
   272                                              (EGLint *) & visual_id) ==
   273         EGL_FALSE || !visual_id) {
   274         /* Use the default visual when all else fails */
   275         XVisualInfo vi_in;
   276         int out_count;
   277         vi_in.screen = screen;
   278 
   279         _this->gles_data->egl_visualinfo = XGetVisualInfo(display,
   280                                                           VisualScreenMask,
   281                                                           &vi_in, &out_count);
   282     } else {
   283         XVisualInfo vi_in;
   284         int out_count;
   285 
   286         vi_in.screen = screen;
   287         vi_in.visualid = visual_id;
   288         _this->gles_data->egl_visualinfo = XGetVisualInfo(display,
   289                                                           VisualScreenMask |
   290                                                           VisualIDMask,
   291                                                           &vi_in, &out_count);
   292     }
   293 
   294     return _this->gles_data->egl_visualinfo;
   295 }
   296 
   297 SDL_GLContext
   298 X11_GLES_CreateContext(_THIS, SDL_Window * window)
   299 {
   300     EGLint context_attrib_list[] = {
   301         EGL_CONTEXT_CLIENT_VERSION,
   302         1,
   303         EGL_NONE
   304     };
   305 
   306     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   307     Display *display = data->videodata->display;
   308     SDL_GLContext context = 1;
   309 
   310     XSync(display, False);
   311 
   312     if (_this->gl_config.major_version) {
   313         context_attrib_list[1] = _this->gl_config.major_version;
   314     }
   315 
   316     _this->gles_data->egl_context =
   317         _this->gles_data->eglCreateContext(_this->gles_data->egl_display,
   318                                            _this->gles_data->egl_config,
   319                                            EGL_NO_CONTEXT, context_attrib_list);
   320     XSync(display, False);
   321 
   322     if (_this->gles_data->egl_context == EGL_NO_CONTEXT) {
   323         SDL_SetError("Could not create EGL context");
   324         return NULL;
   325     }
   326 
   327     _this->gles_data->egl_active = 1;
   328     _this->gles_data->egl_swapinterval = 0;
   329 
   330     if (X11_GLES_MakeCurrent(_this, window, context) < 0) {
   331         X11_GLES_DeleteContext(_this, context);
   332         return NULL;
   333     }
   334 
   335     return context;
   336 }
   337 
   338 int
   339 X11_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   340 {
   341     int retval;
   342 
   343 //    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   344 //    Display *display = data->videodata->display;
   345 
   346     retval = 1;
   347     if (!_this->gles_data->eglMakeCurrent(_this->gles_data->egl_display,
   348                                           _this->gles_data->egl_surface,
   349                                           _this->gles_data->egl_surface,
   350                                           _this->gles_data->egl_context)) {
   351         SDL_SetError("Unable to make EGL context current");
   352         retval = -1;
   353     }
   354 //    XSync(display, False);
   355 
   356     return (retval);
   357 }
   358 
   359 int
   360 X11_GLES_SetSwapInterval(_THIS, int interval)
   361 {
   362     if (_this->gles_data->egl_active != 1) {
   363         SDL_SetError("OpenGL ES context not active");
   364         return -1;
   365     }
   366 
   367     EGLBoolean status;
   368     status = _this->gles_data->eglSwapInterval(_this->gles_data->egl_display, interval);
   369     if (status == EGL_TRUE) {
   370         _this->gles_data->egl_swapinterval = interval;
   371         return 0; 
   372     }
   373 
   374     SDL_SetError("Unable to set the EGL swap interval");
   375     return -1;
   376 }
   377 
   378 int
   379 X11_GLES_GetSwapInterval(_THIS)
   380 {
   381     if (_this->gles_data->egl_active != 1) {
   382         SDL_SetError("OpenGL ES context not active");
   383         return -1;
   384     }
   385 
   386     return _this->gles_data->egl_swapinterval;
   387 }
   388 
   389 void
   390 X11_GLES_SwapWindow(_THIS, SDL_Window * window)
   391 {
   392     _this->gles_data->eglSwapBuffers(_this->gles_data->egl_display,
   393                                      _this->gles_data->egl_surface);
   394 }
   395 
   396 void
   397 X11_GLES_DeleteContext(_THIS, SDL_GLContext context)
   398 {
   399     /* Clean up GLES and EGL */
   400     if (_this->gles_data->egl_context != EGL_NO_CONTEXT ||
   401         _this->gles_data->egl_surface != EGL_NO_SURFACE) {
   402         _this->gles_data->eglMakeCurrent(_this->gles_data->egl_display,
   403                                          EGL_NO_SURFACE, EGL_NO_SURFACE,
   404                                          EGL_NO_CONTEXT);
   405 
   406         if (_this->gles_data->egl_context != EGL_NO_CONTEXT) {
   407             _this->gles_data->eglDestroyContext(_this->gles_data->egl_display,
   408                                                 _this->gles_data->
   409                                                 egl_context);
   410             _this->gles_data->egl_context = EGL_NO_CONTEXT;
   411         }
   412 
   413         if (_this->gles_data->egl_surface != EGL_NO_SURFACE) {
   414             _this->gles_data->eglDestroySurface(_this->gles_data->egl_display,
   415                                                 _this->gles_data->
   416                                                 egl_surface);
   417             _this->gles_data->egl_surface = EGL_NO_SURFACE;
   418         }
   419     }
   420     _this->gles_data->egl_active = 0;
   421 
   422 /* crappy fix */
   423     X11_GLES_UnloadLibrary(_this);
   424 
   425 }
   426 
   427 #endif /* SDL_VIDEO_DRIVER_X11 && SDL_VIDEO_OPENGL_ES */
   428 
   429 /* vi: set ts=4 sw=4 expandtab: */