src/video/SDL_egl.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sun, 21 Jun 2015 17:33:46 +0200
changeset 9771 30a317c4af6c
parent 9637 adf81fe554b9
child 9772 ef27c10db4bf
permissions -rw-r--r--
Fixed crash if initialization of EGL failed but was tried again later.

The internal function SDL_EGL_LoadLibrary() did not delete and remove a mostly
uninitialized data structure if loading the library first failed. A later try to
use EGL then skipped initialization and assumed it was previously successful
because the data structure now already existed. This led to at least one crash
in the internal function SDL_EGL_ChooseConfig() because a NULL pointer was
dereferenced to make a call to eglBindAPI().
gabomdq@7659
     1
/*
gabomdq@7659
     2
 *  Simple DirectMedia Layer
slouken@9619
     3
 *  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
gabomdq@7659
     4
 * 
gabomdq@7659
     5
 *  This software is provided 'as-is', without any express or implied
gabomdq@7659
     6
 *  warranty.  In no event will the authors be held liable for any damages
gabomdq@7659
     7
 *  arising from the use of this software.
gabomdq@7659
     8
 * 
gabomdq@7659
     9
 *  Permission is granted to anyone to use this software for any purpose,
gabomdq@7659
    10
 *  including commercial applications, and to alter it and redistribute it
gabomdq@7659
    11
 *  freely, subject to the following restrictions:
gabomdq@7659
    12
 * 
gabomdq@7659
    13
 *  1. The origin of this software must not be misrepresented; you must not
gabomdq@7659
    14
 *     claim that you wrote the original software. If you use this software
gabomdq@7659
    15
 *     in a product, an acknowledgment in the product documentation would be
gabomdq@7659
    16
 *     appreciated but is not required.
gabomdq@7659
    17
 *  2. Altered source versions must be plainly marked as such, and must not be
gabomdq@7659
    18
 *     misrepresented as being the original software.
gabomdq@7659
    19
 *  3. This notice may not be removed or altered from any source distribution.
gabomdq@7659
    20
 */
icculus@8093
    21
#include "../SDL_internal.h"
gabomdq@7659
    22
gabomdq@7659
    23
#if SDL_VIDEO_OPENGL_EGL
gabomdq@7659
    24
slouken@8734
    25
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
slouken@8734
    26
#include "../core/windows/SDL_windows.h"
slouken@8734
    27
#endif
slouken@8734
    28
gabomdq@7659
    29
#include "SDL_sysvideo.h"
gabomdq@8021
    30
#include "SDL_egl_c.h"
gabomdq@8021
    31
#include "SDL_loadso.h"
gabomdq@8021
    32
#include "SDL_hints.h"
gabomdq@7782
    33
slime73@9595
    34
#ifdef EGL_KHR_create_context
slime73@9595
    35
/* EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension. */
slime73@9595
    36
#ifndef EGL_OPENGL_ES3_BIT_KHR
slime73@9595
    37
#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
slime73@9595
    38
#endif
slime73@9595
    39
#endif /* EGL_KHR_create_context */
slime73@9595
    40
gabomdq@7753
    41
#if SDL_VIDEO_DRIVER_RPI
gabomdq@7782
    42
/* Raspbian places the OpenGL ES/EGL binaries in a non standard path */
gabomdq@7753
    43
#define DEFAULT_EGL "/opt/vc/lib/libEGL.so"
gabomdq@7753
    44
#define DEFAULT_OGL_ES2 "/opt/vc/lib/libGLESv2.so"
gabomdq@7753
    45
#define DEFAULT_OGL_ES_PVR "/opt/vc/lib/libGLES_CM.so"
gabomdq@7753
    46
#define DEFAULT_OGL_ES "/opt/vc/lib/libGLESv1_CM.so"
gabomdq@7782
    47
slouken@9164
    48
#elif SDL_VIDEO_DRIVER_ANDROID || SDL_VIDEO_DRIVER_VIVANTE
gabomdq@7782
    49
/* Android */
gabomdq@7782
    50
#define DEFAULT_EGL "libEGL.so"
gabomdq@7782
    51
#define DEFAULT_OGL_ES2 "libGLESv2.so"
gabomdq@7782
    52
#define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
gabomdq@7782
    53
#define DEFAULT_OGL_ES "libGLESv1_CM.so"
gabomdq@7782
    54
dludwig@8545
    55
#elif SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
gabomdq@8021
    56
/* EGL AND OpenGL ES support via ANGLE */
gabomdq@8021
    57
#define DEFAULT_EGL "libEGL.dll"
gabomdq@8021
    58
