src/video/SDL_egl.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 31 Oct 2018 15:16:51 -0700
changeset 12376 cfc65d4d49ae
parent 12269 754cd2042e21
child 12493 82f9397db3e7
permissions -rw-r--r--
Fixed bug 4349 - SDL_CreateWindow fails with KMS/DRM after upgrading Mesa to 18.2.3

Rainer Sabelka

After I did an upgrade of my arch Linux installation (resulting in an update of Mesa to version 18.2.3), all my SDL2 applications which use the KMS/DRM driver stopped working.
Reason: Creating a Window with SDL_CreateWindow failed because the call to EGL
eglCreateWindowSurface() returns an error "EGL_BAD_MATCH".
After investigating with the debugger I figured, that the configuration, which has been selected from the output of eglChooseConfig(), has an "EGL_NATIVE_VISUAL_ID" which does not match the "format" of the underlying gbm surface.

The attached patch fixes the problem. It does so, by mimicking Weston's behavior.
All configurations returned from eglChooseConfig() which have an visual_id different from the gbm format are discarded, and only from the remaining ones the "best" match is selected.
gabomdq@7659
     1
/*
gabomdq@7659
     2
 *  Simple DirectMedia Layer
slouken@11811
     3
 *  Copyright (C) 1997-2018 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@10878
    28
#if SDL_VIDEO_DRIVER_ANDROID
slouken@10878
    29
#include <android/native_window.h>
slouken@10878
    30
#endif
slouken@8734
    31
gabomdq@7659
    32
#include "SDL_sysvideo.h"
slouken@11175
    33
#include "SDL_log.h"
gabomdq@8021
    34
#include "SDL_egl_c.h"
gabomdq@8021
    35
#include "SDL_loadso.h"
gabomdq@8021
    36
#include "SDL_hints.h"
gabomdq@7782
    37
slime73@9595
    38
#ifdef EGL_KHR_create_context
slime73@9595
    39
/* EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension. */
slime73@9595
    40
#ifndef EGL_OPENGL_ES3_BIT_KHR
slime73@9595
    41
#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
slime73@9595
    42
#endif
slime73@9595
    43
#endif /* EGL_KHR_create_context */
slime73@9595
    44
gabomdq@7753
    45
#if SDL_VIDEO_DRIVER_RPI
gabomdq@7782
    46
/* Raspbian places the OpenGL ES/EGL binaries in a non standard path */
g@11829
    47
#define DEFAULT_EGL ( vc4 ? "libEGL.so.1" : "libbrcmEGL.so" )
g@11829
    48
#define DEFAULT_OGL_ES2 ( vc4 ? "libGLESv2.so.2" : "libbrcmGLESv2.so" )
g@11829
    49
#define ALT_EGL "libEGL.so"
g@11829
    50
#define ALT_OGL_ES2 "libGLESv2.so"
g@11829
    51
#define DEFAULT_OGL_ES_PVR ( vc4 ? "libGLES_CM.so.1" : "libbrcmGLESv2.so" )
g@11829
    52
#define DEFAULT_OGL_ES ( vc4 ? "libGLESv1_CM.so.1" : "libbrcmGLESv2.so" )
gabomdq@7782
    53
slouken@9164
    54
#elif SDL_VIDEO_DRIVER_ANDROID || SDL_VIDEO_DRIVER_VIVANTE
gabomdq@7782
    55
/* Android */
gabomdq@7782
    56
#define DEFAULT_EGL "libEGL.so"
gabomdq@7782
    57
#define DEFAULT_OGL_ES2 "libGLESv2.so"
gabomdq@7782
    58
#define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
gabomdq@7782
    59
#define DEFAULT_OGL_ES "libGLESv1_CM.so"
gabomdq@7782
    60
dludwig@8545
    61
#elif SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
gabomdq@8021
    62
/* EGL AND OpenGL ES support via ANGLE */
gabomdq@8021
    63
#define DEFAULT_EGL "libEGL.dll"
gabomdq@8021
    64
#define DEFAULT_OGL_ES2 "libGLESv2.dll"
gabomdq@8021
    65
#define DEFAULT_OGL_ES_PVR "libGLES_CM.dll"
gabomdq@8021
    66
#define DEFAULT_OGL_ES "libGLESv1_CM.dll"
gabomdq@8021
    67
slouken@11723
    68
#elif SDL_VIDEO_DRIVER_COCOA
slouken@11723
    69
/* EGL AND OpenGL ES support via ANGLE */
slouken@11723
    70
#define DEFAULT_EGL "libEGL.dylib"
slouken@11723
    71
#define DEFAULT_OGL_ES2 "libGLESv2.dylib"
slouken@11723
    72
#define DEFAULT_OGL_ES_PVR "libGLES_CM.dylib"   //???
slouken@11723
    73
#define DEFAULT_OGL_ES "libGLESv1_CM.dylib"     //???
slouken@11723
    74
gabomdq@7753
    75
#else
gabomdq@7782
    76
/* Desktop Linux */
gabomdq@8062
    77
#define DEFAULT_OGL "libGL.so.1"
gabomdq@7753
    78
#define DEFAULT_EGL "libEGL.so.1"
gabomdq@7753
    79
#define DEFAULT_OGL_ES2 "libGLESv2.so.2"
gabomdq@7753
    80
#define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
gabomdq@7753
    81
#define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
gabomdq@7753
    82
#endif /* SDL_VIDEO_DRIVER_RPI */
gabomdq@7659
    83
slouken@11363
    84
#ifdef SDL_VIDEO_STATIC_ANGLE
slouken@11363
    85
#define LOAD_FUNC(NAME) \
slouken@11363
    86
_this->egl_data->NAME = (void *)NAME;
slouken@11363
    87
#else
gabomdq@7659
    88
#define LOAD_FUNC(NAME) \
sezero@11872
    89
_this->egl_data->NAME = SDL_LoadFunction(_this->egl_data->dll_handle, #NAME); \
gabomdq@7659
    90
if (!_this->egl_data->NAME) \
gabomdq@7659
    91
{ \
gabomdq@7659
    92
    return SDL_SetError("Could not retrieve EGL function " #NAME); \
gabomdq@7659
    93
}
slouken@11363
    94
#endif
dludwig@10740
    95
dludwig@10740
    96
static const char * SDL_EGL_GetErrorName(EGLint eglErrorCode)
dludwig@10740
    97
{
dludwig@10740
    98
#define SDL_EGL_ERROR_TRANSLATE(e) case e: return #e;
dludwig@10740
    99
    switch (eglErrorCode) {
dludwig@10740
   100
        SDL_EGL_ERROR_TRANSLATE(EGL_SUCCESS);
dludwig@10740
   101
        SDL_EGL_ERROR_TRANSLATE(EGL_NOT_INITIALIZED);
dludwig@10740
   102
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ACCESS);
dludwig@10740
   103
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ALLOC);
dludwig@10740
   104
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ATTRIBUTE);
dludwig@10740
   105
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONTEXT);
dludwig@10740
   106
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONFIG);
dludwig@10740
   107
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CURRENT_SURFACE);
dludwig@10740
   108
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_DISPLAY);
dludwig@10740
   109
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_SURFACE);
dludwig@10740
   110
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_MATCH);
dludwig@10740
   111
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_PARAMETER);
dludwig@10740
   112
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_PIXMAP);
dludwig@10740
   113
        SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_WINDOW);
