src/video/SDL_egl.c
author David Ludwig <dludwig@pobox.com>
Thu, 29 Dec 2016 11:49:18 -0500
changeset 10740 bb53965b659d
parent 10737 3406a0f8b041
child 10741 a32fd6b7412b
permissions -rw-r--r--
improved SDL_GetError() output generated by EGL code

This change attempts to report the EGL error codes generated by SDL's calls
into EGL, along with the name of the EGL function that failed.
gabomdq@7659
     1
/*
gabomdq@7659
     2
 *  Simple DirectMedia Layer
slouken@10737
     3
 *  Copyright (C) 1997-2017 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
{ \
gabomdq@7659
    75
    return SDL_SetError("Could not retrieve EGL function " #NAME); \
gabomdq@7659
    76
}
dludwig@10740
    77
dludwig@10740
    78
static const char * SDL_EGL_GetErrorName(EGLint eglErrorCode)
dludwig@10740
    79
{
dludwig@10740
    80
#define SDL_EGL_ERROR_TRANSLATE(e) case e: return #e;
dludwig@10740
    81
    switch (eglErrorCode) {
dludwig@10740
    82
        SDL_EGL_ERROR_TRANSLATE(EGL_SUCCESS);
dludwig@10740
    83
        SDL_EGL_ERROR_TRANSLATE(EGL_NOT_INITIALIZED);
dludwig@10740
    84
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ACCESS);
dludwig@10740
    85
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ALLOC);
dludwig@10740
    86
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ATTRIBUTE);
dludwig@10740
    87
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONTEXT);
dludwig@10740
    88
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONFIG);
dludwig@10740
    89
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CURRENT_SURFACE);
dludwig@10740
    90
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_DISPLAY);
dludwig@10740
    91
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_SURFACE);
dludwig@10740
    92
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_MATCH);
dludwig@10740
    93
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_PARAMETER);
dludwig@10740
    94
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_PIXMAP);
dludwig@10740
    95
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_WINDOW);
dludwig@10740
    96
        SDL_EGL_ERROR_TRANSLATE(EGL_CONTEXT_LOST);
dludwig@10740
    97
    }
dludwig@10740
    98
    return "";
dludwig@10740
    99
}
dludwig@10740
   100
dludwig@10740
   101
int SDL_EGL_SetErrorEx(const char * message, const char * eglFunctionName, EGLint eglErrorCode)
dludwig@10740
   102
{
dludwig@10740
   103
    const char * errorText = SDL_EGL_GetErrorName(eglErrorCode);
dludwig@10740
   104
    char altErrorText[32];
dludwig@10740
   105
    if (errorText[0] == '\0') {
dludwig@10740
   106
        /* An unknown-to-SDL error code was reported.  Report its hexadecimal value, instead of its name. */
dludwig@10740
   107
        SDL_snprintf(altErrorText, SDL_arraysize(altErrorText), "0x%x", (unsigned int)eglErrorCode);
dludwig@10740
   108
        errorText = altErrorText;
dludwig@10740
   109
    }
dludwig@10740
   110
    return SDL_SetError("%s (call to %s failed, reporting an error of %s)", message, eglFunctionName, errorText);
dludwig@10740
   111
}
dludwig@10740
   112
gabomdq@7659
   113
/* EGL implementation of SDL OpenGL ES support */
slouken@8976
   114
#ifdef EGL_KHR_create_context        
knut@8962
   115
static int SDL_EGL_HasExtension(_THIS, const char *ext)
knut@8962
   116
{
knut@8962
   117
    int i;
knut@8962
   118
    int len = 0;
slouken@9821
   119
    size_t ext_len;
knut@8962
   120
    const char *exts;
knut@8962
   121
    const char *ext_word;
knut@8962
   122
knut@8962
   123
    ext_len = SDL_strlen(ext);
knut@8962
   124
    exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
knut@8962
   125
slime73@9595
   126
    if (exts) {
knut@8962
   127
        ext_word = exts;
knut@8962
   128
slime73@9595
   129
        for (i = 0; exts[i] != 0; i++) {
slime73@9595
   130
            if (exts[i] == ' ') {
slime73@9595
   131
                if (ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
knut@8962
   132
                    return 1;
knut@8962
   133
                }
knut@8962
   134
knut@8962
   135
                len = 0;
knut@8962
   136
                ext_word = &exts[i + 1];
slime73@9595
   137
            } else {
knut@8962
   138
                len++;
knut@8962
   139
            }
knut@8962
   140
        }
knut@8962
   141
    }
knut@8962
   142
knut@8962
   143
    return 0;
knut@8962
   144
}
slouken@8976
   145
