src/dynapi/SDL_dynapi.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 18 Oct 2017 08:52:04 -0700
changeset 11630 ad4b5d85edee
parent 11376 91e5e5a2cb71
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Fixed bug 3821 - Allow SDL_CreateWindow and SDL_CreateRenderer with OpenGL ES 3.0 (GLES3) for Angle (Windows)

Carlos

Angle supports GLES3 but when using these functions (SDL_CreateWindow and SDL_CreateRenderer), defaults again to GLES2.0.

A current workaround (hack) to retrieve a GLES3.0 context with Angle is:

1) set

SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

after InitSDL AND after calling SDL_CreateWindow (before SDL_CreateRenderer)

2) Comment lines 2032-2044 in SDL_render_gles2.c, funtion GLES2_CreateRenderer

window_flags = SDL_GetWindowFlags(window);
if (!(window_flags & SDL_WINDOW_OPENGL) ||
profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {

changed_window = SDL_TRUE;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);

if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
goto error;
}
}

This retrives a GLES3 context as confirmed using glGetString(GL_VERSION). This should be fixed by modifying a few if's.
icculus@8094
     1
/*
icculus@8094
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
icculus@8094
     4
icculus@8094
     5
  This software is provided 'as-is', without any express or implied
icculus@8094
     6
  warranty.  In no event will the authors be held liable for any damages
icculus@8094
     7
  arising from the use of this software.
icculus@8094
     8
icculus@8094
     9
  Permission is granted to anyone to use this software for any purpose,
icculus@8094
    10
  including commercial applications, and to alter it and redistribute it
icculus@8094
    11
  freely, subject to the following restrictions:
icculus@8094
    12
icculus@8094
    13
  1. The origin of this software must not be misrepresented; you must not
icculus@8094
    14
     claim that you wrote the original software. If you use this software
icculus@8094
    15
     in a product, an acknowledgment in the product documentation would be
icculus@8094
    16
     appreciated but is not required.
icculus@8094
    17
  2. Altered source versions must be plainly marked as such, and must not be
icculus@8094
    18
     misrepresented as being the original software.
icculus@8094
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@8094
    20
*/
icculus@8094
    21
icculus@8094
    22
#include "SDL_config.h"
icculus@8094
    23
#include "SDL_dynapi.h"
icculus@8094
    24
icculus@8094
    25
#if SDL_DYNAMIC_API
icculus@8094
    26
icculus@11348
    27
#if defined(__OS2__)
icculus@11348
    28
#define INCL_DOS
icculus@11348
    29
#define INCL_DOSERRORS
icculus@11348
    30
#include <dos.h>
icculus@11348
    31
#endif
icculus@11348
    32
icculus@8094
    33
#include "SDL.h"
icculus@8094
    34
slouken@11376
    35
/* These headers have system specific definitions, so aren't included above */
icculus@8094
    36
#include "SDL_syswm.h"
slouken@11376
    37
#include "SDL_vulkan.h"
icculus@8094
    38
icculus@8094
    39
/* This is the version of the dynamic API. This doesn't match the SDL version
icculus@8094
    40
   and should not change until there's been a major revamp in API/ABI.
icculus@8094
    41
   So 2.0.5 adds functions over 2.0.4? This number doesn't change;
icculus@8094
    42
   the sizeof (jump_table) changes instead. But 2.1.0 changes how a function
icculus@8094
    43
   works in an incompatible way or removes a function? This number changes,
icculus@8094
    44
   since sizeof (jump_table) isn't sufficient anymore. It's likely
icculus@8094
    45
   we'll forget to bump every time we add a function, so this is the
icculus@8094
    46
   failsafe switch for major API change decisions. Respect it and use it
icculus@8094
    47
   sparingly. */
icculus@8094
    48
#define SDL_DYNAPI_VERSION 1
icculus@8094
    49
icculus@8094
    50
static void SDL_InitDynamicAPI(void);
icculus@8094
    51
icculus@8094
    52