dludwig@10740
   114
        SDL_EGL_ERROR_TRANSLATE(EGL_CONTEXT_LOST);
dludwig@10740
   115
    }
dludwig@10740
   116
    return "";
dludwig@10740
   117
}
dludwig@10740
   118
dludwig@10740
   119
int SDL_EGL_SetErrorEx(const char * message, const char * eglFunctionName, EGLint eglErrorCode)
dludwig@10740
   120
{
dludwig@10740
   121
    const char * errorText = SDL_EGL_GetErrorName(eglErrorCode);
dludwig@10740
   122
    char altErrorText[32];
dludwig@10740
   123
    if (errorText[0] == '\0') {
dludwig@10740
   124
        /* An unknown-to-SDL error code was reported.  Report its hexadecimal value, instead of its name. */
dludwig@10740
   125
        SDL_snprintf(altErrorText, SDL_arraysize(altErrorText), "0x%x", (unsigned int)eglErrorCode);
dludwig@10740
   126
        errorText = altErrorText;
dludwig@10740
   127
    }
dludwig@10740
   128
    return SDL_SetError("%s (call to %s failed, reporting an error of %s)", message, eglFunctionName, errorText);
dludwig@10740
   129
}
dludwig@10740
   130
gabomdq@7659
   131
/* EGL implementation of SDL OpenGL ES support */
slouken@11175
   132
typedef enum {
slouken@11175
   133
    SDL_EGL_DISPLAY_EXTENSION,
slouken@11175
   134
    SDL_EGL_CLIENT_EXTENSION
slouken@11175
   135
} SDL_EGL_ExtensionType;
slouken@11175
   136
slouken@11175
   137
static SDL_bool SDL_EGL_HasExtension(_THIS, SDL_EGL_ExtensionType type, const char *ext)
knut@8962
   138
{
slouken@9821
   139
    size_t ext_len;
slouken@11175
   140
    const char *ext_override;
slouken@11175
   141
    const char *egl_extstr;
slouken@11175
   142
    const char *ext_start;
slouken@11175
   143
slouken@11175
   144
    /* Invalid extensions can be rejected early */
slouken@11175
   145
    if (ext == NULL || *ext == 0 || SDL_strchr(ext, ' ') != NULL) {
slouken@11175
   146
        /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid EGL extension"); */
slouken@11175
   147
        return SDL_FALSE;
slouken@11175
   148
    }
slouken@11175
   149
slouken@11175
   150
    /* Extensions can be masked with an environment variable.
slouken@11175
   151
     * Unlike the OpenGL override, this will use the set bits of an integer
slouken@11175
   152
     * to disable the extension.
slouken@11175
   153
     *  Bit   Action
slouken@11175
   154
     *  0     If set, the display extension is masked and not present to SDL.
slouken@11175
   155
     *  1     If set, the client extension is masked and not present to SDL.
slouken@11175
   156
     */
slouken@11175
   157
    ext_override = SDL_getenv(ext);
slouken@11175
   158
    if (ext_override != NULL) {
slouken@11175
   159
        int disable_ext = SDL_atoi(ext_override);
slouken@11175
   160
        if (disable_ext & 0x01 && type == SDL_EGL_DISPLAY_EXTENSION) {
slouken@11175
   161
            return SDL_FALSE;
slouken@11175
   162
        } else if (disable_ext & 0x02 && type == SDL_EGL_CLIENT_EXTENSION) {
slouken@11175
   163
            return SDL_FALSE;
slouken@11175
   164
        }
slouken@11175
   165
    }
knut@8962
   166
knut@8962
   167
    ext_len = SDL_strlen(ext);
slouken@11175
   168
    switch (type) {
slouken@11175
   169
    case SDL_EGL_DISPLAY_EXTENSION:
slouken@11175
   170
        egl_extstr = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
slouken@11175
   171
        break;
slouken@11175
   172
    case SDL_EGL_CLIENT_EXTENSION:
slouken@11175
   173
        /* EGL_EXT_client_extensions modifies eglQueryString to return client extensions
slouken@11175
   174
         * if EGL_NO_DISPLAY is passed. Implementations without it are required to return NULL.
slouken@11175
   175
         * This behavior is included in EGL 1.5.
slouken@11175
   176
         */
slouken@11175
   177
        egl_extstr = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
slouken@11175
   178
        break;
slouken@11175
   179
    default:
slouken@11175
   180
        /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid extension type"); */
slouken@11175
   181
        return SDL_FALSE;
slouken@11175
   182
    }
knut@8962
   183
slouken@11175
   184
    if (egl_extstr != NULL) {
slouken@11175
   185
        ext_start = egl_extstr;
knut@8962
   186
slouken@11175
   187
        while (*ext_start) {
slouken@11175
   188
            ext_start = SDL_strstr(ext_start, ext);
slouken@11175
   189
            if (ext_start == NULL) {
slouken@11175
   190
                return SDL_FALSE;
slouken@11175
   191
            }
slouken@11175
   192
            /* Check if the match is not just a substring of one of the extensions */
slouken@11175
   193
            if (ext_start == egl_extstr || *(ext_start - 1) == ' ') {
slouken@11175
   194
                if (ext_start[ext_len] == ' ' || ext_start[ext_len] == 0) {
slouken@11175
   195
                    return SDL_TRUE;
knut@8962
   196
                }
slouken@11175
   197
            }
slouken@11175
   198
            /* If the search stopped in the middle of an extension, skip to the end of it */
slouken@11175
   199
            ext_start += ext_len;
slouken@11175
   200
            while (*ext_start != ' ' && *ext_start != 0) {
slouken@11175
   201
                ext_start++;
knut@8962
   202
            }
knut@8962
   203
        }
knut@8962
   204
    }
knut@8962
   205
slouken@11175
   206
    return SDL_FALSE;
knut@8962
   207
}
gabomdq@7659
   208
gabomdq@7659
   209
void *
gabomdq@7659
   210
SDL_EGL_GetProcAddress(_THIS, const char *proc)
gabomdq@7659
   211
{
gabomdq@7659
   212
    static char procname[1024];
gabomdq@7659
   213
    void *retval;
gabomdq@7659
   214
    
gabomdq@7659
   215
    /* eglGetProcAddress is busted on Android http://code.google.com/p/android/issues/detail?id=7681 */
brandon@11516
   216
#if !defined(SDL_VIDEO_DRIVER_ANDROID)
gabomdq@7659
   217
    if (_this->egl_data->eglGetProcAddress) {
gabomdq@7659
   218
        retval = _this->egl_data->eglGetProcAddress(proc);
gabomdq@7659
   219
        if (retval) {
gabomdq@7659
   220
            return retval;
gabomdq@7659
   221
        }
gabomdq@7659
   222
    }
gabomdq@7659
   223
#endif
gabomdq@7659
   224
    
gabomdq@8021
   225
    retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, proc);