#define DEFAULT_OGL_ES2 "libGLESv2.dll"
gabomdq@8021
    59
#define DEFAULT_OGL_ES_PVR "libGLES_CM.dll"
gabomdq@8021
    60
#define DEFAULT_OGL_ES "libGLESv1_CM.dll"
gabomdq@8021
    61
gabomdq@7753
    62
#else
gabomdq@7782
    63
/* Desktop Linux */
gabomdq@8062
    64
#define DEFAULT_OGL "libGL.so.1"
gabomdq@7753
    65
#define DEFAULT_EGL "libEGL.so.1"
gabomdq@7753
    66
#define DEFAULT_OGL_ES2 "libGLESv2.so.2"
gabomdq@7753
    67
#define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
gabomdq@7753
    68
#define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
gabomdq@7753
    69
#endif /* SDL_VIDEO_DRIVER_RPI */
gabomdq@7659
    70
gabomdq@7659
    71
#define LOAD_FUNC(NAME) \
slouken@9162
    72
_this->egl_data->NAME = SDL_LoadFunction(_this->egl_data->dll_handle, #NAME); \
gabomdq@7659
    73
if (!_this->egl_data->NAME) \
gabomdq@7659
    74
{ \
philipp@9771
    75
    SDL_EGL_UnloadLibrary(_this); \
gabomdq@7659
    76
    return SDL_SetError("Could not retrieve EGL function " #NAME); \
gabomdq@7659
    77
}
gabomdq@7659
    78
    
gabomdq@7659
    79
/* EGL implementation of SDL OpenGL ES support */
slouken@8976
    80
#ifdef EGL_KHR_create_context        
knut@8962
    81
static int SDL_EGL_HasExtension(_THIS, const char *ext)
knut@8962
    82
{
knut@8962
    83
    int i;
knut@8962
    84
    int len = 0;
knut@8962
    85
    int ext_len;
knut@8962
    86
    const char *exts;
knut@8962
    87
    const char *ext_word;
knut@8962
    88
knut@8962
    89
    ext_len = SDL_strlen(ext);
knut@8962
    90
    exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
knut@8962
    91
slime73@9595
    92
    if (exts) {
knut@8962
    93
        ext_word = exts;
knut@8962
    94
slime73@9595
    95
        for (i = 0; exts[i] != 0; i++) {
slime73@9595
    96
            if (exts[i] == ' ') {
slime73@9595
    97
                if (ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
knut@8962
    98
                    return 1;
knut@8962
    99
                }
knut@8962
   100
knut@8962
   101
                len = 0;
knut@8962
   102
                ext_word = &exts[i + 1];
slime73@9595
   103
            } else {
knut@8962
   104
                len++;
knut@8962
   105
            }
knut@8962
   106
        }
knut@8962
   107
    }
knut@8962
   108
knut@8962
   109
    return 0;
knut@8962
   110
}
slouken@8976
   111
#endif /* EGL_KHR_create_context */
gabomdq@7659
   112
gabomdq@7659
   113
void *
gabomdq@7659
   114
SDL_EGL_GetProcAddress(_THIS, const char *proc)
gabomdq@7659
   115
{
gabomdq@7659
   116
    static char procname[1024];
gabomdq@7659
   117
    void *retval;
gabomdq@7659
   118
    
gabomdq@7659
   119
    /* eglGetProcAddress is busted on Android http://code.google.com/p/android/issues/detail?id=7681 */
brandon@8753
   120
#if !defined(SDL_VIDEO_DRIVER_ANDROID) && !defined(SDL_VIDEO_DRIVER_MIR) 
gabomdq@7659
   121
    if (_this->egl_data->eglGetProcAddress) {
gabomdq@7659
   122
        retval = _this->egl_data->eglGetProcAddress(proc);
gabomdq@7659
   123
        if (retval) {
gabomdq@7659
   124
            return retval;
gabomdq@7659
   125
        }
gabomdq@7659
   126
    }
gabomdq@7659
   127
#endif
gabomdq@7659
   128
    
gabomdq@8021
   129
    retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, proc);
gabomdq@8021
   130
    if (!retval && SDL_strlen(proc) <= 1022) {
gabomdq@7659
   131
        procname[0] = '_';
gabomdq@8021
   132
        SDL_strlcpy(procname + 1, proc, 1022);
gabomdq@8021
   133
        retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, procname);
gabomdq@7659
   134
    }
gabomdq@7659
   135
    return retval;
gabomdq@7659
   136
}
gabomdq@7659
   137
gabomdq@7659
   138
void
gabomdq@7659
   139
