Don't duplicate workgroup for derivatives

* Because SPIR-V is SSA, we can use the current workgroup for all cross-group
  operations, knowing that the output ID of any such opcode can't also be the
  input (so doing workgroup operations one-at-a-time is still fine, we won't
  corrupt results of later threads by updating earlier ones.
This commit is contained in:
baldurk
2020-04-14 15:11:41 +01:00
parent b17b6e7c4f
commit 80e1cbfba4
3 changed files with 29 additions and 40 deletions
+25 -26
View File
@@ -182,7 +182,7 @@ void ThreadState::EnterFunction(ShaderDebugState *state, const rdcarray<Id> &arg
nextInstruction = debugger.GetInstructionForIter(it);
}
const ShaderVariable &ThreadState::GetSrc(Id id)
const ShaderVariable &ThreadState::GetSrc(Id id) const
{
return ids[id];
}
@@ -252,8 +252,7 @@ void ThreadState::JumpToLabel(Id target)
}
}
void ThreadState::StepNext(ShaderDebugState *state,
const rdcarray<DenseIdMap<ShaderVariable>> &prevWorkgroup)
void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState> &workgroup)
{
Iter it = debugger.GetIterForInstruction(nextInstruction);
nextInstruction++;
@@ -404,8 +403,8 @@ void ThreadState::StepNext(ShaderDebugState *state,
OpDPdx deriv(it);
// coarse derivatives are identical across the quad, based on the top-left.
ShaderVariable var = prevWorkgroup[0][deriv.p];
ShaderVariable other = prevWorkgroup[1][deriv.p];
ShaderVariable var = workgroup[0].GetSrc(deriv.p);
ShaderVariable other = workgroup[1].GetSrc(deriv.p);
for(uint8_t c = 0; c < var.columns; c++)
var.value.fv[c] = other.value.fv[c] - var.value.fv[c];
@@ -421,8 +420,8 @@ void ThreadState::StepNext(ShaderDebugState *state,
OpDPdx deriv(it);
// coarse derivatives are identical across the quad, based on the top-left.
ShaderVariable var = prevWorkgroup[0][deriv.p];
ShaderVariable other = prevWorkgroup[2][deriv.p];
ShaderVariable var = workgroup[0].GetSrc(deriv.p);
ShaderVariable other = workgroup[2].GetSrc(deriv.p);
for(uint8_t c = 0; c < var.columns; c++)
var.value.fv[c] = other.value.fv[c] - var.value.fv[c];
@@ -452,13 +451,13 @@ void ThreadState::StepNext(ShaderDebugState *state,
// top-left
if(xdirection)
{
a = prevWorkgroup[0][deriv.p];
b = prevWorkgroup[1][deriv.p];
a = workgroup[0].GetSrc(deriv.p);
b = workgroup[1].GetSrc(deriv.p);
}
else
{
a = prevWorkgroup[0][deriv.p];
b = prevWorkgroup[2][deriv.p];
a = workgroup[0].GetSrc(deriv.p);
b = workgroup[2].GetSrc(deriv.p);
}
}
else
@@ -466,13 +465,13 @@ void ThreadState::StepNext(ShaderDebugState *state,
// bottom-left
if(xdirection)
{
a = prevWorkgroup[2][deriv.p];
b = prevWorkgroup[3][deriv.p];
a = workgroup[2].GetSrc(deriv.p);
b = workgroup[3].GetSrc(deriv.p);
}
else
{
a = prevWorkgroup[0][deriv.p];
b = prevWorkgroup[2][deriv.p];
a = workgroup[0].GetSrc(deriv.p);
b = workgroup[2].GetSrc(deriv.p);
}
}
}
@@ -483,13 +482,13 @@ void ThreadState::StepNext(ShaderDebugState *state,
// top-right
if(xdirection)
{
a = prevWorkgroup[0][deriv.p];
b = prevWorkgroup[1][deriv.p];
a = workgroup[0].GetSrc(deriv.p);
b = workgroup[1].GetSrc(deriv.p);
}
else
{
a = prevWorkgroup[1][deriv.p];
b = prevWorkgroup[3][deriv.p];
a = workgroup[1].GetSrc(deriv.p);
b = workgroup[3].GetSrc(deriv.p);
}
}
else
@@ -497,13 +496,13 @@ void ThreadState::StepNext(ShaderDebugState *state,
// bottom-right
if(xdirection)
{
a = prevWorkgroup[2][deriv.p];
b = prevWorkgroup[3][deriv.p];
a = workgroup[2].GetSrc(deriv.p);
b = workgroup[3].GetSrc(deriv.p);
}
else
{
a = prevWorkgroup[1][deriv.p];
b = prevWorkgroup[3][deriv.p];
a = workgroup[1].GetSrc(deriv.p);
b = workgroup[3].GetSrc(deriv.p);
}
}
}
@@ -1577,9 +1576,9 @@ void ThreadState::StepNext(ShaderDebugState *state,
if(derivId != Id())
{
// calculate DDX/DDY in coarse fashion
ShaderVariable topleft = prevWorkgroup[0][derivId];
ShaderVariable topright = prevWorkgroup[1][derivId];
ShaderVariable bottomleft = prevWorkgroup[2][derivId];
ShaderVariable topleft = workgroup[0].GetSrc(derivId);
ShaderVariable topright = workgroup[1].GetSrc(derivId);
ShaderVariable bottomleft = workgroup[2].GetSrc(derivId);
ddxCalc = ddyCalc = topleft;
+2 -2
View File
@@ -144,7 +144,7 @@ struct ThreadState
~ThreadState();
void EnterFunction(ShaderDebugState *state, const rdcarray<Id> &arguments);
void StepNext(ShaderDebugState *state, const rdcarray<DenseIdMap<ShaderVariable>> &prevWorkgroup);
void StepNext(ShaderDebugState *state, const rdcarray<ThreadState> &workgroup);
void FillCallstack(ShaderDebugState &state);
@@ -183,7 +183,7 @@ struct ThreadState
uint32_t workgroupIndex;
bool done;
const ShaderVariable &GetSrc(Id id);
const ShaderVariable &GetSrc(Id id) const;
private:
void SetDst(ShaderDebugState *state, Id id, const ShaderVariable &val);
@@ -590,10 +590,6 @@ rdcarray<ShaderDebugState> Debugger::ContinueDebug()
if(active.Finished())
return ret;
rdcarray<DenseIdMap<ShaderVariable>> oldworkgroup;
oldworkgroup.resize(workgroup.size());
rdcarray<bool> activeMask;
// do 100 in a chunk
@@ -602,12 +598,6 @@ rdcarray<ShaderDebugState> Debugger::ContinueDebug()
if(active.Finished())
break;
// set up the old workgroup so that cross-workgroup/cross-quad operations (e.g. DDX/DDY) get
// consistent results even when we step the quad out of order. Otherwise if an operation reads
// and writes from the same register we'd trash data needed for other workgroup elements.
for(size_t i = 0; i < oldworkgroup.size(); i++)
oldworkgroup[i] = workgroup[i].ids;
// calculate the current mask of which threads are active
CalcActiveMask(activeMask);
@@ -653,7 +643,7 @@ rdcarray<ShaderDebugState> Debugger::ContinueDebug()
l++;
}
thread.StepNext(&state, oldworkgroup);
thread.StepNext(&state, workgroup);
state.stepIndex = steps;
state.sourceVars = thread.sourceVars;
thread.FillCallstack(state);
@@ -661,7 +651,7 @@ rdcarray<ShaderDebugState> Debugger::ContinueDebug()
}
else
{
thread.StepNext(NULL, oldworkgroup);
thread.StepNext(NULL, workgroup);
}
}
}