gabomdq@8021
   226
    if (!retval && SDL_strlen(proc) <= 1022) {
gabomdq@7659
   227
        procname[0] = '_';
gabomdq@8021
   228
        SDL_strlcpy(procname + 1, proc, 1022);
gabomdq@8021
   229
        retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, procname);
gabomdq@7659
   230
    }
gabomdq@7659
   231
    return retval;
gabomdq@7659
   232
}
gabomdq@7659
   233
gabomdq@7659
   234
void
gabomdq@7659
   235
SDL_EGL_UnloadLibrary(_THIS)
gabomdq@7659
   236
{
slouken@7865
   237
    if (_this->egl_data) {
slouken@7865
   238
        if (_this->egl_data->egl_display) {
slouken@7865
   239
            _this->egl_data->eglTerminate(_this->egl_data->egl_display);
slouken@7865
   240
            _this->egl_data->egl_display = NULL;
slouken@7865
   241
        }
slouken@7865
   242
gabomdq@8021
   243
        if (_this->egl_data->dll_handle) {
gabomdq@8021
   244
            SDL_UnloadObject(_this->egl_data->dll_handle);
gabomdq@8021
   245
            _this->egl_data->dll_handle = NULL;
slouken@7865
   246
        }
slouken@7865
   247
        if (_this->egl_data->egl_dll_handle) {
gabomdq@8021
   248
            SDL_UnloadObject(_this->egl_data->egl_dll_handle);
slouken@7865
   249
            _this->egl_data->egl_dll_handle = NULL;
slouken@7865
   250
        }
gabomdq@7659
   251
        
gabomdq@7659
   252
        SDL_free(_this->egl_data);
gabomdq@7659
   253
        _this->egl_data = NULL;
gabomdq@7659
   254
    }
gabomdq@7659
   255
}
gabomdq@7659
   256
gabomdq@7659
   257
int
slouken@11175
   258
SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
gabomdq@7659
   259
{
gabomdq@8021
   260
    void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
slouken@10461
   261
    const char *path = NULL;
slouken@11175
   262
    int egl_version_major = 0, egl_version_minor = 0;
dludwig@8545
   263
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
gabomdq@8021
   264
    const char *d3dcompiler;
gabomdq@8021
   265
#endif
connogriofa@11676
   266
#if SDL_VIDEO_DRIVER_RPI
connogriofa@11676
   267
    SDL_bool vc4 = (0 == access("/sys/module/vc4/", F_OK));
connogriofa@11676
   268
#endif
gabomdq@8021
   269
gabomdq@7659
   270
    if (_this->egl_data) {
slouken@11718
   271
        return SDL_SetError("EGL context already created");
gabomdq@7659
   272
    }
slouken@7865
   273
slouken@7865
   274
    _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
slouken@7865
   275
    if (!_this->egl_data) {
slouken@7865
   276
        return SDL_OutOfMemory();
slouken@7865
   277
    }
slouken@7865
   278
dludwig@8545
   279
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
gabomdq@8021
   280
    d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER);
gabomdq@8021
   281
    if (!d3dcompiler) {
slouken@8733
   282
        if (WIN_IsWindowsVistaOrGreater()) {
slouken@8733
   283
            d3dcompiler = "d3dcompiler_46.dll";
slouken@8733
   284
        } else {
slouken@8740
   285
            d3dcompiler = "d3dcompiler_43.dll";
slouken@8733
   286
        }
gabomdq@8021
   287
    }
gabomdq@8021
   288
    if (SDL_strcasecmp(d3dcompiler, "none") != 0) {
slouken@11219
   289
        if (SDL_LoadObject(d3dcompiler) == NULL) {
slouken@11219
   290
            SDL_ClearError();
slouken@11219
   291
        }
gabomdq@8021
   292
    }
slouken@7865
   293
#endif
slouken@7865
   294
slouken@11363
   295
#ifndef SDL_VIDEO_STATIC_ANGLE
gabomdq@7753
   296
    /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
gabomdq@8021
   297
    path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
gabomdq@8021
   298
    if (path != NULL) {
gabomdq@8021
   299
        egl_dll_handle = SDL_LoadObject(path);
gabomdq@8021
   300
    }
gabomdq@8021
   301
gabomdq@8021
   302
    if (egl_dll_handle == NULL) {
slime73@9595
   303
        if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
gabomdq@8062
   304
            if (_this->gl_config.major_version > 1) {
gabomdq@8062
   305
                path = DEFAULT_OGL_ES2;
gabomdq@8062
   306
                egl_dll_handle = SDL_LoadObject(path);
icculus@11462
   307
#ifdef ALT_OGL_ES2
connogriofa@11676
   308
                if (egl_dll_handle == NULL && !vc4) {
icculus@11462
   309
                    path = ALT_OGL_ES2;
icculus@11462
   310
                    egl_dll_handle = SDL_LoadObject(path);
icculus@11462
   311
                }
icculus@11462
   312
#endif
icculus@11462
   313
slime73@9595
   314
            } else {
gabomdq@8062
   315
                path = DEFAULT_OGL_ES;
gabomdq@8062
   316
                egl_dll_handle = SDL_LoadObject(path);
gabomdq@8062
   317
                if (egl_dll_handle == NULL) {
gabomdq@8062
   318
                    path = DEFAULT_OGL_ES_PVR;
gabomdq@8062
   319
                    egl_dll_handle = SDL_LoadObject(path);
gabomdq@8062
   320
                }
connogriofa@11676
   321
#ifdef ALT_OGL_ES2
connogriofa@11676
   322
                if (egl_dll_handle == NULL && !vc4) {
connogriofa@11676
   323
                    path = ALT_OGL_ES2;
connogriofa@11676
   324
                    egl_dll_handle = SDL_LoadObject(path);
connogriofa@11676
   325
                }
connogriofa@11676
   326
#endif
gabomdq@8062
   327
            }
gabomdq@8062
   328
        }
gabomdq@8062
   329
#ifdef DEFAULT_OGL         
gabomdq@8062
   330
        else {
gabomdq@8062
   331
            path = DEFAULT_OGL;
gabomdq@8021
   332
            egl_dll_handle = SDL_LoadObject(path);
gabomdq@8021
   333
        }
gabomdq@8062
   334
#endif        
gabomdq@7753
   335
    }
slouken@7865
   336
    _this->egl_data->egl_dll_handle = egl_dll_handle;
gabomdq@7753
   337
gabomdq@7753
   338
    if (egl_dll_handle == NULL) {
gabomdq@8062
   339
        return SDL_SetError("Could not initialize OpenGL / GLES library");
gabomdq@7753
   340
    }
gabomdq@8021
   341
gabomdq@7753
   342
    /* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */
gabomdq@8021
   343
    if (egl_path != NULL) {
gabomdq@8021
   344
        dll_handle = SDL_LoadObject(egl_path);
gabomdq@8021
   345
    }   
gabomdq@8105
   346
    /* Try loading a EGL symbol, if it does not work try the default library paths */
gabomdq@8872
   347
    if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
gabomdq@8021
   348
        if (dll_handle != NULL) {
gabomdq@8021
   349
            SDL_UnloadObject(dll_handle);
gabomdq@8021
   350
        }
gabomdq@8021
   351
        path = SDL_getenv("SDL_VIDEO_EGL_DRIVER");
gabomdq@7659
   352
        if (path == NULL) {
gabomdq@7659
   353
            path = DEFAULT_EGL;
gabomdq@7659
   354
        }
gabomdq@8021
   355
        dll_handle = SDL_LoadObject(path);
icculus@11462
   356
icculus@11462
   357
#ifdef ALT_EGL
connogriofa@11676
   358
        if (dll_handle == NULL && !vc4) {
icculus@11462
   359
            path = ALT_EGL;
icculus@11462
   360
            dll_handle = SDL_LoadObject(path);
icculus@11462
   361
        }
icculus@11462
   362
#endif
icculus@11462
   363
gabomdq@8872
   364
        if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
gabomdq@8872
   365
            if (dll_handle != NULL) {
gabomdq@8872
   366
                SDL_UnloadObject(dll_handle);
gabomdq@8872
   367
            }
gabomdq@8021
   368
            return SDL_SetError("Could not load EGL library");
gabomdq@8021
   369
        }
gabomdq@8763
   370
        SDL_ClearError();
gabomdq@7753
   371
    }
slouken@11363
   372
#endif
slouken@7865
   373
gabomdq@8021
   374
    _this->egl_data->dll_handle = dll_handle;
gabomdq@7659
   375
gabomdq@7659
   376
    /* Load new function pointers */
gabomdq@7659
   377
    LOAD_FUNC(eglGetDisplay);
gabomdq@7659
   378
    LOAD_FUNC(eglInitialize);
gabomdq@7659
   379
    LOAD_FUNC(eglTerminate);
gabomdq@7659
   380
    LOAD_FUNC(eglGetProcAddress);
gabomdq@7659
   381
    LOAD_FUNC(eglChooseConfig);
gabomdq@7659
   382
    LOAD_FUNC(eglGetConfigAttrib);
gabomdq@7659
   383
    LOAD_FUNC(eglCreateContext);
gabomdq@7659
   384
    LOAD_FUNC(eglDestroyContext);
slouken@11719
   385
    LOAD_FUNC(eglCreatePbufferSurface);
gabomdq@7659
   386
    LOAD_FUNC(eglCreateWindowSurface);
gabomdq@7659
   387
    LOAD_FUNC(eglDestroySurface);
gabomdq@7659
   388
    LOAD_FUNC(eglMakeCurrent);
gabomdq@7659
   389
    LOAD_FUNC(eglSwapBuffers);
gabomdq@7659
   390
    LOAD_FUNC(eglSwapInterval);
gabomdq@7659
   391
    LOAD_FUNC(eglWaitNative);
gabomdq@7659
   392
    LOAD_FUNC(eglWaitGL);
gabomdq@8062
   393
    LOAD_FUNC(eglBindAPI);
knut@8962
   394
    LOAD_FUNC(eglQueryString);
dludwig@10740
   395
    LOAD_FUNC(eglGetError);
dludwig@10740
   396
slouken@11175
   397
    if (_this->egl_data->eglQueryString) {
slouken@11175
   398
        /* EGL 1.5 allows querying for client version */
slouken@11175
   399
        const char *egl_version = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_VERSION);
slouken@11175
   400
        if (egl_version != NULL) {
slouken@11175
   401
            if (SDL_sscanf(egl_version, "%d.%d", &egl_version_major, &egl_version_minor) != 2) {
slouken@11175
   402
                egl_version_major = 0;
slouken@11175
   403
                egl_version_minor = 0;
slouken@11175
   404
                SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not parse EGL version string: %s", egl_version);
slouken@11175
   405
            }
slouken@11175
   406
        }
slouken@11175
   407
    }
slouken@11175
   408
slouken@12269
   409
    _this->egl_data->egl_version_major = egl_version_major;
slouken@12269
   410
    _this->egl_data->egl_version_minor = egl_version_minor;
slouken@12269
   411
slouken@11175
   412
    if (egl_version_major == 1 && egl_version_minor == 5) {
slouken@11175
   413
        LOAD_FUNC(eglGetPlatformDisplay);
slouken@11175
   414
    }
slouken@11175
   415
slouken@11175
   416
    _this->egl_data->egl_display = EGL_NO_DISPLAY;
dludwig@8663
   417
#if !defined(__WINRT__)
slouken@11175
   418
    if (platform) {
slouken@11175
   419
        if (egl_version_major == 1 && egl_version_minor == 5) {
icculus@11418
   420
            _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, (void *)(size_t)native_display, NULL);
slouken@11175
   421
        } else {
slouken@11175
   422
            if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base")) {
sezero@11872
   423
                _this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddress(_this, "eglGetPlatformDisplayEXT");
slouken@11175
   424
                if (_this->egl_data->eglGetPlatformDisplayEXT) {
icculus@11418
   425
                    _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(platform, (void *)(size_t)native_display, NULL);
slouken@11175
   426
                }
slouken@11175
   427
            }
slouken@11175
   428
        }
slouken@11175
   429
    }
slouken@11175
   430
    /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
slouken@11175
   431
    if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
slouken@11175
   432
        _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
slouken@11175
   433
    }
slouken@11175
   434
    if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
gabomdq@7659
   435
        return SDL_SetError("Could not get EGL display");
gabomdq@7659
   436
    }
gabomdq@7659
   437
    
gabomdq@7659
   438
    if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
gabomdq@7659
   439
        return SDL_SetError("Could not initialize EGL");
gabomdq@7659
   440
    }
dludwig@8663
   441
#endif
gabomdq@7659
   442
gabomdq@7659
   443
    if (path) {
gabomdq@8021
   444
        SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
gabomdq@7659
   445
    } else {
gabomdq@8021
   446
        *_this->gl_config.driver_path = '\0';
gabomdq@7659
   447
    }
gabomdq@7659
   448
    
gabomdq@8041
   449
    return 0;
gabomdq@7659
   450
}
gabomdq@7659
   451
slouken@12376
   452
void
slouken@12376
   453
SDL_EGL_SetRequiredVisualId(_THIS, int visual_id) 
slouken@12376
   454
{
slouken@12376
   455
    _this->egl_data->egl_required_visual_id=visual_id;
slouken@12376
   456
}
slouken@12376
   457
slouken@11983
   458
#ifdef DUMP_EGL_CONFIG
slouken@11983
   459
slouken@11983
   460
#define ATTRIBUTE(_attr) { _attr, #_attr }
slouken@11983
   461
slouken@11983
   462