SDL_EGL_UnloadLibrary(_THIS)
gabomdq@7659
   140
{
slouken@7865
   141
    if (_this->egl_data) {
slouken@7865
   142
        if (_this->egl_data->egl_display) {
slouken@7865
   143
            _this->egl_data->eglTerminate(_this->egl_data->egl_display);
slouken@7865
   144
            _this->egl_data->egl_display = NULL;
slouken@7865
   145
        }
slouken@7865
   146
gabomdq@8021
   147
        if (_this->egl_data->dll_handle) {
gabomdq@8021
   148
            SDL_UnloadObject(_this->egl_data->dll_handle);
gabomdq@8021
   149
            _this->egl_data->dll_handle = NULL;
slouken@7865
   150
        }
slouken@7865
   151
        if (_this->egl_data->egl_dll_handle) {
gabomdq@8021
   152
            SDL_UnloadObject(_this->egl_data->egl_dll_handle);
slouken@7865
   153
            _this->egl_data->egl_dll_handle = NULL;
slouken@7865
   154
        }
gabomdq@7659
   155
        
gabomdq@7659
   156
        SDL_free(_this->egl_data);
gabomdq@7659
   157
        _this->egl_data = NULL;
gabomdq@7659
   158
    }
gabomdq@7659
   159
}
gabomdq@7659
   160
gabomdq@7659
   161
int
gabomdq@7753
   162
SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display)
gabomdq@7659
   163
{
gabomdq@8021
   164
    void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
gabomdq@8021
   165
    char *path = NULL;
dludwig@8545
   166
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
gabomdq@8021
   167
    const char *d3dcompiler;
gabomdq@8021
   168
#endif
gabomdq@8021
   169
gabomdq@7659
   170
    if (_this->egl_data) {
gabomdq@7659
   171
        return SDL_SetError("OpenGL ES context already created");
gabomdq@7659
   172
    }
slouken@7865
   173
slouken@7865
   174
    _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
slouken@7865
   175
    if (!_this->egl_data) {
slouken@7865
   176
        return SDL_OutOfMemory();
slouken@7865
   177
    }
slouken@7865
   178
dludwig@8545
   179
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
gabomdq@8021
   180
    d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER);
gabomdq@8021
   181
    if (!d3dcompiler) {
slouken@8733
   182
        if (WIN_IsWindowsVistaOrGreater()) {
slouken@8733
   183
            d3dcompiler = "d3dcompiler_46.dll";
slouken@8733
   184
        } else {
slouken@8740
   185
            d3dcompiler = "d3dcompiler_43.dll";
slouken@8733
   186
        }
gabomdq@8021
   187
    }
gabomdq@8021
   188
    if (SDL_strcasecmp(d3dcompiler, "none") != 0) {
gabomdq@8021
   189
        SDL_LoadObject(d3dcompiler);
gabomdq@8021
   190
    }
slouken@7865
   191
#endif
slouken@7865
   192
gabomdq@7753
   193
    /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
gabomdq@8021
   194
    path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
gabomdq@8021
   195
    if (path != NULL) {
gabomdq@8021
   196
        egl_dll_handle = SDL_LoadObject(path);
gabomdq@8021
   197
    }
gabomdq@8021
   198
gabomdq@8021
   199
    if (egl_dll_handle == NULL) {
slime73@9595
   200
        if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
gabomdq@8062
   201
            if (_this->gl_config.major_version > 1) {
gabomdq@8062
   202
                path = DEFAULT_OGL_ES2;
gabomdq@8062
   203
                egl_dll_handle = SDL_LoadObject(path);
slime73@9595
   204
            } else {
gabomdq@8062
   205
                path = DEFAULT_OGL_ES;
gabomdq@8062
   206
                egl_dll_handle = SDL_LoadObject(path);
gabomdq@8062
   207
                if (egl_dll_handle == NULL) {
gabomdq@8062
   208
                    path = DEFAULT_OGL_ES_PVR;
gabomdq@8062
   209
                    egl_dll_handle = SDL_LoadObject(path);
gabomdq@8062
   210
                }
gabomdq@8062
   211
            }
gabomdq@8062
   212
        }
gabomdq@8062
   213
#ifdef DEFAULT_OGL         
gabomdq@8062
   214
        else {
gabomdq@8062
   215
            path = DEFAULT_OGL;
gabomdq@8021
   216
            egl_dll_handle = SDL_LoadObject(path);
gabomdq@8021
   217
        }
gabomdq@8062
   218
#endif        
gabomdq@7753
   219
    }
slouken@7865
   220
    _this->egl_data->egl_dll_handle = egl_dll_handle;
gabomdq@7753
   221
