mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-27 08:56:44 +00:00
Pass subgroup size and index through to DXIL instruction execute
This commit is contained in:
@@ -2357,6 +2357,7 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui
|
||||
const rdcarray<DXIL::EntryPointInterface::Signature> &dxilInputs =
|
||||
debugger->GetDXILEntryPointInputs();
|
||||
|
||||
globalState.subgroupSize = buf->subgroupSize;
|
||||
for(uint32_t t = 0; t < buf->subgroupSize; t++)
|
||||
{
|
||||
DXDebug::VSLaneData *lane = (DXDebug::VSLaneData *)(initialData.data() + laneDataOffset +
|
||||
@@ -2369,6 +2370,7 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui
|
||||
if(lane->active)
|
||||
RDCASSERTEQUAL(lane->laneIndex, t);
|
||||
workgroupProperties[t][DXILDebug::ThreadProperty::Active] = lane->active;
|
||||
workgroupProperties[t][DXILDebug::ThreadProperty::SubgroupIdx] = t;
|
||||
|
||||
rdcarray<DXILDebug::InputData> inputDatas;
|
||||
for(int i = 0; i < fetcher.inputs.count(); i++)
|
||||
@@ -2404,6 +2406,8 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui
|
||||
data += inputElement.numwords * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
state.m_Builtins[ShaderBuiltin::IndexInSubgroup] = ShaderVariable(rdcstr(), t, 0U, 0U, 0U);
|
||||
|
||||
for(const DXILDebug::InputData &input : inputDatas)
|
||||
{
|
||||
int32_t *rawout = NULL;
|
||||
@@ -3159,6 +3163,7 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
|
||||
DXILDebug::FetchConstantBufferData(m_pDevice, dxbc->GetDXILByteCode(), rs.graphics, refl,
|
||||
globalState, ret->sourceVars);
|
||||
|
||||
globalState.subgroupSize = hit->subgroupSize;
|
||||
for(uint32_t q = 0; q < hit->subgroupSize; q++)
|
||||
{
|
||||
DXDebug::PSLaneData *lane = (DXDebug::PSLaneData *)data;
|
||||
@@ -3170,6 +3175,7 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
|
||||
workgroupProperties[q][DXILDebug::ThreadProperty::Helper] = lane->isHelper;
|
||||
workgroupProperties[q][DXILDebug::ThreadProperty::QuadLane] = lane->quadLane;
|
||||
workgroupProperties[q][DXILDebug::ThreadProperty::QuadId] = lane->quadId;
|
||||
workgroupProperties[q][DXILDebug::ThreadProperty::SubgroupIdx] = q;
|
||||
|
||||
data += sizeof(DXDebug::PSLaneData);
|
||||
|
||||
@@ -3212,6 +3218,7 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
|
||||
data += inputElement.numwords * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
state.m_Builtins[ShaderBuiltin::IndexInSubgroup] = ShaderVariable(rdcstr(), q, 0U, 0U, 0U);
|
||||
state.m_Builtins[ShaderBuiltin::PrimitiveIndex] =
|
||||
ShaderVariable(rdcstr(), lane->primitive, 0U, 0U, 0U);
|
||||
state.m_Builtins[ShaderBuiltin::MSAACoverage] =
|
||||
@@ -3433,6 +3440,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
|
||||
};
|
||||
|
||||
uint32_t numThreads = 1;
|
||||
uint32_t subgroupSize = 1;
|
||||
uint32_t activeLaneIndex = 0;
|
||||
|
||||
rdcflatmap<ShaderBuiltin, ShaderVariable> globalBuiltins;
|
||||
@@ -3594,6 +3602,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
|
||||
else
|
||||
activeLaneIndex = buf->laneIndex;
|
||||
|
||||
subgroupSize = buf->subgroupSize;
|
||||
for(uint32_t t = 0; t < buf->subgroupSize; t++)
|
||||
{
|
||||
DXDebug::CSLaneData *value = (DXDebug::CSLaneData *)(initialData.data() + laneDataOffset +
|
||||
@@ -3616,6 +3625,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
|
||||
activeLaneIndex = lane;
|
||||
|
||||
workgroupProperties[lane][DXILDebug::ThreadProperty::Active] = value->active;
|
||||
workgroupProperties[lane][DXILDebug::ThreadProperty::SubgroupIdx] = t;
|
||||
RDCASSERT(value->active);
|
||||
|
||||
threadBuiltins[lane][ShaderBuiltin::DispatchThreadIndex] =
|
||||
@@ -3629,6 +3639,8 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
|
||||
value->threadid[2] * threadDim[0] * threadDim[1] +
|
||||
value->threadid[1] * threadDim[0] + value->threadid[0],
|
||||
0U, 0U, 0U);
|
||||
threadBuiltins[lane][ShaderBuiltin::IndexInSubgroup] =
|
||||
ShaderVariable(rdcstr(), value->laneIndex, 0U, 0U, 0U);
|
||||
}
|
||||
|
||||
if(activeLaneIndex == ~0U)
|
||||
@@ -3658,6 +3670,9 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
|
||||
groupid[1] * threadDim[1] + ty);
|
||||
RDCASSERTEQUAL(thread_builtins[ShaderBuiltin::DispatchThreadIndex].value.u32v[2],
|
||||
groupid[2] * threadDim[2] + tz);
|
||||
|
||||
RDCASSERTEQUAL(thread_builtins[ShaderBuiltin::IndexInSubgroup].value.u32v[0],
|
||||
i % buf->subgroupSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3668,7 +3683,12 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
|
||||
ShaderVariable(rdcstr(), tx, ty, tz, 0U);
|
||||
thread_builtins[ShaderBuiltin::GroupFlatIndex] = ShaderVariable(
|
||||
rdcstr(), tz * threadDim[0] * threadDim[1] + ty * threadDim[0] + tx, 0U, 0U, 0U);
|
||||
// tightly wrap subgroups, this is likely not how the GPU actually assigns them
|
||||
thread_builtins[ShaderBuiltin::IndexInSubgroup] =
|
||||
ShaderVariable(rdcstr(), i % buf->subgroupSize, 0U, 0U, 0U);
|
||||
workgroupProperties[i][DXILDebug::ThreadProperty::Active] = 1;
|
||||
workgroupProperties[i][DXILDebug::ThreadProperty::SubgroupIdx] =
|
||||
i % buf->subgroupSize;
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -3751,6 +3771,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
|
||||
DXILDebug::GlobalState &globalState = debugger->GetGlobalState();
|
||||
|
||||
globalState.builtins.swap(globalBuiltins);
|
||||
globalState.subgroupSize = subgroupSize;
|
||||
|
||||
for(uint32_t i = 0; i < threadBuiltins.size(); i++)
|
||||
debugger->GetLane(i).m_Builtins.swap(threadBuiltins[i]);
|
||||
|
||||
@@ -620,6 +620,33 @@ enum class AtomicBinOpCode : uint32_t
|
||||
Invalid // Must be last.
|
||||
};
|
||||
|
||||
// WaveOp / WavePrefixOp
|
||||
enum class WaveOpCode : uint32_t
|
||||
{
|
||||
Sum = 0,
|
||||
Product = 1,
|
||||
Min = 2,
|
||||
Max = 3,
|
||||
};
|
||||
|
||||
// WaveBitOp
|
||||
enum class WaveBitOpCode : uint32_t
|
||||
{
|
||||
And = 0,
|
||||
Or = 1,
|
||||
Xor = 2,
|
||||
};
|
||||
|
||||
// WaveMultiPrefixOp
|
||||
enum class WaveMultiPrefixOpCode : uint32_t
|
||||
{
|
||||
Sum = 0,
|
||||
And = 1,
|
||||
Or = 2,
|
||||
Xor = 3,
|
||||
Product = 4,
|
||||
};
|
||||
|
||||
enum class QuadOpKind : uint32_t
|
||||
{
|
||||
ReadAcrossX = 0, // returns the value from the other lane in the quad in the
|
||||
|
||||
@@ -1655,7 +1655,8 @@ bool IsNopInstruction(const Instruction &inst)
|
||||
}
|
||||
|
||||
bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
|
||||
const rdcarray<ThreadState> &workgroup)
|
||||
const rdcarray<ThreadState> &workgroup,
|
||||
const rdcarray<bool> &activeMask)
|
||||
{
|
||||
m_CurrentInstruction = m_FunctionInfo->function->instructions[m_FunctionInstructionIdx];
|
||||
const Instruction &inst = *m_CurrentInstruction;
|
||||
@@ -3529,6 +3530,92 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
|
||||
result.value.u64v[0] = a.value.u64v[0];
|
||||
break;
|
||||
}
|
||||
// Wave/Subgroup Operations
|
||||
case DXOp::WaveGetLaneIndex:
|
||||
{
|
||||
// SV_PrimitiveID
|
||||
result.value.u32v[0] = m_SubgroupIdx;
|
||||
break;
|
||||
}
|
||||
case DXOp::WaveActiveOp:
|
||||
{
|
||||
// WaveActiveOp(value,op,sop)
|
||||
|
||||
ShaderVariable arg;
|
||||
RDCASSERT(GetShaderVariable(inst.args[2], opCode, dxOpCode, arg));
|
||||
WaveOpCode waveOpCode = (WaveOpCode)arg.value.u32v[0];
|
||||
|
||||
RDCASSERT(GetShaderVariable(inst.args[3], opCode, dxOpCode, arg));
|
||||
bool isUnsigned = (arg.value.u32v[0] != 0);
|
||||
|
||||
// determine active lane indices in our subgroup
|
||||
rdcarray<uint32_t> activeLanes;
|
||||
|
||||
const uint32_t firstLaneInSub = m_WorkgroupIndex - m_SubgroupIdx;
|
||||
for(uint32_t lane = firstLaneInSub; lane < firstLaneInSub + m_GlobalState.subgroupSize;
|
||||
lane++)
|
||||
{
|
||||
// wave operations exclude helpers
|
||||
if(activeMask[lane])
|
||||
{
|
||||
if(!m_GlobalState.waveOpsIncludeHelpers && workgroup[lane - firstLaneInSub].m_Helper)
|
||||
continue;
|
||||
activeLanes.push_back(lane - firstLaneInSub);
|
||||
}
|
||||
}
|
||||
|
||||
ShaderVariable accum;
|
||||
RDCASSERT(GetShaderVariable(inst.args[1], opCode, dxOpCode, accum));
|
||||
|
||||
// set the identity
|
||||
switch(waveOpCode)
|
||||
{
|
||||
default:
|
||||
RDCERR("Unhandled wave opcode");
|
||||
accum.value = {};
|
||||
break;
|
||||
case WaveOpCode::Sum: accum.value = {}; break;
|
||||
}
|
||||
|
||||
for(uint32_t lane : activeLanes)
|
||||
{
|
||||
ShaderVariable x;
|
||||
RDCASSERT(workgroup[lane].GetShaderVariable(inst.args[1], opCode, dxOpCode, x));
|
||||
|
||||
switch(waveOpCode)
|
||||
{
|
||||
default: RDCERR("Unhandled wave opcode"); break;
|
||||
case WaveOpCode::Sum:
|
||||
{
|
||||
for(uint8_t c = 0; c < x.columns; c++)
|
||||
{
|
||||
if(isUnsigned)
|
||||
{
|
||||
#undef _IMPL
|
||||
#define _IMPL(I, S, U) comp<U>(accum, c) = comp<U>(accum, c) + comp<U>(x, c)
|
||||
IMPL_FOR_INT_TYPES_FOR_TYPE(_IMPL, x.type);
|
||||
}
|
||||
else
|
||||
{
|
||||
#undef _IMPL
|
||||
#define _IMPL(I, S, U) comp<S>(accum, c) = comp<S>(accum, c) + comp<S>(x, c)
|
||||
IMPL_FOR_INT_TYPES_FOR_TYPE(_IMPL, x.type);
|
||||
|
||||
#undef _IMPL
|
||||
#define _IMPL(T) comp<T>(accum, c) = comp<T>(accum, c) + comp<T>(x, c)
|
||||
|
||||
IMPL_FOR_FLOAT_TYPES_FOR_TYPE(_IMPL, x.type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = accum;
|
||||
|
||||
break;
|
||||
}
|
||||
// Quad Operations
|
||||
case DXOp::QuadReadLaneAt:
|
||||
case DXOp::QuadOp:
|
||||
@@ -3818,7 +3905,6 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
|
||||
|
||||
// Wave/Subgroup Operations
|
||||
case DXOp::WaveIsFirstLane:
|
||||
case DXOp::WaveGetLaneIndex:
|
||||
case DXOp::WaveGetLaneCount:
|
||||
case DXOp::WaveAnyTrue:
|
||||
case DXOp::WaveAllTrue:
|
||||
@@ -3826,7 +3912,6 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
|
||||
case DXOp::WaveActiveBallot:
|
||||
case DXOp::WaveReadLaneAt:
|
||||
case DXOp::WaveReadLaneFirst:
|
||||
case DXOp::WaveActiveOp:
|
||||
case DXOp::WaveActiveBit:
|
||||
case DXOp::WavePrefixOp:
|
||||
case DXOp::WaveAllBitCount:
|
||||
@@ -5321,7 +5406,7 @@ void ThreadState::StepOverNopInstructions()
|
||||
}
|
||||
|
||||
void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper,
|
||||
const rdcarray<ThreadState> &workgroup)
|
||||
const rdcarray<ThreadState> &workgroup, const rdcarray<bool> &activeMask)
|
||||
{
|
||||
m_State = state;
|
||||
|
||||
@@ -5359,7 +5444,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper,
|
||||
}
|
||||
}
|
||||
}
|
||||
ExecuteInstruction(apiWrapper, workgroup);
|
||||
ExecuteInstruction(apiWrapper, workgroup, activeMask);
|
||||
|
||||
m_State = NULL;
|
||||
}
|
||||
@@ -8360,6 +8445,7 @@ void Debugger::InitialiseWorkgroup(const rdcarray<ThreadProperties> &workgroupPr
|
||||
}
|
||||
|
||||
lane.m_Dead = workgroupProperties[i][ThreadProperty::Active] == 0;
|
||||
lane.m_SubgroupIdx = workgroupProperties[i][ThreadProperty::SubgroupIdx];
|
||||
}
|
||||
|
||||
// find quad neighbours
|
||||
@@ -8486,12 +8572,12 @@ rdcarray<ShaderDebugState> Debugger::ContinueDebug(DebugAPIWrapper *apiWrapper)
|
||||
{
|
||||
hasDebugState = true;
|
||||
state.stepIndex = m_Steps;
|
||||
thread.StepNext(&state, apiWrapper, m_Workgroup);
|
||||
thread.StepNext(&state, apiWrapper, m_Workgroup, activeMask);
|
||||
m_Steps++;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread.StepNext(NULL, apiWrapper, m_Workgroup);
|
||||
thread.StepNext(NULL, apiWrapper, m_Workgroup, activeMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,13 +222,14 @@ struct ThreadState
|
||||
void EnterFunction(const DXIL::Function *function, const rdcarray<DXIL::Value *> &args);
|
||||
void EnterEntryPoint(const DXIL::Function *function, ShaderDebugState *state);
|
||||
void StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper,
|
||||
const rdcarray<ThreadState> &workgroup);
|
||||
const rdcarray<ThreadState> &workgroup, const rdcarray<bool> &activeMask);
|
||||
void StepOverNopInstructions();
|
||||
|
||||
bool Finished() const;
|
||||
bool InUniformBlock() const;
|
||||
|
||||
bool ExecuteInstruction(DebugAPIWrapper *apiWrapper, const rdcarray<ThreadState> &workgroup);
|
||||
bool ExecuteInstruction(DebugAPIWrapper *apiWrapper, const rdcarray<ThreadState> &workgroup,
|
||||
const rdcarray<bool> &activeMask);
|
||||
|
||||
void MarkResourceAccess(const rdcstr &name, const ResourceReferenceInfo &resRefInfo,
|
||||
bool directAccess, const ShaderDirectAccess &access,
|
||||
@@ -347,6 +348,8 @@ struct ThreadState
|
||||
rdcfixedarray<uint32_t, 4> m_QuadNeighbours = {~0U, ~0U, ~0U, ~0U};
|
||||
// index in the workgroup
|
||||
uint32_t m_WorkgroupIndex = ~0U;
|
||||
// index in the subgroup
|
||||
uint32_t m_SubgroupIdx = ~0U;
|
||||
bool m_Dead = false;
|
||||
bool m_Ended = false;
|
||||
bool m_Helper = false;
|
||||
@@ -357,6 +360,8 @@ struct GlobalState
|
||||
GlobalState() = default;
|
||||
~GlobalState();
|
||||
BuiltinInputs builtins;
|
||||
uint32_t subgroupSize = 1;
|
||||
bool waveOpsIncludeHelpers = false;
|
||||
|
||||
struct ViewFmt
|
||||
{
|
||||
@@ -518,6 +523,7 @@ enum class ThreadProperty : uint32_t
|
||||
QuadId,
|
||||
QuadLane,
|
||||
Active,
|
||||
SubgroupIdx,
|
||||
Count,
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "dxil_bytecode.h"
|
||||
#include "dxil_common.h"
|
||||
|
||||
RDOC_EXTERN_CONFIG(bool, D3D_Hack_EnableGroups);
|
||||
|
||||
namespace DXIL
|
||||
{
|
||||
enum class ResourcesTag
|
||||
@@ -1868,6 +1870,12 @@ rdcstr Program::GetDebugStatus()
|
||||
"Only supported when debugging pixel shaders dx.op call `%s` %s",
|
||||
callFunc->name.c_str(), ToStr(dxOpCode).c_str());
|
||||
continue;
|
||||
case DXOp::WaveGetLaneIndex:
|
||||
case DXOp::WaveActiveOp:
|
||||
if(!D3D_Hack_EnableGroups())
|
||||
return StringFormat::Fmt("Unsupported dx.op call `%s` %s", callFunc->name.c_str(),
|
||||
ToStr(dxOpCode).c_str());
|
||||
continue;
|
||||
case DXOp::TempRegLoad:
|
||||
case DXOp::TempRegStore:
|
||||
case DXOp::MinPrecXRegLoad:
|
||||
@@ -1889,7 +1897,6 @@ rdcstr Program::GetDebugStatus()
|
||||
case DXOp::OutputControlPointID:
|
||||
case DXOp::CycleCounterLegacy:
|
||||
case DXOp::WaveIsFirstLane:
|
||||
case DXOp::WaveGetLaneIndex:
|
||||
case DXOp::WaveGetLaneCount:
|
||||
case DXOp::WaveAnyTrue:
|
||||
case DXOp::WaveAllTrue:
|
||||
@@ -1897,7 +1904,6 @@ rdcstr Program::GetDebugStatus()
|
||||
case DXOp::WaveActiveBallot:
|
||||
case DXOp::WaveReadLaneAt:
|
||||
case DXOp::WaveReadLaneFirst:
|
||||
case DXOp::WaveActiveOp:
|
||||
case DXOp::WaveActiveBit:
|
||||
case DXOp::WavePrefixOp:
|
||||
case DXOp::WaveAllBitCount:
|
||||
|
||||
@@ -6154,6 +6154,11 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
groupid[1] * threadDim[1] + ty);
|
||||
RDCASSERTEQUAL(thread_builtins[ShaderBuiltin::DispatchThreadIndex].value.u32v[2],
|
||||
groupid[2] * threadDim[2] + tz);
|
||||
|
||||
RDCASSERTEQUAL(thread_builtins[ShaderBuiltin::IndexInSubgroup].value.u32v[0],
|
||||
i % winner->subgroupSize);
|
||||
RDCASSERTEQUAL(thread_builtins[ShaderBuiltin::SubgroupIndexInWorkgroup].value.u32v[0],
|
||||
i / winner->subgroupSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -6165,8 +6170,10 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
thread_builtins[ShaderBuiltin::GroupFlatIndex] = ShaderVariable(
|
||||
rdcstr(), tz * threadDim[0] * threadDim[1] + ty * threadDim[0] + tx, 0U, 0U, 0U);
|
||||
// tightly wrap subgroups, this is likely not how the GPU actually assigns them
|
||||
thread_builtins[ShaderBuiltin::SubgroupIndexInWorkgroup] =
|
||||
thread_builtins[ShaderBuiltin::IndexInSubgroup] =
|
||||
ShaderVariable(rdcstr(), i % winner->subgroupSize, 0U, 0U, 0U);
|
||||
thread_builtins[ShaderBuiltin::SubgroupIndexInWorkgroup] =
|
||||
ShaderVariable(rdcstr(), i / winner->subgroupSize, 0U, 0U, 0U);
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::Active] = 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user