#endif /* EGL_KHR_create_context */
gabomdq@7659
   146
gabomdq@7659
   147
void *
gabomdq@7659
   148
SDL_EGL_GetProcAddress(_THIS, const char *proc)
gabomdq@7659
   149
{
gabomdq@7659
   150
    static char procname[1024];
gabomdq@7659
   151
    void *retval;
gabomdq@7659
   152
    
gabomdq@7659
   153
    /* eglGetProcAddress is busted on Android http://code.google.com/p/android/issues/detail?id=7681 */
brandon@8753
   154
#if !defined(SDL_VIDEO_DRIVER_ANDROID) && !defined(SDL_VIDEO_DRIVER_MIR) 
gabomdq@7659
   155
    if (_this->egl_data->eglGetProcAddress) {
gabomdq@7659
   156
        retval = _this->egl_data->eglGetProcAddress(proc);
gabomdq@7659
   157
        if (retval) {
gabomdq@7659
   158
            return retval;
gabomdq@7659
   159
        }
gabomdq@7659
   160
    }
gabomdq@7659
   161
#endif
gabomdq@7659
   162
    
gabomdq@8021
   163
    retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, proc);
gabomdq@8021
   164
    if (!retval && SDL_strlen(proc) <= 1022) {
gabomdq@7659
   165
        procname[0] = '_';
gabomdq@8021
   166
        SDL_strlcpy(procname + 1, proc, 1022);
gabomdq@8021
   167
        retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, procname);
gabomdq@7659
   168
    }
gabomdq@7659
   169
    return retval;
gabomdq@7659
   170
}
gabomdq@7659
   171
gabomdq@7659
   172
void
gabomdq@7659
   173
SDL_EGL_UnloadLibrary(_THIS)
gabomdq@7659
   174
{
slouken@7865
   175
    if (_this->egl_data) {
slouken@7865
   176
        if (_this->egl_data->egl_display) {
slouken@7865
   177
            _this->egl_data->eglTerminate(_this->egl_data->egl_display);
slouken@7865
   178
            _this->egl_data->egl_display = NULL;
slouken@7865
   179
        }
slouken@7865
   180
gabomdq@8021
   181
        if (_this->egl_data->dll_handle) {
gabomdq@8021
   182
            SDL_UnloadObject(_this->egl_data->dll_handle);
gabomdq@8021
   183
            _this->egl_data->dll_handle = NULL;
slouken@7865
   184
        }
slouken@7865
   185
        if (_this->egl_data->egl_dll_handle) {
gabomdq@8021
   186
            SDL_UnloadObject(_this->egl_data->egl_dll_handle);
slouken@7865
   187
            _this->egl_data->egl_dll_handle = NULL;
slouken@7865
   188
        }
gabomdq@7659
   189
        
gabomdq@7659
   190
        SDL_free(_this->egl_data);
gabomdq@7659
   191
        _this->egl_data = NULL;
gabomdq@7659
   192
    }
gabomdq@7659
   193
}
gabomdq@7659
   194
gabomdq@7659
   195
int
gabomdq@7753
   196
SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display)
gabomdq@7659
   197
{
gabomdq@8021
   198
    void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
slouken@10461
   199
    const char *path = NULL;
dludwig@8545
   200
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
gabomdq@8021
   201
    const char *d3dcompiler;
gabomdq@8021
   202
#endif
gabomdq@8021
   203
gabomdq@7659
   204
    if (_this->egl_data) {
gabomdq@7659
   205
        return SDL_SetError("OpenGL ES context already created");
gabomdq@7659
   206
    }
slouken@7865
   207
slouken@7865
   208
    _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
slouken@7865
   209
    if (!_this->egl_data) {
slouken@7865
   210
        return SDL_OutOfMemory();
slouken@7865
   211
    }
slouken@7865
   212
dludwig@8545
   213
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
gabomdq@8021
   214
    d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER);
gabomdq@8021
   215
    if (!d3dcompiler) {
slouken@8733
   216
        if (WIN_IsWindowsVistaOrGreater()) {
slouken@8733
   217
            d3dcompiler = "d3dcompiler_46.dll";
slouken@8733
   218
        } else {
slouken@8740
   219
            d3dcompiler = "d3dcompiler_43.dll";
slouken@8733
   220
        }
gabomdq@8021
   221
    }