gabomdq@7753
   222
    if (egl_dll_handle == NULL) {
philipp@9771
   223
        SDL_EGL_UnloadLibrary(_this);
gabomdq@8062
   224
        return SDL_SetError("Could not initialize OpenGL / GLES library");
gabomdq@7753
   225
    }
gabomdq@8021
   226
gabomdq@7753
   227
    /* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */
gabomdq@8021
   228
    if (egl_path != NULL) {
gabomdq@8021
   229
        dll_handle = SDL_LoadObject(egl_path);
gabomdq@8021
   230
    }   
gabomdq@8105
   231
    /* Try loading a EGL symbol, if it does not work try the default library paths */
gabomdq@8872
   232
    if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
gabomdq@8021
   233
        if (dll_handle != NULL) {
gabomdq@8021
   234
            SDL_UnloadObject(dll_handle);
gabomdq@8021
   235
        }
gabomdq@8021
   236
        path = SDL_getenv("SDL_VIDEO_EGL_DRIVER");
gabomdq@7659
   237
        if (path == NULL) {
gabomdq@7659
   238
            path = DEFAULT_EGL;
gabomdq@7659
   239
        }
gabomdq@8021
   240
        dll_handle = SDL_LoadObject(path);
gabomdq@8872
   241
        if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
gabomdq@8872
   242
            if (dll_handle != NULL) {
gabomdq@8872
   243
                SDL_UnloadObject(dll_handle);
gabomdq@8872
   244
            }
philipp@9771
   245
            SDL_EGL_UnloadLibrary(_this);
gabomdq@8021
   246
            return SDL_SetError("Could not load EGL library");
gabomdq@8021
   247
        }
gabomdq@8763
   248
        SDL_ClearError();
gabomdq@7753
   249
    }
slouken@7865
   250
gabomdq@8021
   251
    _this->egl_data->dll_handle = dll_handle;
gabomdq@7659
   252
gabomdq@7659
   253
    /* Load new function pointers */
gabomdq@7659
   254
    LOAD_FUNC(eglGetDisplay);
gabomdq@7659
   255
    LOAD_FUNC(eglInitialize);
gabomdq@7659
   256
    LOAD_FUNC(eglTerminate);
gabomdq@7659
   257
    LOAD_FUNC(eglGetProcAddress);
gabomdq@7659
   258
    LOAD_FUNC(eglChooseConfig);
gabomdq@7659
   259
    LOAD_FUNC(eglGetConfigAttrib);
gabomdq@7659
   260
    LOAD_FUNC(eglCreateContext);
gabomdq@7659
   261
    LOAD_FUNC(eglDestroyContext);
gabomdq@7659
   262
    LOAD_FUNC(eglCreateWindowSurface);
gabomdq@7659
   263
    LOAD_FUNC(eglDestroySurface);
gabomdq@7659
   264
    LOAD_FUNC(eglMakeCurrent);
gabomdq@7659
   265
    LOAD_FUNC(eglSwapBuffers);
gabomdq@7659
   266
    LOAD_FUNC(eglSwapInterval);
gabomdq@7659
   267
    LOAD_FUNC(eglWaitNative);
gabomdq@7659
   268
    LOAD_FUNC(eglWaitGL);
gabomdq@8062
   269
    LOAD_FUNC(eglBindAPI);
knut@8962
   270
    LOAD_FUNC(eglQueryString);
gabomdq@7659
   271
    
dludwig@8663
   272
#if !defined(__WINRT__)
gabomdq@7659
   273
    _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
gabomdq@7659
   274
    if (!_this->egl_data->egl_display) {
philipp@9771
   275
        SDL_EGL_UnloadLibrary(_this);
gabomdq@7659
   276
        return SDL_SetError("Could not get EGL display");
gabomdq@7659
   277
    }
gabomdq@7659
   278
    
gabomdq@7659
   279
    if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
philipp@9771
   280
        SDL_EGL_UnloadLibrary(_this);
gabomdq@7659
   281
        return SDL_SetError("Could not initialize EGL");
gabomdq@7659
   282
    }
dludwig@8663
   283
#endif
gabomdq@7659
   284
gabomdq@7659
   285
    _this->gl_config.driver_loaded = 1;
gabomdq@7659
   286
gabomdq@7659
   287
    if (path) {
gabomdq@8021
   288
        SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
gabomdq@7659
   289
    } else {
gabomdq@8021
   290
        *_this->gl_config.driver_path = '\0';
gabomdq@7659
   291
    }
gabomdq@7659
   292
    
gabomdq@8041
   293
    return 0;
gabomdq@7659
   294
}
gabomdq@7659
   295
