Support variable initialisers

* We also set uninitialized variables to 0xcccccccc to make it clearer that they
  are invalid.
This commit is contained in:
baldurk
2020-04-30 17:21:34 +01:00
parent d9a189425c
commit e1a7349b9c
4 changed files with 51 additions and 5 deletions
@@ -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<ShaderVariable, true>(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)
{
@@ -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)
{
@@ -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;
}
};
@@ -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 +