Mac and Linux SDL2 binary snapshots
Edward Rudd
2020-05-02 03f8528315fa46c95991a34f3325d7b33ae5538c
source/src/video/SDL_egl.c
@@ -1,6 +1,6 @@
/*
 *  Simple DirectMedia Layer
 *  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
 *  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
 * 
 *  This software is provided 'as-is', without any express or implied
 *  warranty.  In no event will the authors be held liable for any damages
@@ -27,6 +27,7 @@
#endif
#if SDL_VIDEO_DRIVER_ANDROID
#include <android/native_window.h>
#include "../core/android/SDL_android.h"
#endif
#include "SDL_sysvideo.h"
@@ -81,6 +82,13 @@
#define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
#endif /* SDL_VIDEO_DRIVER_RPI */
/** If we happen to not have this defined because of an older EGL version, just define it 0x0
    as eglGetPlatformDisplayEXT will most likely be NULL if this is missing
*/
#ifndef EGL_PLATFORM_DEVICE_EXT
#define EGL_PLATFORM_DEVICE_EXT 0x0
#endif
#ifdef SDL_VIDEO_STATIC_ANGLE
#define LOAD_FUNC(NAME) \
_this->egl_data->NAME = (void *)NAME;
@@ -92,6 +100,11 @@
    return SDL_SetError("Could not retrieve EGL function " #NAME); \
}
#endif
/* it is allowed to not have some of the EGL extensions on start - attempts to use them will fail later. */
#define LOAD_FUNC_EGLEXT(NAME) \
    _this->egl_data->NAME = _this->egl_data->eglGetProcAddress(#NAME);
static const char * SDL_EGL_GetErrorName(EGLint eglErrorCode)
{
@@ -209,25 +222,35 @@
void *
SDL_EGL_GetProcAddress(_THIS, const char *proc)
{
    static char procname[1024];
    void *retval;
    /* eglGetProcAddress is busted on Android http://code.google.com/p/android/issues/detail?id=7681 */
#if !defined(SDL_VIDEO_DRIVER_ANDROID)
    if (_this->egl_data->eglGetProcAddress) {
    const Uint32 eglver = (((Uint32) _this->egl_data->egl_version_major) << 16) | ((Uint32) _this->egl_data->egl_version_minor);
    const SDL_bool is_egl_15_or_later = eglver >= ((((Uint32) 1) << 16) | 5);
    void *retval = NULL;
    /* EGL 1.5 can use eglGetProcAddress() for any symbol. 1.4 and earlier can't use it for core entry points. */
    if (!retval && is_egl_15_or_later && _this->egl_data->eglGetProcAddress) {
        retval = _this->egl_data->eglGetProcAddress(proc);
    }
    /* Try SDL_LoadFunction() first for EGL <= 1.4, or as a fallback for >= 1.5. */
    if (!retval) {
        static char procname[64];
        retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, proc);
        /* just in case you need an underscore prepended... */
        if (!retval && (SDL_strlen(proc) < (sizeof (procname) - 1))) {
            procname[0] = '_';
            SDL_strlcpy(procname + 1, proc, sizeof (procname) - 1);
            retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, procname);
        }
    }
    /* Try eglGetProcAddress if we on <= 1.4 and still searching... */
    if (!retval && !is_egl_15_or_later && _this->egl_data->eglGetProcAddress) {
        retval = _this->egl_data->eglGetProcAddress(proc);
        if (retval) {
            return retval;
        }
    }
#endif
    retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, proc);
    if (!retval && SDL_strlen(proc) <= 1022) {
        procname[0] = '_';
        SDL_strlcpy(procname + 1, proc, 1022);
        retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, procname);
    }
    return retval;
}
@@ -255,11 +278,10 @@
}
int
SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
SDL_EGL_LoadLibraryOnly(_THIS, const char *egl_path)
{
    void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
    const char *path = NULL;
    int egl_version_major = 0, egl_version_minor = 0;
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
    const char *d3dcompiler;
#endif
@@ -278,16 +300,30 @@
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
    d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER);
    if (!d3dcompiler) {
        if (WIN_IsWindowsVistaOrGreater()) {
            d3dcompiler = "d3dcompiler_46.dll";
        } else {
            d3dcompiler = "d3dcompiler_43.dll";
    if (d3dcompiler) {
        if (SDL_strcasecmp(d3dcompiler, "none") != 0) {
            if (SDL_LoadObject(d3dcompiler) == NULL) {
                SDL_ClearError();
            }
        }
    }
    if (SDL_strcasecmp(d3dcompiler, "none") != 0) {
        if (SDL_LoadObject(d3dcompiler) == NULL) {
            SDL_ClearError();
    } else {
        if (WIN_IsWindowsVistaOrGreater()) {
            /* Try the newer d3d compilers first */
            const char *d3dcompiler_list[] = {
                "d3dcompiler_47.dll", "d3dcompiler_46.dll",
            };
            int i;
            for (i = 0; i < SDL_arraysize(d3dcompiler_list); ++i) {
                if (SDL_LoadObject(d3dcompiler_list[i]) != NULL) {
                    break;
                }
                SDL_ClearError();
            }
        } else {
            if (SDL_LoadObject("d3dcompiler_43.dll") == NULL) {
                SDL_ClearError();
            }
        }
    }
#endif
@@ -391,23 +427,53 @@
    LOAD_FUNC(eglWaitNative);
    LOAD_FUNC(eglWaitGL);
    LOAD_FUNC(eglBindAPI);
    LOAD_FUNC(eglQueryAPI);
    LOAD_FUNC(eglQueryString);
    LOAD_FUNC(eglGetError);
    LOAD_FUNC_EGLEXT(eglQueryDevicesEXT);
    LOAD_FUNC_EGLEXT(eglGetPlatformDisplayEXT);
    _this->gl_config.driver_loaded = 1;
    if (path) {
        SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
    } else {
        *_this->gl_config.driver_path = '\0';
    }
    return 0;
}
static void
SDL_EGL_GetVersion(_THIS) {
    if (_this->egl_data->eglQueryString) {
        /* EGL 1.5 allows querying for client version */
        const char *egl_version = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_VERSION);
        if (egl_version != NULL) {
            if (SDL_sscanf(egl_version, "%d.%d", &egl_version_major, &egl_version_minor) != 2) {
                egl_version_major = 0;
                egl_version_minor = 0;
        const char *egl_version = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_VERSION);
        if (egl_version) {
            int major = 0, minor = 0;
            if (SDL_sscanf(egl_version, "%d.%d", &major, &minor) == 2) {
                _this->egl_data->egl_version_major = major;
                _this->egl_data->egl_version_minor = minor;
            } else {
                SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not parse EGL version string: %s", egl_version);
            }
        }
    }
}
    _this->egl_data->egl_version_major = egl_version_major;
    _this->egl_data->egl_version_minor = egl_version_minor;
int
SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
{
    int egl_version_major, egl_version_minor;
    int library_load_retcode = SDL_EGL_LoadLibraryOnly(_this, egl_path);
    if (library_load_retcode != 0) {
        return library_load_retcode;
    }
    /* EGL 1.5 allows querying for client version with EGL_NO_DISPLAY */
    SDL_EGL_GetVersion(_this);
    egl_version_major = _this->egl_data->egl_version_major;
    egl_version_minor = _this->egl_data->egl_version_minor;
    if (egl_version_major == 1 && egl_version_minor == 5) {
        LOAD_FUNC(eglGetPlatformDisplay);
@@ -432,21 +498,118 @@
        _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
    }
    if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
        _this->gl_config.driver_loaded = 0;
        *_this->gl_config.driver_path = '\0';
        return SDL_SetError("Could not get EGL display");
    }
    
    if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
        _this->gl_config.driver_loaded = 0;
        *_this->gl_config.driver_path = '\0';
        return SDL_SetError("Could not initialize EGL");
    }
#endif
    if (path) {
        SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
    } else {
        *_this->gl_config.driver_path = '\0';
    }
    /* Get the EGL version with a valid egl_display, for EGL <= 1.4 */
    SDL_EGL_GetVersion(_this);
    _this->egl_data->is_offscreen = 0;
    return 0;
}
/**
   On multi GPU machines EGL device 0 is not always the first valid GPU.
   Container environments can restrict access to some GPUs that are still listed in the EGL
   device list. If the requested device is a restricted GPU and cannot be used
   (eglInitialize() will fail) then attempt to automatically and silently select the next
   valid available GPU for EGL to use.
*/
int
SDL_EGL_InitializeOffscreen(_THIS, int device)
{
    void *egl_devices[SDL_EGL_MAX_DEVICES];
    EGLint num_egl_devices = 0;
    const char *egl_device_hint;
    if (_this->gl_config.driver_loaded != 1) {
        return SDL_SetError("SDL_EGL_LoadLibraryOnly() has not been called or has failed.");
    }
    /* Check for all extensions that are optional until used and fail if any is missing */
    if (_this->egl_data->eglQueryDevicesEXT == NULL) {
        return SDL_SetError("eglQueryDevicesEXT is missing (EXT_device_enumeration not supported by the drivers?)");
    }
    if (_this->egl_data->eglGetPlatformDisplayEXT == NULL) {
        return SDL_SetError("eglGetPlatformDisplayEXT is missing (EXT_platform_base not supported by the drivers?)");
    }
    if (_this->egl_data->eglQueryDevicesEXT(SDL_EGL_MAX_DEVICES, egl_devices, &num_egl_devices) != EGL_TRUE) {
        return SDL_SetError("eglQueryDevicesEXT() failed");
    }
    egl_device_hint = SDL_GetHint("SDL_HINT_EGL_DEVICE");
    if (egl_device_hint) {
        device = SDL_atoi(egl_device_hint);
        if (device >= num_egl_devices) {
            return SDL_SetError("Invalid EGL device is requested.");
        }
        _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[device], NULL);
        if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
            return SDL_SetError("eglGetPlatformDisplayEXT() failed.");
        }
        if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
            return SDL_SetError("Could not initialize EGL");
        }
    }
    else {
        int i;
        SDL_bool found = SDL_FALSE;
        EGLDisplay attempted_egl_display;
        /* If no hint is provided lets look for the first device/display that will allow us to eglInit */
        for (i = 0; i < num_egl_devices; i++) {
            attempted_egl_display = _this->egl_data->eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[i], NULL);
            if (attempted_egl_display == EGL_NO_DISPLAY) {
                continue;
            }
            if (_this->egl_data->eglInitialize(attempted_egl_display, NULL, NULL) != EGL_TRUE) {
                _this->egl_data->eglTerminate(attempted_egl_display);
                continue;
            }
            /* We did not fail, we'll pick this one! */
            _this->egl_data->egl_display = attempted_egl_display;
            found = SDL_TRUE;
            break;
        }
        if (!found) {
            return SDL_SetError("Could not find a valid EGL device to initialize");
        }
    }
    /* Get the EGL version with a valid egl_display, for EGL <= 1.4 */
    SDL_EGL_GetVersion(_this);
    _this->egl_data->is_offscreen = 1;
    return 0;
}
void
SDL_EGL_SetRequiredVisualId(_THIS, int visual_id)
{
    _this->egl_data->egl_required_visual_id=visual_id;
}
#ifdef DUMP_EGL_CONFIG
@@ -513,14 +676,8 @@
/* 64 seems nice. */
    EGLint attribs[64];
    EGLint found_configs = 0, value;