gabomdq@7659
   296
int
gabomdq@7659
   297
SDL_EGL_ChooseConfig(_THIS) 
gabomdq@7659
   298
{
gabomdq@7659
   299
    /* 64 seems nice. */
gabomdq@7659
   300
    EGLint attribs[64];
gabomdq@8021
   301
    EGLint found_configs = 0, value;
gabomdq@8015
   302
    /* 128 seems even nicer here */
gabomdq@8015
   303
    EGLConfig configs[128];
gabomdq@8021
   304
    int i, j, best_bitdiff = -1, bitdiff;
gabomdq@7659
   305
    
gabomdq@7659
   306
    if (!_this->egl_data) {
gabomdq@7659
   307
        /* The EGL library wasn't loaded, SDL_GetError() should have info */
gabomdq@7659
   308
        return -1;
gabomdq@7659
   309
    }
gabomdq@7659
   310
  
gabomdq@7659
   311
    /* Get a valid EGL configuration */
gabomdq@7659
   312
    i = 0;
gabomdq@7659
   313
    attribs[i++] = EGL_RED_SIZE;
gabomdq@7659
   314
    attribs[i++] = _this->gl_config.red_size;
gabomdq@7659
   315
    attribs[i++] = EGL_GREEN_SIZE;
gabomdq@7659
   316
    attribs[i++] = _this->gl_config.green_size;
gabomdq@7659
   317
    attribs[i++] = EGL_BLUE_SIZE;
gabomdq@7659
   318
    attribs[i++] = _this->gl_config.blue_size;
gabomdq@7659
   319
    
gabomdq@7659
   320
    if (_this->gl_config.alpha_size) {
gabomdq@7659
   321
        attribs[i++] = EGL_ALPHA_SIZE;
gabomdq@7659
   322
        attribs[i++] = _this->gl_config.alpha_size;
gabomdq@7659
   323
    }
gabomdq@7659
   324
    
gabomdq@7659
   325
    if (_this->gl_config.buffer_size) {
gabomdq@7659
   326
        attribs[i++] = EGL_BUFFER_SIZE;
gabomdq@7659
   327
        attribs[i++] = _this->gl_config.buffer_size;
gabomdq@7659
   328
    }
gabomdq@7659
   329
    
gabomdq@7659
   330
    attribs[i++] = EGL_DEPTH_SIZE;
gabomdq@7659
   331
    attribs[i++] = _this->gl_config.depth_size;
gabomdq@7659
   332
    
gabomdq@7659
   333
    if (_this->gl_config.stencil_size) {
gabomdq@7659
   334
        attribs[i++] = EGL_STENCIL_SIZE;
gabomdq@7659
   335
        attribs[i++] = _this->gl_config.stencil_size;
gabomdq@7659
   336
    }
gabomdq@7659
   337
    
gabomdq@7659
   338
    if (_this->gl_config.multisamplebuffers) {
gabomdq@7659
   339
        attribs[i++] = EGL_SAMPLE_BUFFERS;
gabomdq@7659
   340
        attribs[i++] = _this->gl_config.multisamplebuffers;
gabomdq@7659
   341
    }
gabomdq@7659
   342
    
gabomdq@7659
   343
    if (_this->gl_config.multisamplesamples) {
gabomdq@7659
   344
        attribs[i++] = EGL_SAMPLES;
gabomdq@7659
   345
        attribs[i++] = _this->gl_config.multisamplesamples;
gabomdq@7659
   346
    }
slime73@9595
   347
gabomdq@7659
   348
    attribs[i++] = EGL_RENDERABLE_TYPE;
slime73@9595
   349
    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
slime73@9595
   350
#ifdef EGL_KHR_create_context
slime73@9595
   351
        if (_this->gl_config.major_version >= 3 &&
slime73@9595
   352
            SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
slime73@9595
   353
            attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
slime73@9595
   354
        } else
slime73@9595
   355
#endif
slime73@9595
   356
        if (_this->gl_config.major_version >= 2) {
gabomdq@8062
   357
            attribs[i++] = EGL_OPENGL_ES2_BIT;
gabomdq@8062
   358
        } else {
gabomdq@8062
   359
            attribs[i++] = EGL_OPENGL_ES_BIT;
gabomdq@8062
   360
        }
gabomdq@8062
   361
        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
slime73@9595
   362
    } else {
gabomdq@8062
   363
        attribs[i++] = EGL_OPENGL_BIT;
gabomdq@8062
   364
        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
gabomdq@7659
   365
    }
gabomdq@7659
   366
    
gabomdq@7659
   367
    attribs[i++] = EGL_NONE;
