From 7fe3f8ff90a28bced10c2a38eaea8d6f67c4ab59 Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Sat, 21 Sep 2019 16:39:05 +0300 Subject: [PATCH] windows: detect intel's shitty driver and fall back to ANGLE --- .editorconfig | 3 +- misc/taisei-angle.bat | 10 +---- scripts/taisei.nsi.in | 15 +++---- src/cli.c | 47 ++++++++++++++++++--- src/meson.build | 24 ++++++++++- src/renderer/glcommon/opengl.c | 74 ++++++++++++++++++++++++++++++++++ src/renderer/glescommon/gles.c | 14 +++++++ src/renderer/meson.build | 5 +++ src/taisei.manifest | 30 ++++++++++++++ src/taisei.rc.in | 9 +++-- src/util/env.c | 1 + src/video.c | 3 +- 12 files changed, 203 insertions(+), 32 deletions(-) create mode 100644 src/taisei.manifest diff --git a/.editorconfig b/.editorconfig index f04f2926..f17c07ba 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,11 +9,10 @@ charset = utf-8 indent_style = tab # indent_size = 4 -[*.{py,html,js}] +[*.{py,html,js,nsi.in}] indent_style = space indent_size = 4 [meson.build] indent_style = space indent_size = 4 - diff --git a/misc/taisei-angle.bat b/misc/taisei-angle.bat index 77292f72..b41c5e68 100644 --- a/misc/taisei-angle.bat +++ b/misc/taisei-angle.bat @@ -1,10 +1,2 @@ @echo off - -cd "%~dp0" -set ANGLE_PATH=.\ANGLE -set TAISEI_RENDERER=gles30 -set SDL_OPENGL_ES_DRIVER=1 -set SDL_VIDEO_GL_DRIVER=%ANGLE_PATH%\libGLESv2.dll -set SDL_VIDEO_EGL_DRIVER=%ANGLE_PATH%\libEGL.dll - -start .\taisei.exe %* +"%~dp0\taisei.exe" --renderer gles30 %* diff --git a/scripts/taisei.nsi.in b/scripts/taisei.nsi.in index 9aa44129..98f911de 100644 --- a/scripts/taisei.nsi.in +++ b/scripts/taisei.nsi.in @@ -155,20 +155,17 @@ Section "-Core installation" CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" CreateShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + CreateShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Taisei.lnk" "$INSTDIR\taisei.exe" !if @USE_ANGLE@ == 1 - CreateShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Taisei (OpenGL).lnk" "$INSTDIR\taisei.exe" - CreateShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Taisei (ANGLE).lnk" "$INSTDIR\taisei-angle.bat" "" "$INSTDIR\taisei.exe" 0 SW_SHOWMINIMIZED - !else - CreateShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Taisei.lnk" "$INSTDIR\taisei.exe" + CreateShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Taisei (ANGLE).lnk" "$INSTDIR\taisei.exe" "--renderer gles30" !endif ${If} "$INSTALL_DESKTOP" == "1" + CreateShortcut "$DESKTOP\Taisei.lnk" "$INSTDIR\taisei.exe" + !if @USE_ANGLE@ == 1 - CreateShortcut "$DESKTOP\Taisei (OpenGL).lnk" "$INSTDIR\taisei.exe" - CreateShortcut "$DESKTOP\Taisei (ANGLE).lnk" "$INSTDIR\taisei-angle.bat" "" "$INSTDIR\taisei.exe" 0 SW_SHOWMINIMIZED - !else - CreateShortcut "$DESKTOP\Taisei.lnk" "$INSTDIR\taisei.exe" + CreateShortcut "$DESKTOP\Taisei (ANGLE).lnk" "$INSTDIR\taisei.exe" "--renderer gles30" !endif ${EndIf} @@ -257,7 +254,7 @@ Function .onInit StrCmp $0 "" inst MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \ - "${APPNAME} is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \ + "${APPNAME} is already installed.$\n$\nDo you want to uninstall the old version before installing the new one?$\n$\nIf unsure, choose YES." \ /SD IDYES IDYES uninst IDNO inst Abort diff --git a/src/cli.c b/src/cli.c index 8a7d9a9d..a1c77733 100644 --- a/src/cli.c +++ b/src/cli.c @@ -19,27 +19,53 @@ struct TsOption { struct option opt; const char *help; const char *argname;}; +enum { + OPT_RENDERER = INT_MIN, +}; + static void print_help(struct TsOption* opts) { tsfprintf(stdout, "Usage: taisei [OPTIONS]\nTaisei is an open source Tōhō Project fangame.\n\nOptions:\n"); int margin = 20; for(struct TsOption *opt = opts; opt->opt.name; opt++) { - tsfprintf(stdout, " -%c, --%s ", opt->opt.val,opt->opt.name); + if(opt->opt.val > 0) { + tsfprintf(stdout, " -%c, --%s ", opt->opt.val, opt->opt.name); + } else { + tsfprintf(stdout, " --%s ", opt->opt.name); + } + int length = margin-(int)strlen(opt->opt.name); + if(opt->argname) { tsfprintf(stdout, "%s", opt->argname); length -= (int)strlen(opt->argname); } - for(int i = 0; i < length; i++) - tsfprintf(stdout, " "); - if(opt->argname) + + for(int i = 0; i < length; i++) { + fputc(' ', stdout); + } + + fputs(" ", stdout); + + if(opt->argname && strchr(opt->help, '%')) { tsfprintf(stdout, opt->help, opt->argname); - else + } else { tsfprintf(stdout, "%s", opt->help); + } + tsfprintf(stdout, "\n"); } } int cli_args(int argc, char **argv, CLIAction *a) { + const char *const _renderer_list = + #define R(r) ","#r + TAISEI_BUILDCONF_RENDERER_BACKENDS + #undef R + ; + + char renderer_list[strlen(_renderer_list) + 2]; + snprintf(renderer_list, sizeof(renderer_list), "{%s}", _renderer_list+1); + struct TsOption taisei_opts[] = { {{"replay", required_argument, 0, 'r'}, "Play a replay from %s", "FILE"}, {{"verify-replay", required_argument, 0, 'R'}, "Play a replay from %s in headless mode, crash as soon as it desyncs", "FILE"}, @@ -53,6 +79,7 @@ int cli_args(int argc, char **argv, CLIAction *a) { #endif {{"frameskip", optional_argument, 0, 'f'}, "Disable FPS limiter, render only every %s frame", "FRAME"}, {{"credits", no_argument, 0, 'c'}, "Show the credits scene and exit"}, + {{"renderer", required_argument, 0, OPT_RENDERER}, "Choose the rendering backend", renderer_list}, {{"help", no_argument, 0, 'h'}, "Display this help"}, {{0,0,0,0},0,0} }; @@ -66,6 +93,11 @@ int cli_args(int argc, char **argv, CLIAction *a) { for(int i = 0; i < nopts; i++) { opts[i] = taisei_opts[i].opt; + + if(opts[i].val <= 0) { + continue; + } + *ptr = opts[i].val; ptr++; @@ -160,8 +192,11 @@ int cli_args(int argc, char **argv, CLIAction *a) { case 'c': a->type = CLI_Credits; break; + case OPT_RENDERER: + env_set("TAISEI_RENDERER", optarg, true); + break; default: - log_fatal("Unknown option (this shouldn’t happen)"); + UNREACHABLE; } } diff --git a/src/meson.build b/src/meson.build index 15e5df55..24ca9e3f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -10,8 +10,15 @@ if host_machine.system() == 'windows' winmod = import('windows') rcpath = join_paths(meson.current_build_dir(), 'taisei.rc') + icons_dir = join_paths(meson.source_root(), 'misc', 'icons') + icon_main = join_paths(icons_dir, 'taisei.ico') + icon_replay = join_paths(icons_dir, 'taisei-replay.ico') + manifest = join_paths(meson.current_source_dir(), 'taisei.manifest') + rcdefs = [ - '-DICONS_DIR=@0@'.format(join_paths(meson.source_root(), 'misc', 'icons')) + '-DICON_MAIN=@0@'.format(icon_main), + '-DICON_REPLAY=@0@'.format(icon_replay), + '-DMANIFEST=@0@'.format(manifest), ] if is_debug_build @@ -28,12 +35,25 @@ if host_machine.system() == 'windows' output : 'taisei.rc', ) - version_deps += winmod.compile_resources(rc_target) + if meson.version().version_compare('>=0.47.0') + version_deps += winmod.compile_resources( + rc_target, + depend_files : files( + 'taisei.manifest', + icon_main, + icon_replay, + ) + ) + else + version_deps += winmod.compile_resources(rc_target) + endif # msvcrt is dumb and only supports up to c89. # with this defined, alternative implementations from mingw for e.g. the # printf family of functions will be used, which conform to c11. config.set('__USE_MINGW_ANSI_STDIO', 1) + + taisei_deps += cc.find_library('comctl32') endif use_intel_intrin = get_option('intel_intrin') and cc.links(''' diff --git a/src/renderer/glcommon/opengl.c b/src/renderer/glcommon/opengl.c index b2380e40..56badd74 100644 --- a/src/renderer/glcommon/opengl.c +++ b/src/renderer/glcommon/opengl.c @@ -593,6 +593,78 @@ static APIENTRY GLvoid shim_glClearDepthf(GLfloat depthval) { } #endif +static void detect_broken_intel_driver(void) { +#ifdef TAISEI_BUILDCONF_HAVE_WINDOWS_ANGLE_FALLBACK + extern DECLSPEC int SDLCALL SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid); + + bool is_broken_intel_driver = ( + !glext.version.is_es && + strstartswith((const char*)glGetString(GL_VENDOR), "Intel") && + strstr((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION), " - Build ") + ); + + if(!is_broken_intel_driver) { + return; + } + + int button; + SDL_MessageBoxData mbdata = { 0 }; + + mbdata.flags = SDL_MESSAGEBOX_WARNING; + mbdata.title = "Taisei Project"; + + char *msg = strfmt( + "Looks like you have a broken OpenGL driver.\n" + "Taisei will probably not work correctly, if at all.\n\n" + "Starting the game in ANGLE mode should fix the problem, but may introduce slowdown.\n\n" + "Restart in ANGLE mode now? (If unsure, press YES)" + ); + + mbdata.message = msg; + mbdata.numbuttons = 3; + mbdata.buttons = (SDL_MessageBoxButtonData[]) { + { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 2, "Abort" }, + { 0, 1, "No" }, + { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 0, "Yes (safe)" }, + }; + + int mbresult = SDL_ShowMessageBox(&mbdata, &button); + free(msg); + + if(mbresult < 0) { + log_sdl_error(LOG_ERROR, "SDL_ShowMessageBox"); + } else if(button == 1) { + return; + } else if(button == 2) { + exit(1); + } + + const WCHAR *cmdline = GetCommandLine(); + const WCHAR renderer_args[] = L" --renderer gles30"; + WCHAR new_cmdline[wcslen(cmdline) + wcslen(renderer_args) + 1]; + memcpy(new_cmdline, cmdline, sizeof(WCHAR) * wcslen(cmdline)); + memcpy(new_cmdline + wcslen(cmdline), renderer_args, sizeof(renderer_args)); + + PROCESS_INFORMATION pi; + STARTUPINFO si = { sizeof(si) }; + + CreateProcessW( + NULL, + new_cmdline, + NULL, + NULL, + false, + 0, + NULL, + NULL, + &si, + &pi + ); + + exit(0); +#endif +} + void glcommon_check_capabilities(void) { memset(&glext, 0, sizeof(glext)); @@ -632,6 +704,8 @@ void glcommon_check_capabilities(void) { log_info("OpenGL renderer: %s", (const char*)glGetString(GL_RENDERER)); log_info("GLSL version: %s", glslv); + detect_broken_intel_driver(); + // XXX: this is the legacy way, maybe we shouldn't try this first const char *exts = (const char*)glGetString(GL_EXTENSIONS); diff --git a/src/renderer/glescommon/gles.c b/src/renderer/glescommon/gles.c index 9ede64fb..52682953 100644 --- a/src/renderer/glescommon/gles.c +++ b/src/renderer/glescommon/gles.c @@ -14,6 +14,20 @@ #include "../gl33/gl33.h" void gles_init(RendererBackend *gles_backend, int major, int minor) { +#ifdef TAISEI_BUILDCONF_HAVE_WINDOWS_ANGLE_FALLBACK + char *basepath = SDL_GetBasePath(); + size_t basepath_len = strlen(basepath); + char buf[basepath_len + 32]; + snprintf(buf, sizeof(buf), "%sANGLE\\", basepath); + SDL_free(basepath); + basepath_len += sizeof("ANGLE"); + strlcpy(buf + basepath_len, "libGLESv2.dll", sizeof(buf) - basepath_len); + env_set("SDL_VIDEO_GL_DRIVER", buf, false); + strlcpy(buf + basepath_len, "libEGL.dll", sizeof(buf) - basepath_len); + env_set("SDL_VIDEO_EGL_DRIVER", buf, false); + env_set("SDL_OPENGL_ES_DRIVER", 1, false); +#endif + _r_backend_inherit(gles_backend, &_r_backend_gl33); glcommon_setup_attributes(SDL_GL_CONTEXT_PROFILE_ES, major, minor, 0); glcommon_load_library(); diff --git a/src/renderer/meson.build b/src/renderer/meson.build index 9b6555aa..83dc178f 100644 --- a/src/renderer/meson.build +++ b/src/renderer/meson.build @@ -61,3 +61,8 @@ endforeach r_macro = ' '.join(r_macro) config.set('TAISEI_BUILDCONF_RENDERER_BACKENDS', r_macro) config.set_quoted('TAISEI_BUILDCONF_RENDERER_DEFAULT', default_renderer) +config.set('TAISEI_BUILDCONF_HAVE_WINDOWS_ANGLE_FALLBACK', + host_machine.system() == 'windows' and + enabled_renderers.contains('gles30') and + get_option('install_angle') +) diff --git a/src/taisei.manifest b/src/taisei.manifest new file mode 100644 index 00000000..f881defe --- /dev/null +++ b/src/taisei.manifest @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/taisei.rc.in b/src/taisei.rc.in index 019ad8f2..11d6c3bb 100644 --- a/src/taisei.rc.in +++ b/src/taisei.rc.in @@ -2,16 +2,19 @@ #define IDS_TAISEI 1 #define IDS_REPLAY 2 -#include "winver.h" +#include +#include -IDI_ICON1 ICON "${ICONS_DIR}/taisei.ico" -IDI_ICON2 ICON "${ICONS_DIR}/taisei-replay.ico" +IDI_ICON1 ICON "${ICON_MAIN}" +IDI_ICON2 ICON "${ICON_REPLAY}" STRINGTABLE BEGIN IDS_TAISEI, "Taisei Project" IDS_REPLAY, "Taisei Project replay" END +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "${MANIFEST}" + ${BUILDTYPE_DEFINE} #ifdef DEBUG_BUILD diff --git a/src/util/env.c b/src/util/env.c index a53600b6..fb834ff1 100644 --- a/src/util/env.c +++ b/src/util/env.c @@ -32,6 +32,7 @@ const char *env_get_string_nonempty(const char *var, const char *fallback) { } void env_set_string(const char *var, const char *val, bool override) { + log_debug("%s=%s (%i)", var, val, override); SDL_setenv(var, val, override); } diff --git a/src/video.c b/src/video.c index 565b5dc4..263d2449 100644 --- a/src/video.c +++ b/src/video.c @@ -208,10 +208,11 @@ static void video_new_window_internal(uint display, uint w, uint h, uint32_t fla title, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display), - w, h, flags + w, h, flags | SDL_WINDOW_HIDDEN ); if(video.window) { + SDL_ShowWindow(video.window); SDL_SetWindowMinimumSize(video.window, SCREEN_W / 4, SCREEN_H / 4); video_update_mode_settings(); return;