diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index 397e62ff4..9aa914723 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -543,6 +543,11 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader this->apiWrapper->FillInputValue(var, builtin, (uint32_t)location, component); } + else + { + // make it obvious when uninitialised outputs are written + memset(var.value.u64v, 0xcc, sizeof(var.value.u64v)); + } if(sourceName != rawName) { @@ -885,8 +890,19 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader // global variables should all be pointers into opaque storage RDCASSERT(type.type == DataType::PointerType); + auto uninitialisedCallback = [this](ShaderVariable &var, const Decorations &, + const DataType &, uint64_t, const rdcstr &) { + if(!var.members.empty()) + return; + + memset(var.value.u64v, 0xcc, sizeof(var.value.u64v)); + }; + WalkVariable(decorations[v.id], dataTypes[type.InnerType()], ~0U, var, - rdcstr(), NULL); + rdcstr(), uninitialisedCallback); + + if(v.initializer != Id()) + AssignValue(var, active.ids[v.initializer]); if(v.storage == StorageClass::Private) { diff --git a/renderdoc/driver/shaders/spirv/spirv_processor.cpp b/renderdoc/driver/shaders/spirv/spirv_processor.cpp index 1b2936be8..95f0f0266 100644 --- a/renderdoc/driver/shaders/spirv/spirv_processor.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_processor.cpp @@ -492,7 +492,8 @@ void Processor::RegisterOp(Iter it) // only register global variables here if(decoded.storageClass != rdcspv::StorageClass::Function) - globals.push_back(Variable(decoded.resultType, decoded.result, decoded.storageClass)); + globals.push_back( + Variable(decoded.resultType, decoded.result, decoded.storageClass, decoded.initializer)); } else if(opdata.op == Op::ConstantNull) { diff --git a/renderdoc/driver/shaders/spirv/spirv_processor.h b/renderdoc/driver/shaders/spirv/spirv_processor.h index ce4aa7ca4..55c1293f9 100644 --- a/renderdoc/driver/shaders/spirv/spirv_processor.h +++ b/renderdoc/driver/shaders/spirv/spirv_processor.h @@ -430,10 +430,11 @@ struct EntryPoint struct Variable { Variable() = default; - Variable(Id t, Id i, StorageClass s) : type(t), id(i), storage(s) {} + Variable(Id t, Id i, StorageClass s, Id init) : type(t), id(i), storage(s), initializer(init) {} Id type; Id id; StorageClass storage; + Id initializer; bool operator<(const Variable &o) const { @@ -441,13 +442,15 @@ struct Variable return id < o.id; if(type != o.type) return type < o.type; - return storage < o.storage; + if(storage != o.storage) + return storage < o.storage; + return initializer < o.initializer; } bool operator!=(const Variable &o) const { return !operator==(o); } bool operator==(const Variable &o) const { - return id == o.id && type == o.type && storage == o.storage; + return id == o.id && type == o.type && storage == o.storage && initializer == o.initializer; } }; diff --git a/util/test/demos/vk/vk_shader_debug_zoo.cpp b/util/test/demos/vk/vk_shader_debug_zoo.cpp index 3e23e3988..ef5532e27 100644 --- a/util/test/demos/vk/vk_shader_debug_zoo.cpp +++ b/util/test/demos/vk/vk_shader_debug_zoo.cpp @@ -2438,6 +2438,30 @@ void main() %_mat = OpLoad %float4x4 %_ptrmat %_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec +)EOTEST", + }); + + // test variables with initialisers + append_tests({ + R"EOTEST( + ; this has a constant initialiser, so should already be ready + %_out_float4 = OpLoad %float4 %priv_float4_init +)EOTEST", + R"EOTEST( + ; this is uninitialised, but unforuntately that means we can't test our debugging + ; against the real thing when it's undefined. But we can at least expose it so that + ; when manually checking we see the uninitialised values + %_uninit = OpLoad %float4 %priv_float4 + %_x = OpVectorTimesScalar %float4 %_uninit %float_0_0 + %_out_float4 = OpFAdd %float4 %_x %float4_1234 +)EOTEST", + R"EOTEST( + ; this is uninitialised, but unforuntately that means we can't test our debugging + ; against the real thing when it's undefined. But we can at least expose it so that + ; when manually checking we see the uninitialised values + %_uninit = OpLoad %float4 %Color + %_x = OpVectorTimesScalar %float4 %_uninit %float_0_0 + %_out_float4 = OpFAdd %float4 %_x %float4_1234 )EOTEST", }); } @@ -2916,6 +2940,8 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource %float2_00 = OpConstantComposite %float2 %float_0_0 %float_0_0 %float2_12 = OpConstantComposite %float2 %float_1_0 %float_2_0 + %priv_float4_init = OpVariable %ptr_Private_float4 Private %float4_1234 + )EOSHADER"; std::string ret = capabilities +