mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-28 18:31:40 +00:00
Add support for storage buffer access
This commit is contained in:
@@ -488,7 +488,7 @@ void RichResourceTextPaint(const QWidget *owner, QPainter *painter, QRect rect,
|
||||
}
|
||||
else
|
||||
{
|
||||
name = QFormatStr("Unknown 0x%1").arg(ptr->val.pointer, 16, 16);
|
||||
name = QFormatStr("Unknown 0x%1").arg(ptr->val.pointer, 16, 16, QLatin1Char('0'));
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +210,20 @@ void ThreadState::WritePointerValue(Id pointer, const ShaderVariable &val)
|
||||
// plus any additional ones for other pointers.
|
||||
Id ptrid = debugger.GetPointerBaseId(var);
|
||||
|
||||
rdcarray<ShaderVariableChange> changes;
|
||||
ShaderVariableChange basechange;
|
||||
basechange.before = debugger.EvaluatePointerVariable(ids[ptrid]);
|
||||
|
||||
if(debugger.IsOpaquePointer(ids[ptrid]))
|
||||
{
|
||||
// if this is a write to a SSBO pointer, don't record any alias changes, just record a no-op
|
||||
// change to this pointer
|
||||
basechange.after = basechange.before = debugger.GetPointerValue(ids[pointer]);
|
||||
m_State->changes.push_back(basechange);
|
||||
debugger.WriteThroughPointer(var, val);
|
||||
return;
|
||||
}
|
||||
|
||||
rdcarray<ShaderVariableChange> changes;
|
||||
basechange.before = debugger.GetPointerValue(ids[ptrid]);
|
||||
|
||||
rdcarray<Id> &pointers = pointersForId[ptrid];
|
||||
|
||||
@@ -220,13 +231,13 @@ void ThreadState::WritePointerValue(Id pointer, const ShaderVariable &val)
|
||||
|
||||
// for every other pointer, evaluate its value now before
|
||||
for(size_t i = 0; i < pointers.size(); i++)
|
||||
changes[i].before = debugger.EvaluatePointerVariable(ids[pointers[i]]);
|
||||
changes[i].before = debugger.GetPointerValue(ids[pointers[i]]);
|
||||
|
||||
debugger.WriteThroughPointer(var, val);
|
||||
|
||||
// now evaluate the value after
|
||||
for(size_t i = 0; i < pointers.size(); i++)
|
||||
changes[i].after = debugger.EvaluatePointerVariable(ids[pointers[i]]);
|
||||
changes[i].after = debugger.GetPointerValue(ids[pointers[i]]);
|
||||
|
||||
// if the pointer we're writing is one of the aliased pointers, be sure we add it even if
|
||||
// it's a no-op change
|
||||
@@ -247,7 +258,7 @@ void ThreadState::WritePointerValue(Id pointer, const ShaderVariable &val)
|
||||
|
||||
// always add a change for the base storage variable written itself, even if that's a no-op.
|
||||
// This one is not included in any of the pointers lists above
|
||||
basechange.after = debugger.EvaluatePointerVariable(ids[ptrid]);
|
||||
basechange.after = debugger.GetPointerValue(ids[ptrid]);
|
||||
m_State->changes.push_back(basechange);
|
||||
}
|
||||
}
|
||||
@@ -266,7 +277,7 @@ void ThreadState::SetDst(Id id, const ShaderVariable &val)
|
||||
if(m_State)
|
||||
{
|
||||
ShaderVariableChange change;
|
||||
change.after = debugger.EvaluatePointerVariable(ids[id]);
|
||||
change.after = debugger.GetPointerValue(ids[id]);
|
||||
m_State->changes.push_back(change);
|
||||
|
||||
debugger.AddSourceVars(sourceVars, id);
|
||||
@@ -289,7 +300,7 @@ void ThreadState::ProcessScopeChange(const rdcarray<Id> &oldLive, const rdcarray
|
||||
if(liveGlobals.contains(id))
|
||||
continue;
|
||||
|
||||
m_State->changes.push_back({debugger.EvaluatePointerVariable(ids[id])});
|
||||
m_State->changes.push_back({debugger.GetPointerValue(ids[id])});
|
||||
}
|
||||
|
||||
for(const Id id : newLive)
|
||||
@@ -297,7 +308,7 @@ void ThreadState::ProcessScopeChange(const rdcarray<Id> &oldLive, const rdcarray
|
||||
if(liveGlobals.contains(id))
|
||||
continue;
|
||||
|
||||
m_State->changes.push_back({ShaderVariable(), debugger.EvaluatePointerVariable(ids[id])});
|
||||
m_State->changes.push_back({ShaderVariable(), debugger.GetPointerValue(ids[id])});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +474,7 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
|
||||
(void)load.memoryAccess;
|
||||
|
||||
// get the pointer value, evaluate it (i.e. dereference) and store the result
|
||||
SetDst(load.result, debugger.EvaluatePointerVariable(GetSrc(load.pointer)));
|
||||
SetDst(load.result, debugger.ReadFromPointer(GetSrc(load.pointer)));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -486,7 +497,7 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
|
||||
(void)copy.memoryAccess0;
|
||||
(void)copy.memoryAccess1;
|
||||
|
||||
WritePointerValue(copy.target, debugger.EvaluatePointerVariable(GetSrc(copy.source)));
|
||||
WritePointerValue(copy.target, debugger.ReadFromPointer(GetSrc(copy.source)));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -506,6 +517,41 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
|
||||
|
||||
break;
|
||||
}
|
||||
case Op::ArrayLength:
|
||||
{
|
||||
OpArrayLength len(it);
|
||||
|
||||
ShaderVariable structPointer = GetSrc(len.structure);
|
||||
|
||||
// get the pointer base offset (should be zero for any binding but could be non-zero for a
|
||||
// buffer_device_address pointer)
|
||||
uint64_t offset = structPointer.value.u64v[BufferPointerByteOffsetVariableSlot];
|
||||
|
||||
// add the offset of the member
|
||||
const DataType &pointerType = debugger.GetTypeForId(len.structure);
|
||||
const DataType &structType = debugger.GetType(pointerType.InnerType());
|
||||
|
||||
offset += structType.children[len.arraymember].decorations.offset;
|
||||
|
||||
ShaderVariable result;
|
||||
result.rows = result.columns = 1;
|
||||
result.type = VarType::UInt;
|
||||
|
||||
BindpointIndex bind = debugger.GetPointerValue(structPointer).GetBinding();
|
||||
|
||||
uint64_t byteLen = debugger.GetAPIWrapper()->GetBufferLength(bind) - offset;
|
||||
|
||||
const Decorations &dec = debugger.GetDecorations(structType.children[len.arraymember].type);
|
||||
|
||||
RDCASSERT(dec.flags & Decorations::HasArrayStride);
|
||||
byteLen /= dec.arrayStride;
|
||||
|
||||
result.value.uv[0] = uint32_t(byteLen);
|
||||
|
||||
SetDst(len.result, result);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -576,7 +622,7 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
|
||||
debugger.MakeCompositePointer(ids[extract.composite], extract.composite, extract.indexes);
|
||||
|
||||
// then evaluate it, to get the extracted value
|
||||
SetDst(extract.result, debugger.EvaluatePointerVariable(ptr));
|
||||
SetDst(extract.result, debugger.ReadFromPointer(ptr));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -2490,4 +2536,5 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
|
||||
|
||||
m_State = NULL;
|
||||
}
|
||||
|
||||
}; // namespace rdcspv
|
||||
|
||||
@@ -52,9 +52,11 @@ public:
|
||||
virtual ~DebugAPIWrapper() {}
|
||||
virtual void AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src, rdcstr d) = 0;
|
||||
|
||||
// TODO handle arrays of cbuffers
|
||||
virtual void ReadConstantBufferValue(uint32_t set, uint32_t bind, uint32_t offset,
|
||||
uint32_t byteSize, void *dst) = 0;
|
||||
virtual uint64_t GetBufferLength(BindpointIndex bind) = 0;
|
||||
|
||||
virtual void ReadBufferValue(BindpointIndex bind, uint64_t offset, uint64_t byteSize, void *dst) = 0;
|
||||
virtual void WriteBufferValue(BindpointIndex bind, uint64_t offset, uint64_t byteSize,
|
||||
const void *src) = 0;
|
||||
virtual void FillInputValue(ShaderVariable &var, ShaderBuiltin builtin, uint32_t location,
|
||||
uint32_t component) = 0;
|
||||
|
||||
@@ -91,7 +93,11 @@ public:
|
||||
uint32_t component) = 0;
|
||||
};
|
||||
|
||||
// this could be cleaner if ShaderVariable wasn't a very public struct, but it's not worth it so
|
||||
// we just reserve value slots that we know won't be used in opaque variables
|
||||
static const uint32_t TextureTypeVariableSlot = 8;
|
||||
static const uint32_t BufferPointerByteOffsetVariableSlot = 8;
|
||||
static const uint32_t BufferPointerTypeIdVariableSlot = 9;
|
||||
|
||||
typedef ShaderVariable (*ExtInstImpl)(ThreadState &, uint32_t, const rdcarray<Id> &);
|
||||
|
||||
@@ -237,16 +243,20 @@ public:
|
||||
uint32_t GetInstructionForFunction(Id id);
|
||||
uint32_t GetInstructionForLabel(Id id);
|
||||
const DataType &GetType(Id typeId);
|
||||
const DataType &GetTypeForId(Id ssaId);
|
||||
const Decorations &GetDecorations(Id typeId);
|
||||
rdcstr GetRawName(Id id) const;
|
||||
rdcstr GetHumanName(Id id);
|
||||
void AddSourceVars(rdcarray<SourceVariableMapping> &sourceVars, Id id);
|
||||
void AllocateVariable(Id id, Id typeId, DebugVariableType sourceVarType, const rdcstr &sourceName,
|
||||
ShaderVariable &outVar);
|
||||
|
||||
ShaderVariable EvaluatePointerVariable(const ShaderVariable &v) const;
|
||||
ShaderVariable ReadFromPointer(const ShaderVariable &v) const;
|
||||
ShaderVariable GetPointerValue(const ShaderVariable &v) const;
|
||||
ShaderVariable MakePointerVariable(Id id, const ShaderVariable *v, uint32_t scalar0 = ~0U,
|
||||
uint32_t scalar1 = ~0U) const;
|
||||
Id GetPointerBaseId(const ShaderVariable &v) const;
|
||||
bool IsOpaquePointer(const ShaderVariable &v) const;
|
||||
void WriteThroughPointer(const ShaderVariable &ptr, const ShaderVariable &val);
|
||||
ShaderVariable MakeCompositePointer(const ShaderVariable &base, Id id, rdcarray<uint32_t> &indices);
|
||||
|
||||
@@ -256,6 +266,7 @@ public:
|
||||
const rdcarray<Id> &GetLiveGlobals() { return liveGlobals; }
|
||||
const rdcarray<SourceVariableMapping> &GetGlobalSourceVars() { return globalSourceVars; }
|
||||
ThreadState &GetActiveLane() { return workgroup[activeLaneIndex]; }
|
||||
const ThreadState &GetActiveLane() const { return workgroup[activeLaneIndex]; }
|
||||
private:
|
||||
virtual void PreParse(uint32_t maxId);
|
||||
virtual void PostParse();
|
||||
@@ -267,6 +278,9 @@ private:
|
||||
uint32_t ApplyDerivatives(uint32_t quadIndex, const Decorations &curDecorations,
|
||||
uint32_t location, const DataType &inType, ShaderVariable &outVar);
|
||||
|
||||
void WalkVariable(const DataType &type, uint64_t byteOffset, ShaderVariable &var, bool initialise,
|
||||
std::function<void(ShaderVariable &, const DataType &, uint64_t)> callback) const;
|
||||
|
||||
void AddSourceVars(rdcarray<SourceVariableMapping> &sourceVars, const DataType &inType,
|
||||
const rdcstr &sourceName, const rdcstr &varName, uint32_t &offset);
|
||||
void MakeSignatureNames(const rdcarray<SPIRVInterfaceAccess> &sigList, rdcarray<rdcstr> &sigNames);
|
||||
|
||||
@@ -86,6 +86,16 @@ const rdcspv::DataType &Debugger::GetType(Id typeId)
|
||||
return dataTypes[typeId];
|
||||
}
|
||||
|
||||
const rdcspv::DataType &Debugger::GetTypeForId(Id ssaId)
|
||||
{
|
||||
return dataTypes[idTypes[ssaId]];
|
||||
}
|
||||
|
||||
const Decorations &Debugger::GetDecorations(Id typeId)
|
||||
{
|
||||
return decorations[typeId];
|
||||
}
|
||||
|
||||
void Debugger::MakeSignatureNames(const rdcarray<SPIRVInterfaceAccess> &sigList,
|
||||
rdcarray<rdcstr> &sigNames)
|
||||
{
|
||||
@@ -462,8 +472,8 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader
|
||||
}
|
||||
|
||||
// pick up uniform globals, which could be cbuffers, and push constants
|
||||
else if((v.storage == StorageClass::Uniform || v.storage == StorageClass::PushConstant) &&
|
||||
(decorations[v.id].flags & Decorations::BufferBlock) == 0)
|
||||
else if(v.storage == StorageClass::Uniform || v.storage == StorageClass::StorageBuffer ||
|
||||
v.storage == StorageClass::PushConstant)
|
||||
{
|
||||
ShaderVariable var;
|
||||
var.name = GetRawName(v.id);
|
||||
@@ -477,6 +487,9 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader
|
||||
|
||||
const DataType &innertype = dataTypes[type.InnerType()];
|
||||
|
||||
const bool ssbo = (v.storage == StorageClass::StorageBuffer) ||
|
||||
(decorations[innertype.id].flags & Decorations::BufferBlock);
|
||||
|
||||
if(innertype.type == DataType::ArrayType)
|
||||
{
|
||||
RDCERR("uniform Arrays not supported yet");
|
||||
@@ -489,6 +502,9 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader
|
||||
{
|
||||
if(v.storage == StorageClass::PushConstant)
|
||||
sourceName = "_pushconsts";
|
||||
else if(ssbo)
|
||||
sourceName = StringFormat::Fmt("_buffer_set%u_bind%u", decorations[v.id].set,
|
||||
decorations[v.id].binding);
|
||||
else
|
||||
sourceName = StringFormat::Fmt("_cbuffer_set%u_bind%u", decorations[v.id].set,
|
||||
decorations[v.id].binding);
|
||||
@@ -502,19 +518,47 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader
|
||||
d.flags = Decorations::Flags(d.flags | Decorations::HasDescriptorSet);
|
||||
}
|
||||
|
||||
uint32_t offset = 0;
|
||||
AllocateVariable(d, d, DebugVariableType::Constant, sourceName, 0, innertype, var);
|
||||
|
||||
global.constantBlocks.push_back(var);
|
||||
cbufferIDs.push_back(v.id);
|
||||
|
||||
SourceVariableMapping sourceVar;
|
||||
sourceVar.name = sourceName;
|
||||
sourceVar.type = VarType::Unknown;
|
||||
sourceVar.rows = 0;
|
||||
sourceVar.columns = 0;
|
||||
sourceVar.offset = 0;
|
||||
sourceVar.variables.push_back(DebugVariableReference(DebugVariableType::Constant, var.name));
|
||||
|
||||
if(ssbo)
|
||||
{
|
||||
var.rows = 1;
|
||||
var.columns = 1;
|
||||
var.type = VarType::ReadWriteResource;
|
||||
|
||||
uint32_t set = 0, bind = 0;
|
||||
if(decorations[v.id].flags & Decorations::HasDescriptorSet)
|
||||
set = decorations[v.id].set;
|
||||
if(decorations[v.id].flags & Decorations::HasBinding)
|
||||
bind = decorations[v.id].binding;
|
||||
|
||||
// TODO handle arrays
|
||||
var.SetBinding((int32_t)set, (int32_t)bind, 0U);
|
||||
|
||||
sourceVar.type = VarType::ReadWriteResource;
|
||||
sourceVar.rows = 1;
|
||||
sourceVar.columns = 1;
|
||||
sourceVar.variables.push_back(
|
||||
DebugVariableReference(DebugVariableType::ReadWriteResource, var.name));
|
||||
|
||||
global.readWriteResources.push_back(var);
|
||||
readWriteIDs.push_back(v.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
AllocateVariable(d, d, DebugVariableType::Constant, sourceName, 0, innertype, var);
|
||||
|
||||
sourceVar.type = VarType::ConstantBlock;
|
||||
sourceVar.rows = 0;
|
||||
sourceVar.columns = 0;
|
||||
sourceVar.variables.push_back(DebugVariableReference(DebugVariableType::Constant, var.name));
|
||||
|
||||
global.constantBlocks.push_back(var);
|
||||
cbufferIDs.push_back(v.id);
|
||||
}
|
||||
|
||||
globalSourceVars.push_back(sourceVar);
|
||||
}
|
||||
@@ -790,7 +834,7 @@ rdcarray<ShaderDebugState> Debugger::ContinueDebug()
|
||||
initial.nextInstruction = active.nextInstruction;
|
||||
|
||||
for(const Id &v : active.live)
|
||||
initial.changes.push_back({ShaderVariable(), EvaluatePointerVariable(active.ids[v])});
|
||||
initial.changes.push_back({ShaderVariable(), GetPointerValue(active.ids[v])});
|
||||
|
||||
initial.sourceVars = active.sourceVars;
|
||||
|
||||
@@ -847,7 +891,7 @@ rdcarray<ShaderDebugState> Debugger::ContinueDebug()
|
||||
{
|
||||
thread.live.erase(l);
|
||||
ShaderVariableChange change;
|
||||
change.before = EvaluatePointerVariable(thread.ids[id]);
|
||||
change.before = GetPointerValue(thread.ids[id]);
|
||||
state.changes.push_back(change);
|
||||
|
||||
rdcstr name = GetRawName(id);
|
||||
@@ -909,11 +953,115 @@ ShaderVariable Debugger::MakeCompositePointer(const ShaderVariable &base, Id id,
|
||||
if(base.type == VarType::GPUPointer)
|
||||
leaf = (const ShaderVariable *)(uintptr_t)base.value.u64v[0];
|
||||
|
||||
if(leaf->type == VarType::ReadWriteResource)
|
||||
{
|
||||
ShaderVariable ret = MakePointerVariable(id, leaf);
|
||||
|
||||
uint64_t byteOffset = base.value.u64v[BufferPointerByteOffsetVariableSlot];
|
||||
|
||||
const DataType *type = &dataTypes[idTypes[id]];
|
||||
|
||||
RDCASSERT(type->type == DataType::PointerType);
|
||||
type = &dataTypes[type->InnerType()];
|
||||
|
||||
// first walk any aggregate types
|
||||
size_t i = 0;
|
||||
while(i < indices.size() &&
|
||||
(type->type == DataType::ArrayType || type->type == DataType::StructType))
|
||||
{
|
||||
if(type->type == DataType::ArrayType)
|
||||
{
|
||||
// look up the array stride
|
||||
const Decorations &dec = decorations[type->id];
|
||||
RDCASSERT(dec.flags & Decorations::HasArrayStride);
|
||||
|
||||
// offset increases by index * arrayStride
|
||||
byteOffset += indices[i] * dec.arrayStride;
|
||||
|
||||
// new type is the inner type
|
||||
type = &dataTypes[type->InnerType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise it's a struct member
|
||||
const DataType::Child &child = type->children[indices[i]];
|
||||
|
||||
// offset increases by member offset
|
||||
RDCASSERT(child.decorations.flags & Decorations::HasOffset);
|
||||
byteOffset += child.decorations.offset;
|
||||
|
||||
// new type is the child type
|
||||
type = &dataTypes[child.type];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
size_t remaining = indices.size() - i;
|
||||
if(remaining == 2)
|
||||
{
|
||||
// pointer to a scalar in a matrix. indices[i] is column, indices[i + 1] is row
|
||||
|
||||
const Decorations &dec = decorations[type->id];
|
||||
RDCASSERT(dec.flags & Decorations::HasMatrixStride);
|
||||
|
||||
// type is the resulting scalar (first inner does matrix->colun type, second does column
|
||||
// type->scalar type)
|
||||
type = &dataTypes[dataTypes[type->InnerType()].InnerType()];
|
||||
|
||||
if(dec.flags & Decorations::RowMajor)
|
||||
{
|
||||
byteOffset += dec.matrixStride * indices[i + 1] + indices[i] * (type->scalar().width / 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteOffset += dec.matrixStride * indices[i] + indices[i + 1] * (type->scalar().width / 8);
|
||||
}
|
||||
}
|
||||
else if(remaining == 1)
|
||||
{
|
||||
if(type->type == DataType::VectorType)
|
||||
{
|
||||
// pointer to a scalar in a vector.
|
||||
|
||||
// type is the resulting scalar (first inner does matrix->colun type, second does column
|
||||
// type->scalar type)
|
||||
type = &dataTypes[dataTypes[type->InnerType()].InnerType()];
|
||||
|
||||
byteOffset += indices[i] * (type->scalar().width / 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// pointer to a column in a matrix
|
||||
|
||||
const Decorations &dec = decorations[type->id];
|
||||
RDCASSERT(dec.flags & Decorations::HasMatrixStride);
|
||||
|
||||
// type is the resulting vector
|
||||
type = &dataTypes[type->InnerType()];
|
||||
|
||||
if(dec.flags & Decorations::RowMajor)
|
||||
{
|
||||
// TODO need to store dec.matrixStride as the stride between elements for this pointer
|
||||
// when reading
|
||||
byteOffset += indices[i] * (type->scalar().width / 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteOffset += dec.matrixStride * indices[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret.value.u64v[BufferPointerTypeIdVariableSlot] = type->id.value();
|
||||
ret.value.u64v[BufferPointerByteOffsetVariableSlot] = byteOffset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// first walk any struct member/array indices
|
||||
size_t i = 0;
|
||||
while(!leaf->members.empty())
|
||||
while(i < indices.size() && !leaf->members.empty())
|
||||
{
|
||||
RDCASSERT(i < indices.size(), i, indices.size());
|
||||
leaf = &leaf->members[indices[i++]];
|
||||
}
|
||||
|
||||
@@ -934,13 +1082,94 @@ ShaderVariable Debugger::MakeCompositePointer(const ShaderVariable &base, Id id,
|
||||
return MakePointerVariable(id, leaf, scalar0, scalar1);
|
||||
}
|
||||
|
||||
ShaderVariable Debugger::EvaluatePointerVariable(const ShaderVariable &ptr) const
|
||||
ShaderVariable Debugger::GetPointerValue(const ShaderVariable &ptr) const
|
||||
{
|
||||
// opaque pointers display as their inner value
|
||||
if(IsOpaquePointer(ptr))
|
||||
{
|
||||
const ShaderVariable *inner = (const ShaderVariable *)(uintptr_t)ptr.value.u64v[0];
|
||||
ShaderVariable ret = *inner;
|
||||
ret.name = ptr.name;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// every other kind of pointer displays as its contents
|
||||
return ReadFromPointer(ptr);
|
||||
}
|
||||
|
||||
ShaderVariable Debugger::ReadFromPointer(const ShaderVariable &ptr) const
|
||||
{
|
||||
if(ptr.type != VarType::GPUPointer)
|
||||
return ptr;
|
||||
|
||||
const ShaderVariable *inner = (const ShaderVariable *)(uintptr_t)ptr.value.u64v[0];
|
||||
|
||||
ShaderVariable ret;
|
||||
ret = *(const ShaderVariable *)(uintptr_t)ptr.value.u64v[0];
|
||||
|
||||
if(inner->type == VarType::ReadWriteResource)
|
||||
{
|
||||
rdcspv::Id typeId =
|
||||
rdcspv::Id::fromWord(uint32_t(ptr.value.u64v[BufferPointerTypeIdVariableSlot]));
|
||||
uint64_t byteOffset = ptr.value.u64v[BufferPointerByteOffsetVariableSlot];
|
||||
|
||||
BindpointIndex bind = inner->GetBinding();
|
||||
|
||||
WalkVariable(dataTypes[typeId], byteOffset, ret, true, [this, bind](ShaderVariable &var,
|
||||
const DataType &type,
|
||||
uint64_t offset) {
|
||||
if(type.type == DataType::MatrixType)
|
||||
{
|
||||
const Decorations &dec = decorations[type.id];
|
||||
RDCASSERT(dec.flags & Decorations::HasMatrixStride);
|
||||
|
||||
if(dec.flags & Decorations::RowMajor)
|
||||
{
|
||||
for(uint8_t r = 0; r < var.rows; r++)
|
||||
{
|
||||
apiWrapper->ReadBufferValue(bind, offset + r * dec.matrixStride,
|
||||
VarTypeByteSize(var.type) * var.columns,
|
||||
&var.value.uv[r * var.columns]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShaderValue tmp = {};
|
||||
// read column-wise
|
||||
for(uint8_t c = 0; c < var.columns; c++)
|
||||
{
|
||||
apiWrapper->ReadBufferValue(bind, offset + c * dec.matrixStride,
|
||||
VarTypeByteSize(var.type) * var.rows, &tmp.uv[c * var.rows]);
|
||||
}
|
||||
|
||||
// transpose into our row major storage
|
||||
for(uint8_t r = 0; r < var.rows; r++)
|
||||
{
|
||||
for(uint8_t c = 0; c < var.columns; c++)
|
||||
{
|
||||
if(VarTypeByteSize(var.type) == 8)
|
||||
var.value.u64v[r * var.columns + c] = tmp.u64v[c * var.rows + r];
|
||||
else
|
||||
var.value.uv[r * var.columns + c] = tmp.uv[c * var.rows + r];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(type.type == DataType::VectorType)
|
||||
{
|
||||
apiWrapper->ReadBufferValue(bind, offset, VarTypeByteSize(var.type) * var.columns,
|
||||
var.value.uv);
|
||||
}
|
||||
else if(type.type == DataType::ScalarType)
|
||||
{
|
||||
apiWrapper->ReadBufferValue(bind, offset, VarTypeByteSize(var.type), var.value.uv);
|
||||
}
|
||||
});
|
||||
|
||||
ret.name = ptr.name;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = *inner;
|
||||
ret.name = ptr.name;
|
||||
|
||||
// we don't support pointers to scalars since our 'unit' of pointer is a ShaderVariable, so check
|
||||
@@ -1010,10 +1239,85 @@ Id Debugger::GetPointerBaseId(const ShaderVariable &ptr) const
|
||||
return Id::fromWord(ptr.value.uv[4]);
|
||||
}
|
||||
|
||||
bool Debugger::IsOpaquePointer(const ShaderVariable &ptr) const
|
||||
{
|
||||
if(ptr.type != VarType::GPUPointer)
|
||||
return false;
|
||||
|
||||
ShaderVariable *inner = (ShaderVariable *)(uintptr_t)ptr.value.u64v[0];
|
||||
return inner->type == VarType::ReadOnlyResource || inner->type == VarType::ReadWriteResource;
|
||||
}
|
||||
|
||||
void Debugger::WriteThroughPointer(const ShaderVariable &ptr, const ShaderVariable &val)
|
||||
{
|
||||
ShaderVariable *storage = (ShaderVariable *)(uintptr_t)ptr.value.u64v[0];
|
||||
|
||||
if(storage->type == VarType::ReadWriteResource)
|
||||
{
|
||||
rdcspv::Id typeId =
|
||||
rdcspv::Id::fromWord(uint32_t(ptr.value.u64v[BufferPointerTypeIdVariableSlot]));
|
||||
uint64_t byteOffset = ptr.value.u64v[BufferPointerByteOffsetVariableSlot];
|
||||
|
||||
const DataType &type = dataTypes[typeId];
|
||||
|
||||
BindpointIndex bind = storage->GetBinding();
|
||||
|
||||
WalkVariable(dataTypes[typeId], byteOffset, (ShaderVariable &)val, false,
|
||||
[this, bind](ShaderVariable &var, const DataType &type, uint64_t offset) {
|
||||
if(type.type == DataType::MatrixType)
|
||||
{
|
||||
const Decorations &dec = decorations[type.id];
|
||||
RDCASSERT(dec.flags & Decorations::HasMatrixStride);
|
||||
|
||||
if(dec.flags & Decorations::RowMajor)
|
||||
{
|
||||
for(uint8_t r = 0; r < var.rows; r++)
|
||||
{
|
||||
apiWrapper->WriteBufferValue(bind, offset + r * dec.matrixStride,
|
||||
VarTypeByteSize(var.type) * var.columns,
|
||||
&var.value.uv[r * var.columns]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShaderValue tmp = {};
|
||||
|
||||
// transpose from our row major storage
|
||||
for(uint8_t r = 0; r < var.rows; r++)
|
||||
{
|
||||
for(uint8_t c = 0; c < var.columns; c++)
|
||||
{
|
||||
if(VarTypeByteSize(var.type) == 8)
|
||||
tmp.u64v[c * var.rows + r] = var.value.u64v[r * var.columns + c];
|
||||
else
|
||||
tmp.uv[c * var.rows + r] = var.value.uv[r * var.columns + c];
|
||||
}
|
||||
}
|
||||
|
||||
// read column-wise
|
||||
for(uint8_t c = 0; c < var.columns; c++)
|
||||
{
|
||||
apiWrapper->WriteBufferValue(bind, offset + c * dec.matrixStride,
|
||||
VarTypeByteSize(var.type) * var.rows,
|
||||
&tmp.uv[c * var.rows]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(type.type == DataType::VectorType)
|
||||
{
|
||||
apiWrapper->WriteBufferValue(
|
||||
bind, offset, VarTypeByteSize(var.type) * var.columns, var.value.uv);
|
||||
}
|
||||
else if(type.type == DataType::ScalarType)
|
||||
{
|
||||
apiWrapper->WriteBufferValue(bind, offset, VarTypeByteSize(var.type),
|
||||
var.value.uv);
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we don't support pointers to scalars since our 'unit' of pointer is a ShaderVariable, so check
|
||||
// if we have scalar indices to apply:
|
||||
uint32_t scalar0 = ptr.value.uv[2];
|
||||
@@ -1370,16 +1674,17 @@ uint32_t Debugger::AllocateVariable(const Decorations &varDecorations,
|
||||
}
|
||||
else if(sourceVarType == DebugVariableType::Constant)
|
||||
{
|
||||
uint32_t set = 0, bind = 0;
|
||||
BindpointIndex bindpoint;
|
||||
// TODO handle arrays
|
||||
if(varDecorations.flags & Decorations::HasDescriptorSet)
|
||||
set = varDecorations.set;
|
||||
bindpoint.bindset = (int32_t)varDecorations.set;
|
||||
if(varDecorations.flags & Decorations::HasBinding)
|
||||
bind = varDecorations.binding;
|
||||
bindpoint.bind = (int32_t)varDecorations.binding;
|
||||
|
||||
// non-matrix case is simple, just read the size of the variable
|
||||
if(sourceVar.rows == 1)
|
||||
{
|
||||
apiWrapper->ReadConstantBufferValue(set, bind, offset, VarByteSize(outVar), outVar.value.uv);
|
||||
apiWrapper->ReadBufferValue(bindpoint, offset, VarByteSize(outVar), outVar.value.uv);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1401,8 +1706,7 @@ uint32_t Debugger::AllocateVariable(const Decorations &varDecorations,
|
||||
for(uint32_t c = 0; c < sourceVar.columns; c++)
|
||||
{
|
||||
// read the column
|
||||
apiWrapper->ReadConstantBufferValue(set, bind, offset + c * matrixStride, colSize,
|
||||
&tmp.uv[0]);
|
||||
apiWrapper->ReadBufferValue(bindpoint, offset + c * matrixStride, colSize, &tmp.uv[0]);
|
||||
|
||||
// now write it into the appropiate elements in the destination ShaderValue
|
||||
for(uint32_t r = 0; r < sourceVar.rows; r++)
|
||||
@@ -1416,8 +1720,8 @@ uint32_t Debugger::AllocateVariable(const Decorations &varDecorations,
|
||||
for(uint32_t r = 0; r < sourceVar.rows; r++)
|
||||
{
|
||||
// read the column into the destination ShaderValue, which is tightly packed with rows
|
||||
apiWrapper->ReadConstantBufferValue(set, bind, offset + r * matrixStride, rowSize,
|
||||
&outVar.value.uv[r * sourceVar.columns]);
|
||||
apiWrapper->ReadBufferValue(bindpoint, offset + r * matrixStride, rowSize,
|
||||
&outVar.value.uv[r * sourceVar.columns]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1427,6 +1731,90 @@ uint32_t Debugger::AllocateVariable(const Decorations &varDecorations,
|
||||
return outVar.rows;
|
||||
}
|
||||
|
||||
void Debugger::WalkVariable(
|
||||
const DataType &type, uint64_t byteOffset, ShaderVariable &var, bool initialise,
|
||||
std::function<void(ShaderVariable &, const DataType &, uint64_t)> callback) const
|
||||
{
|
||||
switch(type.type)
|
||||
{
|
||||
case DataType::ScalarType:
|
||||
{
|
||||
if(initialise)
|
||||
{
|
||||
var.type = type.scalar().Type();
|
||||
var.rows = 1;
|
||||
var.columns = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataType::VectorType:
|
||||
{
|
||||
if(initialise)
|
||||
{
|
||||
var.type = type.scalar().Type();
|
||||
var.rows = 1;
|
||||
var.columns = RDCMAX(1U, type.vector().count);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataType::MatrixType:
|
||||
{
|
||||
if(initialise)
|
||||
{
|
||||
var.type = type.scalar().Type();
|
||||
var.columns = RDCMAX(1U, type.matrix().count);
|
||||
var.rows = RDCMAX(1U, type.vector().count);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataType::StructType:
|
||||
{
|
||||
for(int32_t i = 0; i < type.children.count(); i++)
|
||||
{
|
||||
if(initialise)
|
||||
{
|
||||
var.members.push_back(ShaderVariable());
|
||||
var.members.back().name = StringFormat::Fmt("_child%d", i);
|
||||
}
|
||||
|
||||
WalkVariable(dataTypes[type.children[i].type],
|
||||
byteOffset + type.children[i].decorations.offset, var.members.back(),
|
||||
initialise, callback);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case DataType::ArrayType:
|
||||
{
|
||||
ShaderVariable len = GetActiveLane().ids[type.length];
|
||||
for(uint32_t i = 0; i < len.value.u.x; i++)
|
||||
{
|
||||
if(initialise)
|
||||
{
|
||||
var.members.push_back(ShaderVariable());
|
||||
var.members.back().name = StringFormat::Fmt("[%u]", i);
|
||||
}
|
||||
|
||||
WalkVariable(dataTypes[type.InnerType()], byteOffset, var.members.back(), initialise,
|
||||
callback);
|
||||
|
||||
byteOffset += decorations[type.id].arrayStride;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case DataType::PointerType:
|
||||
case DataType::ImageType:
|
||||
case DataType::SamplerType:
|
||||
case DataType::SampledImageType:
|
||||
case DataType::UnknownType:
|
||||
{
|
||||
RDCERR("Unexpected variable type %d", type.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback(var, type, byteOffset);
|
||||
}
|
||||
|
||||
uint32_t Debugger::ApplyDerivatives(uint32_t quadIndex, const Decorations &curDecorations,
|
||||
uint32_t location, const DataType &inType, ShaderVariable &outVar)
|
||||
{
|
||||
|
||||
@@ -143,11 +143,15 @@ class VulkanAPIWrapper : public rdcspv::DebugAPIWrapper
|
||||
rdcarray<DescSetSnapshot> m_DescSets;
|
||||
|
||||
public:
|
||||
VulkanAPIWrapper(WrappedVulkan *vk, VulkanCreationInfo &creation, VkShaderStageFlagBits stage)
|
||||
: m_DebugData(vk->GetReplay()->GetShaderDebugData()), m_Creation(creation)
|
||||
VulkanAPIWrapper(WrappedVulkan *vk, VulkanCreationInfo &creation, VkShaderStageFlagBits stage,
|
||||
uint32_t eid)
|
||||
: m_DebugData(vk->GetReplay()->GetShaderDebugData()), m_Creation(creation), m_EventID(eid)
|
||||
{
|
||||
m_pDriver = vk;
|
||||
|
||||
// when we're first setting up, the state is pristine and no replay is needed
|
||||
m_ResourcesDirty = false;
|
||||
|
||||
const VulkanRenderState &state = m_pDriver->GetRenderState();
|
||||
|
||||
const bool compute = (stage == VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
@@ -277,40 +281,52 @@ public:
|
||||
m_pDriver->vkDestroySampler(dev, it->second, NULL);
|
||||
}
|
||||
|
||||
void ResetReplay()
|
||||
{
|
||||
// replay the draw to get back to 'normal' state for this event, and mark that we need to replay
|
||||
// back to pristine state next time we need to fetch data.
|
||||
m_pDriver->ReplayLog(0, m_EventID, eReplay_OnlyDraw);
|
||||
m_ResourcesDirty = true;
|
||||
}
|
||||
|
||||
virtual void AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src,
|
||||
rdcstr d) override
|
||||
{
|
||||
m_pDriver->AddDebugMessage(c, sv, src, d);
|
||||
}
|
||||
|
||||
virtual void ReadConstantBufferValue(uint32_t set, uint32_t bind, uint32_t offset,
|
||||
uint32_t byteSize, void *dst) override
|
||||
virtual uint64_t GetBufferLength(BindpointIndex bind) override
|
||||
{
|
||||
rdcpair<uint32_t, uint32_t> key = make_rdcpair(set, bind);
|
||||
auto insertIt = cbufferCache.insert(std::make_pair(key, bytebuf()));
|
||||
bytebuf &data = insertIt.first->second;
|
||||
if(insertIt.second)
|
||||
bool valid = true;
|
||||
const VkDescriptorBufferInfo &bufData =
|
||||
GetDescriptor<VkDescriptorBufferInfo>("reading buffer length", bind, valid);
|
||||
if(valid)
|
||||
{
|
||||
if(set == PushConstantBindSet)
|
||||
{
|
||||
data = pushData;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO handle arrays here
|
||||
BindpointIndex index(set, bind, 0);
|
||||
if(bufData.range != VK_WHOLE_SIZE)
|
||||
return bufData.range;
|
||||
|
||||
bool valid = true;
|
||||
const VkDescriptorBufferInfo &bufData =
|
||||
GetDescriptor<VkDescriptorBufferInfo>("reading constant buffer value", index, valid);
|
||||
if(valid)
|
||||
m_pDriver->GetDebugManager()->GetBufferData(GetResID(bufData.buffer), bufData.offset,
|
||||
bufData.range, data);
|
||||
}
|
||||
return m_Creation.m_Buffer[GetResID(bufData.buffer)].size - bufData.offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void ReadBufferValue(BindpointIndex bind, uint64_t offset, uint64_t byteSize,
|
||||
void *dst) override
|
||||
{
|
||||
const bytebuf &data = PopulateBuffer(bind);
|
||||
|
||||
if(offset + byteSize <= data.size())
|
||||
memcpy(dst, data.data() + offset, byteSize);
|
||||
memcpy(dst, data.data() + (size_t)offset, (size_t)byteSize);
|
||||
}
|
||||
|
||||
virtual void WriteBufferValue(BindpointIndex bind, uint64_t offset, uint64_t byteSize,
|
||||
const void *src) override
|
||||
{
|
||||
bytebuf &data = PopulateBuffer(bind);
|
||||
|
||||
if(offset + byteSize <= data.size())
|
||||
memcpy(data.data() + (size_t)offset, src, (size_t)byteSize);
|
||||
}
|
||||
|
||||
virtual void FillInputValue(ShaderVariable &var, ShaderBuiltin builtin, uint32_t location,
|
||||
@@ -1014,6 +1030,9 @@ private:
|
||||
ShaderDebugData &m_DebugData;
|
||||
VulkanCreationInfo &m_Creation;
|
||||
|
||||
bool m_ResourcesDirty = false;
|
||||
uint32_t m_EventID;
|
||||
|
||||
std::map<ResourceId, VkImageView> m_SampleViews;
|
||||
|
||||
typedef rdcpair<ResourceId, float> SamplerBiasKey;
|
||||
@@ -1021,7 +1040,7 @@ private:
|
||||
|
||||
bytebuf pushData;
|
||||
|
||||
std::map<rdcpair<uint32_t, uint32_t>, bytebuf> cbufferCache;
|
||||
std::map<BindpointIndex, bytebuf> bufferCache;
|
||||
template <typename T>
|
||||
const T &GetDescriptor(const rdcstr &access, BindpointIndex index, bool &valid)
|
||||
{
|
||||
@@ -1086,6 +1105,40 @@ private:
|
||||
return elemData[index.arrayIndex];
|
||||
}
|
||||
|
||||
bytebuf &PopulateBuffer(BindpointIndex bind)
|
||||
{
|
||||
auto insertIt = bufferCache.insert(std::make_pair(bind, bytebuf()));
|
||||
bytebuf &data = insertIt.first->second;
|
||||
if(insertIt.second)
|
||||
{
|
||||
if(bind.bindset == PushConstantBindSet)
|
||||
{
|
||||
data = pushData;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool valid = true;
|
||||
const VkDescriptorBufferInfo &bufData =
|
||||
GetDescriptor<VkDescriptorBufferInfo>("accessing buffer value", bind, valid);
|
||||
if(valid)
|
||||
{
|
||||
// if the resources might be dirty from side-effects from the draw, replay back to right
|
||||
// before it.
|
||||
if(m_ResourcesDirty)
|
||||
{
|
||||
m_pDriver->ReplayLog(0, m_EventID, eReplay_WithoutDraw);
|
||||
m_ResourcesDirty = false;
|
||||
}
|
||||
|
||||
m_pDriver->GetDebugManager()->GetBufferData(GetResID(bufData.buffer), bufData.offset,
|
||||
bufData.range, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
VkPipeline MakePipe(const ShaderConstParameters ¶ms, bool uintTex, bool sintTex)
|
||||
{
|
||||
VkSpecializationMapEntry specMaps[sizeof(params) / sizeof(uint32_t)];
|
||||
@@ -2884,6 +2937,9 @@ ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, u
|
||||
if(!(draw->flags & DrawFlags::Drawcall))
|
||||
return new ShaderDebugTrace();
|
||||
|
||||
// get ourselves in pristine state before this draw (without any side effects it may have had)
|
||||
m_pDriver->ReplayLog(0, eventId, eReplay_WithoutDraw);
|
||||
|
||||
const VulkanCreationInfo::Pipeline &pipe = c.m_Pipeline[state.graphics.pipeline];
|
||||
VulkanCreationInfo::ShaderModule &shader = c.m_ShaderModule[pipe.shaders[0].module];
|
||||
rdcstr entryPoint = pipe.shaders[0].entryPoint;
|
||||
@@ -2894,7 +2950,8 @@ ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, u
|
||||
|
||||
shadRefl.PopulateDisassembly(shader.spirv);
|
||||
|
||||
VulkanAPIWrapper *apiWrapper = new VulkanAPIWrapper(m_pDriver, c, VK_SHADER_STAGE_VERTEX_BIT);
|
||||
VulkanAPIWrapper *apiWrapper =
|
||||
new VulkanAPIWrapper(m_pDriver, c, VK_SHADER_STAGE_VERTEX_BIT, eventId);
|
||||
|
||||
std::map<ShaderBuiltin, ShaderVariable> &builtins = apiWrapper->builtin_inputs;
|
||||
builtins[ShaderBuiltin::BaseInstance] = ShaderVariable(rdcstr(), draw->instanceOffset, 0U, 0U, 0U);
|
||||
@@ -2994,6 +3051,7 @@ ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, u
|
||||
debugger->Parse(shader.spirv.GetSPIRV());
|
||||
ShaderDebugTrace *ret = debugger->BeginDebug(apiWrapper, ShaderStage::Vertex, entryPoint, spec,
|
||||
shadRefl.instructionLines, shadRefl.patchData, 0);
|
||||
apiWrapper->ResetReplay();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -3032,6 +3090,9 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_
|
||||
if(!(draw->flags & DrawFlags::Drawcall))
|
||||
return new ShaderDebugTrace();
|
||||
|
||||
// get ourselves in pristine state before this draw (without any side effects it may have had)
|
||||
m_pDriver->ReplayLog(0, eventId, eReplay_WithoutDraw);
|
||||
|
||||
const VulkanCreationInfo::Pipeline &pipe = c.m_Pipeline[state.graphics.pipeline];
|
||||
VulkanCreationInfo::ShaderModule &shader = c.m_ShaderModule[pipe.shaders[4].module];
|
||||
rdcstr entryPoint = pipe.shaders[4].entryPoint;
|
||||
@@ -3042,7 +3103,8 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_
|
||||
|
||||
shadRefl.PopulateDisassembly(shader.spirv);
|
||||
|
||||
VulkanAPIWrapper *apiWrapper = new VulkanAPIWrapper(m_pDriver, c, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
VulkanAPIWrapper *apiWrapper =
|
||||
new VulkanAPIWrapper(m_pDriver, c, VK_SHADER_STAGE_FRAGMENT_BIT, eventId);
|
||||
|
||||
std::map<ShaderBuiltin, ShaderVariable> &builtins = apiWrapper->builtin_inputs;
|
||||
builtins[ShaderBuiltin::DeviceIndex] = ShaderVariable(rdcstr(), 0U, 0U, 0U, 0U);
|
||||
@@ -3594,6 +3656,7 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_
|
||||
|
||||
ret = debugger->BeginDebug(apiWrapper, ShaderStage::Pixel, entryPoint, spec,
|
||||
shadRefl.instructionLines, shadRefl.patchData, destIdx);
|
||||
apiWrapper->ResetReplay();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3654,6 +3717,9 @@ ShaderDebugTrace *VulkanReplay::DebugThread(uint32_t eventId, const uint32_t gro
|
||||
if(!(draw->flags & DrawFlags::Dispatch))
|
||||
return new ShaderDebugTrace();
|
||||
|
||||
// get ourselves in pristine state before this dispatch (without any side effects it may have had)
|
||||
m_pDriver->ReplayLog(0, eventId, eReplay_WithoutDraw);
|
||||
|
||||
const VulkanCreationInfo::Pipeline &pipe = c.m_Pipeline[state.compute.pipeline];
|
||||
VulkanCreationInfo::ShaderModule &shader = c.m_ShaderModule[pipe.shaders[5].module];
|
||||
rdcstr entryPoint = pipe.shaders[5].entryPoint;
|
||||
@@ -3664,7 +3730,8 @@ ShaderDebugTrace *VulkanReplay::DebugThread(uint32_t eventId, const uint32_t gro
|
||||
|
||||
shadRefl.PopulateDisassembly(shader.spirv);
|
||||
|
||||
VulkanAPIWrapper *apiWrapper = new VulkanAPIWrapper(m_pDriver, c, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
VulkanAPIWrapper *apiWrapper =
|
||||
new VulkanAPIWrapper(m_pDriver, c, VK_SHADER_STAGE_COMPUTE_BIT, eventId);
|
||||
|
||||
uint32_t threadDim[3];
|
||||
threadDim[0] = shadRefl.refl.dispatchThreadsDimension[0];
|
||||
@@ -3693,6 +3760,7 @@ ShaderDebugTrace *VulkanReplay::DebugThread(uint32_t eventId, const uint32_t gro
|
||||
debugger->Parse(shader.spirv.GetSPIRV());
|
||||
ShaderDebugTrace *ret = debugger->BeginDebug(apiWrapper, ShaderStage::Compute, entryPoint, spec,
|
||||
shadRefl.instructionLines, shadRefl.patchData, 0);
|
||||
apiWrapper->ResetReplay();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -3706,5 +3774,10 @@ rdcarray<ShaderDebugState> VulkanReplay::ContinueDebug(ShaderDebugger *debugger)
|
||||
|
||||
VkMarkerRegion region("ContinueDebug Simulation Loop");
|
||||
|
||||
return spvDebugger->ContinueDebug();
|
||||
rdcarray<ShaderDebugState> ret = spvDebugger->ContinueDebug();
|
||||
|
||||
VulkanAPIWrapper *api = (VulkanAPIWrapper *)spvDebugger->GetAPIWrapper();
|
||||
api->ResetReplay();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ void main()
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
std::string pixel_glsl = R"EOSHADER(
|
||||
std::string pixel_glsl_header = R"EOSHADER(
|
||||
#version 460 core
|
||||
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
@@ -128,14 +128,18 @@ layout(set = 0, binding = 3) uniform texture2D sampledImage;
|
||||
|
||||
layout(set = 0, binding = 4) uniform sampler2D linearSampledImage;
|
||||
|
||||
/*
|
||||
struct dummy
|
||||
{
|
||||
uvec4 val;
|
||||
uvec4 val2;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 5, std430) buffer storebuftype
|
||||
{
|
||||
vec4 x;
|
||||
uvec4 y;
|
||||
dummy y;
|
||||
vec4 arr[];
|
||||
} storebuf;
|
||||
*/
|
||||
|
||||
//layout(set = 0, binding = 6, rgba32f) uniform coherent image2D storeImage;
|
||||
|
||||
@@ -151,12 +155,15 @@ layout(push_constant) uniform PushData {
|
||||
layout(offset = 16) ivec4 data;
|
||||
} push;
|
||||
|
||||
layout(location = 0, index = 0) out vec4 Color;
|
||||
|
||||
#define inout_type in
|
||||
|
||||
)EOSHADER" + v2f + R"EOSHADER(
|
||||
|
||||
layout(location = 0, index = 0) out vec4 Color;
|
||||
)EOSHADER";
|
||||
|
||||
std::string pixel_glsl1 = pixel_glsl_header + R"EOSHADER(
|
||||
void main()
|
||||
{
|
||||
float posinf = linearData.oneVal/linearData.zeroVal.x;
|
||||
@@ -492,7 +499,7 @@ void main()
|
||||
break;
|
||||
}
|
||||
)EOSHADER"
|
||||
R"EOSHADER(
|
||||
R"EOSHADER(
|
||||
case 51:
|
||||
{
|
||||
Color = fwidthFine(vec4(inpos, inposIncreased));
|
||||
@@ -859,7 +866,7 @@ void main()
|
||||
break;
|
||||
}
|
||||
)EOSHADER"
|
||||
R"EOSHADER(
|
||||
R"EOSHADER(
|
||||
case 102:
|
||||
{
|
||||
uint a = zerou + 0x0dadbeef;
|
||||
@@ -1046,6 +1053,54 @@ void main()
|
||||
Color = unpacked;
|
||||
break;
|
||||
}
|
||||
case 127:
|
||||
{
|
||||
uint len = storebuf.arr.length();
|
||||
Color = vec4(float(len), float(len), float(len), float(len));
|
||||
break;
|
||||
}
|
||||
case 128:
|
||||
{
|
||||
// test storage buffer write here, we'll read from it in GLSL test 2
|
||||
storebuf.x = vec4(3.1f, 4.1f, 5.9f, 2.6f);
|
||||
storebuf.y.val = uvec4(31, 41, 59, 26);
|
||||
storebuf.arr[flatData.intval - flatData.test] = vec4(inpos, inposIncreased);
|
||||
|
||||
Color = storebuf.x;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
std::string pixel_glsl2 = pixel_glsl_header + R"EOSHADER(
|
||||
void main()
|
||||
{
|
||||
uint test = flatData.test;
|
||||
|
||||
Color = vec4(0,0,0,0);
|
||||
switch(test)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// test loading from the storage buffer (after a nice big barrier)
|
||||
Color = storebuf.x;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
// test loading from the storage buffer (after a nice big barrier)
|
||||
Color = vec4(storebuf.y.val);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// test loading from the storage buffer (after a nice big barrier)
|
||||
Color = storebuf.arr[flatData.intval - flatData.test];
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -1689,10 +1744,26 @@ void main()
|
||||
"OpCopyMemory %Color %gl_FragCoord\n"
|
||||
"; no_out\n",
|
||||
|
||||
"%_src = OpAccessChain %ptr_Uniform_float4 %buffer %uint_0\n"
|
||||
"%_dst = OpAccessChain %ptr_Uniform_float4 %buffer %uint_2 %uint_3\n"
|
||||
"OpCopyMemory %_dst %_src\n"
|
||||
"OpCopyMemory %Color %_src\n"
|
||||
"; no_out\n",
|
||||
|
||||
"%frag = OpLoad %float4 %gl_FragCoord\n"
|
||||
"%_out_float4 = OpCopyObject %float4 %frag\n",
|
||||
});
|
||||
|
||||
// test SSBO pointers
|
||||
append_tests({
|
||||
"%_y = OpAccessChain %ptr_Uniform_dummy %buffer %uint_1\n"
|
||||
"%_src = OpAccessChain %ptr_Uniform_uint4 %_y %uint_0\n"
|
||||
"%_dst = OpAccessChain %ptr_Uniform_uint4 %_y %uint_1\n"
|
||||
"%_tmp = OpLoad %uint4 %_src\n"
|
||||
"OpStore %_dst %_tmp\n"
|
||||
"%_out_uint4 = OpLoad %uint4 %_dst\n",
|
||||
});
|
||||
|
||||
// disabled while shaderc has a bug that doesn't respect the target environment
|
||||
/*
|
||||
if(vk_version >= 0x12)
|
||||
@@ -1959,6 +2030,16 @@ void main()
|
||||
OpDecorate %Color Index 0
|
||||
OpDecorate %Color Location 0
|
||||
OpDecorate %gl_FragCoord BuiltIn FragCoord
|
||||
|
||||
OpDecorate %rtarray_float4 ArrayStride 16
|
||||
OpMemberDecorate %dummy 0 Offset 0
|
||||
OpMemberDecorate %dummy 1 Offset 16
|
||||
OpMemberDecorate %buftype 0 Offset 0
|
||||
OpMemberDecorate %buftype 1 Offset 16
|
||||
OpMemberDecorate %buftype 2 Offset 48
|
||||
OpDecorate %buftype BufferBlock
|
||||
OpDecorate %buffer DescriptorSet 0
|
||||
OpDecorate %buffer Binding 5
|
||||
)EOSHADER";
|
||||
|
||||
std::string typesConstants = R"EOSHADER(
|
||||
@@ -1988,6 +2069,8 @@ void main()
|
||||
|
||||
%mainfunc = OpTypeFunction %void
|
||||
|
||||
%rtarray_float4 = OpTypeRuntimeArray %float4
|
||||
|
||||
%v2f = OpTypeStruct %float2 %float2 %float2 %float %float %float
|
||||
%flatv2f = OpTypeStruct %uint %uint
|
||||
|
||||
@@ -1997,6 +2080,9 @@ void main()
|
||||
%f32f32 = OpTypeStruct %float %float
|
||||
%f32i32 = OpTypeStruct %float %int
|
||||
|
||||
%dummy = OpTypeStruct %uint4 %uint4
|
||||
%buftype = OpTypeStruct %float4 %dummy %rtarray_float4
|
||||
|
||||
%ptr_Input_v2f = OpTypePointer Input %v2f
|
||||
%ptr_Input_flatv2f = OpTypePointer Input %flatv2f
|
||||
%ptr_Input_uint = OpTypePointer Input %uint
|
||||
@@ -2023,6 +2109,9 @@ void main()
|
||||
%ptr_Uniform_int3 = OpTypePointer Uniform %int3
|
||||
%ptr_Uniform_int4 = OpTypePointer Uniform %int4
|
||||
|
||||
%ptr_Uniform_dummy = OpTypePointer Uniform %dummy
|
||||
%ptr_Uniform_buftype = OpTypePointer Uniform %buftype
|
||||
|
||||
%linearData = OpVariable %ptr_Input_v2f Input
|
||||
%flatData = OpVariable %ptr_Input_flatv2f Input
|
||||
%gl_FragCoord = OpVariable %ptr_Input_float4 Input
|
||||
@@ -2031,6 +2120,8 @@ void main()
|
||||
%priv_int = OpVariable %ptr_Private_int Private
|
||||
%priv_float = OpVariable %ptr_Private_float Private
|
||||
|
||||
%buffer = OpVariable %ptr_Uniform_buftype Uniform
|
||||
|
||||
%flatv2f_test_idx = OpConstant %int 0
|
||||
%flatv2f_intval_idx = OpConstant %int 1
|
||||
|
||||
@@ -2264,6 +2355,9 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
{
|
||||
optDevExts.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME);
|
||||
|
||||
// we require this to pixel shader debug anyway, so we might as well require it for all tests.
|
||||
features.fragmentStoresAndAtomics = VK_TRUE;
|
||||
|
||||
VulkanGraphicsTest::Prepare(argc, argv);
|
||||
|
||||
vk_version = 0x10;
|
||||
@@ -2291,10 +2385,15 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
|
||||
make_asm_tests();
|
||||
|
||||
size_t lastTest = pixel_glsl.rfind("case ");
|
||||
size_t lastTest = pixel_glsl1.rfind("case ");
|
||||
lastTest += sizeof("case ") - 1;
|
||||
|
||||
const uint32_t numGLSLTests = atoi(pixel_glsl.c_str() + lastTest) + 1;
|
||||
const uint32_t numGLSL1Tests = atoi(pixel_glsl1.c_str() + lastTest) + 1;
|
||||
|
||||
lastTest = pixel_glsl2.rfind("case ");
|
||||
lastTest += sizeof("case ") - 1;
|
||||
|
||||
const uint32_t numGLSL2Tests = atoi(pixel_glsl2.c_str() + lastTest) + 1;
|
||||
|
||||
const uint32_t numASMTests = (uint32_t)asm_tests.size();
|
||||
|
||||
@@ -2317,7 +2416,7 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
{setlayout}, {vkh::PushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 16, sizeof(Vec4i))}));
|
||||
|
||||
// calculate number of tests, wrapping each row at 256
|
||||
uint32_t texWidth = AlignUp(std::max(numGLSLTests, numASMTests), 256U);
|
||||
uint32_t texWidth = AlignUp(std::max(std::max(numGLSL1Tests, numGLSL2Tests), numASMTests), 256U);
|
||||
uint32_t texHeight = std::max(1U, texWidth / 256U);
|
||||
texWidth /= texHeight;
|
||||
|
||||
@@ -2360,10 +2459,15 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
|
||||
pipeCreateInfo.stages = {
|
||||
CompileShaderModule(vertex, ShaderLang::glsl, ShaderStage::vert, "main"),
|
||||
CompileShaderModule(pixel_glsl, ShaderLang::glsl, ShaderStage::frag, "main"),
|
||||
CompileShaderModule(pixel_glsl1, ShaderLang::glsl, ShaderStage::frag, "main"),
|
||||
};
|
||||
|
||||
VkPipeline glslpipe = createGraphicsPipeline(pipeCreateInfo);
|
||||
VkPipeline glslpipe1 = createGraphicsPipeline(pipeCreateInfo);
|
||||
|
||||
pipeCreateInfo.stages[1] =
|
||||
CompileShaderModule(pixel_glsl2, ShaderLang::glsl, ShaderStage::frag, "main");
|
||||
|
||||
VkPipeline glslpipe2 = createGraphicsPipeline(pipeCreateInfo);
|
||||
|
||||
SPIRVTarget target = SPIRVTarget::vulkan;
|
||||
|
||||
@@ -2639,7 +2743,7 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
vkCmdClearColorImage(cmd, store_image.image, VK_IMAGE_LAYOUT_GENERAL,
|
||||
vkh::ClearColorValue(6.66f, 6.66f, 6.66f, 6.66f), 1,
|
||||
vkh::ImageSubresourceRange());
|
||||
vkCmdFillBuffer(cmd, store_buffer.buffer, 0, VK_WHOLE_SIZE, 0xcccccccc);
|
||||
vkCmdFillBuffer(cmd, store_buffer.buffer, 0, VK_WHOLE_SIZE, 0x42424242);
|
||||
vkCmdFillBuffer(cmd, store_texbuffer.buffer, 0, VK_WHOLE_SIZE, 0);
|
||||
|
||||
vkh::cmdPipelineBarrier(
|
||||
@@ -2666,7 +2770,7 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
s.extent.width = texWidth;
|
||||
s.extent.height = texHeight;
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, glslpipe);
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, glslpipe1);
|
||||
vkCmdSetViewport(cmd, 0, 1, &v);
|
||||
vkCmdSetScissor(cmd, 0, 1, &s);
|
||||
vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0});
|
||||
@@ -2680,8 +2784,8 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
{vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}),
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
pushMarker(cmd, "GLSL tests");
|
||||
uint32_t numTests = numGLSLTests;
|
||||
pushMarker(cmd, "GLSL1 tests");
|
||||
uint32_t numTests = numGLSL1Tests;
|
||||
uint32_t offset = 0;
|
||||
// loop drawing 256 tests at a time
|
||||
while(numTests > 0)
|
||||
@@ -2696,10 +2800,6 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
vkCmdEndRenderPass(cmd);
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, asmpipe);
|
||||
vkCmdSetViewport(cmd, 0, 1, &v);
|
||||
|
||||
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, {descset}, {});
|
||||
vkCmdPushConstants(cmd, layout, VK_SHADER_STAGE_FRAGMENT_BIT, 16, sizeof(Vec4i), &push);
|
||||
|
||||
vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, s,
|
||||
{vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}),
|
||||
@@ -2720,6 +2820,45 @@ OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource
|
||||
|
||||
vkCmdEndRenderPass(cmd);
|
||||
|
||||
// sync all the storage work
|
||||
vkh::cmdPipelineBarrier(
|
||||
cmd,
|
||||
{
|
||||
vkh::ImageMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL,
|
||||
store_image.image),
|
||||
},
|
||||
{
|
||||
vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
store_buffer.buffer),
|
||||
vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
store_texbuffer.buffer),
|
||||
});
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, glslpipe2);
|
||||
|
||||
vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, s,
|
||||
{vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}),
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
pushMarker(cmd, "GLSL2 tests");
|
||||
numTests = numGLSL2Tests;
|
||||
offset = 0;
|
||||
// loop drawing 256 tests at a time
|
||||
while(numTests > 0)
|
||||
{
|
||||
uint32_t num = std::min(numTests, 256U);
|
||||
vkCmdDraw(cmd, 3, num, 0, offset);
|
||||
offset += num;
|
||||
numTests -= num;
|
||||
}
|
||||
popMarker(cmd);
|
||||
|
||||
vkCmdEndRenderPass(cmd);
|
||||
|
||||
FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
|
||||
|
||||
vkEndCommandBuffer(cmd);
|
||||
|
||||
@@ -13,87 +13,45 @@ class VK_Shader_Debug_Zoo(rdtest.TestCase):
|
||||
|
||||
failed = False
|
||||
|
||||
rdtest.log.begin_section("GLSL tests")
|
||||
draw = self.find_draw("GLSL tests")
|
||||
for child in range(len(draw.children)):
|
||||
section = draw.children[child]
|
||||
self.controller.SetFrameEvent(section.eventId, False)
|
||||
pipe: rd.PipeState = self.controller.GetPipelineState()
|
||||
for test_name in ["GLSL1 tests", "GLSL2 tests", "ASM tests"]:
|
||||
rdtest.log.begin_section(test_name)
|
||||
draw = self.find_draw(test_name)
|
||||
for child in range(len(draw.children)):
|
||||
section = draw.children[child]
|
||||
self.controller.SetFrameEvent(section.eventId, False)
|
||||
pipe: rd.PipeState = self.controller.GetPipelineState()
|
||||
|
||||
for test in range(section.numInstances):
|
||||
x = 4 * test + 1
|
||||
y = 4 * child + 1
|
||||
for test in range(section.numInstances):
|
||||
x = 4 * test + 1
|
||||
y = 4 * child + 1
|
||||
|
||||
# Debug the shader
|
||||
trace: rd.ShaderDebugTrace = self.controller.DebugPixel(x, y, rd.ReplayController.NoPreference,
|
||||
rd.ReplayController.NoPreference)
|
||||
# Debug the shader
|
||||
trace: rd.ShaderDebugTrace = self.controller.DebugPixel(x, y, rd.ReplayController.NoPreference,
|
||||
rd.ReplayController.NoPreference)
|
||||
|
||||
if trace.debugger is None:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not debug at all".format(test, child))
|
||||
self.controller.FreeTrace(trace)
|
||||
continue
|
||||
if trace.debugger is None:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not debug at all".format(test, child))
|
||||
self.controller.FreeTrace(trace)
|
||||
continue
|
||||
|
||||
cycles, variables = self.process_trace(trace)
|
||||
cycles, variables = self.process_trace(trace)
|
||||
|
||||
output: rd.SourceVariableMapping = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0)
|
||||
output: rd.SourceVariableMapping = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0)
|
||||
|
||||
debugged = self.evaluate_source_var(output, variables)
|
||||
debugged = self.evaluate_source_var(output, variables)
|
||||
|
||||
try:
|
||||
self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, x, y, debugged.value.fv[0:4])
|
||||
except rdtest.TestFailureException as ex:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not match. {}".format(test, child, str(ex)))
|
||||
continue
|
||||
finally:
|
||||
self.controller.FreeTrace(trace)
|
||||
try:
|
||||
self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, x, y, debugged.value.fv[0:4])
|
||||
except rdtest.TestFailureException as ex:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not match. {}".format(test, child, str(ex)))
|
||||
continue
|
||||
finally:
|
||||
self.controller.FreeTrace(trace)
|
||||
|
||||
rdtest.log.success("Test {} in sub-section {} matched as expected".format(test, child))
|
||||
rdtest.log.end_section("GLSL tests")
|
||||
|
||||
self.controller.SetFrameEvent(draw.eventId, False)
|
||||
|
||||
pipe: rd.PipeState = self.controller.GetPipelineState()
|
||||
|
||||
rdtest.log.begin_section("ASM tests")
|
||||
draw = self.find_draw("ASM tests")
|
||||
for child in range(len(draw.children)):
|
||||
section = draw.children[child]
|
||||
self.controller.SetFrameEvent(section.eventId, False)
|
||||
pipe: rd.PipeState = self.controller.GetPipelineState()
|
||||
|
||||
for test in range(section.numInstances):
|
||||
x = 4 * test + 1
|
||||
y = 4 * child + 1
|
||||
|
||||
# Debug the shader
|
||||
trace: rd.ShaderDebugTrace = self.controller.DebugPixel(x, y, rd.ReplayController.NoPreference,
|
||||
rd.ReplayController.NoPreference)
|
||||
|
||||
if trace.debugger is None:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not debug at all".format(test, child))
|
||||
self.controller.FreeTrace(trace)
|
||||
continue
|
||||
|
||||
cycles, variables = self.process_trace(trace)
|
||||
|
||||
output: rd.SourceVariableMapping = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0)
|
||||
|
||||
debugged = self.evaluate_source_var(output, variables)
|
||||
|
||||
try:
|
||||
self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, x, y, debugged.value.fv[0:4])
|
||||
except rdtest.TestFailureException as ex:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not match. {}".format(test, child, str(ex)))
|
||||
continue
|
||||
finally:
|
||||
self.controller.FreeTrace(trace)
|
||||
|
||||
rdtest.log.success("Test {} in sub-section {} matched as expected".format(test, child))
|
||||
rdtest.log.end_section("ASM tests")
|
||||
rdtest.log.success("Test {} in sub-section {} matched as expected".format(test, child))
|
||||
rdtest.log.end_section(test_name)
|
||||
|
||||
if failed:
|
||||
raise rdtest.TestFailureException("Some tests were not as expected")
|
||||
|
||||
Reference in New Issue
Block a user