typedef struct {
slouken@11983
   463
    EGLint attribute;
slouken@11983
   464
    char const* name;
slouken@11983
   465
} Attribute;
slouken@11983
   466
slouken@11983
   467
Attribute attributes[] = {
slouken@11983
   468
        ATTRIBUTE( EGL_BUFFER_SIZE ),
slouken@11983
   469
        ATTRIBUTE( EGL_ALPHA_SIZE ),
slouken@11983
   470
        ATTRIBUTE( EGL_BLUE_SIZE ),
slouken@11983
   471
        ATTRIBUTE( EGL_GREEN_SIZE ),
slouken@11983
   472
        ATTRIBUTE( EGL_RED_SIZE ),
slouken@11983
   473
        ATTRIBUTE( EGL_DEPTH_SIZE ),
slouken@11983
   474
        ATTRIBUTE( EGL_STENCIL_SIZE ),
slouken@11983
   475
        ATTRIBUTE( EGL_CONFIG_CAVEAT ),
slouken@11983
   476
        ATTRIBUTE( EGL_CONFIG_ID ),
slouken@11983
   477
        ATTRIBUTE( EGL_LEVEL ),
slouken@11983
   478
        ATTRIBUTE( EGL_MAX_PBUFFER_HEIGHT ),
slouken@11983
   479
        ATTRIBUTE( EGL_MAX_PBUFFER_WIDTH ),
slouken@11983
   480
        ATTRIBUTE( EGL_MAX_PBUFFER_PIXELS ),
slouken@11983
   481
        ATTRIBUTE( EGL_NATIVE_RENDERABLE ),
slouken@11983
   482
        ATTRIBUTE( EGL_NATIVE_VISUAL_ID ),
slouken@11983
   483
        ATTRIBUTE( EGL_NATIVE_VISUAL_TYPE ),
slouken@11983
   484
        ATTRIBUTE( EGL_SAMPLES ),
slouken@11983
   485
        ATTRIBUTE( EGL_SAMPLE_BUFFERS ),
slouken@11983
   486
        ATTRIBUTE( EGL_SURFACE_TYPE ),
slouken@11983
   487
        ATTRIBUTE( EGL_TRANSPARENT_TYPE ),
slouken@11983
   488
        ATTRIBUTE( EGL_TRANSPARENT_BLUE_VALUE ),
slouken@11983
   489
        ATTRIBUTE( EGL_TRANSPARENT_GREEN_VALUE ),
slouken@11983
   490
        ATTRIBUTE( EGL_TRANSPARENT_RED_VALUE ),
slouken@11983
   491
        ATTRIBUTE( EGL_BIND_TO_TEXTURE_RGB ),
slouken@11983
   492
        ATTRIBUTE( EGL_BIND_TO_TEXTURE_RGBA ),
slouken@11983
   493
        ATTRIBUTE( EGL_MIN_SWAP_INTERVAL ),
slouken@11983
   494
        ATTRIBUTE( EGL_MAX_SWAP_INTERVAL ),
slouken@11983
   495
        ATTRIBUTE( EGL_LUMINANCE_SIZE ),
slouken@11983
   496
        ATTRIBUTE( EGL_ALPHA_MASK_SIZE ),
slouken@11983
   497
        ATTRIBUTE( EGL_COLOR_BUFFER_TYPE ),
slouken@11983
   498
        ATTRIBUTE( EGL_RENDERABLE_TYPE ),
slouken@11983
   499
        ATTRIBUTE( EGL_MATCH_NATIVE_PIXMAP ),
slouken@11983
   500
        ATTRIBUTE( EGL_CONFORMANT ),
slouken@11983
   501
};
slouken@11983
   502
slouken@11983
   503
slouken@11983
   504
static void dumpconfig(_THIS, EGLConfig config)
slouken@11983
   505
{
slouken@11983
   506
    int attr;
slouken@11983
   507
    for (attr = 0 ; attr<sizeof(attributes)/sizeof(Attribute) ; attr++) {
slouken@11983
   508
        EGLint value;
slouken@11983
   509
        _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, config, attributes[attr].attribute, &value);
slouken@11983
   510
        SDL_Log("\t%-32s: %10d (0x%08x)\n", attributes[attr].name, value, value);
slouken@11983
   511
    }
slouken@11983
   512
}
slouken@11983
   513
slouken@11983
   514
#endif /* DUMP_EGL_CONFIG */
slouken@11983
   515
gabomdq@7659
   516
int
gabomdq@7659
   517
SDL_EGL_ChooseConfig(_THIS) 
gabomdq@7659
   518
{
slouken@11175
   519
/* 64 seems nice. */
gabomdq@7659
   520
    EGLint attribs[64];
gabomdq@8021
   521
    EGLint found_configs = 0, value;
gabomdq@8015
   522
    /* 128 seems even nicer here */
gabomdq@8015
   523
    EGLConfig configs[128];
gabomdq@8021
   524
    int i, j, best_bitdiff = -1, bitdiff;
slouken@11175
   525
   
gabomdq@7659
   526
    if (!_this->egl_data) {
gabomdq@7659
   527
        /* The EGL library wasn't loaded, SDL_GetError() should have info */
gabomdq@7659
   528
        return -1;
gabomdq@7659
   529
    }
gabomdq@7659
   530
  
gabomdq@7659
   531
    /* Get a valid EGL configuration */
gabomdq@7659
   532
    i = 0;
gabomdq@7659
   533
    attribs[i++] = EGL_RED_SIZE;
gabomdq@7659
   534
    attribs[i++] = _this->gl_config.red_size;
gabomdq@7659
   535
    attribs[i++] = EGL_GREEN_SIZE;
gabomdq@7659
   536
    attribs[i++] = _this->gl_config.green_size;
gabomdq@7659
   537
    attribs[i++] = EGL_BLUE_SIZE;
gabomdq@7659
   538
    attribs[i++] = _this->gl_config.blue_size;
gabomdq@7659
   539
    
gabomdq@7659
   540
    if (_this->gl_config.alpha_size) {
gabomdq@7659
   541
        attribs[i++] = EGL_ALPHA_SIZE;
gabomdq@7659
   542
        attribs[i++] = _this->gl_config.alpha_size;
gabomdq@7659
   543
    }
gabomdq@7659
   544
    
gabomdq@7659
   545
    if (_this->gl_config.buffer_size) {
gabomdq@7659
   546
        attribs[i++] = EGL_BUFFER_SIZE;
gabomdq@7659
   547
        attribs[i++] = _this->gl_config.buffer_size;
gabomdq@7659
   548
    }
gabomdq@7659
   549
    
gabomdq@7659
   550
    attribs[i++] = EGL_DEPTH_SIZE;
gabomdq@7659
   551
    attribs[i++] = _this->gl_config.depth_size;
gabomdq@7659
   552
    
gabomdq@7659
   553
    if (_this->gl_config.stencil_size) {
gabomdq@7659
   554
        attribs[i++] = EGL_STENCIL_SIZE;
gabomdq@7659
   555
        attribs[i++] = _this->gl_config.stencil_size;
gabomdq@7659
   556
    }
gabomdq@7659
   557
    
gabomdq@7659
   558
    if (_this->gl_config.multisamplebuffers) {
gabomdq@7659
   559
        attribs[i++] = EGL_SAMPLE_BUFFERS;
gabomdq@7659
   560
        attribs[i++] = _this->gl_config.multisamplebuffers;
gabomdq@7659
   561
    }
gabomdq@7659
   562
    
gabomdq@7659
   563
    if (_this->gl_config.multisamplesamples) {
gabomdq@7659
   564
        attribs[i++] = EGL_SAMPLES;
gabomdq@7659
   565
        attribs[i++] = _this->gl_config.multisamplesamples;
gabomdq@7659
   566
    }
slime73@9595
   567
gabomdq@7659
   568
    attribs[i++] = EGL_RENDERABLE_TYPE;
slime73@9595
   569
    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
slime73@9595
   570
#ifdef EGL_KHR_create_context
slime73@9595
   571
        if (_this->gl_config.major_version >= 3 &&
slouken@11175
   572
            SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
slime73@9595
   573
            attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
slime73@9595
   574
        } else
slime73@9595
   575
#endif
slime73@9595
   576
        if (_this->gl_config.major_version >= 2) {
gabomdq@8062
   577
            attribs[i++] = EGL_OPENGL_ES2_BIT;
gabomdq@8062
   578
        } else {
gabomdq@8062
   579
            attribs[i++] = EGL_OPENGL_ES_BIT;
gabomdq@8062
   580
        }
gabomdq@8062
   581
        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
slime73@9595
   582
    } else {
gabomdq@8062
   583
        attribs[i++] = EGL_OPENGL_BIT;
gabomdq@8062
   584
        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
gabomdq@7659
   585
    }
