From 3e18acdb3dd7aaaa411f0cd03e48f4438e1d68f2 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Fri, 13 Apr 2018 15:24:00 +0100 Subject: [PATCH] glsl compat: Convert to highest GLSL version accepted by the target driver With many more apps using GLES 3.1+, we're now hitting the case where GLSL 330 is not sufficient. Unfortunately GLSL 420+ is not supported on mac (which has been stranded at 410), so forcing output to anything above 410 will completely break mac. The only sensible option here is to give up with the GLSL compat and either use a ref-rast, a 3rd party library to convert to metal, or require on-device replay. All of these options are substantial work, so for now generate code at the highest supported shader level for the given host device driver. This means shaders using GLSL 420+ features should now work on decent Windows / Linux drivers, but will (continue) to fail on mac. --- gapis/api/gles/compat.go | 1 + gapis/api/gles/find_issues.go | 1 + gapis/api/gles/version.go | 56 ++++++++++++++------------- gapis/shadertools/cc/libmanager.cpp | 3 +- gapis/shadertools/cc/libmanager.h | 1 + gapis/shadertools/cc/spirv2glsl.cpp | 4 +- gapis/shadertools/cc/spirv2glsl.h | 2 +- gapis/shadertools/shadertools.go | 3 ++ gapis/shadertools/shadertools_test.go | 1 + 9 files changed, 41 insertions(+), 31 deletions(-) diff --git a/gapis/api/gles/compat.go b/gapis/api/gles/compat.go index ee99859b71..c67f15fc41 100644 --- a/gapis/api/gles/compat.go +++ b/gapis/api/gles/compat.go @@ -415,6 +415,7 @@ func compat(ctx context.Context, device *device.Instance, onError onCompatError) ShaderType: st, Relaxed: true, // find_issues will still report bad GLSL. StripOptimizations: true, + TargetGLSLVersion: version.MaxGLSL().AsInt(), } // Trim any prefix whitespace / newlines. diff --git a/gapis/api/gles/find_issues.go b/gapis/api/gles/find_issues.go index 7929d0c169..738c9d6e14 100644 --- a/gapis/api/gles/find_issues.go +++ b/gapis/api/gles/find_issues.go @@ -170,6 +170,7 @@ func (t *findIssues) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, o ShaderType: st, CheckAfterChanges: true, Disassemble: true, + TargetGLSLVersion: 430, } if _, err := shadertools.ConvertGlsl(shader.Source, &opts); err != nil { diff --git a/gapis/api/gles/version.go b/gapis/api/gles/version.go index a74af668e0..f1628c34c6 100644 --- a/gapis/api/gles/version.go +++ b/gapis/api/gles/version.go @@ -51,44 +51,46 @@ func (v Version) AtLeastGL(major, minor int) bool { return !v.IsES && v.AtLeast(major, minor) } -var versionRe = regexp.MustCompile(`^(OpenGL ES.*? )?(\d+)\.(\d+).*`) - -// ParseVersion parses the GL version major, minor and flavour from the output of glGetString(GL_VERSION). -func ParseVersion(str string) (*Version, error) { - if match := versionRe.FindStringSubmatch(str); match != nil { - isES := len(match[1]) > 0 // Desktop GL doesn't have a flavour prefix. - major, _ := strconv.Atoi(match[2]) - minor, _ := strconv.Atoi(match[3]) - return &Version{IsES: isES, Major: major, Minor: minor}, nil - } - return nil, fmt.Errorf("Unknown GL_VERSION format: %s", str) -} - -// GLSLVersion returns the highest supported GLSL version for the given GL version. -func GLSLVersion(glVersion string) (Version, error) { - v, err := ParseVersion(glVersion) - if err != nil { - return Version{}, err - } +// MaxGLSL returns the highest supported GLSL version for the given GL version. +func (v Version) MaxGLSL() Version { major, minor, isES := v.Major, v.Minor, v.IsES switch { case major == 2 && isES: - return Version{Major: 1, Minor: 0}, nil + return Version{Major: 1, Minor: 0} case major == 3 && isES: - return Version{Major: 3, Minor: 0}, nil + return Version{Major: 3, Minor: 0} case major == 2 && minor == 0 && !isES: - return Version{Major: 1, Minor: 1}, nil + return Version{Major: 1, Minor: 1} case major == 2 && minor == 1 && !isES: - return Version{Major: 1, Minor: 2}, nil + return Version{Major: 1, Minor: 2} case major == 3 && minor == 0 && !isES: - return Version{Major: 1, Minor: 3}, nil + return Version{Major: 1, Minor: 3} case major == 3 && minor == 1 && !isES: - return Version{Major: 1, Minor: 4}, nil + return Version{Major: 1, Minor: 4} case major == 3 && minor == 2 && !isES: - return Version{Major: 1, Minor: 5}, nil + return Version{Major: 1, Minor: 5} default: - return Version{Major: major, Minor: minor}, nil + return Version{Major: major, Minor: minor} } } + +// AsInt returns the version in the form Mmm, where M is the major version and +// m is the minor version. +func (v Version) AsInt() int { + return v.Major*100 + v.Minor*10 +} + +var versionRe = regexp.MustCompile(`^(OpenGL ES.*? )?(\d+)\.(\d+).*`) + +// ParseVersion parses the GL version major, minor and flavour from the output of glGetString(GL_VERSION). +func ParseVersion(str string) (*Version, error) { + if match := versionRe.FindStringSubmatch(str); match != nil { + isES := len(match[1]) > 0 // Desktop GL doesn't have a flavour prefix. + major, _ := strconv.Atoi(match[2]) + minor, _ := strconv.Atoi(match[3]) + return &Version{IsES: isES, Major: major, Minor: minor}, nil + } + return nil, fmt.Errorf("Unknown GL_VERSION format: %s", str) +} diff --git a/gapis/shadertools/cc/libmanager.cpp b/gapis/shadertools/cc/libmanager.cpp index e43b644f0e..9ab3e0e977 100644 --- a/gapis/shadertools/cc/libmanager.cpp +++ b/gapis/shadertools/cc/libmanager.cpp @@ -292,7 +292,8 @@ code_with_debug_info_t* convertGlsl(const char* input, size_t length, const conv strcpy(result->disassembly_string, tmp.c_str()); } - std::string source = spirv2glsl(std::move(spirv_new), options->strip_optimizations); + std::string source = spirv2glsl(std::move(spirv_new), + options->target_glsl_version, options->strip_optimizations); result->source_code = new char[source.length() + 1]; strcpy(result->source_code, source.c_str()); diff --git a/gapis/shadertools/cc/libmanager.h b/gapis/shadertools/cc/libmanager.h index 159f49bc12..810b10d437 100644 --- a/gapis/shadertools/cc/libmanager.h +++ b/gapis/shadertools/cc/libmanager.h @@ -76,6 +76,7 @@ typedef struct convert_options_t { bool disassemble; bool relaxed; bool strip_optimizations; + int target_glsl_version; } convert_options_t; typedef struct compile_options_t { diff --git a/gapis/shadertools/cc/spirv2glsl.cpp b/gapis/shadertools/cc/spirv2glsl.cpp index 05c4e3a6a0..e7bccbcc99 100644 --- a/gapis/shadertools/cc/spirv2glsl.cpp +++ b/gapis/shadertools/cc/spirv2glsl.cpp @@ -21,10 +21,10 @@ // so it is important we never include both at the same time. #include "third_party/SPIRV-Cross/spirv_glsl.hpp" -std::string spirv2glsl(std::vector spirv, bool strip_optimizations) { +std::string spirv2glsl(std::vector spirv, int glsl_version, bool strip_optimizations) { spirv_cross::CompilerGLSL glsl(std::move(spirv)); spirv_cross::CompilerGLSL::Options cross_options; - cross_options.version = 330; + cross_options.version = glsl_version == 0 ? 330 : glsl_version; cross_options.es = false; cross_options.force_temporary = false; cross_options.vertex.fixup_clipspace = false; diff --git a/gapis/shadertools/cc/spirv2glsl.h b/gapis/shadertools/cc/spirv2glsl.h index 8832c0799a..9d3c56a1f7 100644 --- a/gapis/shadertools/cc/spirv2glsl.h +++ b/gapis/shadertools/cc/spirv2glsl.h @@ -17,4 +17,4 @@ #include #include -std::string spirv2glsl(std::vector spirv, bool strip_optimizations); +std::string spirv2glsl(std::vector spirv, int glsl_version, bool strip_optimizations); diff --git a/gapis/shadertools/shadertools.go b/gapis/shadertools/shadertools.go index bf46531dcd..a8f09a8761 100644 --- a/gapis/shadertools/shadertools.go +++ b/gapis/shadertools/shadertools.go @@ -117,6 +117,8 @@ func (t ShaderType) String() string { type ConvertOptions struct { // The type of shader. ShaderType ShaderType + // The target GLSL version (default 330). + TargetGLSLVersion int // Shader source preamble. Preamble string // Whether to add prefix to all non-builtin symbols. @@ -175,6 +177,7 @@ func ConvertGlsl(source string, o *ConvertOptions) (CodeWithDebugInfo, error) { disassemble: C.bool(o.Disassemble), relaxed: C.bool(o.Relaxed), strip_optimizations: C.bool(o.StripOptimizations), + target_glsl_version: C.int(o.TargetGLSLVersion), } result := C.convertGlsl(cstr(source), C.size_t(len(source)), &opts) defer C.deleteGlslCodeWithDebug(result) diff --git a/gapis/shadertools/shadertools_test.go b/gapis/shadertools/shadertools_test.go index b08d6bbb25..92efb56da7 100644 --- a/gapis/shadertools/shadertools_test.go +++ b/gapis/shadertools/shadertools_test.go @@ -59,6 +59,7 @@ void main() ShaderType: shadertools.TypeFragment, CheckAfterChanges: true, StripOptimizations: true, + TargetGLSLVersion: 330, }, `#version 310 es layout(early_fragment_tests) in;