gabomdq@8021
   222
    if (SDL_strcasecmp(d3dcompiler, "none") != 0) {
gabomdq@8021
   223
        SDL_LoadObject(d3dcompiler);
gabomdq@8021
   224
    }
slouken@7865
   225
#endif
slouken@7865
   226
gabomdq@7753
   227
    /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
gabomdq@8021
   228
    path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
gabomdq@8021
   229
    if (path != NULL) {
gabomdq@8021
   230
        egl_dll_handle = SDL_LoadObject(path);
gabomdq@8021
   231
    }
gabomdq@8021
   232
gabomdq@8021
   233
    if (egl_dll_handle == NULL) {
slime73@9595
   234
        if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
gabomdq@8062
   235
            if (_this->gl_config.major_version > 1) {
gabomdq@8062
   236
                path = DEFAULT_OGL_ES2;
gabomdq@8062
   237
                egl_dll_handle = SDL_LoadObject(path);
slime73@9595
   238
            } else {
gabomdq@8062
   239
                path = DEFAULT_OGL_ES;
gabomdq@8062
   240
                egl_dll_handle = SDL_LoadObject(path);
gabomdq@8062
   241
                if (egl_dll_handle == NULL) {
gabomdq@8062
   242
                    path = DEFAULT_OGL_ES_PVR;
gabomdq@8062
   243
                    egl_dll_handle = SDL_LoadObject(path);
gabomdq@8062
   244
                }
gabomdq@8062
   245
            }
gabomdq@8062
   246
        }
gabomdq@8062
   247
#ifdef DEFAULT_OGL         
gabomdq@8062
   248
        else {
gabomdq@8062
   249
            path = DEFAULT_OGL;
gabomdq@8021
   250
            egl_dll_handle = SDL_LoadObject(path);
gabomdq@8021
   251
        }
gabomdq@8062
   252
#endif        
gabomdq@7753
   253
    }
slouken@7865
   254
    _this->egl_data->egl_dll_handle = egl_dll_handle;
gabomdq@7753
   255
gabomdq@7753
   256
    if (egl_dll_handle == NULL) {
gabomdq@8062
   257
        return SDL_SetError("Could not initialize OpenGL / GLES library");
gabomdq@7753
   258
    }
gabomdq@8021
   259
gabomdq@7753
   260
    /* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */
gabomdq@8021
   261
    if (egl_path != NULL) {
gabomdq@8021
   262
        dll_handle = SDL_LoadObject(egl_path);
gabomdq@8021
   263
    }   
gabomdq@8105
   264
    /* Try loading a EGL symbol, if it does not work try the default library paths */
gabomdq@8872
   265
    if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
gabomdq@8021
   266
        if (dll_handle != NULL) {
gabomdq@8021
   267
            SDL_UnloadObject(dll_handle);
gabomdq@8021
   268
        }
gabomdq@8021
   269
        path = SDL_getenv("SDL_VIDEO_EGL_DRIVER");
gabomdq@7659
   270
        if (path == NULL) {
gabomdq@7659
   271
            path = DEFAULT_EGL;
gabomdq@7659
   272
        }
gabomdq@8021
   273
        dll_handle = SDL_LoadObject(path);
gabomdq@8872
   274
        if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
gabomdq@8872
   275
            if (dll_handle != NULL) {
gabomdq@8872
   276
                SDL_UnloadObject(dll_handle);
gabomdq@8872
   277
            }
gabomdq@8021
   278
            return SDL_SetError("Could not load EGL library");
gabomdq@8021
   279
        }
gabomdq@8763
   280
        SDL_ClearError();
gabomdq@7753
   281
    }
slouken@7865
   282
gabomdq@8021
   283
    _this->egl_data->dll_handle = dll_handle;
gabomdq@7659
   284
gabomdq@7659
   285
    /* Load new function pointers */
gabomdq@7659
   286
    LOAD_FUNC(eglGetDisplay);
gabomdq@7659
   287
    LOAD_FUNC(eglInitialize);
gabomdq@7659
   288
    LOAD_FUNC(eglTerminate);
gabomdq@7659
   289
    LOAD_FUNC(eglGetProcAddress);
gabomdq@7659
   290
    LOAD_FUNC(eglChooseConfig);
gabomdq@7659
   291
    LOAD_FUNC(eglGetConfigAttrib);
gabomdq@7659
   292
    LOAD_FUNC(eglCreateContext);
