Change how pixel debug quad is generated from derivatives

* Should be a bit more accurate, making some assumptions about coarse
  and fine derivatives, but hopefully means shader debugging is less
  divergent from the actual output.
This commit is contained in:
baldurk
2015-07-14 21:09:25 +02:00
parent 441e30187d
commit 8552c18efc
3 changed files with 140 additions and 21 deletions
+114 -8
View File
@@ -1451,7 +1451,7 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
if(rtView != NULL)
uavslot = 1;
extractHlsl += "struct PSInitialData { uint hit; float3 pos; uint prim; uint fface; uint sample; uint covge; float derivValid; PSInput IN; PSInput INddx; PSInput INddy; };\n\n";
extractHlsl += "struct PSInitialData { uint hit; float3 pos; uint prim; uint fface; uint sample; uint covge; float derivValid; PSInput IN; PSInput INddx; PSInput INddy; PSInput INddxfine; PSInput INddyfine; };\n\n";
extractHlsl += "RWStructuredBuffer<PSInitialData> PSInitialBuffer : register(u" + ToStr::Get(uavslot) + ");\n\n";
extractHlsl += "void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim : SV_PrimitiveID, uint sample : SV_SampleIndex, uint covge : SV_Coverage, bool fface : SV_IsFrontFace)\n{\n";
extractHlsl += " uint idx = " + ToStr::Get(overdrawLevels) + ";\n";
@@ -1467,11 +1467,16 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
extractHlsl += " PSInitialBuffer[idx].derivValid = ddx(debug_pixelPos.x);\n";
extractHlsl += " PSInitialBuffer[idx].INddx = (PSInput)0;\n";
extractHlsl += " PSInitialBuffer[idx].INddy = (PSInput)0;\n";
extractHlsl += " PSInitialBuffer[idx].INddxfine = (PSInput)0;\n";
extractHlsl += " PSInitialBuffer[idx].INddyfine = (PSInput)0;\n";
for(size_t i=0; i < floatInputs.size(); i++)
{
const string &name = floatInputs[i];
extractHlsl += " PSInitialBuffer[idx].INddx." + name + " = ddx(IN." + name + ");\n";
extractHlsl += " PSInitialBuffer[idx].INddy." + name + " = ddy(IN." + name + ");\n";
extractHlsl += " PSInitialBuffer[idx].INddxfine." + name + " = ddx_fine(IN." + name + ");\n";
extractHlsl += " PSInitialBuffer[idx].INddyfine." + name + " = ddy_fine(IN." + name + ");\n";
}
extractHlsl += "\n}";
@@ -1484,7 +1489,7 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
+ sizeof(uint32_t) // uint sample;
+ sizeof(uint32_t) // uint covge;
+ sizeof(float) // float derivValid;
+ structureStride*3; // PSInput IN, INddx, INddy;
+ structureStride*5; // PSInput IN, INddx, INddy, INddxfine, INddyfine;
HRESULT hr = S_OK;
@@ -1588,6 +1593,7 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
State quad[4];
// figure out the TL pixel's coords. Assume even top left (towards 0,0)
// this isn't spec'd but is a reasonable assumption.
int xTL = x&(~1);
int yTL = y&(~1);
@@ -1734,6 +1740,32 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
quad[i].SetHelper();
}
// We make the assumption that the coarse derivatives are
// generated from (0,0) in the quad, and fine derivatives
// are generated from the destination index and its
// neighbours in X and Y.
// This isn't spec'd but we must assume something and this
// will hopefully get us closest to reproducing actual
// results.
//
// For debugging, we need members of the quad to be able
// to generate coarse and fine derivatives.
//
// For (0,0) we only need the coarse derivatives to get
// our neighbours (1,0) and (0,1) which will give us
// coarse and fine derivatives being identical.
//
// For the others we will need to use a combination of
// coarse and fine derivatives to get the diagonal element
// in the quad. E.g. for (1,1):
//
// (1,0) = (1,1) - ddx_fine
// (0,1) = (1,1) - ddy_fine
// (0,0) = (1,1) - ddy_fine - ddx_coarse
//
// This only works if coarse and fine are calculated as we
// are assuming.
ddx = (float *)data;
for(size_t i=0; i < initialValues.size(); i++)
@@ -1742,8 +1774,7 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
if(initialValues[i].reg >= 0)
{
// left
if(destIdx == 0 || destIdx == 2)
if(destIdx == 0)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
@@ -1751,7 +1782,7 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
traces[3].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddx[w];
}
}
else
else if(destIdx == 1)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
@@ -1759,6 +1790,20 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
traces[2].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddx[w];
}
}
else if(destIdx == 2)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
traces[1].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddx[w];
}
}
else if(destIdx == 3)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
traces[0].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddx[w];
}
}
}
ddx += initialValues[i].numwords;
@@ -1772,8 +1817,7 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
if(initialValues[i].reg >= 0)
{
// top
if(destIdx == 0 || destIdx == 1)
if(destIdx == 0)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
@@ -1781,7 +1825,14 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
traces[3].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddy[w];
}
}
else
else if(destIdx == 1)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
traces[2].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddy[w];
}
}
else if(destIdx == 2)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
@@ -1793,6 +1844,61 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI
ddy += initialValues[i].numwords;
}
float *ddxfine = ddy;
for(size_t i=0; i < initialValues.size(); i++)
{
if(!initialValues[i].included) continue;
if(initialValues[i].reg >= 0)
{
if(destIdx == 2)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
traces[3].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddxfine[w];
}
}
else if(destIdx == 3)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
traces[2].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddxfine[w];
}
}
}
ddxfine += initialValues[i].numwords;
}
float *ddyfine = ddxfine;
for(size_t i=0; i < initialValues.size(); i++)
{
if(!initialValues[i].included) continue;
if(initialValues[i].reg >= 0)
{
if(destIdx == 1)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
traces[3].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] += ddyfine[w];
}
}
else if(destIdx == 3)
{
for(int w=0; w < initialValues[i].numwords; w++)
{
traces[1].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddyfine[w];
traces[0].inputs[initialValues[i].reg].value.fv[initialValues[i].elem+w] -= ddyfine[w];
}
}
}
ddyfine += initialValues[i].numwords;
}
}
vector<ShaderDebugState> states;
+24 -11
View File
@@ -703,14 +703,20 @@ void State::SetDst(const ASMOperand &dstoper, const ASMOperation &op, const Shad
}
}
ShaderVariable State::DDX(State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const
ShaderVariable State::DDX(bool fine, State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const
{
ShaderVariable ret;
VarType optype = OperationType(op.operation);
// left pixel in the quad
if(quadIndex % 2 == 0)
if(!fine)
{
// use top-left pixel's neighbours
ret =
sub(quad[1].GetSrc(oper, op), quad[0].GetSrc(oper, op), optype);
}
// find direct neighbours - left pixel in the quad
else if(quadIndex % 2 == 0)
{
ret =
sub(quad[quadIndex+1].GetSrc(oper, op), quad[quadIndex].GetSrc(oper, op), optype);
@@ -724,14 +730,20 @@ ShaderVariable State::DDX(State quad[4], const DXBC::ASMOperand &oper, const DXB
return ret;
}
ShaderVariable State::DDY(State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const
ShaderVariable State::DDY(bool fine, State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const
{
ShaderVariable ret;
VarType optype = OperationType(op.operation);
// top pixel in the quad
if(quadIndex / 2 == 0)
if(!fine)
{
// use top-left pixel's neighbours
ret =
sub(quad[2].GetSrc(oper, op), quad[0].GetSrc(oper, op), optype);
}
// find direct neighbours - top pixel in the quad
else if(quadIndex / 2 == 0)
{
ret =
sub(quad[quadIndex+2].GetSrc(oper, op), quad[quadIndex].GetSrc(oper, op), optype);
@@ -1861,7 +1873,7 @@ State State::GetNext(GlobalState &global, State quad[4]) const
if(quad == NULL)
RDCERR("Attempt to use derivative instruction not in pixel shader. Undefined results will occur!");
else
s.SetDst(op.operands[0], op, s.DDX(quad, op.operands[1], op));
s.SetDst(op.operands[0], op, s.DDX(op.operation == OPCODE_DERIV_RTX_FINE, quad, op.operands[1], op));
break;
case OPCODE_DERIV_RTY:
case OPCODE_DERIV_RTY_COARSE:
@@ -1869,7 +1881,7 @@ State State::GetNext(GlobalState &global, State quad[4]) const
if(quad == NULL)
RDCERR("Attempt to use derivative instruction not in pixel shader. Undefined results will occur!");
else
s.SetDst(op.operands[0], op, s.DDY(quad, op.operands[1], op));
s.SetDst(op.operands[0], op, s.DDY(op.operation == OPCODE_DERIV_RTY_FINE, quad, op.operands[1], op));
break;
/////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -3539,8 +3551,9 @@ State State::GetNext(GlobalState &global, State quad[4]) const
}
else
{
ddxCalc = s.DDX(quad, op.operands[1], op);
ddyCalc = s.DDY(quad, op.operands[1], op);
// texture samples use coarse derivatives
ddxCalc = s.DDX(false, quad, op.operands[1], op);
ddyCalc = s.DDY(false, quad, op.operands[1], op);
}
}
else if(op.operation == OPCODE_SAMPLE_D)
+2 -2
View File
@@ -163,8 +163,8 @@ class State : public ShaderDebugState
// negation/abs functions
ShaderVariable GetSrc(const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const;
ShaderVariable DDX(State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const;
ShaderVariable DDY(State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const;
ShaderVariable DDX(bool fine, State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const;
ShaderVariable DDY(bool fine, State quad[4], const DXBC::ASMOperand &oper, const DXBC::ASMOperation &op) const;
VarType OperationType(const DXBC::OpcodeType &op) const;