slime73@9827
   586
slouken@11677
   587
    if (_this->egl_data->egl_surfacetype) {
slouken@11677
   588
        attribs[i++] = EGL_SURFACE_TYPE;
slouken@11677
   589
        attribs[i++] = _this->egl_data->egl_surfacetype;
slouken@11677
   590
    }
slouken@11677
   591
gabomdq@7659
   592
    attribs[i++] = EGL_NONE;
slime73@9827
   593
gabomdq@7659
   594
    if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display,
gabomdq@7659
   595
        attribs,
gabomdq@8015
   596
        configs, SDL_arraysize(configs),
gabomdq@7659
   597
        &found_configs) == EGL_FALSE ||
gabomdq@7659
   598
        found_configs == 0) {
dludwig@10740
   599
        return SDL_EGL_SetError("Couldn't find matching EGL config", "eglChooseConfig");
gabomdq@7659
   600
    }
slime73@9827
   601
gabomdq@8015
   602
    /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */
gabomdq@8015
   603
    /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
gabomdq@8021
   604
slime73@9595
   605
    for (i = 0; i < found_configs; i++ ) {
slouken@12376
   606
        if (_this->egl_data->egl_required_visual_id)
slouken@12376
   607
        {
slouken@12376
   608
            EGLint format;
slouken@12376
   609
            _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
slouken@12376
   610
                                            configs[i], 
slouken@12376
   611
                                            EGL_NATIVE_VISUAL_ID, &format);
slouken@12376
   612
            if (_this->egl_data->egl_required_visual_id != format)
slouken@12376
   613
                continue;
slouken@12376
   614
        }
slouken@12376
   615
gabomdq@8015
   616
        bitdiff = 0;
gabomdq@8021
   617
        for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
gabomdq@8015
   618
            if (attribs[j] == EGL_NONE) {
gabomdq@8015
   619
               break;
gabomdq@8015
   620
            }
gabomdq@8015
   621
            
gabomdq@8015
   622
            if ( attribs[j+1] != EGL_DONT_CARE && (
gabomdq@8015
   623
                attribs[j] == EGL_RED_SIZE ||
gabomdq@8015
   624
                attribs[j] == EGL_GREEN_SIZE ||
gabomdq@8015
   625
                attribs[j] == EGL_BLUE_SIZE ||
gabomdq@8015
   626
                attribs[j] == EGL_ALPHA_SIZE ||
gabomdq@8015
   627
                attribs[j] == EGL_DEPTH_SIZE ||
gabomdq@8015
   628
                attribs[j] == EGL_STENCIL_SIZE)) {
gabomdq@8015
   629
                _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], attribs[j], &value);
gabomdq@8015
   630
                bitdiff += value - attribs[j + 1]; /* value is always >= attrib */
gabomdq@8015
   631
            }
gabomdq@8015
   632
        }
gabomdq@8015
   633
gabomdq@8015
   634
        if (bitdiff < best_bitdiff || best_bitdiff == -1) {
gabomdq@8015
   635
            _this->egl_data->egl_config = configs[i];
gabomdq@8015
   636
            
gabomdq@8015
   637
            best_bitdiff = bitdiff;
gabomdq@8015
   638
        }
slime73@9595
   639
slime73@9595
   640
        if (bitdiff == 0) {
slime73@9595
   641
            break; /* we found an exact match! */
slime73@9595
   642
        }
gabomdq@8015
   643
    }
slouken@11983
   644
slouken@11983
   645
#ifdef DUMP_EGL_CONFIG
slouken@11983
   646
    dumpconfig(_this, _this->egl_data->egl_config);
slouken@11983
   647
#endif
gabomdq@8015
   648
    
gabomdq@7659
   649
    return 0;
gabomdq@7659
   650
}
gabomdq@7659
   651
gabomdq@7659
   652
SDL_GLContext
gabomdq@7659
   653
SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
gabomdq@7659
   654
{
slime73@9595
   655
    /* max 14 values plus terminator. */
slime73@9595
   656
    EGLint attribs[15];
slime73@9595
   657
    int attr = 0;
slime73@9595
   658
gabomdq@8061
   659
    EGLContext egl_context, share_context = EGL_NO_CONTEXT;
slime73@9595
   660
    EGLint profile_mask = _this->gl_config.profile_mask;
slime73@9637
   661
    EGLint major_version = _this->gl_config.major_version;
slime73@9637
   662
    EGLint minor_version = _this->gl_config.minor_version;
slime73@9637
   663
    SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
slime73@9595
   664
gabomdq@7659
   665
    if (!_this->egl_data) {
gabomdq@7659
   666
        /* The EGL library wasn't loaded, SDL_GetError() should have info */
gabomdq@7659
   667
        return NULL;
gabomdq@7659
   668
    }
slime73@9595
   669
gabomdq@8061
   670
    if (_this->gl_config.share_with_current_context) {
gabomdq@8061
   671
        share_context = (EGLContext)SDL_GL_GetCurrentContext();
gabomdq@7659
   672
    }
slime73@9595
   673
slouken@12269
   674
#if SDL_VIDEO_DRIVER_ANDROID
slouken@12269
   675
    if ((_this->gl_config.flags & SDL_GL_CONTEXT_DEBUG_FLAG) != 0) {
slouken@12269
   676
        /* If SDL_GL_CONTEXT_DEBUG_FLAG is set but EGL_KHR_debug unsupported, unset.
slouken@12269
   677
         * This is required because some Android devices like to complain about it
slouken@12269
   678
         * by "silently" failing, logging a hint which could be easily overlooked:
slouken@12269
   679
         * E/libEGL  (26984): validate_display:255 error 3008 (EGL_BAD_DISPLAY)
slouken@12269
   680
         * The following explicitly checks for EGL_KHR_debug before EGL 1.5
slouken@12269
   681
         */
slouken@12269
   682
        int egl_version_major = _this->egl_data->egl_version_major;
slouken@12269
   683
        int egl_version_minor = _this->egl_data->egl_version_minor;
slouken@12269
   684
        if (((egl_version_major < 1) || (egl_version_major == 1 && egl_version_minor < 5)) &&
slouken@12269
   685
            !SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_debug")) {
slouken@12269
   686
            /* SDL profile bits match EGL profile bits. */
slouken@12269
   687
            _this->gl_config.flags &= ~SDL_GL_CONTEXT_DEBUG_FLAG;
slouken@12269
   688
        }
slouken@12269
   689
    }
slouken@12269
   690
#endif
slouken@12269
   691
slime73@9595
   692
    /* Set the context version and other attributes. */
slime73@9637
   693
    if ((major_version < 3 || (minor_version == 0 && profile_es)) &&
slime73@9637
   694
        _this->gl_config.flags == 0 &&
slime73@9637
   695
        (profile_mask == 0 || profile_es)) {
slime73@9637
   696
        /* Create a context without using EGL_KHR_create_context attribs.
slime73@9637
   697
         * When creating a GLES context without EGL_KHR_create_context we can
slime73@9637
   698
         * only specify the major version. When creating a desktop GL context
slime73@9637
   699
         * we can't specify any version, so we only try in that case when the
slime73@9637
   700
         * version is less than 3.0 (matches SDL's GLX/WGL behavior.)
slime73@9637
   701
         */
slime73@9637
   702
        if (profile_es) {
slime73@9595
   703
            attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION;
slime73@9637
   704
            attribs[attr++] = SDL_max(major_version, 1);
slime73@9595
   705
        }
slime73@9595
   706
    } else {
slime73@9595
   707
#ifdef EGL_KHR_create_context
slime73@9595
   708
        /* The Major/minor version, context profiles, and context flags can
slime73@9595
   709
         * only be specified when this extension is available.
slime73@9595
   710
         */
slouken@11175
   711
        if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
slime73@9595
   712
            attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
slime73@9637
   713
            attribs[attr++] = major_version;
slime73@9595
   714
            attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;
slime73@9637
   715
            attribs[attr++] = minor_version;
slime73@9595
   716
slime73@9595
   717
            /* SDL profile bits match EGL profile bits. */
slime73@9595
   718
            if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
slime73@9595
   719
                attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
slime73@9595
   720
                attribs[attr++] = profile_mask;
slime73@9595
   721
            }
slime73@9595
   722
slime73@9595
   723
            /* SDL flags match EGL flags. */
slime73@9595
   724
            if (_this->gl_config.flags != 0) {
slime73@9595
   725
                attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
slime73@9595
   726
                attribs[attr++] = _this->gl_config.flags;
slime73@9595
   727
            }
slime73@9595
   728
        } else
slime73@9595
   729
#endif /* EGL_KHR_create_context */
slime73@9595
   730
        {
slime73@9595
   731
            SDL_SetError("Could not create EGL context (context attributes are not supported)");
slime73@9595
   732
            return NULL;
slime73@9595
   733
        }
slime73@9595
   734
    }
slime73@9595
   735
flibitijibibo@11347
   736
    if (_this->gl_config.no_error) {
flibitijibibo@11347
   737
#ifdef EGL_KHR_create_context_no_error
flibitijibibo@11347
   738
        if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context_no_error")) {
flibitijibibo@11347
   739
            attribs[attr++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
flibitijibibo@11347
   740
            attribs[attr++] = _this->gl_config.no_error;
flibitijibibo@11347
   741
        } else
flibitijibibo@11347
   742
#endif
flibitijibibo@11347
   743
        {
flibitijibibo@11347
   744
            SDL_SetError("EGL implementation does not support no_error contexts");
flibitijibibo@11347
   745
            return NULL;
flibitijibibo@11347
   746
        }
flibitijibibo@11347
   747
    }
flibitijibibo@11347
   748
slime73@9595
   749
    attribs[attr++] = EGL_NONE;
slime73@9595
   750
gabomdq@8062
   751
    /* Bind the API */
slime73@9637
   752
    if (profile_es) {
gabomdq@8062
   753
        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
slime73@9595
   754
    } else {
slime73@9595
   755
        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
slime73@9595
   756
    }
gabomdq@7659
   757
slime73@9595
   758
    egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
slime73@9595
   759
                                      _this->egl_data->egl_config,
slime73@9595
   760
                                      share_context, attribs);
knut@8962
   761
gabomdq@7659
   762
    if (egl_context == EGL_NO_CONTEXT) {
dludwig@10740
   763
        SDL_EGL_SetError("Could not create EGL context", "eglCreateContext");
gabomdq@7659
   764
        return NULL;
gabomdq@7659
   765
    }
slime73@9595
   766
gabomdq@7659
   767
    _this->egl_data->egl_swapinterval = 0;
slime73@9595
   768
gabomdq@7659
   769
    if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
dludwig@10740
   770
        /* Save the SDL error set by SDL_EGL_MakeCurrent */
dludwig@10740
   771
        char errorText[1024];
dludwig@10740
   772
        SDL_strlcpy(errorText, SDL_GetError(), SDL_arraysize(errorText));
dludwig@10740
   773
dludwig@10740
   774
        /* Delete the context, which may alter the value returned by SDL_GetError() */
gabomdq@7659
   775
        SDL_EGL_DeleteContext(_this, egl_context);
dludwig@10740
   776
dludwig@10740
   777
        /* Restore the SDL error */
dludwig@10740
   778
        SDL_SetError("%s", errorText);
dludwig@10740
   779
gabomdq@7659
   780
        return NULL;
gabomdq@7659
   781
    }
slime73@9595
   782
gabomdq@7659
   783
    return (SDL_GLContext) egl_context;
gabomdq@7659
   784
}
gabomdq@7659
   785
gabomdq@7659
   786
int
gabomdq@7659
   787
SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
gabomdq@7659
   788
{
gabomdq@7679
   789
    EGLContext egl_context = (EGLContext) context;
gabomdq@7679
   790
gabomdq@7659
   791
    if (!_this->egl_data) {
gabomdq@7659
   792
        return SDL_SetError("OpenGL not initialized");
gabomdq@7659
   793
    }
gabomdq@7659
   794
    
gabomdq@7659
   795
    /* The android emulator crashes badly if you try to eglMakeCurrent 
gabomdq@7659
   796
     * with a valid context and invalid surface, so we have to check for both here.
gabomdq@7659
   797
     */
gabomdq@7659
   798
    if (!egl_context || !egl_surface) {
gabomdq@7659
   799
         _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
slime73@9595
   800
    } else {
gabomdq@7659
   801
        if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
gabomdq@7659
   802
            egl_surface, egl_surface, egl_context)) {
dludwig@10740
   803
            return SDL_EGL_SetError("Unable to make EGL context current", "eglMakeCurrent");
gabomdq@7659
   804
        }
