Skip to content
Permalink
Browse files

windows: detect intel's shitty driver and fall back to ANGLE

  • Loading branch information...
Akaricchi committed Sep 21, 2019
1 parent 1fdc00f commit 7fe3f8ff90a28bced10c2a38eaea8d6f67c4ab59
@@ -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

@@ -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 %*
@@ -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

@@ -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;
}
}

@@ -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('''
@@ -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);

@@ -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();
@@ -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')
)
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Supports Windows Vista / Server 2008 -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Supports Windows 7 / Server 2008 R2 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Supports Windows 8 / Server 2012 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Supports Windows 8.1 / Server 2012 R2 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Supports Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
</assembly>
@@ -2,16 +2,19 @@
#define IDS_TAISEI 1
#define IDS_REPLAY 2

#include "winver.h"
#include <winver.h>
#include <windows.h>

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
@@ -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);
}

@@ -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;

0 comments on commit 7fe3f8f

Please sign in to comment.
You can’t perform that action at this time.