taisei/src/renderer/glcommon/shaders.c

205 lines
5.7 KiB
C
Raw Normal View History

/*
* 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>.
2019-07-03 20:00:56 +02:00
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "shaders.h"
#include "util.h"
#include "opengl.h"
#include "rwops/rwops_autobuf.h"
ShaderLangInfoArray glcommon_shader_lang_table = { 0 };
static void add_glsl_version_parsed(GLSLVersion v) {
dynarray_foreach_elem(&glcommon_shader_lang_table, ShaderLangInfo *lang, {
if(!memcmp(&lang->glsl.version, &v, sizeof(v))) {
return;
}
});
ShaderLangInfo *lang = dynarray_append(&glcommon_shader_lang_table);
lang->lang = SHLANG_GLSL;
lang->glsl.version = v;
if(v.profile == GLSL_PROFILE_NONE && v.version >= 330) {
v.profile = GLSL_PROFILE_CORE;
lang = dynarray_append(&glcommon_shader_lang_table);
lang->lang = SHLANG_GLSL;
lang->glsl.version = v;
}
}
static void add_glsl_version_nonstandard(const char *vstr) {
// because intel wants to be fucking special again
char a, b, c;
if(sscanf(vstr, "%c.%c%c - ", &a, &b, &c) == 3) {
if(isdigit(a) && isdigit(b) && isdigit(c)) {
GLSLVersion v = { 0 };
v.version = (a - '0') * 100 + (b - '0') * 10 + (c - '0');
v.profile = GLSL_PROFILE_NONE;
add_glsl_version_parsed(v);
v.profile = GLSL_PROFILE_CORE;
add_glsl_version_parsed(v);
v.profile = GLSL_PROFILE_COMPATIBILITY;
add_glsl_version_parsed(v);
}
}
}
static void add_glsl_version(const char *vstr) {
if(!*vstr) {
// Special case: the very first GLSL version doesn't have a version string.
// We'll just ignore it, it's way too old to be useful anyway.
return;
}
GLSLVersion v;
if(glsl_parse_version(vstr, &v) == vstr) {
add_glsl_version_nonstandard(vstr);
return;
}
add_glsl_version_parsed(v);
}
static void glcommon_build_shader_lang_table_fallback(void);
static void glcommon_build_shader_lang_table_finish(void);
void glcommon_build_shader_lang_table(void) {
dynarray_ensure_capacity(&glcommon_shader_lang_table, 8);
// NOTE: The ability to query supported GLSL versions was added in GL 4.3,
// but it's not exposed by any extension. This is pretty silly.
GLint num_versions = 0;
if(!glext.version.is_webgl) {
glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &num_versions);
}
for(int i = 0; i < num_versions; ++i) {
add_glsl_version((char*)glGetStringi(GL_SHADING_LANGUAGE_VERSION, i));
}
if(glcommon_shader_lang_table.num_elements < 1) {
glcommon_build_shader_lang_table_fallback();
}
// TODO: Maybe also detect compatibility profile somehow.
glcommon_build_shader_lang_table_finish();
}
static void glcommon_build_shader_lang_table_fallback(void) {
log_warn("Can not reliably determine all supported GLSL versions, resorting to guesswork.");
struct vtable {
uint gl;
GLSLVersion glsl;
};
static struct vtable version_map[] = {
// OpenGL Core
{ 45, { 450, GLSL_PROFILE_NONE } },
{ 46, { 460, GLSL_PROFILE_NONE } },
{ 44, { 440, GLSL_PROFILE_NONE } },
{ 43, { 430, GLSL_PROFILE_NONE } },
{ 42, { 420, GLSL_PROFILE_NONE } },
{ 41, { 410, GLSL_PROFILE_NONE } },
{ 40, { 400, GLSL_PROFILE_NONE } },
{ 33, { 330, GLSL_PROFILE_NONE } },
{ 32, { 150, GLSL_PROFILE_NONE } },
{ 31, { 140, GLSL_PROFILE_NONE } },
{ 30, { 130, GLSL_PROFILE_NONE } },
{ 21, { 120, GLSL_PROFILE_NONE } },
{ 20, { 110, GLSL_PROFILE_NONE } },
// OpenGL ES
{ 32, { 320, GLSL_PROFILE_ES } },
{ 31, { 310, GLSL_PROFILE_ES } },
{ 30, { 300, GLSL_PROFILE_ES } },
// { 20, { 100, GLSL_PROFILE_ES } },
};
const char *glslvstr = (char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
const char *glslvstr_orig = glslvstr;
static const char gles_prefix[] = "OpenGL ES GLSL ES";
GLSLProfile profile = GLSL_PROFILE_NONE;
uint major, minor;
OpenGL ES 3.0 rendering backend (#148) * First steps towards shader transpilation Needs to be manually enabled via -Dshader_transpiler=true. Requires shaderc. https://github.com/google/shaderc Not yet functional due to missing SPIRV-Cross integration. SPIRV-Cross currently does not have an official C API, and crossc is too minimal to be useful. The current plan is to extend crossc and vendor it, while also sending PRs upstream. * Integrate crossc; shader transpilation for GLES now works * fix leak * gles30 backend now playable on Mesa with 3.2 context Some rendering issues are present. Identified so far: - Marisa's lasers are invisible - Death effect looks wrong Also, a small pixmap manipulation library has been written, and the texture uploading API redesigned around it. * fix marisa lasers in GLES (uniform name clashed with builtin) * fix player death effect in GLES (another name clash) * Dump ANGLE's translated shader code in debug log * fix screenshots * Drop support for triangle fans, switch to strips Fans offer no advantage over strips, and they've been removed in D3D10+, so ANGLE has to emulate them. * crude workaround for an ANGLE bug * Re-enable GL debug labels, fix an issue with them that affected ANGLE (but was always technically a bug) * fix race condition in shaderc initialization * New SDL_RWops interface for vertex buffers * Optimize VBO streaming via buffering updates Measurable performance improvement even with the main gl33 renderer, drastic improvement with ANGLE. * Fix the depth texture binding problem under ANGLE Apparently it hates GL_DEPTH_COMPONENT16 for some reason. Sized internal formats are not supported in GLES 2.0 anyway, so not using them is probably a good idea. * fix GLES2.0 segfault (the backend still doesn't work, though) * dump GL extensions at info log level, not debug * get around a Mesa bug; more correct texture format table for GLES2 * Correct GLES3 texture format table according to the spec Not a Mesa bug after all * require crossc>=1.5.0, fallback to subproject * Request at least 8bit per color channel in GL backends * Forbid lto for static windows builds with shader_transpiler=true * fix edge case segfault * Add basic ANGLE bundling support to the build system Windows only, and no NSIS support yet * Fix various windows-related build system and installer brokenness * Disable gles backends by default * update documentation
2018-10-02 00:36:10 +02:00
if(glslvstr == NULL) {
log_error("Failed to obtain the GLSL version string");
OpenGL ES 3.0 rendering backend (#148) * First steps towards shader transpilation Needs to be manually enabled via -Dshader_transpiler=true. Requires shaderc. https://github.com/google/shaderc Not yet functional due to missing SPIRV-Cross integration. SPIRV-Cross currently does not have an official C API, and crossc is too minimal to be useful. The current plan is to extend crossc and vendor it, while also sending PRs upstream. * Integrate crossc; shader transpilation for GLES now works * fix leak * gles30 backend now playable on Mesa with 3.2 context Some rendering issues are present. Identified so far: - Marisa's lasers are invisible - Death effect looks wrong Also, a small pixmap manipulation library has been written, and the texture uploading API redesigned around it. * fix marisa lasers in GLES (uniform name clashed with builtin) * fix player death effect in GLES (another name clash) * Dump ANGLE's translated shader code in debug log * fix screenshots * Drop support for triangle fans, switch to strips Fans offer no advantage over strips, and they've been removed in D3D10+, so ANGLE has to emulate them. * crude workaround for an ANGLE bug * Re-enable GL debug labels, fix an issue with them that affected ANGLE (but was always technically a bug) * fix race condition in shaderc initialization * New SDL_RWops interface for vertex buffers * Optimize VBO streaming via buffering updates Measurable performance improvement even with the main gl33 renderer, drastic improvement with ANGLE. * Fix the depth texture binding problem under ANGLE Apparently it hates GL_DEPTH_COMPONENT16 for some reason. Sized internal formats are not supported in GLES 2.0 anyway, so not using them is probably a good idea. * fix GLES2.0 segfault (the backend still doesn't work, though) * dump GL extensions at info log level, not debug * get around a Mesa bug; more correct texture format table for GLES2 * Correct GLES3 texture format table according to the spec Not a Mesa bug after all * require crossc>=1.5.0, fallback to subproject * Request at least 8bit per color channel in GL backends * Forbid lto for static windows builds with shader_transpiler=true * fix edge case segfault * Add basic ANGLE bundling support to the build system Windows only, and no NSIS support yet * Fix various windows-related build system and installer brokenness * Disable gles backends by default * update documentation
2018-10-02 00:36:10 +02:00
glcommon_free_shader_lang_table();
return;
}
if(strstartswith(glslvstr, gles_prefix)) {
glslvstr += strlen(gles_prefix);
profile = GLSL_PROFILE_ES;
}
if(sscanf(glslvstr, " %u.%u", &major, &minor) == 2) {
GLSLVersion glsl_version = { major * 100 + minor, profile };
// This one *must* work.
add_glsl_version_parsed(glsl_version);
// Let's be a bit optimistic here and just assume that all the older versions are supported (except those commented out).
// This seems to be the common behavior anyway.
for(struct vtable *v = version_map; v < version_map + sizeof(version_map)/sizeof(*version_map); ++v) {
if(v->glsl.version < glsl_version.version && v->glsl.profile == profile) {
add_glsl_version_parsed(v->glsl);
}
}
} else {
log_error("Failed to parse GLSL version string: %s", glslvstr_orig);
// We could try to infer it from the context version, but whatever.
// If we got here, then we're probably fucked anyway.
glcommon_free_shader_lang_table();
return;
}
}
static void glcommon_build_shader_lang_table_finish(void) {
if(glcommon_shader_lang_table.num_elements > 0) {
char *str;
SDL_RWops *abuf = SDL_RWAutoBuffer((void**)&str, 256);
SDL_RWprintf(abuf, "Supported GLSL versions: ");
char vbuf[32];
dynarray_foreach(&glcommon_shader_lang_table, int i, ShaderLangInfo *lang, {
assert(lang->lang == SHLANG_GLSL);
glsl_format_version(vbuf, sizeof(vbuf), lang->glsl.version);
if(i == 0) {
SDL_RWprintf(abuf, "%s", vbuf);
} else {
SDL_RWprintf(abuf, ", %s", vbuf);
}
});
SDL_WriteU8(abuf, 0);
log_info("%s", str);
SDL_RWclose(abuf);
dynarray_compact(&glcommon_shader_lang_table);
} else {
log_error("Can not determine supported GLSL versions. Looks like the OpenGL implementation is non-conformant. Expect nothing to work.");
}
}
void glcommon_free_shader_lang_table(void) {
dynarray_free_data(&glcommon_shader_lang_table);
}