gabomdq@7659
   293
    LOAD_FUNC(eglDestroyContext);
gabomdq@7659
   294
    LOAD_FUNC(eglCreateWindowSurface);
gabomdq@7659
   295
    LOAD_FUNC(eglDestroySurface);
gabomdq@7659
   296
    LOAD_FUNC(eglMakeCurrent);
gabomdq@7659
   297
    LOAD_FUNC(eglSwapBuffers);
gabomdq@7659
   298
    LOAD_FUNC(eglSwapInterval);
gabomdq@7659
   299
    LOAD_FUNC(eglWaitNative);
gabomdq@7659
   300
    LOAD_FUNC(eglWaitGL);
gabomdq@8062
   301
    LOAD_FUNC(eglBindAPI);
knut@8962
   302
    LOAD_FUNC(eglQueryString);
dludwig@10740
   303
    LOAD_FUNC(eglGetError);
dludwig@10740
   304
dludwig@8663
   305
#if !defined(__WINRT__)
gabomdq@7659
   306
    _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
gabomdq@7659
   307
    if (!_this->egl_data->egl_display) {
gabomdq@7659
   308
        return SDL_SetError("Could not get EGL display");
gabomdq@7659
   309
    }
gabomdq@7659
   310
    
gabomdq@7659
   311
    if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
gabomdq@7659
   312
        return SDL_SetError("Could not initialize EGL");
gabomdq@7659
   313
    }
dludwig@8663
   314
#endif
gabomdq@7659
   315
gabomdq@7659
   316
    _this->gl_config.driver_loaded = 1;
gabomdq@7659
   317
gabomdq@7659
   318
    if (path) {
gabomdq@8021
   319
        SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
gabomdq@7659
   320
    } else {
gabomdq@8021
   321
        *_this->gl_config.driver_path = '\0';
gabomdq@7659
   322
    }
gabomdq@7659
   323
    
gabomdq@8041
   324
    return 0;
gabomdq@7659
   325
}
gabomdq@7659
   326
gabomdq@7659
   327
int
gabomdq@7659
   328