#ifdef SDL_VIDEO_DRIVER_KMSDRM
    /* Intel EGL on KMS/DRM (al least) returns invalid configs that confuse the bitdiff search used */
    /* later in this function, so we simply use the first one when using the KMSDRM driver for now. */
    EGLConfig configs[1];
#else
    /* 128 seems even nicer here */
    EGLConfig configs[128];
#endif
    int i, j, best_bitdiff = -1, bitdiff;
   
    if (!_this->egl_data) {
@@ -565,6 +722,11 @@
        attribs[i++] = _this->gl_config.multisamplesamples;
    }
    if (_this->egl_data->is_offscreen) {
        attribs[i++] = EGL_SURFACE_TYPE;
        attribs[i++] = EGL_PBUFFER_BIT;
    }
    attribs[i++] = EGL_RENDERABLE_TYPE;
    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
#ifdef EGL_KHR_create_context
@@ -603,6 +765,16 @@
    /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
    for (i = 0; i < found_configs; i++ ) {
        if (_this->egl_data->egl_required_visual_id)
        {
            EGLint format;
            _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
                                            configs[i],
                                            EGL_NATIVE_VISUAL_ID, &format);
            if (_this->egl_data->egl_required_visual_id != format)
                continue;
        }
        bitdiff = 0;
        for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
            if (attribs[j] == EGL_NONE) {
@@ -875,6 +1047,10 @@
                                            EGL_NATIVE_VISUAL_ID, &format);
        ANativeWindow_setBuffersGeometry(nw, 0, 0, format);
        /* Update SurfaceView holder format.
         * May triggers a sequence surfaceDestroyed(), surfaceCreated(), surfaceChanged(). */
        Android_JNI_SetSurfaceViewFormat(format);
    }
#endif    
    if (_this->gl_config.framebuffer_srgb_capable) {
@@ -902,6 +1078,25 @@
    return surface;
}
EGLSurface
SDL_EGL_CreateOffscreenSurface(_THIS, int width, int height)
{
    EGLint attributes[] = {
        EGL_WIDTH, width,
        EGL_HEIGHT, height,
        EGL_NONE
    };
    if (SDL_EGL_ChooseConfig(_this) != 0) {
        return EGL_NO_SURFACE;
    }
    return _this->egl_data->eglCreatePbufferSurface(
        _this->egl_data->egl_display,
        _this->egl_data->egl_config,
        attributes);
}
void
SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) 
{