gabomdq@8062
   368
   
gabomdq@7659
   369
    if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display,
gabomdq@7659
   370
        attribs,
gabomdq@8015
   371
        configs, SDL_arraysize(configs),
gabomdq@7659
   372
        &found_configs) == EGL_FALSE ||
gabomdq@7659
   373
        found_configs == 0) {
gabomdq@7659
   374
        return SDL_SetError("Couldn't find matching EGL config");
gabomdq@7659
   375
    }
gabomdq@7659
   376
    
gabomdq@8015
   377
    /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */
gabomdq@8015
   378
    /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
gabomdq@8021
   379
slime73@9595
   380
    for (i = 0; i < found_configs; i++ ) {
gabomdq@8015
   381
        bitdiff = 0;
gabomdq@8021
   382
        for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
gabomdq@8015
   383
            if (attribs[j] == EGL_NONE) {
gabomdq@8015
   384
               break;
gabomdq@8015
   385
            }
gabomdq@8015
   386
            
gabomdq@8015
   387
            if ( attribs[j+1] != EGL_DONT_CARE && (
gabomdq@8015
   388
                attribs[j] == EGL_RED_SIZE ||
gabomdq@8015
   389
                attribs[j] == EGL_GREEN_SIZE ||
gabomdq@8015
   390
                attribs[j] == EGL_BLUE_SIZE ||
gabomdq@8015
   391
                attribs[j] == EGL_ALPHA_SIZE ||
gabomdq@8015
   392
                attribs[j] == EGL_DEPTH_SIZE ||
gabomdq@8015
   393
                attribs[j] == EGL_STENCIL_SIZE)) {
gabomdq@8015
   394
                _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], attribs[j], &value);
gabomdq@8015
   395
                bitdiff += value - attribs[j + 1]; /* value is always >= attrib */
gabomdq@8015
   396
            }
gabomdq@8015
   397
        }
gabomdq@8015
   398
gabomdq@8015
   399
        if (bitdiff < best_bitdiff || best_bitdiff == -1) {
gabomdq@8015
   400
            _this->egl_data->egl_config = configs[i];
gabomdq@8015
   401
            
gabomdq@8015
   402
            best_bitdiff = bitdiff;
gabomdq@8015
   403
        }
slime73@9595
   404
slime73@9595
   405
        if (bitdiff == 0) {
slime73@9595
   406
            break; /* we found an exact match! */
slime73@9595
   407
        }
gabomdq@8015
   408
    }
gabomdq@8015
   409
    
gabomdq@7659
   410
    return 0;
gabomdq@7659
   411
}
gabomdq@7659
   412
gabomdq@7659
   413
SDL_GLContext
gabomdq@7659
   414
SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
gabomdq@7659
   415
{
slime73@9595
   416
    /* max 14 values plus terminator. */
slime73@9595
   417
    EGLint attribs[15];
slime73@9595
   418
    int attr = 0;
slime73@9595
   419
gabomdq@8061
   420
    EGLContext egl_context, share_context = EGL_NO_CONTEXT;
slime73@9595
   421
    EGLint profile_mask = _this->gl_config.profile_mask;
slime73@9637
   422
    EGLint major_version = _this->gl_config.major_version;
slime73@9637
   423
    EGLint minor_version = _this->gl_config.minor_version;
slime73@9637
   424
    SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
slime73@9595
   425
gabomdq@7659
   426
    if (!_this->egl_data) {
gabomdq@7659
   427
        /* The EGL library wasn't loaded, SDL_GetError() should have info */
gabomdq@7659
   428
        return NULL;
gabomdq@7659
   429
    }
slime73@9595
   430
gabomdq@8061
   431
    if (_this->gl_config.share_with_current_context) {
gabomdq@8061
   432
        share_context = (EGLContext)SDL_GL_GetCurrentContext();
gabomdq@7659
   433
    }
slime73@9595
   434
slime73@9595
   435
    /* Set the context version and other attributes. */
slime73@9637
   436
    if ((major_version < 3 || (minor_version == 0 && profile_es)) &&
slime73@9637
   437
        _this->gl_config.flags == 0 &&
slime73@9637
   438
        (profile_mask == 0 || profile_es)) {
slime73@9637
   439
        /* Create a context without using EGL_KHR_create_context attribs.
slime73@9637
   440
         * When creating a GLES context without EGL_KHR_create_context we can
slime73@9637
   441
         * only specify the major version. When creating a desktop GL context
slime73@9637
   442
         * we can't specify any version, so we only try in that case when the
slime73@9637
   443
         * version is less than 3.0 (matches SDL's GLX/WGL behavior.)
slime73@9637
   444
         */
slime73@9637
   445
        if (profile_es) {
slime73@9595
   446
            attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION;
slime73@9637
   447
            attribs[attr++] = SDL_max(major_version, 1);
slime73@9595
   448
        }
slime73@9595
   449
    } else {
slime73@9595
   450
#ifdef EGL_KHR_create_context
slime73@9595
   451
        /* The Major/minor version, context profiles, and context flags can
slime73@9595
   452
         * only be specified when this extension is available.
slime73@9595
   453
         */
slime73@9595
   454
        if (SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
slime73@9595
   455
            attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
slime73@9637
   456
            attribs[attr++] = major_version;
slime73@9595
   457
            attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;
slime73@9637
   458
            attribs[attr++] = minor_version;
slime73@9595
   459
slime73@9595
   460
            /* SDL profile bits match EGL profile bits. */
slime73@9595
   461
            if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
slime73@9595
   462
                attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
slime73@9595
   463
                attribs[attr++] = profile_mask;
slime73@9595
   464
            }
slime73@9595
   465
slime73@9595
   466
            /* SDL flags match EGL flags. */
slime73@9595
   467
            if (_this->gl_config.flags != 0) {
slime73@9595
   468
                attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
slime73@9595
   469
                attribs[attr++] = _this->gl_config.flags;
slime73@9595
   470
            }
slime73@9595
   471
        } else
slime73@9595
   472
#endif /* EGL_KHR_create_context */
slime73@9595
   473
        {
slime73@9595
   474
            SDL_SetError("Could not create EGL context (context attributes are not supported)");
slime73@9595
   475
            return NULL;
slime73@9595
   476
        }
slime73@9595
   477
    }