SDL_EGL_ChooseConfig(_THIS) 
gabomdq@7659
   329
{
gabomdq@7659
   330
    /* 64 seems nice. */
gabomdq@7659
   331
    EGLint attribs[64];
gabomdq@8021
   332
    EGLint found_configs = 0, value;
gabomdq@8015
   333
    /* 128 seems even nicer here */
gabomdq@8015
   334
    EGLConfig configs[128];
gabomdq@8021
   335
    int i, j, best_bitdiff = -1, bitdiff;
gabomdq@7659
   336
    
gabomdq@7659
   337
    if (!_this->egl_data) {
gabomdq@7659
   338
        /* The EGL library wasn't loaded, SDL_GetError() should have info */
gabomdq@7659
   339
        return -1;
gabomdq@7659
   340
    }
gabomdq@7659
   341
  
gabomdq@7659
   342
    /* Get a valid EGL configuration */
gabomdq@7659
   343
    i = 0;
gabomdq@7659
   344
    attribs[i++] = EGL_RED_SIZE;
gabomdq@7659
   345
    attribs[i++] = _this->gl_config.red_size;
gabomdq@7659
   346
    attribs[i++] = EGL_GREEN_SIZE;
gabomdq@7659
   347
    attribs[i++] = _this->gl_config.green_size;
gabomdq@7659
   348
    attribs[i++] = EGL_BLUE_SIZE;
gabomdq@7659
   349
    attribs[i++] = _this->gl_config.blue_size;
gabomdq@7659
   350
    
gabomdq@7659
   351
    if (_this->gl_config.alpha_size) {
gabomdq@7659
   352
        attribs[i++] = EGL_ALPHA_SIZE;
gabomdq@7659
   353
        attribs[i++] = _this->gl_config.alpha_size;
gabomdq@7659
   354
    }
gabomdq@7659
   355
    
gabomdq@7659
   356
    if (_this->gl_config.buffer_size) {
gabomdq@7659
   357
        attribs[i++] = EGL_BUFFER_SIZE;
gabomdq@7659
   358
        attribs[i++] = _this->gl_config.buffer_size;
gabomdq@7659
   359
    }
gabomdq@7659
   360
    
gabomdq@7659
   361
    attribs[i++] = EGL_DEPTH_SIZE;
gabomdq@7659
   362
    attribs[i++] = _this->gl_config.depth_size;
gabomdq@7659
   363
    
gabomdq@7659
   364
    if (_this->gl_config.stencil_size) {
gabomdq@7659
   365
        attribs[i++] = EGL_STENCIL_SIZE;
gabomdq@7659
   366
        attribs[i++] = _this->gl_config.stencil_size;
gabomdq@7659
   367
    }
gabomdq@7659
   368
    
gabomdq@7659
   369
    if (_this->gl_config.multisamplebuffers) {
gabomdq@7659
   370
        attribs[i++] = EGL_SAMPLE_BUFFERS;
gabomdq@7659
   371
        attribs[i++] = _this->gl_config.multisamplebuffers;
gabomdq@7659
   372
    }
gabomdq@7659
   373
    
gabomdq@7659
   374
    if (_this->gl_config.multisamplesamples) {
gabomdq@7659
   375
        attribs[i++] = EGL_SAMPLES;
gabomdq@7659
   376
        attribs[i++] = _this->gl_config.multisamplesamples;
gabomdq@7659
   377
    }
slime73@9595
   378
slime73@9827
   379
    if (_this->gl_config.framebuffer_srgb_capable) {
slime73@9827
   380
#ifdef EGL_KHR_gl_colorspace
slime73@9827
   381
        if (SDL_EGL_HasExtension(_this, "EGL_KHR_gl_colorspace")) {
slime73@9827
   382
            attribs[i++] = EGL_GL_COLORSPACE_KHR;
slime73@9827
   383
            attribs[i++] = EGL_GL_COLORSPACE_SRGB_KHR;
slime73@9827
   384
        } else
slime73@9827
   385
#endif
slime73@9827
   386
        {
slime73@9827
   387
            return SDL_SetError("EGL implementation does not support sRGB system framebuffers");
slime73@9827
   388
        }
slime73@9827
   389
    }
slime73@9827
   390
gabomdq@7659
   391
    attribs[i++] = EGL_RENDERABLE_TYPE;
slime73@9595
   392
    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
slime73@9595
   393
#ifdef EGL_KHR_create_context
slime73@9595
   394
        if (_this->gl_config.major_version >= 3 &&
slime73@9595
   395
            SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
slime73@9595
   396
            attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
slime73@9595
   397
        } else
slime73@9595
   398
#endif
slime73@9595
   399
        if (_this->gl_config.major_version >= 2) {
gabomdq@8062
   400
            attribs[i++] = EGL_OPENGL_ES2_BIT;
gabomdq@8062
   401
        } else {
gabomdq@8062
   402
            attribs[i++] = EGL_OPENGL_ES_BIT;
gabomdq@8062
   403
        }
gabomdq@8062
   404
        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
slime73@9595
   405
    } else {
gabomdq@8062
   406
        attribs[i++] = EGL_OPENGL_BIT;
gabomdq@8062
   407
        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
gabomdq@7659
   408
    }
slime73@9827
   409
gabomdq@7659
   410
    attribs[i++] = EGL_NONE;
slime73@9827
   411
gabomdq@7659
   412
    if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display,
gabomdq@7659
   413
        attribs,
gabomdq@8015
   414
        configs, SDL_arraysize(configs),
gabomdq@7659
   415
        &found_configs) == EGL_FALSE ||
gabomdq@7659
   416
        found_configs == 0) {
dludwig@10740
   417
        return SDL_EGL_SetError("Couldn't find matching EGL config", "eglChooseConfig");
gabomdq@7659
   418
    }
slime73@9827
   419
gabomdq@8015
   420
    /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */
gabomdq@8015
   421
    /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
gabomdq@8021
   422
slime73@9595
   423
    for (i = 0; i < found_configs; i++ ) {
gabomdq@8015
   424
        bitdiff = 0;
gabomdq@8021
   425
        for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
gabomdq@8015
   426
            if (attribs[j] == EGL_NONE) {
gabomdq@8015
   427
               break;
gabomdq@8015
   428
            }
gabomdq@8015
   429
            
gabomdq@8015
   430
            if ( attribs[j+1] != EGL_DONT_CARE && (
gabomdq@8015
   431
                attribs[j] == EGL_RED_SIZE ||
gabomdq@8015
   432
                attribs[j] == EGL_GREEN_SIZE ||
gabomdq@8015
   433
                attribs[j] == EGL_BLUE_SIZE ||
gabomdq@8015
   434
                attribs[j] == EGL_ALPHA_SIZE ||
gabomdq@8015
   435
                attribs[j] == EGL_DEPTH_SIZE ||
gabomdq@8015
   436
                attribs[j] == EGL_STENCIL_SIZE)) {
gabomdq@8015
   437
                _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], attribs[j], &value);
