src/video/SDL_egl.c
changeset 11175 cbc6a8a5b701
parent 10878 7fa08228d9e3
child 11192 3c8377f1a323
     1.1 --- a/src/video/SDL_egl.c	Mon Jul 31 13:49:22 2017 -0400
     1.2 +++ b/src/video/SDL_egl.c	Wed Aug 02 10:22:48 2017 -0700
     1.3 @@ -30,6 +30,7 @@
     1.4  #endif
     1.5  
     1.6  #include "SDL_sysvideo.h"
     1.7 +#include "SDL_log.h"
     1.8  #include "SDL_egl_c.h"
     1.9  #include "SDL_loadso.h"
    1.10  #include "SDL_hints.h"
    1.11 @@ -114,38 +115,82 @@
    1.12  }
    1.13  
    1.14  /* EGL implementation of SDL OpenGL ES support */
    1.15 -#ifdef EGL_KHR_create_context        
    1.16 -static int SDL_EGL_HasExtension(_THIS, const char *ext)
    1.17 +typedef enum {
    1.18 +    SDL_EGL_DISPLAY_EXTENSION,
    1.19 +    SDL_EGL_CLIENT_EXTENSION
    1.20 +} SDL_EGL_ExtensionType;
    1.21 +
    1.22 +static SDL_bool SDL_EGL_HasExtension(_THIS, SDL_EGL_ExtensionType type, const char *ext)
    1.23  {
    1.24 -    int i;
    1.25 -    int len = 0;
    1.26      size_t ext_len;
    1.27 -    const char *exts;
    1.28 -    const char *ext_word;
    1.29 +    const char *ext_override;
    1.30 +    const char *egl_extstr;
    1.31 +    const char *ext_start;
    1.32 +
    1.33 +    /* Invalid extensions can be rejected early */
    1.34 +    if (ext == NULL || *ext == 0 || SDL_strchr(ext, ' ') != NULL) {
    1.35 +        /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid EGL extension"); */
    1.36 +        return SDL_FALSE;
    1.37 +    }
    1.38 +
    1.39 +    /* Extensions can be masked with an environment variable.
    1.40 +     * Unlike the OpenGL override, this will use the set bits of an integer
    1.41 +     * to disable the extension.
    1.42 +     *  Bit   Action
    1.43 +     *  0     If set, the display extension is masked and not present to SDL.
    1.44 +     *  1     If set, the client extension is masked and not present to SDL.
    1.45 +     */
    1.46 +    ext_override = SDL_getenv(ext);
    1.47 +    if (ext_override != NULL) {
    1.48 +        int disable_ext = SDL_atoi(ext_override);
    1.49 +        if (disable_ext & 0x01 && type == SDL_EGL_DISPLAY_EXTENSION) {
    1.50 +            return SDL_FALSE;
    1.51 +        } else if (disable_ext & 0x02 && type == SDL_EGL_CLIENT_EXTENSION) {
    1.52 +            return SDL_FALSE;
    1.53 +        }
    1.54 +    }
    1.55  
    1.56      ext_len = SDL_strlen(ext);
    1.57 -    exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
    1.58 +    switch (type) {
    1.59 +    case SDL_EGL_DISPLAY_EXTENSION:
    1.60 +        egl_extstr = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
    1.61 +        break;
    1.62 +    case SDL_EGL_CLIENT_EXTENSION:
    1.63 +        /* EGL_EXT_client_extensions modifies eglQueryString to return client extensions
    1.64 +         * if EGL_NO_DISPLAY is passed. Implementations without it are required to return NULL.
    1.65 +         * This behavior is included in EGL 1.5.
    1.66 +         */
    1.67 +        egl_extstr = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    1.68 +        break;
    1.69 +    default:
    1.70 +        /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid extension type"); */
    1.71 +        return SDL_FALSE;
    1.72 +    }
    1.73  
    1.74 -    if (exts) {
    1.75 -        ext_word = exts;
    1.76 +    if (egl_extstr != NULL) {
    1.77 +        ext_start = egl_extstr;
    1.78  
    1.79 -        for (i = 0; exts[i] != 0; i++) {
    1.80 -            if (exts[i] == ' ') {
    1.81 -                if (ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
    1.82 -                    return 1;
    1.83 +        while (*ext_start) {
    1.84 +            ext_start = SDL_strstr(ext_start, ext);
    1.85 +            if (ext_start == NULL) {
    1.86 +                return SDL_FALSE;
    1.87 +            }
    1.88 +            /* Check if the match is not just a substring of one of the extensions */
    1.89 +            if (ext_start == egl_extstr || *(ext_start - 1) == ' ') {
    1.90 +                if (ext_start[ext_len] == ' ' || ext_start[ext_len] == 0) {
    1.91 +                    return SDL_TRUE;
    1.92                  }
    1.93 -
    1.94 -                len = 0;
    1.95 -                ext_word = &exts[i + 1];
    1.96 -            } else {
    1.97 -                len++;
    1.98 +            }
    1.99 +            /* If the search stopped in the middle of an extension, skip to the end of it */
   1.100 +            ext_start += ext_len;
   1.101 +            while (*ext_start != ' ' && *ext_start != 0) {
   1.102 +                ext_start++;
   1.103              }
   1.104          }
   1.105      }
   1.106  
   1.107 -    return 0;
   1.108 +    return SDL_FALSE;
   1.109  }
   1.110 -#endif /* EGL_KHR_create_context */
   1.111  
   1.112  void *
   1.113  SDL_EGL_GetProcAddress(_THIS, const char *proc)
   1.114 @@ -196,10 +241,11 @@
   1.115  }
   1.116  
   1.117  int
   1.118 -SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display)
   1.119 +SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
   1.120  {
   1.121      void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
   1.122      const char *path = NULL;
   1.123 +    int egl_version_major = 0, egl_version_minor = 0;
   1.124  #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
   1.125      const char *d3dcompiler;
   1.126  #endif
   1.127 @@ -305,9 +351,41 @@
   1.128      LOAD_FUNC(eglQueryString);
   1.129      LOAD_FUNC(eglGetError);
   1.130  
   1.131 +    if (_this->egl_data->eglQueryString) {
   1.132 +        /* EGL 1.5 allows querying for client version */
   1.133 +        const char *egl_version = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_VERSION);
   1.134 +        if (egl_version != NULL) {
   1.135 +            if (SDL_sscanf(egl_version, "%d.%d", &egl_version_major, &egl_version_minor) != 2) {
   1.136 +                egl_version_major = 0;
   1.137 +                egl_version_minor = 0;
   1.138 +                SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not parse EGL version string: %s", egl_version);
   1.139 +            }
   1.140 +        }
   1.141 +    }
   1.142 +
   1.143 +    if (egl_version_major == 1 && egl_version_minor == 5) {
   1.144 +        LOAD_FUNC(eglGetPlatformDisplay);
   1.145 +    }
   1.146 +
   1.147 +    _this->egl_data->egl_display = EGL_NO_DISPLAY;
   1.148  #if !defined(__WINRT__)
   1.149 -    _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
   1.150 -    if (!_this->egl_data->egl_display) {
   1.151 +    if (platform) {
   1.152 +        if (egl_version_major == 1 && egl_version_minor == 5) {
   1.153 +            _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, native_display, NULL);
   1.154 +        } else {
   1.155 +            if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base")) {
   1.156 +                _this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddress(_this, "eglGetPlatformDisplayEXT");
   1.157 +                if (_this->egl_data->eglGetPlatformDisplayEXT) {
   1.158 +                    _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(platform, native_display, NULL);
   1.159 +                }
   1.160 +            }
   1.161 +        }
   1.162 +    }
   1.163 +    /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
   1.164 +    if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
   1.165 +        _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
   1.166 +    }
   1.167 +    if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
   1.168          return SDL_SetError("Could not get EGL display");
   1.169      }
   1.170      
   1.171 @@ -328,13 +406,19 @@
   1.172  int
   1.173  SDL_EGL_ChooseConfig(_THIS) 
   1.174  {
   1.175 -    /* 64 seems nice. */
   1.176 +/* 64 seems nice. */
   1.177      EGLint attribs[64];
   1.178      EGLint found_configs = 0, value;
   1.179 +#ifdef SDL_VIDEO_DRIVER_KMSDRM
   1.180 +    /* Intel EGL on KMS/DRM (al least) returns invalid configs that confuse the bitdiff search used */
   1.181 +    /* later in this function, so we simply use the first one when using the KMSDRM driver for now. */
   1.182 +    EGLConfig configs[1];
   1.183 +#else
   1.184      /* 128 seems even nicer here */
   1.185      EGLConfig configs[128];
   1.186 +#endif
   1.187      int i, j, best_bitdiff = -1, bitdiff;
   1.188 -    
   1.189 +   
   1.190      if (!_this->egl_data) {
   1.191          /* The EGL library wasn't loaded, SDL_GetError() should have info */
   1.192          return -1;
   1.193 @@ -379,7 +463,7 @@
   1.194  
   1.195      if (_this->gl_config.framebuffer_srgb_capable) {
   1.196  #ifdef EGL_KHR_gl_colorspace
   1.197 -        if (SDL_EGL_HasExtension(_this, "EGL_KHR_gl_colorspace")) {
   1.198 +        if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_gl_colorspace")) {
   1.199              attribs[i++] = EGL_GL_COLORSPACE_KHR;
   1.200              attribs[i++] = EGL_GL_COLORSPACE_SRGB_KHR;
   1.201          } else
   1.202 @@ -393,7 +477,7 @@
   1.203      if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   1.204  #ifdef EGL_KHR_create_context
   1.205          if (_this->gl_config.major_version >= 3 &&
   1.206 -            SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
   1.207 +            SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
   1.208              attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
   1.209          } else
   1.210  #endif
   1.211 @@ -495,7 +579,7 @@
   1.212          /* The Major/minor version, context profiles, and context flags can
   1.213           * only be specified when this extension is available.
   1.214           */
   1.215 -        if (SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
   1.216 +        if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
   1.217              attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
   1.218              attribs[attr++] = major_version;
   1.219              attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;