cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_egl.c (18598B)


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