gabomdq@8015
   438
                bitdiff += value - attribs[j + 1]; /* value is always >= attrib */
gabomdq@8015
   439
            }
gabomdq@8015
   440
        }
gabomdq@8015
   441
gabomdq@8015
   442
        if (bitdiff < best_bitdiff || best_bitdiff == -1) {
gabomdq@8015
   443
            _this->egl_data->egl_config = configs[i];
gabomdq@8015
   444
            
gabomdq@8015
   445
            best_bitdiff = bitdiff;
gabomdq@8015
   446
        }
slime73@9595
   447
slime73@9595
   448
        if (bitdiff == 0) {
slime73@9595
   449
            break; /* we found an exact match! */
slime73@9595
   450
        }
gabomdq@8015
   451
    }
gabomdq@8015
   452
    
gabomdq@7659
   453
    return 0;
gabomdq@7659
   454
}
gabomdq@7659
   455
gabomdq@7659
   456
SDL_GLContext
gabomdq@7659
   457
SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
gabomdq@7659
   458
{
slime73@9595
   459
    /* max 14 values plus terminator. */
slime73@9595
   460
    EGLint attribs[15];
slime73@9595
   461
    int attr = 0;
slime73@9595
   462
gabomdq@8061
   463
    EGLContext egl_context, share_context = EGL_NO_CONTEXT;
slime73@9595
   464
    EGLint profile_mask = _this->gl_config.profile_mask;
slime73@9637
   465
    EGLint major_version = _this->gl_config.major_version;
slime73@9637
   466
    EGLint minor_version = _this->gl_config.minor_version;
slime73@9637
   467
    SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
slime73@9595
   468
gabomdq@7659
   469
    if (!_this->egl_data) {
gabomdq@7659
   470
        /* The EGL library wasn't loaded, SDL_GetError() should have info */
gabomdq@7659
   471
        return NULL;
gabomdq@7659
   472
    }
slime73@9595
   473
gabomdq@8061
   474
    if (_this->gl_config.share_with_current_context) {
gabomdq@8061
   475
        share_context = (EGLContext)SDL_GL_GetCurrentContext();
gabomdq@7659
   476
    }
slime73@9595
   477
slime73@9595
   478
    /* Set the context version and other attributes. */
slime73@9637
   479
    if ((major_version < 3 || (minor_version == 0 && profile_es)) &&
slime73@9637
   480
        _this->gl_config.flags == 0 &&
slime73@9637
   481
        (profile_mask == 0 || profile_es)) {
slime73@9637
   482
        /* Create a context without using EGL_KHR_create_context attribs.
slime73@9637
   483
         * When creating a GLES context without EGL_KHR_create_context we can
slime73@9637
   484
         * only specify the major version. When creating a desktop GL context
slime73@9637
   485
         * we can't specify any version, so we only try in that case when the
slime73@9637
   486
         * version is less than 3.0 (matches SDL's GLX/WGL behavior.)
slime73@9637
   487
         */
slime73@9637
   488
        if (profile_es) {
slime73@9595
   489
            attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION;
slime73@9637
   490
            attribs[attr++] = SDL_max(major_version, 1);
slime73@9595
   491
        }
slime73@9595
   492
    } else {
slime73@9595
   493
#ifdef EGL_KHR_create_context
slime73@9595
   494
        /* The Major/minor version, context profiles, and context flags can
slime73@9595
   495
         * only be specified when this extension is available.
slime73@9595
   496
         */
slime73@9595
   497
        if (SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
slime73@9595
   498
            attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
slime73@9637
   499
            attribs[attr++] = major_version;
slime73@9595
   500
            attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;
slime73@9637
   501
            attribs[attr++] = minor_version;
slime73@9595
   502
slime73@9595
   503
            /* SDL profile bits match EGL profile bits. */
slime73@9595
   504
            if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
slime73@9595
   505
                attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
slime73@9595
   506
                attribs[attr++] = profile_mask;
slime73@9595
   507
            }
slime73@9595
   508
slime73@9595
   509
            /* SDL flags match EGL flags. */
slime73@9595
   510
            if (_this->gl_config.flags != 0) {
slime73@9595
   511
                attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
slime73@9595
   512
                attribs[attr++] = _this->gl_config.flags;
slime73@9595
   513
            }
slime73@9595
   514
        } else
slime73@9595
   515
#endif /* EGL_KHR_create_context */
slime73@9595
   516
        {
slime73@9595
   517
            SDL_SetError("Could not create EGL context (context attributes are not supported)");
slime73@9595
   518
            return NULL;
slime73@9595
   519
        }
slime73@9595
   520
    }
