Add support for storage buffer access

This commit is contained in:
baldurk
2020-04-23 19:14:08 +01:00
parent 0d1e0af9b1
commit f506dcf395
7 changed files with 783 additions and 164 deletions
+1 -1
View File
@@ -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;
}
}
+58 -11
View File
@@ -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
+18 -4
View File
@@ -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)
{
+102 -29
View File
@@ -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 &params, 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;
}
+159 -20
View File
@@ -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);
+31 -73
View File
@@ -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")