slime73@9595
   478
slime73@9595
   479
    attribs[attr++] = EGL_NONE;
slime73@9595
   480
gabomdq@8062
   481
    /* Bind the API */
slime73@9637
   482
    if (profile_es) {
gabomdq@8062
   483
        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
slime73@9595
   484
    } else {
slime73@9595
   485
        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
slime73@9595
   486
    }
gabomdq@7659
   487
slime73@9595
   488
    egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
slime73@9595
   489
                                      _this->egl_data->egl_config,
slime73@9595
   490
                                      share_context, attribs);
knut@8962
   491
gabomdq@7659
   492
    if (egl_context == EGL_NO_CONTEXT) {
gabomdq@7659
   493
        SDL_SetError("Could not create EGL context");
gabomdq@7659
   494
        return NULL;
gabomdq@7659
   495
    }
slime73@9595
   496
gabomdq@7659
   497
    _this->egl_data->egl_swapinterval = 0;
slime73@9595
   498
gabomdq@7659
   499
    if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
gabomdq@7659
   500
        SDL_EGL_DeleteContext(_this, egl_context);
gabomdq@7659
   501
        SDL_SetError("Could not make EGL context current");
gabomdq@7659
   502
        return NULL;
gabomdq@7659
   503
    }
slime73@9595
   504
gabomdq@7659
   505
    return (SDL_GLContext) egl_context;
gabomdq@7659
   506
}
gabomdq@7659
   507
gabomdq@7659
   508
int
gabomdq@7659
   509
SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
gabomdq@7659
   510
{
gabomdq@7679
   511
    EGLContext egl_context = (EGLContext) context;
gabomdq@7679
   512
gabomdq@7659
   513
    if (!_this->egl_data) {
gabomdq@7659
   514
        return SDL_SetError("OpenGL not initialized");
gabomdq@7659
   515
    }
gabomdq@7659
   516
    
gabomdq@7659
   517
    /* The android emulator crashes badly if you try to eglMakeCurrent 
gabomdq@7659
   518
     * with a valid context and invalid surface, so we have to check for both here.
gabomdq@7659
   519
     */
gabomdq@7659
   520
    if (!egl_context || !egl_surface) {
gabomdq@7659
   521
         _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
slime73@9595
   522
    } else {
gabomdq@7659
   523
        if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
gabomdq@7659
   524
            egl_surface, egl_surface, egl_context)) {
gabomdq@7659
   525
            return SDL_SetError("Unable to make EGL context current");
gabomdq@7659
   526
        }
gabomdq@7659
   527
    }
gabomdq@7659
   528
      
gabomdq@7659
   529
    return 0;
gabomdq@7659
   530
}
gabomdq@7659
   531
gabomdq@7659
   532
int
gabomdq@7659
   533
