From 57400e1bf8343d95e1b09ad13c0f2d689ebc155b Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 8 Apr 2020 10:49:19 +0100 Subject: [PATCH] Add support for extended instruction sets * Implement a few instructions in GLSL.std.450 --- renderdoc/driver/shaders/spirv/CMakeLists.txt | 1 + .../shaders/spirv/renderdoc_spirv.vcxproj | 1 + .../spirv/renderdoc_spirv.vcxproj.filters | 1 + .../driver/shaders/spirv/spirv_debug.cpp | 47 ++++++ renderdoc/driver/shaders/spirv/spirv_debug.h | 19 ++- .../shaders/spirv/spirv_debug_glsl450.cpp | 155 ++++++++++++++++++ .../shaders/spirv/spirv_debug_setup.cpp | 32 ++++ util/test/demos/vk/vk_shader_debug_zoo.cpp | 72 ++++++++ 8 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp diff --git a/renderdoc/driver/shaders/spirv/CMakeLists.txt b/renderdoc/driver/shaders/spirv/CMakeLists.txt index fdd6d67d9..070c290f9 100644 --- a/renderdoc/driver/shaders/spirv/CMakeLists.txt +++ b/renderdoc/driver/shaders/spirv/CMakeLists.txt @@ -99,6 +99,7 @@ set(sources spirv_compile.cpp spirv_compile.h spirv_debug_setup.cpp + spirv_debug_glsl450.cpp spirv_debug.cpp spirv_debug.h spirv_reflect.cpp diff --git a/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj b/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj index c2d6cb0e4..845ec7025 100644 --- a/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj +++ b/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj @@ -157,6 +157,7 @@ precompiled.h + Level4 diff --git a/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj.filters b/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj.filters index a399a686e..16ba365de 100644 --- a/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj.filters +++ b/renderdoc/driver/shaders/spirv/renderdoc_spirv.vcxproj.filters @@ -145,6 +145,7 @@ + diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.cpp b/renderdoc/driver/shaders/spirv/spirv_debug.cpp index ae7978ba8..da5ab07d3 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug.cpp @@ -781,6 +781,53 @@ void ThreadState::StepNext(ShaderDebugState *state, break; } + ////////////////////////////////////////////////////////////////////////////// + // + // Extended instruction set handling + // + ////////////////////////////////////////////////////////////////////////////// + + case Op::ExtInst: + { + Id result = Id::fromWord(it.word(2)); + Id extinst = Id::fromWord(it.word(3)); + + if(global.extInsts.find(extinst) == global.extInsts.end()) + { + RDCERR("Unknown extended instruction set %u", extinst.value()); + break; + } + + const ExtInstDispatcher &dispatch = global.extInsts[extinst]; + + // ignore nonsemantic instructions + if(dispatch.nonsemantic) + break; + + uint32_t instruction = it.word(4); + + if(instruction >= dispatch.functions.size()) + { + RDCERR("Unsupported instruction %u in set %s (only %zu instructions defined)", instruction, + dispatch.name.c_str(), dispatch.functions.size()); + break; + } + + if(dispatch.functions[instruction] == NULL) + { + RDCWARN("Unimplemented extended instruction %s::%s", dispatch.name.c_str(), + dispatch.names[instruction].c_str()); + break; + } + + rdcarray params; + for(size_t i = 5; i < it.size(); i++) + params.push_back(Id::fromWord(it.word(i))); + + SetDst(state, result, dispatch.functions[instruction](*this, params)); + break; + } + ////////////////////////////////////////////////////////////////////////////// // // Comparison opcodes diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.h b/renderdoc/driver/shaders/spirv/spirv_debug.h index 9147be145..3bd67cddb 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.h +++ b/renderdoc/driver/shaders/spirv/spirv_debug.h @@ -58,12 +58,28 @@ public: uint32_t component) = 0; }; +struct ThreadState; + +typedef ShaderVariable (*ExtInstImpl)(ThreadState &, const rdcarray &); + +struct ExtInstDispatcher +{ + rdcstr name; + bool nonsemantic = false; + rdcarray names; + rdcarray functions; +}; + +void ConfigureGLSLStd450(ExtInstDispatcher &extinst); + struct GlobalState { public: GlobalState() {} // allocated storage for opaque uniform blocks, does not change over the course of debugging rdcarray constantBlocks; + + SparseIdMap extInsts; }; struct StackFrame @@ -132,8 +148,9 @@ struct ThreadState uint32_t workgroupIndex; bool done; -private: const ShaderVariable &GetSrc(Id id); + +private: void SetDst(ShaderDebugState *state, Id id, const ShaderVariable &val); void ProcessScopeChange(ShaderDebugState &state, const rdcarray &oldLive, const rdcarray &newLive); diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp new file mode 100644 index 000000000..f964f1415 --- /dev/null +++ b/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp @@ -0,0 +1,155 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "spirv_debug.h" +#include + +#if defined(_MSC_VER) +#define finite _finite +#endif + +namespace rdcspv +{ +namespace glsl +{ +#define CHECK_PARAMS(n) \ + if(params.size() != n) \ + { \ + RDCERR("Unexpected number of parameters (%zu) to %s, expected %u", params.size(), \ + __PRETTY_FUNCTION_SIGNATURE__, n); \ + return ShaderVariable(); \ + } + +ShaderVariable FAbs(ThreadState &state, const rdcarray ¶ms) +{ + CHECK_PARAMS(1); + + ShaderVariable var = state.GetSrc(params[0]); + + for(uint32_t c = 0; c < var.columns; c++) + var.value.fv[c] = fabs(var.value.fv[c]); + + return var; +} + +ShaderVariable Floor(ThreadState &state, const rdcarray ¶ms) +{ + CHECK_PARAMS(1); + + ShaderVariable var = state.GetSrc(params[0]); + + for(uint32_t c = 0; c < var.columns; c++) + var.value.fv[c] = floor(var.value.fv[c]); + + return var; +} + +ShaderVariable Pow(ThreadState &state, const rdcarray ¶ms) +{ + CHECK_PARAMS(2); + + ShaderVariable var = state.GetSrc(params[0]); + ShaderVariable y = state.GetSrc(params[1]); + + for(uint32_t c = 0; c < var.columns; c++) + var.value.fv[c] = powf(var.value.fv[c], y.value.fv[c]); + + return var; +} + +ShaderVariable FMix(ThreadState &state, const rdcarray ¶ms) +{ + CHECK_PARAMS(3); + + ShaderVariable var = state.GetSrc(params[0]); + ShaderVariable y = state.GetSrc(params[1]); + ShaderVariable a = state.GetSrc(params[2]); + + for(uint32_t c = 0; c < var.columns; c++) + { + float xf = var.value.fv[c]; + float yf = y.value.fv[c]; + float af = a.value.fv[c]; + + var.value.fv[c] = xf * (1 - af) + yf * af; + } + + return var; +} + +ShaderVariable Normalize(ThreadState &state, const rdcarray ¶ms) +{ + CHECK_PARAMS(1); + + ShaderVariable var = state.GetSrc(params[0]); + + float sqrlength = 0.0f; + + for(uint32_t c = 0; c < var.columns; c++) + sqrlength += (var.value.fv[c] * var.value.fv[c]); + + float invlength = 1.0f / sqrt(sqrlength); + + for(uint32_t c = 0; c < var.columns; c++) + var.value.fv[c] *= invlength; + + return var; +} + +ShaderVariable Cross(ThreadState &state, const rdcarray ¶ms) +{ + CHECK_PARAMS(2); + + ShaderVariable x = state.GetSrc(params[0]); + ShaderVariable y = state.GetSrc(params[1]); + + RDCASSERT(x.columns == 3 && y.columns == 3, x.columns, y.columns); + + ShaderVariable var = x; + + var.value.fv[0] = x.value.fv[1] * y.value.fv[2] - y.value.fv[1] * x.value.fv[2]; + var.value.fv[1] = x.value.fv[2] * y.value.fv[0] - y.value.fv[2] * x.value.fv[0]; + var.value.fv[2] = x.value.fv[0] * y.value.fv[1] - y.value.fv[0] * x.value.fv[1]; + + return var; +} +}; // namespace glsl + +void ConfigureGLSLStd450(ExtInstDispatcher &extinst) +{ + extinst.names.resize((size_t)GLSLstd450::Max); + for(size_t i = 0; i < extinst.names.size(); i++) + extinst.names[i] = ToStr(GLSLstd450(i)); + + extinst.functions.resize(extinst.names.size()); + +#define EXT(func) extinst.functions[(uint32_t)GLSLstd450::func] = &glsl::func; + EXT(FAbs); + EXT(Floor); + EXT(Pow); + EXT(FMix); + EXT(Cross); + EXT(Normalize); +} +}; // namespace rdcspv diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index a954ea328..f2d6d44b2 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -200,6 +200,38 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader } } + for(auto it = extSets.begin(); it != extSets.end(); it++) + { + Id id = it->first; + const rdcstr &setname = it->second; + + if(setname == "GLSL.std.450") + { + ExtInstDispatcher extinst; + + extinst.name = setname; + + ConfigureGLSLStd450(extinst); + + global.extInsts[id] = extinst; + } + else if(setname.beginsWith("NonSemantic.")) + { + ExtInstDispatcher extinst; + + extinst.name = setname; + + extinst.nonsemantic = true; + + global.extInsts[id] = extinst; + } + else + { + RDCERR("Unsupported extended instruction set: %s", setname.c_str()); + return new ShaderDebugTrace; + } + } + for(const rdcstr &e : extensions) { if(e == "SPV_GOOGLE_decorate_string" || e == "SPV_GOOGLE_hlsl_functionality1") diff --git a/util/test/demos/vk/vk_shader_debug_zoo.cpp b/util/test/demos/vk/vk_shader_debug_zoo.cpp index b45c73a23..f25e5a191 100644 --- a/util/test/demos/vk/vk_shader_debug_zoo.cpp +++ b/util/test/demos/vk/vk_shader_debug_zoo.cpp @@ -192,6 +192,78 @@ void main() Color = dFdyFine(vec4(inpos, inposIncreased)); break; } + case 13: + { + Color = vec4(abs(posone*2.5f), abs(negone*2.5f), abs(zerof*2.5f), 1.0f); + break; + } + case 14: + { + Color = vec4(pow(posone*2.5f, posone*1.3f), pow(posone*2.5f, posone*0.45f), + pow(vec2(posone*2.5f, posone*1.3f), vec2(posone*0.9f, posone*8.5f))); + break; + } + case 15: + { + Color = vec4(normalize(posone*2.5f), normalize(posone), normalize(negone), 1.0f); + break; + } + case 16: + { + Color = vec4(normalize(vec2(posone*2.5f, negone*1.8f)), normalize(vec2(posone*8.5f, negone*7.1f))); + break; + } + case 17: + { + Color = vec4(normalize(vec3(posone*2.5f, negone*1.8f, posone*8.5f)), 1.0f); + break; + } + case 18: + { + Color = normalize(vec4(posone*2.5f, negone*1.8f, posone*8.5f, negone*5.2f)); + break; + } + case 19: + { + Color = vec4(floor(posone*2.5f), floor(posone*2.4f), floor(posone*2.6f), floor(zerof)); + break; + } + case 20: + { + Color = vec4(floor(negone*2.5f), floor(negone*2.4f), floor(negone*2.6f), 1.0f); + break; + } + case 21: + { + Color = vec4(mix(posone*1.1f, posone*3.3f, 0.5f), + mix(posone*1.1f, posone*3.3f, 0.2f), + mix(posone*1.1f, posone*3.3f, 0.8f), + 1.0f); + break; + } + case 22: + { + Color = vec4(mix(posone*1.1f, posone*3.3f, 1.5f), + mix(posone*1.1f, posone*3.3f, -0.3f), + 0.0f, + 1.0f); + break; + } + case 23: + { + Color = vec4(mix(posone*3.3f, posone*1.1f, 0.5f), + mix(posone*3.3f, posone*1.1f, 0.2f), + mix(posone*3.3f, posone*1.1f, 0.8f), + 1.0f); + break; + } + case 24: + { + vec3 a = vec3(posone*2.5f, negone*1.8f, posone*8.5f); + vec3 b = vec3(negone*6.3f, posone*3.2f, negone*0.4f); + Color = vec4(cross(a, b), 1.0f); + break; + } default: break; } }