icculus@8094
    53
/* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP.
icculus@8094
    54
   Even self-contained stuff might call SDL_Error and break everything. */
icculus@8094
    55
icculus@8094
    56
icculus@8094
    57
/* behold, the macro salsa! */
icculus@8094
    58
icculus@8094
    59
/* !!! FIXME: ...disabled...until we write it.  :) */
icculus@8094
    60
#define DISABLE_JUMP_MAGIC 1
icculus@8094
    61
icculus@8094
    62
#if DISABLE_JUMP_MAGIC
icculus@8094
    63
/* Can't use the macro for varargs nonsense. This is atrocious. */
icculus@8094
    64
#define SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, logname, prio) \
slouken@11360
    65
    _static void SDLCALL SDL_Log##logname##name(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    66
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    67
        jump_table.SDL_LogMessageV(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \
icculus@8094
    68
        va_end(ap); \
icculus@8094
    69
    }
icculus@8094
    70
icculus@8094
    71
#define SDL_DYNAPI_VARARGS(_static, name, initcall) \
slouken@11360
    72
    _static int SDLCALL SDL_SetError##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    73
        char buf[512]; /* !!! FIXME: dynamic allocation */ \
icculus@8094
    74
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    75
        jump_table.SDL_vsnprintf(buf, sizeof (buf), fmt, ap); \
icculus@8094
    76
        va_end(ap); \
icculus@8094
    77
        return jump_table.SDL_SetError("%s", buf); \
icculus@8094
    78
    } \
slouken@11360
    79
    _static int SDLCALL SDL_sscanf##name(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    80
        int retval; va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    81
        retval = jump_table.SDL_vsscanf(buf, fmt, ap); \
icculus@8094
    82
        va_end(ap); \
icculus@8094
    83
        return retval; \
icculus@8094
    84
    } \
slouken@11360
    85
    _static int SDLCALL SDL_snprintf##name(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    86
        int retval; va_list ap; initcall; va_start(ap, fmt); \
slouken@8820
    87
        retval = jump_table.SDL_vsnprintf(buf, maxlen, fmt, ap); \
icculus@8094
    88
        va_end(ap); \
icculus@8094
    89
        return retval; \
icculus@8094
    90
    } \
slouken@11360
    91
    _static void SDLCALL SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    92
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    93
        jump_table.SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); \
icculus@8094
    94
        va_end(ap); \
icculus@8094
    95
    } \
slouken@11360
    96
    _static void SDLCALL SDL_LogMessage##name(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    97
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    98
        jump_table.SDL_LogMessageV(category, priority, fmt, ap); \
icculus@8094
    99
        va_end(ap); \
icculus@8094
   100
    } \
icculus@8094
   101
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Verbose, VERBOSE) \
icculus@8094
   102
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Debug, DEBUG) \
icculus@8094
   103
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Info, INFO) \
icculus@8094
   104
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Warn, WARN) \
icculus@8094
   105
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Error, ERROR) \
icculus@8094
   106
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Critical, CRITICAL)
icculus@8094
   107
#endif
icculus@8094
   108
icculus@8094
   109
icculus@8094
   110
/* Typedefs for function pointers for jump table, and predeclare funcs */
icculus@8094
   111
/* The DEFAULT funcs will init jump table and then call real function. */
icculus@8094
   112
/* The REAL funcs are the actual functions, name-mangled to not clash. */
icculus@8094
   113
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
slouken@11360
   114
    typedef rc (SDLCALL *SDL_DYNAPIFN_##fn) params; \
slouken@11360
   115
    static rc SDLCALL fn##_DEFAULT params; \
slouken@11360
   116
    extern rc SDLCALL fn##_REAL params;
icculus@8094
   117
#include "SDL_dynapi_procs.h"
icculus@8094
   118
#undef SDL_DYNAPI_PROC
icculus@8094
   119
icculus@8094
   120
/* The jump table! */
icculus@8094
   121
typedef struct {
icculus@8094
   122
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) SDL_DYNAPIFN_##fn fn;
icculus@8094
   123
    #include "SDL_dynapi_procs.h"
icculus@8094
   124
    #undef SDL_DYNAPI_PROC
icculus@8094
   125
} SDL_DYNAPI_jump_table;
icculus@8094
   126
