mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-17 20:16:31 +00:00
SPIR-V debugger support for VK_KHR_compute_shader_derivatives
i.e. SPV_KHR_compute_shader_derivatives SPV_NV_compute_shader_derivatives
This commit is contained in:
@@ -174,9 +174,13 @@ static ShaderVariable MakeIdentity(const rdcspv::DataType &type, float val, bool
|
||||
|
||||
namespace rdcspv
|
||||
{
|
||||
ThreadState::ThreadState(Debugger &debug, const GlobalState &globalState)
|
||||
ThreadState::ThreadState(Debugger &debug, const GlobalState &globalState, ShaderStage stage)
|
||||
: debugger(debug), global(globalState)
|
||||
{
|
||||
// Default to Coarse, choose Fine for compute shaders
|
||||
defaultDeriveType = DerivType::Coarse;
|
||||
if(stage == ShaderStage::Compute)
|
||||
defaultDeriveType = DerivType::Fine;
|
||||
}
|
||||
|
||||
ThreadState::~ThreadState()
|
||||
@@ -1173,6 +1177,7 @@ void ThreadState::StepNext(bool useDebugState, const uint32_t steps,
|
||||
// spec allows the implementation to choose what DPdx means (coarse or fine), so we choose
|
||||
// coarse which seems a reasonable default. In future we could driver-detect the selection in
|
||||
// use (assuming it's not dynamic base on circumstances)
|
||||
// Compute shaders use Fine by default
|
||||
case Op::DPdx:
|
||||
case Op::DPdy:
|
||||
case Op::DPdxCoarse:
|
||||
@@ -1187,9 +1192,11 @@ void ThreadState::StepNext(bool useDebugState, const uint32_t steps,
|
||||
if(opdata.op == Op::DPdy || opdata.op == Op::DPdyCoarse || opdata.op == Op::DPdyFine)
|
||||
dir = DDY;
|
||||
|
||||
DerivType type = Coarse;
|
||||
DerivType type = defaultDeriveType;
|
||||
if(opdata.op == Op::DPdxFine || opdata.op == Op::DPdyFine)
|
||||
type = Fine;
|
||||
if(opdata.op == Op::DPdxCoarse || opdata.op == Op::DPdyCoarse)
|
||||
type = Coarse;
|
||||
|
||||
SetDst(deriv.result, CalcDeriv(dir, type, workgroup, deriv.p));
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ class Debugger;
|
||||
|
||||
struct ThreadState
|
||||
{
|
||||
ThreadState(Debugger &debug, const GlobalState &globalState);
|
||||
ThreadState(Debugger &debug, const GlobalState &globalState, ShaderStage stage);
|
||||
~ThreadState();
|
||||
|
||||
void EnterEntryPoint(bool useDebugState);
|
||||
@@ -454,6 +454,7 @@ private:
|
||||
AtomicStore(&atomic_pendingResultStatus, (int32_t)status);
|
||||
}
|
||||
|
||||
DerivType defaultDeriveType;
|
||||
ShaderDebugState pendingDebugState;
|
||||
bool hasDebugState = false;
|
||||
uint32_t stepIndex = 0;
|
||||
|
||||
@@ -467,6 +467,7 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
|
||||
"SPV_KHR_subgroup_vote",
|
||||
"SPV_KHR_terminate_invocation",
|
||||
"SPV_KHR_vulkan_memory_model",
|
||||
"SPV_KHR_compute_shader_derivatives",
|
||||
|
||||
// EXT extensions
|
||||
"SPV_EXT_demote_to_helper_invocation",
|
||||
@@ -486,6 +487,7 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
|
||||
"SPV_GOOGLE_decorate_string",
|
||||
"SPV_GOOGLE_hlsl_functionality1",
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_NV_compute_shader_derivatives",
|
||||
};
|
||||
|
||||
// whitelist supported extensions
|
||||
@@ -616,6 +618,8 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
|
||||
case Capability::GroupNonUniformVote:
|
||||
case Capability::SubgroupBallotKHR:
|
||||
case Capability::SubgroupVoteKHR:
|
||||
case Capability::ComputeDerivativeGroupQuadsKHR:
|
||||
case Capability::ComputeDerivativeGroupLinearKHR:
|
||||
{
|
||||
supported = true;
|
||||
break;
|
||||
@@ -665,14 +669,6 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
|
||||
break;
|
||||
}
|
||||
|
||||
// SPV_KHR_compute_shader_derivatives
|
||||
case Capability::ComputeDerivativeGroupQuadsKHR:
|
||||
case Capability::ComputeDerivativeGroupLinearKHR:
|
||||
{
|
||||
supported = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// SPV_KHR_float_controls2
|
||||
case Capability::FloatControls2:
|
||||
{
|
||||
@@ -1064,7 +1060,7 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *api, const ShaderStage s
|
||||
queuedJobs.resize(threadsInWorkgroup);
|
||||
for(uint32_t i = 0; i < threadsInWorkgroup; i++)
|
||||
{
|
||||
workgroup.push_back(ThreadState(*this, global));
|
||||
workgroup.push_back(ThreadState(*this, global, stage));
|
||||
queuedDeviceThreadSteps[i] = false;
|
||||
queuedGpuMathOps[i] = false;
|
||||
queuedGpuSampleGatherOps[i] = false;
|
||||
@@ -1706,6 +1702,11 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *api, const ShaderStage s
|
||||
lane.quadLaneIndex = apiWrapper->GetThreadProperty(i, ThreadProperty::QuadLane);
|
||||
lane.quadId = apiWrapper->GetThreadProperty(i, ThreadProperty::QuadId);
|
||||
}
|
||||
if(stage == ShaderStage::Compute)
|
||||
{
|
||||
lane.quadLaneIndex = apiWrapper->GetThreadProperty(i, ThreadProperty::QuadLane);
|
||||
lane.quadId = apiWrapper->GetThreadProperty(i, ThreadProperty::QuadId);
|
||||
}
|
||||
|
||||
lane.subgroupId = apiWrapper->GetThreadProperty(i, ThreadProperty::SubgroupId);
|
||||
lane.dead = apiWrapper->GetThreadProperty(i, ThreadProperty::Active) == 0;
|
||||
|
||||
@@ -547,6 +547,13 @@ enum class ThreadScope : uint32_t
|
||||
|
||||
BITMASK_OPERATORS(ThreadScope);
|
||||
|
||||
enum class ComputeDerivativeMode : uint8_t
|
||||
{
|
||||
None,
|
||||
Linear,
|
||||
Quad,
|
||||
};
|
||||
|
||||
class Processor
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -917,6 +917,8 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
|
||||
|
||||
CheckDebuggable(reflection.debugInfo.debuggable, reflection.debugInfo.debugStatus);
|
||||
|
||||
patchData.derivativeMode = ComputeDerivativeMode::None;
|
||||
|
||||
const EntryPoint *entry = NULL;
|
||||
for(const EntryPoint &e : entries)
|
||||
{
|
||||
@@ -967,6 +969,12 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st
|
||||
patchData.maxPrimitives = e.executionModes.others[idx].outputPrimitivesEXT;
|
||||
}
|
||||
|
||||
if(e.executionModes.others.contains(rdcspv::ExecutionMode::DerivativeGroupQuadsKHR))
|
||||
patchData.derivativeMode = ComputeDerivativeMode::Quad;
|
||||
|
||||
if(e.executionModes.others.contains(rdcspv::ExecutionMode::DerivativeGroupLinearKHR))
|
||||
patchData.derivativeMode = ComputeDerivativeMode::Linear;
|
||||
|
||||
// vulkan spec says "If an object is decorated with the WorkgroupSize decoration, this must take
|
||||
// precedence over any execution mode set for LocalSize."
|
||||
for(auto it : constants)
|
||||
|
||||
@@ -78,6 +78,7 @@ struct SPIRVPatchData
|
||||
rdcarray<uint32_t> specIDs;
|
||||
|
||||
rdcspv::ThreadScope threadScope;
|
||||
rdcspv::ComputeDerivativeMode derivativeMode;
|
||||
|
||||
// for mesh shaders, the maximum number of vertices/primitives generated by each meshlet
|
||||
uint32_t maxVertices = 0, maxPrimitives = 0;
|
||||
|
||||
@@ -6469,15 +6469,39 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
threadDim[1] = shadRefl.refl->dispatchThreadsDimension[1];
|
||||
threadDim[2] = shadRefl.refl->dispatchThreadsDimension[2];
|
||||
|
||||
if((threadid[0] >= threadDim[0]) || (threadid[1] >= threadDim[1]) || (threadid[2] >= threadDim[2]))
|
||||
{
|
||||
RDCLOG("Invalid threadid %d,%d,%d selected from group %dx%dx%d", threadid[0], threadid[1],
|
||||
threadid[2], threadDim[0], threadDim[1], threadDim[2]);
|
||||
return new ShaderDebugTrace();
|
||||
}
|
||||
if((groupid[0] >= action->dispatchDimension[0]) || (groupid[1] >= action->dispatchDimension[1]) ||
|
||||
(groupid[2] >= action->dispatchDimension[2]))
|
||||
{
|
||||
RDCLOG("Invalid groupid %d,%d,%d selected from dispatch %dx%dx%d", groupid[0], groupid[1],
|
||||
groupid[2], action->dispatchDimension[0], action->dispatchDimension[1],
|
||||
action->dispatchDimension[2]);
|
||||
return new ShaderDebugTrace();
|
||||
}
|
||||
|
||||
SubgroupCapability subgroupCapability = SubgroupCapability::None;
|
||||
uint32_t maxSubgroupSize = 1;
|
||||
CalculateSubgroupProperties(maxSubgroupSize, subgroupCapability);
|
||||
|
||||
uint32_t numThreads = 1;
|
||||
|
||||
if(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
bool hasQuadDerivatives =
|
||||
(shadRefl.patchData.derivativeMode != rdcspv::ComputeDerivativeMode::None);
|
||||
bool hasSubgroupScoope =
|
||||
(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Subgroup) ? true : false;
|
||||
bool hasWorkgroupScope =
|
||||
(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Workgroup) ? true : false;
|
||||
|
||||
if(hasQuadDerivatives)
|
||||
numThreads = RDCMAX(numThreads, 4U);
|
||||
if(hasSubgroupScoope)
|
||||
numThreads = RDCMAX(numThreads, maxSubgroupSize);
|
||||
if(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Workgroup)
|
||||
if(hasWorkgroupScope)
|
||||
numThreads = RDCMAX(numThreads, threadDim[0] * threadDim[1] * threadDim[2]);
|
||||
|
||||
apiWrapper->thread_builtins.resize(numThreads);
|
||||
@@ -6493,9 +6517,32 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
global_builtins[ShaderBuiltin::GroupIndex] =
|
||||
ShaderVariable(rdcstr(), groupid[0], groupid[1], groupid[2], 0U);
|
||||
|
||||
const uint32_t quadIdOffset = 10000;
|
||||
const uint32_t quadDerivMode = (uint32_t)shadRefl.patchData.derivativeMode;
|
||||
|
||||
uint32_t countQuadX = ~0U;
|
||||
uint32_t countQuadY = ~0U;
|
||||
uint32_t quadW = ~0U;
|
||||
uint32_t quadH = ~0U;
|
||||
|
||||
if(hasQuadDerivatives)
|
||||
{
|
||||
// linear: 4x1x1
|
||||
// quad: 2x2x1
|
||||
const uint32_t quadWidths[3] = {~0U, 4, 2};
|
||||
const uint32_t quadHeights[3] = {~0U, 1, 2};
|
||||
quadW = quadWidths[quadDerivMode];
|
||||
quadH = quadHeights[quadDerivMode];
|
||||
countQuadX = threadDim[0] / quadW;
|
||||
countQuadY = threadDim[1] / quadH;
|
||||
|
||||
RDCASSERTEQUAL(threadDim[0], countQuadX * quadW);
|
||||
RDCASSERTEQUAL(threadDim[1], countQuadY * quadH);
|
||||
}
|
||||
|
||||
// if we need to fetch subgroup data, do that now
|
||||
uint32_t laneIndex = 0;
|
||||
if(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
if(hasSubgroupScoope)
|
||||
{
|
||||
SpecData specData = {};
|
||||
|
||||
@@ -6643,19 +6690,16 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
// output is in input signature order.
|
||||
byte *LaneData = (byte *)(winner + 1);
|
||||
|
||||
numThreads = 4;
|
||||
const uint32_t subgroupSize = winner->subgroupSize;
|
||||
|
||||
if(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
{
|
||||
RDCASSERTNOTEQUAL(subgroupSize, 0);
|
||||
numThreads = RDCMAX(numThreads, subgroupSize);
|
||||
}
|
||||
RDCASSERTNOTEQUAL(subgroupSize, 0);
|
||||
numThreads = RDCMAX(numThreads, subgroupSize);
|
||||
|
||||
if(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Workgroup)
|
||||
{
|
||||
if(hasQuadDerivatives)
|
||||
RDCASSERT(numThreads >= 4);
|
||||
|
||||
if(hasWorkgroupScope)
|
||||
numThreads = RDCMAX(numThreads, threadDim[0] * threadDim[1] * threadDim[2]);
|
||||
}
|
||||
|
||||
apiWrapper->global_builtins[ShaderBuiltin::NumSubgroups] =
|
||||
ShaderVariable(rdcstr(), winner->numSubgroups, 0U, 0U, 0U);
|
||||
@@ -6676,13 +6720,36 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
ComputeLaneData *compData = (ComputeLaneData *)value;
|
||||
value += sizeof(ComputeLaneData);
|
||||
|
||||
// should we try to verify that the GPU assigned subgroups as we expect? this assumes tightly wrapped subgroups
|
||||
uint32_t lane = t;
|
||||
|
||||
if(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Workgroup)
|
||||
uint32_t quadId = ~0U;
|
||||
uint32_t quadLaneIndex = ~0U;
|
||||
if(hasQuadDerivatives)
|
||||
{
|
||||
lane = compData->threadid[2] * threadDim[0] * threadDim[1] +
|
||||
compData->threadid[1] * threadDim[0] + compData->threadid[0];
|
||||
uint32_t quadX = (compData->threadid[0] / quadW);
|
||||
uint32_t quadY = (compData->threadid[1] / quadH);
|
||||
uint32_t quadZ = compData->threadid[2];
|
||||
quadId = quadX + (quadY * countQuadX) + (quadZ * countQuadY * countQuadX);
|
||||
quadLaneIndex = (compData->threadid[0] % quadW) + (compData->threadid[1] % quadH) * 2;
|
||||
|
||||
apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::QuadLane] = quadLaneIndex;
|
||||
apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::QuadId] =
|
||||
quadId + quadIdOffset;
|
||||
}
|
||||
|
||||
if(hasWorkgroupScope)
|
||||
{
|
||||
// When quad derivatives are enabled, use the quad derivative layout
|
||||
if(hasQuadDerivatives)
|
||||
{
|
||||
lane = quadId * 4 + quadLaneIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume linear layout for the subgroup : tightly wrapped
|
||||
lane = compData->threadid[2] * threadDim[0] * threadDim[1] +
|
||||
compData->threadid[1] * threadDim[0] + compData->threadid[0];
|
||||
}
|
||||
}
|
||||
|
||||
if(rdcfixedarray<uint32_t, 3>(compData->threadid) == threadid && subgroupData->isActive)
|
||||
@@ -6716,24 +6783,42 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
}
|
||||
|
||||
// if we're simulating the whole workgroup we need to fill in the thread IDs of other threads
|
||||
if(shadRefl.patchData.threadScope & rdcspv::ThreadScope::Workgroup)
|
||||
if(hasWorkgroupScope)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for(uint32_t tz = 0; tz < threadDim[2]; tz++)
|
||||
{
|
||||
for(uint32_t ty = 0; ty < threadDim[1]; ty++)
|
||||
{
|
||||
for(uint32_t tx = 0; tx < threadDim[0]; tx++)
|
||||
{
|
||||
uint32_t quadId = ~0U;
|
||||
uint32_t quadLaneIndex = ~0U;
|
||||
|
||||
uint32_t lane = ~0U;
|
||||
if(hasQuadDerivatives)
|
||||
{
|
||||
// When quad derivatives are enabled, use the quad derivative layout
|
||||
uint32_t quadX = (tx / quadW);
|
||||
uint32_t quadY = (ty / quadH);
|
||||
uint32_t quadZ = tz;
|
||||
quadId = quadX + (quadY * countQuadX) + (quadZ * countQuadY * countQuadX);
|
||||
quadLaneIndex = (tx % quadW) + (ty % quadH) * 2;
|
||||
lane = quadId * 4 + quadLaneIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume linear layout for the subgroup : tightly wrapped
|
||||
lane = tz * threadDim[0] * threadDim[1] + ty * threadDim[0] + tx;
|
||||
}
|
||||
std::unordered_map<ShaderBuiltin, ShaderVariable> &thread_builtins =
|
||||
apiWrapper->thread_builtins[i];
|
||||
apiWrapper->thread_builtins[lane];
|
||||
|
||||
thread_builtins[ShaderBuiltin::GroupThreadIndex] =
|
||||
ShaderVariable(rdcstr(), tx, ty, tz, 0U);
|
||||
thread_builtins[ShaderBuiltin::GroupFlatIndex] = ShaderVariable(
|
||||
rdcstr(), tz * threadDim[0] * threadDim[1] + ty * threadDim[0] + tx, 0U, 0U, 0U);
|
||||
|
||||
if(apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::Active])
|
||||
if(apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::Active])
|
||||
{
|
||||
// assert that this is the thread we expect it to be
|
||||
RDCASSERTEQUAL(thread_builtins[ShaderBuiltin::DispatchThreadIndex].value.u32v[0],
|
||||
@@ -6744,9 +6829,18 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
groupid[2] * threadDim[2] + tz);
|
||||
|
||||
RDCASSERTEQUAL(thread_builtins[ShaderBuiltin::IndexInSubgroup].value.u32v[0],
|
||||
i % subgroupSize);
|
||||
lane % subgroupSize);
|
||||
RDCASSERTEQUAL(thread_builtins[ShaderBuiltin::SubgroupIndexInWorkgroup].value.u32v[0],
|
||||
i / subgroupSize);
|
||||
lane / subgroupSize);
|
||||
|
||||
if(hasQuadDerivatives)
|
||||
{
|
||||
RDCASSERTEQUAL(
|
||||
apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::QuadLane],
|
||||
quadLaneIndex);
|
||||
RDCASSERTEQUAL(apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::QuadId],
|
||||
quadId + quadIdOffset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -6755,20 +6849,27 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
groupid[1] * threadDim[1] + ty, groupid[2] * threadDim[2] + tz, 0U);
|
||||
// tightly wrap subgroups, this is likely not how the GPU actually assigns them
|
||||
thread_builtins[ShaderBuiltin::IndexInSubgroup] =
|
||||
ShaderVariable(rdcstr(), i % subgroupSize, 0U, 0U, 0U);
|
||||
ShaderVariable(rdcstr(), lane % subgroupSize, 0U, 0U, 0U);
|
||||
thread_builtins[ShaderBuiltin::SubgroupIndexInWorkgroup] =
|
||||
ShaderVariable(rdcstr(), i / subgroupSize, 0U, 0U, 0U);
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::Active] = 1;
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::SubgroupId] =
|
||||
i % subgroupSize;
|
||||
}
|
||||
ShaderVariable(rdcstr(), lane / subgroupSize, 0U, 0U, 0U);
|
||||
apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::Active] = 1;
|
||||
apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::SubgroupId] =
|
||||
lane % subgroupSize;
|
||||
|
||||
i++;
|
||||
if(hasQuadDerivatives)
|
||||
{
|
||||
apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::QuadLane] =
|
||||
quadLaneIndex;
|
||||
apiWrapper->thread_props[lane][(size_t)rdcspv::ThreadProperty::QuadId] = quadId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Each member of a quad should belong to the same subgroup. We assume this and do not validate it
|
||||
|
||||
// Add inactive padding lanes to round up to the subgroup size
|
||||
const uint32_t numPaddingThreads = AlignUp(numThreads, subgroupSize) - numThreads;
|
||||
if(numPaddingThreads > 0)
|
||||
@@ -6806,11 +6907,11 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we have more than one thread here, that means we need to simulate the whole workgroup.
|
||||
// if we need to simulate the whole workgroup.
|
||||
// we assume the layout of this is irrelevant and don't attempt to read it back from the GPU
|
||||
// like we do with subgroups. We lay things out in plain linear order, along X and then Y and
|
||||
// then Z, with groups iterated together.
|
||||
if(numThreads > 1)
|
||||
if(hasWorkgroupScope)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for(uint32_t tz = 0; tz < threadDim[2]; tz++)
|
||||
@@ -6830,6 +6931,19 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
rdcstr(), tz * threadDim[0] * threadDim[1] + ty * threadDim[0] + tx, 0U, 0U, 0U);
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::Active] = 1;
|
||||
|
||||
if(hasQuadDerivatives)
|
||||
{
|
||||
uint32_t quadX = (tx / quadW);
|
||||
uint32_t quadY = (ty / quadH);
|
||||
uint32_t quadZ = tz;
|
||||
uint32_t quadId =
|
||||
quadIdOffset + quadX + (quadY * countQuadX) + (quadZ * countQuadY * countQuadX);
|
||||
uint32_t quadLaneIndex = (tx % quadW) + (ty % quadH) * 2;
|
||||
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::QuadLane] = quadLaneIndex;
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::QuadId] = quadId;
|
||||
}
|
||||
|
||||
if(rdcfixedarray<uint32_t, 3>({tx, ty, tz}) == threadid)
|
||||
{
|
||||
laneIndex = i;
|
||||
@@ -6840,8 +6954,49 @@ ShaderDebugTrace *VulkanReplay::DebugComputeCommon(ShaderStage stage, uint32_t e
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(hasQuadDerivatives)
|
||||
{
|
||||
// need to simulate the whole quad, do not readback from the GPU like we do with subgroups
|
||||
// the quad is guaranteed to be in the same subgroup
|
||||
// We lay things out in linear or quad order
|
||||
RDCASSERTEQUAL(numThreads, 4U);
|
||||
uint32_t txMin = (threadid[0] / quadW) * quadW;
|
||||
uint32_t tyMin = (threadid[1] / quadH) * quadH;
|
||||
uint32_t tz = threadid[2];
|
||||
uint32_t quadZ = tz;
|
||||
for(uint32_t i = 0; i < 4U; ++i)
|
||||
{
|
||||
uint32_t tx = txMin + (i % quadW);
|
||||
uint32_t ty = tyMin + (i / quadW);
|
||||
std::unordered_map<ShaderBuiltin, ShaderVariable> &thread_builtins =
|
||||
apiWrapper->thread_builtins[i];
|
||||
thread_builtins[ShaderBuiltin::DispatchThreadIndex] =
|
||||
ShaderVariable(rdcstr(), groupid[0] * threadDim[0] + tx, groupid[1] * threadDim[1] + ty,
|
||||
groupid[2] * threadDim[2] + tz, 0U);
|
||||
thread_builtins[ShaderBuiltin::GroupThreadIndex] = ShaderVariable(rdcstr(), tx, ty, tz, 0U);
|
||||
thread_builtins[ShaderBuiltin::GroupFlatIndex] = ShaderVariable(
|
||||
rdcstr(), tz * threadDim[0] * threadDim[1] + ty * threadDim[0] + tx, 0U, 0U, 0U);
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::Active] = 1;
|
||||
|
||||
if(hasQuadDerivatives)
|
||||
{
|
||||
uint32_t quadX = (tx / quadW);
|
||||
uint32_t quadY = (ty / quadH);
|
||||
uint32_t quadId =
|
||||
quadIdOffset + quadX + (quadY * countQuadX) + (quadZ * countQuadY * countQuadX);
|
||||
uint32_t quadLaneIndex = (tx % quadW) + (ty % quadH) * 2;
|
||||
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::QuadLane] = quadLaneIndex;
|
||||
apiWrapper->thread_props[i][(size_t)rdcspv::ThreadProperty::QuadId] = quadId;
|
||||
}
|
||||
|
||||
if(rdcfixedarray<uint32_t, 3>({tx, ty, tz}) == threadid)
|
||||
laneIndex = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCASSERTEQUAL(numThreads, 1U);
|
||||
// simple single-thread case
|
||||
apiWrapper->thread_props[0][(size_t)rdcspv::ThreadProperty::Active] = 1;
|
||||
apiWrapper->thread_props[0][(size_t)rdcspv::ThreadProperty::SubgroupId] = 0;
|
||||
|
||||
Reference in New Issue
Block a user