diff --git a/gapis/api/gles/compat.go b/gapis/api/gles/compat.go index 6ec5351da8..6447c53ef6 100644 --- a/gapis/api/gles/compat.go +++ b/gapis/api/gles/compat.go @@ -455,8 +455,9 @@ func compat(ctx context.Context, device *device.Instance) (transform.Transformer log.W(ctx, "%v compat: %v", cmd, err) } opts := shadertools.Options{ - ShaderType: st, - Relaxed: true, // find_issues will still report bad GLSL. + ShaderType: st, + Relaxed: true, // find_issues will still report bad GLSL. + StripOptimizations: true, } // Trim any prefix whitespace / newlines. diff --git a/gapis/shadertools/CMakeFiles.cmake b/gapis/shadertools/CMakeFiles.cmake index 008952877d..ddcc62ba00 100644 --- a/gapis/shadertools/CMakeFiles.cmake +++ b/gapis/shadertools/CMakeFiles.cmake @@ -19,6 +19,7 @@ set(files shadertools.go + shadertools_test.go ) set(dirs cc diff --git a/gapis/shadertools/cc/libmanager.cpp b/gapis/shadertools/cc/libmanager.cpp index ea1fb0671e..527f4baa82 100644 --- a/gapis/shadertools/cc/libmanager.cpp +++ b/gapis/shadertools/cc/libmanager.cpp @@ -233,7 +233,7 @@ code_with_debug_info_t* convertGlsl(const char* input, size_t length, const opti strcpy(result->disassembly_string, tmp.c_str()); } - std::string source = spirv2glsl(std::move(spirv_new)); + std::string source = spirv2glsl(std::move(spirv_new), 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 19aca6e1c9..ecd81435ce 100644 --- a/gapis/shadertools/cc/libmanager.h +++ b/gapis/shadertools/cc/libmanager.h @@ -69,6 +69,7 @@ typedef struct options_t { bool check_after_changes; bool disassemble; bool relaxed; + bool strip_optimizations; } options_t; typedef struct spirv_binary_t { diff --git a/gapis/shadertools/cc/spirv2glsl.cpp b/gapis/shadertools/cc/spirv2glsl.cpp index 6c629f3948..5f0abe28dc 100644 --- a/gapis/shadertools/cc/spirv2glsl.cpp +++ b/gapis/shadertools/cc/spirv2glsl.cpp @@ -21,7 +21,7 @@ // 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) { +std::string spirv2glsl(std::vector spirv, bool strip_optimizations) { spirv_cross::CompilerGLSL glsl(std::move(spirv)); spirv_cross::CompilerGLSL::Options cross_options; cross_options.version = 330; @@ -29,5 +29,8 @@ std::string spirv2glsl(std::vector spirv) { cross_options.force_temporary = false; cross_options.vertex.fixup_clipspace = false; glsl.set_options(cross_options); + if (strip_optimizations) { + glsl.unset_execution_mode(spv::ExecutionModeEarlyFragmentTests); + } return glsl.compile(); } diff --git a/gapis/shadertools/cc/spirv2glsl.h b/gapis/shadertools/cc/spirv2glsl.h index 0564c7260c..8832c0799a 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); +std::string spirv2glsl(std::vector spirv, bool strip_optimizations); diff --git a/gapis/shadertools/shadertools.go b/gapis/shadertools/shadertools.go index 197c119ca9..e8a795d26b 100644 --- a/gapis/shadertools/shadertools.go +++ b/gapis/shadertools/shadertools.go @@ -37,7 +37,7 @@ var mutex sync.Mutex // Instruction represents a SPIR-V instruction. type Instruction struct { - Id uint32 // Result id. + ID uint32 // Result identifer. Opcode uint32 // Opcode. Words []uint32 // Operands. Name string // Optional symbol name. @@ -50,12 +50,13 @@ type CodeWithDebugInfo struct { Info []Instruction // A set of SPIR-V debug instructions. } +// FormatDebugInfo returns the instructions as a string. func FormatDebugInfo(insts []Instruction, linePrefix string) string { var buffer bytes.Buffer for _, inst := range insts { buffer.WriteString(linePrefix) - if inst.Id != 0 { - buffer.WriteString(fmt.Sprintf("%%%-5v = ", inst.Id)) + if inst.ID != 0 { + buffer.WriteString(fmt.Sprintf("%%%-5v = ", inst.ID)) } else { buffer.WriteString(fmt.Sprintf(" = ")) } @@ -125,6 +126,11 @@ type Options struct { Disassemble bool // If true, let some minor invalid statements compile. Relaxed bool + // If true, optimizations that require high-end GL versions, or extensions + // will be stripped. These optimizations should have no impact on the end + // result of the shader, but may impact performance. + // Example: Early Fragment Test. + StripOptimizations bool } // ConvertGlsl modifies the given GLSL according to the options specified via @@ -159,6 +165,7 @@ func ConvertGlsl(source string, o *Options) (CodeWithDebugInfo, error) { check_after_changes: C.bool(o.CheckAfterChanges), disassemble: C.bool(o.Disassemble), relaxed: C.bool(o.Relaxed), + strip_optimizations: C.bool(o.StripOptimizations), } result := C.convertGlsl(cstr(source), C.size_t(len(source)), &opts) defer C.deleteGlslCodeWithDebug(result) @@ -169,18 +176,18 @@ func ConvertGlsl(source string, o *Options) (CodeWithDebugInfo, error) { } if result.info != nil { - c_insts := (*[1 << 30]C.struct_instruction_t)(unsafe.Pointer(result.info.insts)) + cInsts := (*[1 << 30]C.struct_instruction_t)(unsafe.Pointer(result.info.insts)) for i := 0; i < int(result.info.insts_num); i++ { - c_inst := c_insts[i] + cInst := cInsts[i] inst := Instruction{ - Id: uint32(c_inst.id), - Opcode: uint32(c_inst.opcode), - Words: make([]uint32, 0, c_inst.words_num), - Name: C.GoString(c_inst.name), + ID: uint32(cInst.id), + Opcode: uint32(cInst.opcode), + Words: make([]uint32, 0, cInst.words_num), + Name: C.GoString(cInst.name), } - c_words := (*[1 << 30]C.uint32_t)(unsafe.Pointer(c_inst.words)) - for j := 0; j < int(c_inst.words_num); j++ { - inst.Words = append(inst.Words, uint32(c_words[j])) + cWords := (*[1 << 30]C.uint32_t)(unsafe.Pointer(cInst.words)) + for j := 0; j < int(cInst.words_num); j++ { + inst.Words = append(inst.Words, uint32(cWords[j])) } ret.Info = append(ret.Info, inst) } diff --git a/gapis/shadertools/shadertools_test.go b/gapis/shadertools/shadertools_test.go new file mode 100644 index 0000000000..0f96de32b9 --- /dev/null +++ b/gapis/shadertools/shadertools_test.go @@ -0,0 +1,89 @@ +// Copyright (C) 2017 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shadertools_test + +import ( + "testing" + + "github.com/google/gapid/core/assert" + "github.com/google/gapid/core/log" + "github.com/google/gapid/gapis/shadertools" +) + +func TestConvertGlsl(t *testing.T) { + for _, test := range []struct { + desc string + opts shadertools.Options + src string + expected string + }{ + { + "Test shadertools propagates early_fragment_tests", + shadertools.Options{ + ShaderType: shadertools.TypeFragment, + CheckAfterChanges: true, + }, + `#version 310 es +layout(early_fragment_tests) in; +out highp vec4 color; +void main() { color = vec4(1., 1., 1., 1.); }`, + `#version 330 +#ifdef GL_ARB_shading_language_420pack +#extension GL_ARB_shading_language_420pack : require +#endif +#extension GL_ARB_shader_image_load_store : require +layout(early_fragment_tests) in; + +out vec4 color; + +void main() +{ + color = vec4(1.0); +} + +`}, { + "Test shadertools strips early_fragment_tests", + shadertools.Options{ + ShaderType: shadertools.TypeFragment, + CheckAfterChanges: true, + StripOptimizations: true, + }, + `#version 310 es +layout(early_fragment_tests) in; +out highp vec4 color; +void main() { color = vec4(1., 1., 1., 1.); }`, + `#version 330 +#ifdef GL_ARB_shading_language_420pack +#extension GL_ARB_shading_language_420pack : require +#endif + +out vec4 color; + +void main() +{ + color = vec4(1.0); +} + +`}, + } { + t.Run(test.desc, func(t *testing.T) { + ctx := log.Testing(t) + out, err := shadertools.ConvertGlsl(test.src, &test.opts) + if assert.For(ctx, "err").ThatError(err).Succeeded() { + assert.For(ctx, "src").ThatString(out.SourceCode).Equals(test.expected) + } + }) + } +} diff --git a/third_party/SPIRV-Cross b/third_party/SPIRV-Cross index 68274c27da..4263956c02 160000 --- a/third_party/SPIRV-Cross +++ b/third_party/SPIRV-Cross @@ -1 +1 @@ -Subproject commit 68274c27da5a97a150fb6c2615e3e32949e7a0ca +Subproject commit 4263956c02bf4dd767ddec38dfac658381e93f5e