gles: create angle context in webgl mode on windows
Cubemaps are broken in ANGLE's D3D11 backend, except in WebGL mode for some reason. This is a terrible workaround, but it beats fucked up rendering in stage backgrounds.
This commit is contained in:
parent
97e99df9fc
commit
cab432f843
11 changed files with 282 additions and 20 deletions
|
@ -216,9 +216,12 @@ dep_gamemode = dependency('gamemode', required : f
|
|||
dep_m = cc.find_library('m', required : false)
|
||||
|
||||
dep_basisu_transcoder = subproject('basis_universal').get_variable('basisu_transcoder_dep')
|
||||
dep_glad = subproject('glad').get_variable('glad_dep')
|
||||
dep_koishi = subproject('koishi').get_variable('koishi_dep')
|
||||
|
||||
sub_glad = subproject('glad')
|
||||
dep_glad_gl = sub_glad.get_variable('glad_gl_dep')
|
||||
dep_glad_egl = sub_glad.get_variable('glad_egl_dep')
|
||||
|
||||
taisei_deps = [
|
||||
dep_basisu_transcoder,
|
||||
dep_cglm,
|
||||
|
|
|
@ -282,23 +282,29 @@ static void gl41_set_viewport(const FloatRect *vp) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static void gl33_init_context(SDL_Window *window) {
|
||||
R.gl_context = SDL_GL_CreateContext(window);
|
||||
static SDL_GLContext gl33_create_context(SDL_Window *window) {
|
||||
SDL_GLContext ctx = SDL_GL_CreateContext(window);
|
||||
|
||||
int gl_profile;
|
||||
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &gl_profile);
|
||||
|
||||
if(!R.gl_context && gl_profile != SDL_GL_CONTEXT_PROFILE_ES) {
|
||||
if(!ctx && gl_profile != SDL_GL_CONTEXT_PROFILE_ES) {
|
||||
log_error("Failed to create OpenGL context: %s", SDL_GetError());
|
||||
log_warn("Attempting to create a fallback context");
|
||||
SDL_GL_ResetAttributes();
|
||||
R.gl_context = SDL_GL_CreateContext(window);
|
||||
ctx = SDL_GL_CreateContext(window);
|
||||
}
|
||||
|
||||
if(!R.gl_context) {
|
||||
if(!ctx) {
|
||||
log_fatal("Failed to create OpenGL context: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void gl33_init_context(SDL_Window *window) {
|
||||
R.gl_context = GLVT.create_context(window);
|
||||
|
||||
glcommon_load_functions();
|
||||
glcommon_check_capabilities();
|
||||
|
||||
|
@ -1537,6 +1543,7 @@ RendererBackend _r_backend_gl33 = {
|
|||
},
|
||||
.custom = &(GLBackendData) {
|
||||
.vtable = {
|
||||
.create_context = gl33_create_context,
|
||||
.init_context = gl33_init_context,
|
||||
}
|
||||
},
|
||||
|
|
|
@ -9,5 +9,5 @@ r_glcommon_src = files(
|
|||
r_glcommon_libdeps = []
|
||||
|
||||
if not static_gles30
|
||||
r_glcommon_libdeps += dep_glad
|
||||
r_glcommon_libdeps += dep_glad_gl
|
||||
endif
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
typedef struct GLVTable {
|
||||
// GLTextureTypeInfo* (*texture_type_info)(TextureType type);
|
||||
// GLTexFormatCapabilities (*texture_format_caps)(GLenum internal_fmt);
|
||||
SDL_GLContext (*create_context)(SDL_Window *window);
|
||||
void (*init_context)(SDL_Window *window);
|
||||
void (*get_viewport)(FloatRect *vp);
|
||||
void (*set_viewport)(const FloatRect *vp);
|
||||
|
@ -25,5 +26,5 @@ typedef struct GLBackendData {
|
|||
GLVTable vtable;
|
||||
} GLBackendData;
|
||||
|
||||
#define GLVT_OF(backend) (((GLBackendData*)backend.custom)->vtable)
|
||||
#define GLVT_OF(backend) (((GLBackendData*)(backend).custom)->vtable)
|
||||
#define GLVT GLVT_OF(_r_backend)
|
||||
|
|
189
src/renderer/glescommon/angle_egl.c
Normal file
189
src/renderer/glescommon/angle_egl.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "angle_egl.h"
|
||||
#include "../glcommon/debug.h"
|
||||
#include "glad/egl.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* All this garbage here serves one purpose: create a WebGL-compatible ANGLE context.
|
||||
*
|
||||
* To do this we should only need to pass one additional attribute to eglCreateContext.
|
||||
*
|
||||
* Unfortunately, SDL2's EGL code is totally opaque to the application, so that can't be done in a
|
||||
* sane way. So we have to sidestep SDL a bit and create a context manually, relying on some
|
||||
* implementation details.
|
||||
*
|
||||
* SDL3 seems to have fixed this problem with some new EGL-related APIs, thankfully.
|
||||
*
|
||||
* This code is a bad hack; please don't copy this if you're looking for a proper EGL example.
|
||||
*/
|
||||
|
||||
// EGL_ANGLE_create_context_webgl_compatibility
|
||||
#define EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x33AC
|
||||
|
||||
// EGL_ANGLE_create_context_extensions_enabled
|
||||
#define EGL_EXTENSIONS_ENABLED_ANGLE 0x345F
|
||||
|
||||
static GLADapiproc egl_load_function(void *libegl, const char *name) {
|
||||
return SDL_LoadFunction(libegl, name);
|
||||
}
|
||||
|
||||
static const char *egl_error_string(EGLint error) {
|
||||
#define E(e) \
|
||||
case e: return #e;
|
||||
|
||||
switch(error) {
|
||||
E(EGL_SUCCESS)
|
||||
E(EGL_NOT_INITIALIZED)
|
||||
E(EGL_BAD_ACCESS)
|
||||
E(EGL_BAD_ALLOC)
|
||||
E(EGL_BAD_ATTRIBUTE)
|
||||
E(EGL_BAD_CONTEXT)
|
||||
E(EGL_BAD_CONFIG)
|
||||
E(EGL_BAD_CURRENT_SURFACE)
|
||||
E(EGL_BAD_DISPLAY)
|
||||
E(EGL_BAD_SURFACE)
|
||||
E(EGL_BAD_MATCH)
|
||||
E(EGL_BAD_PARAMETER)
|
||||
E(EGL_BAD_NATIVE_PIXMAP)
|
||||
E(EGL_BAD_NATIVE_WINDOW)
|
||||
E(EGL_CONTEXT_LOST)
|
||||
}
|
||||
|
||||
#undef E
|
||||
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
static const char *egl_get_error_string(void) {
|
||||
return egl_error_string(eglGetError());
|
||||
}
|
||||
|
||||
static EGLConfig get_egl_config(EGLDisplay display, int major_version) {
|
||||
EGLint attribs[64];
|
||||
EGLConfig configs[128];
|
||||
int i = 0;
|
||||
|
||||
int colorbits = 8;
|
||||
|
||||
attribs[i++] = EGL_RED_SIZE;
|
||||
attribs[i++] = colorbits;
|
||||
attribs[i++] = EGL_GREEN_SIZE;
|
||||
attribs[i++] = colorbits;
|
||||
attribs[i++] = EGL_BLUE_SIZE;
|
||||
attribs[i++] = colorbits;
|
||||
attribs[i++] = EGL_ALPHA_SIZE;
|
||||
attribs[i++] = 0;
|
||||
attribs[i++] = EGL_DEPTH_SIZE;
|
||||
attribs[i++] = 0;
|
||||
attribs[i++] = EGL_CONFIG_CAVEAT;
|
||||
attribs[i++] = EGL_NONE;
|
||||
attribs[i++] = EGL_RENDERABLE_TYPE;
|
||||
attribs[i++] = (major_version > 2) ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
EGLint found_configs;
|
||||
|
||||
if(!eglChooseConfig(display, attribs, configs, ARRAY_SIZE(configs), &found_configs)) {
|
||||
log_fatal("eglChooseConfig failed: %s", egl_get_error_string());
|
||||
}
|
||||
|
||||
if(!found_configs) {
|
||||
log_fatal("No EGL configs found");
|
||||
}
|
||||
|
||||
log_debug("Found %i configs", found_configs);
|
||||
|
||||
int choosen_config = 0;
|
||||
|
||||
for(int i = 0; i < found_configs; ++i) {
|
||||
EGLint r, g, b;
|
||||
eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &r);
|
||||
eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &g);
|
||||
eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &b);
|
||||
|
||||
if(r == colorbits && g == colorbits && b == colorbits) {
|
||||
// just grab the first one that looks like it'll work
|
||||
choosen_config = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return configs[choosen_config];
|
||||
}
|
||||
|
||||
static EGLDisplay egl_display_from_sdl(SDL_Window *window) {
|
||||
// this is dumb as hell, but it's the only way
|
||||
EGLContext ctx = SDL_GL_CreateContext(window);
|
||||
|
||||
if(!ctx) {
|
||||
log_sdl_error(LOG_FATAL, "SDL_GL_CreateContext");
|
||||
}
|
||||
|
||||
EGLDisplay display = eglGetCurrentDisplay();
|
||||
assert(display != EGL_NO_DISPLAY);
|
||||
|
||||
SDL_GL_DeleteContext(ctx);
|
||||
return display;
|
||||
}
|
||||
|
||||
SDL_GLContext gles_create_context_angle(SDL_Window *window, int major, int minor, bool webgl) {
|
||||
void *libegl = SDL_LoadObject(NOT_NULL(env_get("SDL_VIDEO_EGL_DRIVER", NULL)));
|
||||
|
||||
if(!libegl) {
|
||||
log_sdl_error(LOG_FATAL, "SDL_LoadObject");
|
||||
}
|
||||
|
||||
gladLoadEGLUserPtr(EGL_NO_DISPLAY, egl_load_function, libegl);
|
||||
EGLDisplay display = egl_display_from_sdl(window);
|
||||
gladLoadEGLUserPtr(display, egl_load_function, libegl);
|
||||
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
EGLConfig config = get_egl_config(display, major);
|
||||
|
||||
EGLint attribs[64];
|
||||
int i = 0;
|
||||
|
||||
attribs[i++] = EGL_CONTEXT_MAJOR_VERSION;
|
||||
attribs[i++] = major;
|
||||
|
||||
attribs[i++] = EGL_CONTEXT_MINOR_VERSION;
|
||||
attribs[i++] = minor;
|
||||
|
||||
attribs[i++] = EGL_CONTEXT_OPENGL_DEBUG;
|
||||
attribs[i++] = glcommon_debug_requested();
|
||||
|
||||
attribs[i++] = EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE;
|
||||
attribs[i++] = webgl;
|
||||
|
||||
attribs[i++] = EGL_EXTENSIONS_ENABLED_ANGLE;
|
||||
attribs[i++] = EGL_TRUE;
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, attribs);
|
||||
|
||||
if(context == EGL_NO_CONTEXT) {
|
||||
log_fatal("eglCreateContext failed: %s", egl_get_error_string());
|
||||
}
|
||||
|
||||
if(SDL_GL_MakeCurrent(window, context)) {
|
||||
log_sdl_error(LOG_FATAL, "SDL_GL_MakeCurrent");
|
||||
}
|
||||
|
||||
assert(SDL_GL_GetCurrentContext() == context);
|
||||
|
||||
SDL_UnloadObject(libegl);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
12
src/renderer/glescommon/angle_egl.h
Normal file
12
src/renderer/glescommon/angle_egl.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
SDL_GLContext gles_create_context_angle(SDL_Window *window, int major, int minor, bool webgl);
|
16
src/renderer/glescommon/angle_egl_stub.c
Normal file
16
src/renderer/glescommon/angle_egl_stub.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "angle_egl.h"
|
||||
#include "util.h"
|
||||
|
||||
SDL_GLContext gles_create_context_angle(SDL_Window *window, int major, int minor, bool webgl) {
|
||||
log_fatal("Built without custom ANGLE EGL code path");
|
||||
}
|
|
@ -11,8 +11,27 @@
|
|||
#include "gles.h"
|
||||
#include "../common/backend.h"
|
||||
#include "../gl33/gl33.h"
|
||||
#include "angle_egl.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// Enable WebGL compatibility mode on Windows, because cubemaps are broken in the D3D11 backend
|
||||
// except in WebGL mode for some reason.
|
||||
#define ANGLE_WEBGL_DEFAULT true
|
||||
#else
|
||||
#define ANGLE_WEBGL_DEFAULT false
|
||||
#endif
|
||||
|
||||
attr_unused
|
||||
static SDL_GLContext gles_create_context_webgl(SDL_Window *window) {
|
||||
int major, minor;
|
||||
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
|
||||
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
|
||||
return gles_create_context_angle(window, major, minor, true);
|
||||
}
|
||||
|
||||
void gles_init(RendererBackend *gles_backend, int major, int minor) {
|
||||
GLVT_OF(*gles_backend).create_context = GLVT_OF(_r_backend_gl33).create_context;
|
||||
|
||||
#ifdef TAISEI_BUILDCONF_HAVE_ANGLE
|
||||
// Load ANGLE by default by setting up some SDL-specific environment vars.
|
||||
// These are not overwritten if they are already set in the environment, so
|
||||
|
@ -37,6 +56,10 @@ void gles_init(RendererBackend *gles_backend, int major, int minor) {
|
|||
#endif
|
||||
|
||||
env_set("SDL_OPENGL_ES_DRIVER", 1, false);
|
||||
|
||||
if(env_get("TAISEI_ANGLE_WEBGL", ANGLE_WEBGL_DEFAULT)) {
|
||||
GLVT_OF(*gles_backend).create_context = gles_create_context_webgl;
|
||||
}
|
||||
#endif // TAISEI_BUILDCONF_HAVE_ANGLE
|
||||
|
||||
_r_backend_inherit(gles_backend, &_r_backend_gl33);
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
|
||||
r_glescommon_deps = ['gl33'] + r_gl33_deps
|
||||
r_glescommon_libdeps = r_gl33_libdeps
|
||||
|
||||
r_glescommon_src = files(
|
||||
'gles.c',
|
||||
)
|
||||
|
||||
r_glescommon_deps = ['gl33'] + r_gl33_deps
|
||||
r_glescommon_libdeps = r_gl33_libdeps
|
||||
if config.get('TAISEI_BUILDCONF_HAVE_ANGLE', false)
|
||||
r_glescommon_src += files('angle_egl.c')
|
||||
r_glescommon_libdeps += dep_glad_egl
|
||||
else
|
||||
r_glescommon_src += files('angle_egl_stub.c')
|
||||
endif
|
||||
|
|
|
@ -77,17 +77,26 @@ glad_args = [
|
|||
glad_sources = []
|
||||
glad_includes = include_directories('include')
|
||||
|
||||
subdir('src')
|
||||
|
||||
glad_lib = static_library('glad', glad_sources,
|
||||
glad_gl_lib = static_library('gladGL', files('src/gl.c'),
|
||||
install : not meson.is_subproject(),
|
||||
build_by_default : not meson.is_subproject(),
|
||||
include_directories : glad_includes,
|
||||
)
|
||||
|
||||
glad_dep = declare_dependency(
|
||||
glad_egl_lib = static_library('gladEGL', files('src/egl.c'),
|
||||
install : not meson.is_subproject(),
|
||||
build_by_default : not meson.is_subproject(),
|
||||
include_directories : glad_includes,
|
||||
)
|
||||
|
||||
glad_gl_dep = declare_dependency(
|
||||
include_directories : glad_includes,
|
||||
link_with : glad_lib
|
||||
link_with : glad_gl_lib
|
||||
)
|
||||
|
||||
glad_egl_dep = declare_dependency(
|
||||
include_directories : glad_includes,
|
||||
link_with : glad_egl_lib
|
||||
)
|
||||
|
||||
if glad_program.found()
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
glad_sources += files(
|
||||
'gl.c',
|
||||
'egl.c',
|
||||
)
|
Loading…
Reference in a new issue