icculus@8094
   127
/* Predeclare the default functions for initializing the jump table. */
slouken@11360
   128
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) static rc SDLCALL fn##_DEFAULT params;
icculus@8094
   129
#include "SDL_dynapi_procs.h"
icculus@8094
   130
#undef SDL_DYNAPI_PROC
icculus@8094
   131
icculus@8094
   132
/* The actual jump table. */
icculus@8094
   133
static SDL_DYNAPI_jump_table jump_table = {
icculus@8094
   134
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) fn##_DEFAULT,
icculus@8094
   135
    #include "SDL_dynapi_procs.h"
icculus@8094
   136
    #undef SDL_DYNAPI_PROC
icculus@8094
   137
};
icculus@8094
   138
icculus@8094
   139
/* Default functions init the function table then call right thing. */
icculus@8094
   140
#if DISABLE_JUMP_MAGIC
icculus@8094
   141
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
slouken@11360
   142
    static rc SDLCALL fn##_DEFAULT params { \
icculus@8094
   143
        SDL_InitDynamicAPI(); \
icculus@8094
   144
        ret jump_table.fn args; \
icculus@8094
   145
    }
icculus@8094
   146
#define SDL_DYNAPI_PROC_NO_VARARGS 1
icculus@8094
   147
#include "SDL_dynapi_procs.h"
icculus@8094
   148
#undef SDL_DYNAPI_PROC
icculus@8094
   149
#undef SDL_DYNAPI_PROC_NO_VARARGS
icculus@8094
   150
SDL_DYNAPI_VARARGS(static, _DEFAULT, SDL_InitDynamicAPI())
icculus@8094
   151
#else
icculus@8094
   152
/* !!! FIXME: need the jump magic. */
icculus@8094
   153
#error Write me.
icculus@8094
   154
#endif
icculus@8094
   155
icculus@8094
   156
/* Public API functions to jump into the jump table. */
icculus@8094
   157
#if DISABLE_JUMP_MAGIC
icculus@8094
   158
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
slouken@11360
   159
    rc SDLCALL fn params { ret jump_table.fn args; }
icculus@8094
   160
#define SDL_DYNAPI_PROC_NO_VARARGS 1
icculus@8094
   161
#include "SDL_dynapi_procs.h"
icculus@8094
   162
#undef SDL_DYNAPI_PROC
icculus@8094
   163
#undef SDL_DYNAPI_PROC_NO_VARARGS
icculus@8094
   164
SDL_DYNAPI_VARARGS(,,)
icculus@8094
   165
#else
icculus@8094
   166
/* !!! FIXME: need the jump magic. */
icculus@8094
   167
#error Write me.
icculus@8094
   168
#endif
icculus@8094
   169
icculus@8094
   170
icculus@8094
   171
icculus@8094
   172
/* Here's the exported entry point that fills in the jump table. */
icculus@8094
   173
/*  Use specific types when an "int" might suffice to keep this sane. */
icculus@8094
   174
typedef Sint32 (SDLCALL *SDL_DYNAPI_ENTRYFN)(Uint32 apiver, void *table, Uint32 tablesize);
icculus@8094
   175
extern DECLSPEC Sint32 SDLCALL SDL_DYNAPI_entry(Uint32, void *, Uint32);
icculus@8094
   176
icculus@8094
   177
Sint32
icculus@8094
   178
SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize)
icculus@8094
   179
{
icculus@8094
   180
    SDL_DYNAPI_jump_table *output_jump_table = (SDL_DYNAPI_jump_table *) table;
icculus@8094
   181
icculus@8094
   182
    if (apiver != SDL_DYNAPI_VERSION) {
icculus@8094
   183
        /* !!! FIXME: can maybe handle older versions? */
icculus@8094
   184
        return -1;  /* not compatible. */
icculus@8094
   185
    } else if (tablesize > sizeof (jump_table)) {
icculus@8094
   186
        return -1;  /* newer version of SDL with functions we can't provide. */
icculus@8094
   187
    }
icculus@8094
   188
icculus@8094
   189
    /* Init our jump table first. */
icculus@8094
   190
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_REAL;
icculus@8094
   191
    #include "SDL_dynapi_procs.h"
icculus@8094
   192
    #undef SDL_DYNAPI_PROC
icculus@8094
   193
icculus@8094
   194
    /* Then the external table... */
icculus@8094
   195
    if (output_jump_table != &jump_table) {
icculus@8094
   196
        jump_table.SDL_memcpy(output_jump_table, &jump_table, tablesize);
icculus@8094
   197
    }
icculus@8094
   198
icculus@8094
   199
    /* Safe to call SDL functions now; jump table is initialized! */
icculus@8094
   200
icculus@8094
   201
    return 0;  /* success! */
icculus@8094
   202
}
icculus@8094
   203
icculus@8094
   204
icculus@8094
   205
/* Obviously we can't use SDL_LoadObject() to load SDL.  :)  */
icculus@8094
   206
/* Also obviously, we never close the loaded library. */
icculus@8101
   207
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
icculus@8094
   208
#ifndef WIN32_LEAN_AND_MEAN
icculus@8094
   209
#define WIN32_LEAN_AND_MEAN 1
icculus@8094
   210
#endif
icculus@8094
   211
#include <windows.h>
icculus@8094
   212
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@8094
   213
{
icculus@8094
   214
    HANDLE lib = LoadLibraryA(fname);
icculus@9305
   215
    void *retval = NULL;
icculus@9305
   216
    if (lib) {
icculus@9305
   217
        retval = GetProcAddress(lib, sym);
icculus@9305
   218
        if (retval == NULL) {
icculus@9305
   219
            FreeLibrary(lib);
icculus@9305
   220
        }
icculus@9305
   221
    }
icculus@9305
   222
    return retval;
icculus@8094
   223
}
icculus@8094
   224
icculus@11119
   225
#elif defined(unix) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) || defined(__QNX__)
icculus@8094
   226
#include <dlfcn.h>
icculus@8094
   227
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@8094
   228
{
icculus@8094
   229
    void *lib = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
icculus@9305
   230
    void *retval = NULL;
icculus@9305
   231
    if (lib != NULL) {
icculus@9305
   232
        retval = dlsym(lib, sym);
icculus@9305
   233
        if (retval == NULL) {
icculus@9305
   234
            dlclose(lib);
icculus@9305
   235
        }
icculus@9305
   236
    }
icculus@9305
   237
    return retval;
icculus@8094
   238
}
icculus@11345
   239
icculus@11345
   240
#elif defined(__OS2__)
icculus@11345
   241
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@11345
   242
{
icculus@11345
   243
    HMODULE hmodule;
icculus@11345
   244
    PFN retval = NULL;
icculus@11345
   245
    char error[256];
slouken@11359
   246
    if (DosLoadModule(&error, sizeof(error), fname, &hmodule) == NO_ERROR) {
slouken@11359
   247
        if (DosQueryProcAddr(hmodule, 0, sym, &retval) != NO_ERROR) {
icculus@11345
   248
            DosFreeModule(hmodule);
icculus@11345
   249
        }
icculus@11345
   250
    }
icculus@11345
   251
    return (void *) retval;
icculus@11345
   252
}
icculus@11345
   253
icculus@8094
   254
#else
icculus@8094
   255
#error Please define your platform.
icculus@8094
   256
#endif
icculus@8094
   257
icculus@8094
   258
icculus@8094
   259
static void
icculus@8094
   260