slime73@9595
   521
slime73@9595
   522
    attribs[attr++] = EGL_NONE;
slime73@9595
   523
gabomdq@8062
   524
    /* Bind the API */
slime73@9637
   525
    if (profile_es) {
gabomdq@8062
   526
        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
slime73@9595
   527
    } else {
slime73@9595
   528
        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
slime73@9595
   529
    }
gabomdq@7659
   530
slime73@9595
   531
    egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
slime73@9595
   532
                                      _this->egl_data->egl_config,
slime73@9595
   533
                                      share_context, attribs);
knut@8962
   534
gabomdq@7659
   535
    if (egl_context == EGL_NO_CONTEXT) {
dludwig@10740
   536
        SDL_EGL_SetError("Could not create EGL context", "eglCreateContext");
gabomdq@7659
   537
        return NULL;
gabomdq@7659
   538
    }
slime73@9595
   539
gabomdq@7659
   540
    _this->egl_data->egl_swapinterval = 0;
slime73@9595
   541
gabomdq@7659
   542
    if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
dludwig@10740
   543
        /* Save the SDL error set by SDL_EGL_MakeCurrent */
dludwig@10740
   544
        char errorText[1024];
dludwig@10740
   545
        SDL_strlcpy(errorText, SDL_GetError(), SDL_arraysize(errorText));
dludwig@10740
   546
dludwig@10740
   547
        /* Delete the context, which may alter the value returned by SDL_GetError() */
gabomdq@7659
   548
        SDL_EGL_DeleteContext(_this, egl_context);
dludwig@10740
   549
dludwig@10740
   550
        /* Restore the SDL error */
dludwig@10740
   551
        SDL_SetError("%s", errorText);
dludwig@10740
   552
gabomdq@7659
   553
        return NULL;
gabomdq@7659
   554
    }
slime73@9595
   555
gabomdq@7659
   556
    return (SDL_GLContext) egl_context;
gabomdq@7659
   557
}
gabomdq@7659
   558
gabomdq@7659
   559
int
gabomdq@7659
   560
SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
gabomdq@7659
   561
{
gabomdq@7679
   562
    EGLContext egl_context = (EGLContext) context;
gabomdq@7679
   563
gabomdq@7659
   564
    if (!_this->egl_data) {
gabomdq@7659
   565
        return SDL_SetError("OpenGL not initialized");
gabomdq@7659
   566
    }
gabomdq@7659
   567
    
gabomdq@7659
   568
    /* The android emulator crashes badly if you try to eglMakeCurrent 
gabomdq@7659
   569
     * with a valid context and invalid surface, so we have to check for both here.
gabomdq@7659
   570
     */
gabomdq@7659
   571
    if (!egl_context || !egl_surface) {
gabomdq@7659
   572
         _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
slime73@9595
   573
    } else {
gabomdq@7659
   574
        if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
gabomdq@7659
   575
            egl_surface, egl_surface, egl_context)) {
dludwig@10740
   576
            return SDL_EGL_SetError("Unable to make EGL context current", "eglMakeCurrent");
gabomdq@7659
   577
        }
gabomdq@7659
   578
    }
gabomdq@7659
   579
      
gabomdq@7659
   580
    return 0;
gabomdq@7659
   581
}
gabomdq@7659
   582
gabomdq@7659
   583
int
gabomdq@7659
   584
SDL_EGL_SetSwapInterval(_THIS, int interval)
gabomdq@7659
   585
{
gabomdq@7679
   586
    EGLBoolean status;
gabomdq@7679
   587
    
gabomdq@7702
   588
    if (!_this->egl_data) {
gabomdq@7702
   589
        return SDL_SetError("EGL not initialized");
gabomdq@7659
   590
    }
gabomdq@7659
   591
    
gabomdq@7659
   592
    status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval);
gabomdq@7659
   593
    if (status == EGL_TRUE) {
gabomdq@7659
   594
        _this->egl_data->egl_swapinterval = interval;
gabomdq@7659
   595
        return 0;
gabomdq@7659
   596
    }
gabomdq@7659
   597
    
dludwig@10740
   598
    return SDL_EGL_SetError("Unable to set the EGL swap interval", "eglSwapInterval");