gabomdq@7659
   805
    }
gabomdq@7659
   806
      
gabomdq@7659
   807
    return 0;
gabomdq@7659
   808
}
gabomdq@7659
   809
gabomdq@7659
   810
int
gabomdq@7659
   811
SDL_EGL_SetSwapInterval(_THIS, int interval)
gabomdq@7659
   812
{
gabomdq@7679
   813
    EGLBoolean status;
gabomdq@7679
   814
    
gabomdq@7702
   815
    if (!_this->egl_data) {
gabomdq@7702
   816
        return SDL_SetError("EGL not initialized");
gabomdq@7659
   817
    }
gabomdq@7659
   818
    
gabomdq@7659
   819
    status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval);
gabomdq@7659
   820
    if (status == EGL_TRUE) {
gabomdq@7659
   821
        _this->egl_data->egl_swapinterval = interval;
gabomdq@7659
   822
        return 0;
gabomdq@7659
   823
    }
gabomdq@7659
   824
    
dludwig@10740
   825
    return SDL_EGL_SetError("Unable to set the EGL swap interval", "eglSwapInterval");
gabomdq@7659
   826
}
gabomdq@7659
   827
gabomdq@7659
   828
int
gabomdq@7659
   829
SDL_EGL_GetSwapInterval(_THIS)
gabomdq@7659
   830
{
gabomdq@7702
   831
    if (!_this->egl_data) {
philipp@10169
   832
        SDL_SetError("EGL not initialized");
philipp@10169
   833
        return 0;
gabomdq@7659
   834
    }
gabomdq@7659
   835
    
gabomdq@7659
   836
    return _this->egl_data->egl_swapinterval;
gabomdq@7659
   837
}
gabomdq@7659
   838
slouken@10693
   839
int
gabomdq@7659
   840
SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface)
gabomdq@7659
   841
{
slouken@10693
   842
    if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface)) {
dludwig@10740
   843
        return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers");
slouken@10693
   844
    }
slouken@10693
   845
    return 0;
gabomdq@7659
   846
}
gabomdq@7659
   847
gabomdq@7659
   848
void
gabomdq@7659
   849
SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
gabomdq@7659
   850
{
gabomdq@7679
   851
    EGLContext egl_context = (EGLContext) context;
gabomdq@7679
   852
gabomdq@7659
   853
    /* Clean up GLES and EGL */
gabomdq@7659
   854
    if (!_this->egl_data) {
gabomdq@7659
   855
        return;
gabomdq@7659
   856
    }
gabomdq@7659
   857
    
gabomdq@7896
   858
    if (egl_context != NULL && egl_context != EGL_NO_CONTEXT) {
gabomdq@7659
   859
        _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context);
gabomdq@7659
   860
    }
gabomdq@7659
   861
        
gabomdq@7659
   862
}
gabomdq@7659
   863
gabomdq@7659
   864
EGLSurface *
gabomdq@7659
   865
SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) 
gabomdq@7659
   866
{
deveee@11830
   867
    /* max 2 values plus terminator. */
deveee@11830
   868
    EGLint attribs[3];
deveee@11830
   869
    int attr = 0;
slouken@12201
   870
dludwig@10740
   871
    EGLSurface * surface;
dludwig@10740
   872
gabomdq@8041
   873
    if (SDL_EGL_ChooseConfig(_this) != 0) {
slouken@8045
   874
        return EGL_NO_SURFACE;
gabomdq@8041
   875
    }
gabomdq@8041
   876
    
slouken@10878
   877
#if SDL_VIDEO_DRIVER_ANDROID
slouken@8976
   878
    {
slouken@8976
   879
        /* Android docs recommend doing this!
slouken@8976
   880
         * Ref: http://developer.android.com/reference/android/app/NativeActivity.html 
slouken@8976
   881
         */
slouken@8976
   882
        EGLint format;
slouken@8976
   883
        _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
slouken@8976
   884
                                            _this->egl_data->egl_config, 
slouken@8976
   885
                                            EGL_NATIVE_VISUAL_ID, &format);
gabomdq@8971
   886
slouken@8976
   887
        ANativeWindow_setBuffersGeometry(nw, 0, 0, format);
slouken@8976
   888
    }
gabomdq@8971
   889
#endif    
deveee@11830
   890
    if (_this->gl_config.framebuffer_srgb_capable) {
deveee@11830
   891
#ifdef EGL_KHR_gl_colorspace
deveee@11830
   892
        if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_gl_colorspace")) {
deveee@11830
   893
            attribs[attr++] = EGL_GL_COLORSPACE_KHR;
deveee@11830
   894
            attribs[attr++] = EGL_GL_COLORSPACE_SRGB_KHR;
deveee@11830
   895
        } else
deveee@11830
   896
#endif
deveee@11830
   897
        {
deveee@11830
   898
            SDL_SetError("EGL implementation does not support sRGB system framebuffers");
deveee@11830
   899
            return EGL_NO_SURFACE;
deveee@11830
   900
        }
deveee@11830
   901
    }
slouken@12201
   902
deveee@11830
   903
    attribs[attr++] = EGL_NONE;
gabomdq@8971
   904
    
dludwig@10740
   905
    surface = _this->egl_data->eglCreateWindowSurface(
gabomdq@7659
   906
            _this->egl_data->egl_display,
gabomdq@7659
   907
            _this->egl_data->egl_config,
deveee@11830
   908
            nw, &attribs[0]);
dludwig@10740
   909
    if (surface == EGL_NO_SURFACE) {
dludwig@10740
   910
        SDL_EGL_SetError("unable to create an EGL window surface", "eglCreateWindowSurface");
dludwig@10740
   911
    }
dludwig@10740
   912
    return surface;
gabomdq@7659
   913
}
gabomdq@7659
   914
gabomdq@7659
   915
void
gabomdq@7659
   916
SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) 
gabomdq@7659
   917
{
gabomdq@7659
   918
    if (!_this->egl_data) {
gabomdq@7659
   919
        return;
gabomdq@7659
   920
    }
gabomdq@7659
   921
    
gabomdq@7659
   922
    if (egl_surface != EGL_NO_SURFACE) {
gabomdq@7659
   923
        _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface);
gabomdq@7659
   924
    }
gabomdq@7659
   925
}
gabomdq@7659
   926
gabomdq@7659
   927
#endif /* SDL_VIDEO_OPENGL_EGL */
gabomdq@7659
   928
gabomdq@7659
   929
/* vi: set ts=4 sw=4 expandtab: */
philipp@11192
   930