SDL_InitDynamicAPILocked(void)
icculus@8094
   261
{
icculus@8094
   262
    const char *libname = SDL_getenv_REAL("SDL_DYNAMIC_API");
icculus@8094
   263
    SDL_DYNAPI_ENTRYFN entry = SDL_DYNAPI_entry;  /* funcs from here by default. */
icculus@8094
   264
icculus@8094
   265
    if (libname) {
icculus@8094
   266
        entry = (SDL_DYNAPI_ENTRYFN) get_sdlapi_entry(libname, "SDL_DYNAPI_entry");
icculus@8094
   267
        if (!entry) {
icculus@8094
   268
            /* !!! FIXME: fail to startup here instead? */
icculus@8094
   269
            /* !!! FIXME: definitely warn user. */
icculus@8094
   270
            /* Just fill in the function pointers from this library. */
icculus@8094
   271
            entry = SDL_DYNAPI_entry;
icculus@8094
   272
        }
icculus@8094
   273
    }
icculus@8094
   274
icculus@8094
   275
    if (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0) {
icculus@8094
   276
        /* !!! FIXME: fail to startup here instead? */
icculus@8094
   277
        /* !!! FIXME: definitely warn user. */
icculus@8094
   278
        /* Just fill in the function pointers from this library. */
icculus@8094
   279
        if (entry != SDL_DYNAPI_entry) {
icculus@8094
   280
            if (!SDL_DYNAPI_entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table))) {
icculus@8094
   281
                /* !!! FIXME: now we're screwed. Should definitely abort now. */
icculus@8094
   282
            }
icculus@8094
   283
        }
icculus@8094
   284
    }
icculus@8094
   285
icculus@8094
   286
    /* we intentionally never close the newly-loaded lib, of course. */
icculus@8094
   287
}
icculus@8094
   288
icculus@8094
   289
static void
icculus@8094
   290
SDL_InitDynamicAPI(void)
icculus@8094
   291
{
icculus@8094
   292
    /* So the theory is that every function in the jump table defaults to
icculus@8094
   293
     *  calling this function, and then replaces itself with a version that
icculus@8094
   294
     *  doesn't call this function anymore. But it's possible that, in an
icculus@8094
   295
     *  extreme corner case, you can have a second thread hit this function
icculus@8094
   296
     *  while the jump table is being initialized by the first.
icculus@8094
   297
     * In this case, a spinlock is really painful compared to what spinlocks
icculus@8094
   298
     *  _should_ be used for, but this would only happen once, and should be
icculus@8094
   299
     *  insanely rare, as you would have to spin a thread outside of SDL (as
icculus@8094
   300
     *  SDL_CreateThread() would also call this function before building the
icculus@8094
   301
     *  new thread).
icculus@8094
   302
     */
icculus@10003
   303
    static SDL_bool already_initialized = SDL_FALSE;
icculus@8094
   304
icculus@8094
   305
    /* SDL_AtomicLock calls SDL mutex functions to emulate if
icculus@8094
   306
       SDL_ATOMIC_DISABLED, which we can't do here, so in such a
icculus@8094
   307
       configuration, you're on your own. */
icculus@8094
   308
    #if !SDL_ATOMIC_DISABLED
icculus@8094
   309
    static SDL_SpinLock lock = 0;
icculus@8094
   310
    SDL_AtomicLock_REAL(&lock);
icculus@8094
   311
    #endif
icculus@8094
   312
icculus@8094
   313
    if (!already_initialized) {
icculus@8094
   314
        SDL_InitDynamicAPILocked();
icculus@8094
   315
        already_initialized = SDL_TRUE;
icculus@8094
   316
    }
icculus@8094
   317
icculus@8094
   318
    #if !SDL_ATOMIC_DISABLED
icculus@8094
   319
    SDL_AtomicUnlock_REAL(&lock);
icculus@8094
   320
    #endif
icculus@8094
   321
}
icculus@8094
   322
icculus@8094
   323
#endif  /* SDL_DYNAMIC_API */
icculus@8094
   324
icculus@8094
   325
/* vi: set ts=4 sw=4 expandtab: */