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