gabomdq@7659
   599
}
gabomdq@7659
   600
gabomdq@7659
   601
int
gabomdq@7659
   602
SDL_EGL_GetSwapInterval(_THIS)
gabomdq@7659
   603
{
gabomdq@7702
   604
    if (!_this->egl_data) {
philipp@10169
   605
        SDL_SetError("EGL not initialized");
philipp@10169
   606
        return 0;
gabomdq@7659
   607
    }
gabomdq@7659
   608
    
gabomdq@7659
   609
    return _this->egl_data->egl_swapinterval;
gabomdq@7659
   610
}
gabomdq@7659
   611
slouken@10693
   612
int
gabomdq@7659
   613
SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface)
gabomdq@7659
   614
{
slouken@10693
   615
    if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface)) {
dludwig@10740
   616
        return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers");
slouken@10693
   617
    }
slouken@10693
   618
    return 0;
gabomdq@7659
   619
}
gabomdq@7659
   620
gabomdq@7659
   621
void
gabomdq@7659
   622
SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
gabomdq@7659
   623
{
gabomdq@7679
   624
    EGLContext egl_context = (EGLContext) context;
gabomdq@7679
   625
gabomdq@7659
   626
    /* Clean up GLES and EGL */
gabomdq@7659
   627
    if (!_this->egl_data) {
gabomdq@7659
   628
        return;
gabomdq@7659
   629
    }
gabomdq@7659
   630
    
gabomdq@7896
   631
    if (egl_context != NULL && egl_context != EGL_NO_CONTEXT) {
gabomdq@7659
   632
        SDL_EGL_MakeCurrent(_this, NULL, NULL);
gabomdq@7659
   633
        _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context);
gabomdq@7659
   634
    }
gabomdq@7659
   635
        
gabomdq@7659
   636
}
gabomdq@7659
   637
gabomdq@7659
   638
EGLSurface *
gabomdq@7659
   639
SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) 
gabomdq@7659
   640
{
dludwig@10740
   641
    EGLSurface * surface;
dludwig@10740
   642
gabomdq@8041
   643
    if (SDL_EGL_ChooseConfig(_this) != 0) {
slouken@8045
   644
        return EGL_NO_SURFACE;
gabomdq@8041
   645
    }
gabomdq@8041
   646
    
gabomdq@8971
   647
#if __ANDROID__
slouken@8976
   648
    {
slouken@8976
   649
        /* Android docs recommend doing this!
slouken@8976
   650
         * Ref: http://developer.android.com/reference/android/app/NativeActivity.html 
slouken@8976
   651
         */
slouken@8976
   652
        EGLint format;
slouken@8976
   653
        _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
slouken@8976
   654
                                            _this->egl_data->egl_config, 
slouken@8976
   655
                                            EGL_NATIVE_VISUAL_ID, &format);
gabomdq@8971
   656
slouken@8976
   657
        ANativeWindow_setBuffersGeometry(nw, 0, 0, format);
slouken@8976
   658
    }
gabomdq@8971
   659
#endif    
gabomdq@8971
   660
    
dludwig@10740
   661
    surface = _this->egl_data->eglCreateWindowSurface(
gabomdq@7659
   662
            _this->egl_data->egl_display,
gabomdq@7659
   663
            _this->egl_data->egl_config,
gabomdq@7659
   664
            nw, NULL);
dludwig@10740
   665
    if (surface == EGL_NO_SURFACE) {
dludwig@10740
   666
        SDL_EGL_SetError("unable to create an EGL window surface", "eglCreateWindowSurface");
dludwig@10740
   667
    }
dludwig@10740
   668
    return surface;
gabomdq@7659
   669
}
gabomdq@7659
   670
gabomdq@7659
   671
void
gabomdq@7659
   672
SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) 
gabomdq@7659
   673
{
gabomdq@7659
   674
    if (!_this->egl_data) {
gabomdq@7659
   675
        return;
gabomdq@7659
   676
    }
gabomdq@7659
   677
    
gabomdq@7659
   678
    if (egl_surface != EGL_NO_SURFACE) {
gabomdq@7659
   679
        _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface);
gabomdq@7659
   680
    }
gabomdq@7659
   681
}
gabomdq@7659
   682
gabomdq@7659
   683
#endif /* SDL_VIDEO_OPENGL_EGL */
gabomdq@7659
   684
gabomdq@7659
   685
/* vi: set ts=4 sw=4 expandtab: */
slouken@7865
   686