SDL_EGL_SetSwapInterval(_THIS, int interval)
gabomdq@7659
   534
{
gabomdq@7679
   535
    EGLBoolean status;
gabomdq@7679
   536
    
gabomdq@7702
   537
    if (!_this->egl_data) {
gabomdq@7702
   538
        return SDL_SetError("EGL not initialized");
gabomdq@7659
   539
    }
gabomdq@7659
   540
    
gabomdq@7659
   541
    status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval);
gabomdq@7659
   542
    if (status == EGL_TRUE) {
gabomdq@7659
   543
        _this->egl_data->egl_swapinterval = interval;
gabomdq@7659
   544
        return 0;
gabomdq@7659
   545
    }
gabomdq@7659
   546
    
gabomdq@7659
   547
    return SDL_SetError("Unable to set the EGL swap interval");
gabomdq@7659
   548
}
gabomdq@7659
   549
gabomdq@7659
   550
int
gabomdq@7659
   551
SDL_EGL_GetSwapInterval(_THIS)
gabomdq@7659
   552
{
gabomdq@7702
   553
    if (!_this->egl_data) {
gabomdq@7702
   554
        return SDL_SetError("EGL not initialized");
gabomdq@7659
   555
    }
gabomdq@7659
   556
    
gabomdq@7659
   557
    return _this->egl_data->egl_swapinterval;
gabomdq@7659
   558
}
gabomdq@7659
   559
gabomdq@7659
   560
void
gabomdq@7659
   561
SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface)
gabomdq@7659
   562
{
gabomdq@7659
   563
    _this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface);
gabomdq@7659
   564
}
gabomdq@7659
   565
gabomdq@7659
   566
void
gabomdq@7659
   567
SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
gabomdq@7659
   568
{
gabomdq@7679
   569
    EGLContext egl_context = (EGLContext) context;
gabomdq@7679
   570
gabomdq@7659
   571
    /* Clean up GLES and EGL */
gabomdq@7659
   572
    if (!_this->egl_data) {
gabomdq@7659
   573
        return;
gabomdq@7659
   574
    }
gabomdq@7659
   575
    
gabomdq@7896
   576
    if (egl_context != NULL && egl_context != EGL_NO_CONTEXT) {
gabomdq@7659
   577
        SDL_EGL_MakeCurrent(_this, NULL, NULL);
gabomdq@7659
   578
        _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context);
gabomdq@7659
   579
    }
gabomdq@7659
   580
        
gabomdq@7659
   581
}
gabomdq@7659
   582
gabomdq@7659
   583
EGLSurface *
gabomdq@7659
   584
SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) 
gabomdq@7659
   585
{
gabomdq@8041
   586
    if (SDL_EGL_ChooseConfig(_this) != 0) {
slouken@8045
   587
        return EGL_NO_SURFACE;
gabomdq@8041
   588
    }
gabomdq@8041
   589
    
gabomdq@8971
   590
#if __ANDROID__
slouken@8976
   591
    {
slouken@8976
   592
        /* Android docs recommend doing this!
slouken@8976
   593
         * Ref: http://developer.android.com/reference/android/app/NativeActivity.html 
slouken@8976
   594
         */
slouken@8976
   595
        EGLint format;
slouken@8976
   596
        _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
slouken@8976
   597
                                            _this->egl_data->egl_config, 
slouken@8976
   598
                                            EGL_NATIVE_VISUAL_ID, &format);
gabomdq@8971
   599
slouken@8976
   600
        ANativeWindow_setBuffersGeometry(nw, 0, 0, format);
slouken@8976
   601
    }
gabomdq@8971
   602
#endif    
gabomdq@8971
   603
    
gabomdq@7659
   604
    return _this->egl_data->eglCreateWindowSurface(
gabomdq@7659
   605
            _this->egl_data->egl_display,
gabomdq@7659
   606
            _this->egl_data->egl_config,
gabomdq@7659
   607
            nw, NULL);
gabomdq@7659
   608
}
gabomdq@7659
   609
gabomdq@7659
   610
void
gabomdq@7659
   611
SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) 
gabomdq@7659
   612
{
gabomdq@7659
   613
    if (!_this->egl_data) {
gabomdq@7659
   614
        return;
gabomdq@7659
   615
    }
gabomdq@7659
   616
    
gabomdq@7659
   617
    if (egl_surface != EGL_NO_SURFACE) {
gabomdq@7659
   618
        _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface);
gabomdq@7659
   619
    }
gabomdq@7659
   620
}
gabomdq@7659
   621
gabomdq@7659
   622
#endif /* SDL_VIDEO_OPENGL_EGL */
gabomdq@7659
   623
gabomdq@7659
   624
/* vi: set ts=4 sw=4 expandtab: */
slouken@7865
   625