Refactor ShaderDebugTrace to not return a single list of complete states

* The ShaderDebugTrace now only sets up the initial state of an opaque
  ShaderDebugger handle.
* This handle can then be passed to a new function - ContinueDebug - to
  iteratively return N more states. The number of states is implementation
  defined and may be a fixed number or it may run for a fixed time.
* The states themselves no longer contain a complete snapshot of all variables,
  but instead only the changed variables for that iteration. The changes are
  stored as before and after value to make it easier to step forwards and
  backwards (only the ShaderDebugState is needed to move forward or backwards,
  you don't have to search back for the last set value of a variable to 'undo' a
  change).
This commit is contained in:
baldurk
2020-02-06 17:58:42 +00:00
parent fa9289c372
commit 661ee35f30
29 changed files with 1804 additions and 1705 deletions
+2 -2
View File
@@ -588,13 +588,13 @@ struct IShaderViewer
:return: The current step.
:rtype: ``int``
)");
virtual int CurrentStep() = 0;
virtual uint32_t CurrentStep() = 0;
DOCUMENT(R"(Sets the current step in the debugging.
:param int step: The current step to jump to.
)");
virtual void SetCurrentStep(int step) = 0;
virtual void SetCurrentStep(uint32_t step) = 0;
DOCUMENT(R"(Toggles a breakpoint at a given instruction.
+1
View File
@@ -320,6 +320,7 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderSampler)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderSourceFile)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderVariable)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderEncoding)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderVariableChange)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, DebugVariableReference)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, SourceVariableMapping)
TEMPLATE_ARRAY_INSTANTIATE(rdcarray, SigParameter)
+1 -1
View File
@@ -3810,7 +3810,7 @@ void BufferViewer::debugVertex()
trace = r->DebugVertex(vertid, m_Config.curInstance, index, m_Ctx.CurDrawcall()->instanceOffset,
m_Ctx.CurDrawcall()->vertexOffset);
if(trace->states.isEmpty())
if(trace->debugger == NULL)
{
r->FreeTrace(trace);
trace = NULL;
@@ -3138,7 +3138,7 @@ void D3D11PipelineStateViewer::on_debugThread_clicked()
m_Ctx.Replay().AsyncInvoke([&trace, &done, thread](IReplayController *r) {
trace = r->DebugThread(thread.g, thread.t);
if(trace->states.isEmpty())
if(trace->debugger == NULL)
{
r->FreeTrace(trace);
trace = NULL;
+1 -1
View File
@@ -720,7 +720,7 @@ void PixelHistoryView::startDebug(EventTag tag)
trace = r->DebugPixel((uint32_t)m_Pixel.x(), (uint32_t)m_Pixel.y(),
m_Display.subresource.sample, tag.primitive);
if(trace->states.isEmpty())
if(trace->debugger == NULL)
{
r->FreeTrace(trace);
trace = NULL;
+337 -200
View File
@@ -45,16 +45,12 @@ namespace
struct VariableTag
{
VariableTag() : offset(0), globalSourceVar(-1), localSourceVar(-1) {}
VariableTag(QString name, uint32_t offs, int32_t globalVar, int32_t localVar)
: fullname(name), offset(offs), globalSourceVar(globalVar), localSourceVar(localVar)
VariableTag(rdcstr name, uint32_t offs, int32_t globalVar, int32_t localVar)
: offset(offs), globalSourceVar(globalVar), localSourceVar(localVar)
{
debugVar.name = name;
}
VariableTag(QString name, DebugVariableReference var) : fullname(name), offset(0), debugVar(var)
{
}
QString fullname;
VariableTag(DebugVariableReference var) : offset(0), debugVar(var) {}
uint32_t offset;
int32_t globalSourceVar;
int32_t localSourceVar;
@@ -392,27 +388,6 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
m_DisassemblyView->setReadOnly(false);
SetTextAndUpdateMargin0(m_DisassemblyView, disasm);
m_DisassemblyView->setReadOnly(true);
bool preferSourceDebug = false;
for(const ShaderCompileFlag &flag : m_ShaderDetails->debugInfo.compileFlags.flags)
{
if(flag.name == "preferSourceDebug")
{
preferSourceDebug = true;
break;
}
}
updateDebugging();
// we do updateDebugging() again because the first call finds the scintilla for the current
// source file, the second time jumps to it.
if(preferSourceDebug)
{
gotoSourceDebugging();
updateDebugging();
}
});
});
}
@@ -641,7 +616,47 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
ui->debugVars->installEventFilter(this);
ui->watch->installEventFilter(this);
SetCurrentStep(0);
m_Ctx.Replay().AsyncInvoke([this](IReplayController *r) {
rdcarray<ShaderDebugState> states = r->ContinueDebug(m_Trace->debugger);
bool finished = false;
do
{
rdcarray<ShaderDebugState> nextStates = r->ContinueDebug(m_Trace->debugger);
states.append(nextStates);
finished = nextStates.empty();
} while(!finished);
m_States = states;
for(const ShaderVariableChange &c : GetCurrentState().changes)
m_Variables.push_back(c.after);
GUIInvoke::call(this, [this]() {
bool preferSourceDebug = false;
for(const ShaderCompileFlag &flag : m_ShaderDetails->debugInfo.compileFlags.flags)
{
if(flag.name == "preferSourceDebug")
{
preferSourceDebug = true;
break;
}
}
updateDebugState();
// we do updateDebugging() again because the first call finds the scintilla for the current
// source file, the second time jumps to it.
if(preferSourceDebug)
{
gotoSourceDebugging();
updateDebugState();
}
});
});
m_CurrentStateIdx = 0;
QObject::connect(ui->watch, &RDTableWidget::keyPress, this, &ShaderViewer::watch_keyPress);
@@ -873,7 +888,7 @@ void ShaderViewer::OnCaptureClosed()
void ShaderViewer::OnEventChanged(uint32_t eventId)
{
updateDebugging();
updateDebugState();
updateWindowTitle();
}
@@ -1000,7 +1015,7 @@ void ShaderViewer::debug_contextMenu(const QPoint &pos)
else
gotoDisassemblyDebugging();
updateDebugging();
updateDebugState();
});
QAction intDisplay(tr("Integer register display"), this);
@@ -1129,7 +1144,7 @@ void ShaderViewer::variables_contextMenu(const QPoint &pos)
QObject::connect(&addWatch, &QAction::triggered, [this, tree] {
if(tree == ui->sourceVars)
AddWatch(tree->selectedItem()->tag().value<VariableTag>().fullname);
AddWatch(tree->selectedItem()->tag().value<VariableTag>().debugVar.name);
else
AddWatch(tree->selectedItem()->text(0));
});
@@ -1304,7 +1319,7 @@ void ShaderViewer::on_watch_itemChanged(QTableWidgetItem *item)
recurse = false;
updateDebugging();
updateDebugState();
}
bool ShaderViewer::stepBack()
@@ -1312,39 +1327,50 @@ bool ShaderViewer::stepBack()
if(!m_Trace)
return false;
if(CurrentStep() == 0)
if(IsFirstState())
return false;
if(isSourceDebugging())
{
const ShaderDebugState &oldstate = m_Trace->states[CurrentStep()];
LineColumnInfo oldLine = m_Trace->lineInfo[GetCurrentState().nextInstruction];
LineColumnInfo oldLine =
m_Trace->lineInfo[qMin(m_Trace->lineInfo.size() - 1, (size_t)oldstate.nextInstruction)];
while(CurrentStep() < m_Trace->states.count())
// first step to the next instruction in a backwards direction that's on a different line from
// the current one
do
{
m_CurrentStep--;
applyBackwardsChange();
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
if(m_Breakpoints.contains((int)state.nextInstruction))
if(m_Breakpoints.contains((int)GetCurrentState().nextInstruction))
break;
if(m_CurrentStep == 0)
if(IsFirstState())
break;
if(m_Trace->lineInfo[state.nextInstruction].sourceEqual(oldLine))
if(m_Trace->lineInfo[GetCurrentState().nextInstruction].sourceEqual(oldLine))
continue;
break;
} while(true);
oldLine = m_Trace->lineInfo[GetCurrentState().nextInstruction];
// now since a line can have multiple instructions, keep stepping (looking forward) until we
// reach the first instruction with an identical line info
while(!IsFirstState() &&
m_Trace->lineInfo[GetPreviousState().nextInstruction].sourceEqual(oldLine))
{
applyBackwardsChange();
if(m_Breakpoints.contains((int)GetCurrentState().nextInstruction))
break;
}
SetCurrentStep(CurrentStep());
updateDebugState();
}
else
{
SetCurrentStep(CurrentStep() - 1);
applyBackwardsChange();
updateDebugState();
}
return true;
@@ -1355,38 +1381,35 @@ bool ShaderViewer::stepNext()
if(!m_Trace)
return false;
if(CurrentStep() + 1 >= m_Trace->states.count())
if(IsLastState())
return false;
if(isSourceDebugging())
{
const ShaderDebugState &oldstate = m_Trace->states[CurrentStep()];
LineColumnInfo oldLine = m_Trace->lineInfo[GetCurrentState().nextInstruction];
LineColumnInfo oldLine = m_Trace->lineInfo[oldstate.nextInstruction];
while(CurrentStep() < m_Trace->states.count())
do
{
m_CurrentStep++;
applyForwardsChange();
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
if(m_Breakpoints.contains((int)state.nextInstruction))
if(m_Breakpoints.contains((int)GetCurrentState().nextInstruction))
break;
if(m_CurrentStep + 1 >= m_Trace->states.count())
if(IsLastState())
break;
if(m_Trace->lineInfo[state.nextInstruction].sourceEqual(oldLine))
if(m_Trace->lineInfo[GetCurrentState().nextInstruction].sourceEqual(oldLine))
continue;
break;
}
} while(true);
SetCurrentStep(CurrentStep());
updateDebugState();
}
else
{
SetCurrentStep(CurrentStep() + 1);
applyForwardsChange();
updateDebugState();
}
return true;
@@ -1450,6 +1473,40 @@ int ShaderViewer::instructionForDisassemblyLine(sptr_t line)
return -1;
}
bool ShaderViewer::IsFirstState() const
{
return m_CurrentStateIdx == 0;
}
bool ShaderViewer::IsLastState() const
{
return m_CurrentStateIdx == m_States.size() - 1;
}
const ShaderDebugState &ShaderViewer::GetPreviousState() const
{
if(m_CurrentStateIdx > 0)
return m_States[m_CurrentStateIdx - 1];
return m_States.front();
}
const ShaderDebugState &ShaderViewer::GetCurrentState() const
{
if(m_CurrentStateIdx < m_States.size())
return m_States[m_CurrentStateIdx];
return m_States.back();
}
const ShaderDebugState &ShaderViewer::GetNextState() const
{
if(m_CurrentStateIdx + 1 < m_States.size())
return m_States[m_CurrentStateIdx + 1];
return m_States.back();
}
void ShaderViewer::runToSample()
{
runTo({}, true, ShaderEvents::SampleLoadGather);
@@ -1475,33 +1532,125 @@ void ShaderViewer::runTo(QVector<size_t> runToInstruction, bool forward, ShaderE
if(!m_Trace)
return;
int step = CurrentStep();
int inc = forward ? 1 : -1;
bool firstStep = true;
while(step < m_Trace->states.count())
// this is effectively infinite as we break out before moving to next/previous state if that would
// be first/last
while((forward && !IsLastState()) || (!forward && !IsFirstState()))
{
if(runToInstruction.contains(m_Trace->states[step].nextInstruction))
// break immediately even on the very first step if it's the one we want to go to
if(runToInstruction.contains(GetCurrentState().nextInstruction))
break;
if(!firstStep && (step + inc >= 0) && (step + inc < m_Trace->states.count()) &&
(m_Trace->states[step + inc].flags & condition))
// after the first step, break on condition
if(!firstStep && (GetCurrentState().flags & condition))
break;
if(!firstStep && m_Breakpoints.contains((int)m_Trace->states[step].nextInstruction))
// or breakpoint
if(!firstStep && m_Breakpoints.contains((int)GetCurrentState().nextInstruction))
break;
firstStep = false;
if(step + inc < 0 || step + inc >= m_Trace->states.count())
break;
step += inc;
if(forward)
{
if(IsLastState())
break;
applyForwardsChange();
}
else
{
if(IsFirstState())
break;
applyBackwardsChange();
}
}
SetCurrentStep(step);
updateDebugState();
}
void ShaderViewer::applyBackwardsChange()
{
if(!IsFirstState())
{
for(const ShaderVariableChange &c : GetCurrentState().changes)
{
// if the before name is empty, this is a variable that came into scope/was created
if(c.before.name.empty())
{
// delete the matching variable (should only be one)
for(size_t i = 0; i < m_Variables.size(); i++)
{
if(c.after.name == m_Variables[i].name)
{
m_Variables.erase(i);
break;
}
}
}
else
{
ShaderVariable *v = NULL;
for(size_t i = 0; i < m_Variables.size(); i++)
{
if(c.before.name == m_Variables[i].name)
{
v = &m_Variables[i];
break;
}
}
if(v)
*v = c.before;
else
m_Variables.push_back(c.before);
}
}
m_CurrentStateIdx--;
}
}
void ShaderViewer::applyForwardsChange()
{
if(!IsLastState())
{
m_CurrentStateIdx++;
for(const ShaderVariableChange &c : GetCurrentState().changes)
{
// if the after name is empty, this is a variable going out of scope/being deleted
if(c.after.name.empty())
{
// delete the matching variable (should only be one)
for(size_t i = 0; i < m_Variables.size(); i++)
{
if(c.before.name == m_Variables[i].name)
{
m_Variables.erase(i);
break;
}
}
}
else
{
ShaderVariable *v = NULL;
for(size_t i = 0; i < m_Variables.size(); i++)
{
if(c.after.name == m_Variables[i].name)
{
v = &m_Variables[i];
break;
}
}
if(v)
*v = c.after;
else
m_Variables.push_back(c.after);
}
}
}
}
QString ShaderViewer::stringRep(const ShaderVariable &var)
@@ -1672,7 +1821,7 @@ RDTreeWidgetItem *ShaderViewer::findVarInTree(RDTreeWidgetItem *root, QString na
{
if(fullmatch)
{
if(root->tag().value<VariableTag>().fullname == name)
if(root->tag().value<VariableTag>().debugVar.name == rdcstr(name))
return root;
}
else
@@ -1760,7 +1909,7 @@ bool ShaderViewer::getVar(RDTreeWidgetItem *item, ShaderVariable *var, QString *
if(reg)
{
*var = *reg;
var->name = tag.fullname;
var->name = tag.debugVar.name;
if(regNames)
*regNames = reg->name;
@@ -1780,9 +1929,8 @@ bool ShaderViewer::getVar(RDTreeWidgetItem *item, ShaderVariable *var, QString *
if(tag.globalSourceVar >= 0 && tag.globalSourceVar < m_Trace->sourceVars.count())
mapping = m_Trace->sourceVars[tag.globalSourceVar];
else if(tag.localSourceVar >= 0 &&
tag.localSourceVar < m_Trace->states[m_CurrentStep].sourceVars.count())
mapping = m_Trace->states[m_CurrentStep].sourceVars[tag.localSourceVar];
else if(tag.localSourceVar >= 0 && tag.localSourceVar < GetCurrentState().sourceVars.count())
mapping = GetCurrentState().sourceVars[tag.localSourceVar];
else
qCritical() << "Couldn't find expected source variable!" << tag.globalSourceVar
<< tag.localSourceVar;
@@ -1801,7 +1949,7 @@ bool ShaderViewer::getVar(RDTreeWidgetItem *item, ShaderVariable *var, QString *
return true;
ShaderVariable &ret = *var;
ret.name = tag.fullname;
ret.name = tag.debugVar.name;
ret.rowMajor = true;
ret.rows = mapping.rows;
ret.columns = mapping.columns;
@@ -1862,7 +2010,7 @@ void ShaderViewer::highlightMatchingVars(RDTreeWidgetItem *root, const QString v
for(int i = 0; i < root->childCount(); i++)
{
RDTreeWidgetItem *item = root->child(i);
if(item->tag().value<VariableTag>().fullname == varName)
if(item->tag().value<VariableTag>().debugVar.name == rdcstr(varName))
item->setBackgroundColor(highlightColor);
else
item->setBackground(QBrush());
@@ -1871,9 +2019,9 @@ void ShaderViewer::highlightMatchingVars(RDTreeWidgetItem *root, const QString v
}
}
void ShaderViewer::updateDebugging()
void ShaderViewer::updateDebugState()
{
if(!m_Trace || m_CurrentStep < 0 || m_CurrentStep >= m_Trace->states.count())
if(!m_Trace || m_States.empty())
return;
if(ui->debugToggle->isEnabled())
@@ -1884,16 +2032,9 @@ void ShaderViewer::updateDebugging()
ui->debugToggle->setText(tr("Debug in Source"));
}
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
const ShaderDebugState &state = GetCurrentState();
uint32_t nextInst = state.nextInstruction;
bool done = false;
if(m_CurrentStep == m_Trace->states.count() - 1)
{
nextInst--;
done = true;
}
const bool done = IsLastState();
// add current instruction marker
m_DisassemblyView->markerDeleteAll(CURRENT_MARKER);
@@ -2027,7 +2168,7 @@ void ShaderViewer::updateDebugging()
RDTreeWidgetItem *node = new RDTreeWidgetItem({name, name, lit("Constant"), QString()});
node->setTag(QVariant::fromValue(
VariableTag(name, DebugVariableReference(DebugVariableType::Constant, name))));
VariableTag(DebugVariableReference(DebugVariableType::Constant, name))));
for(int j = 0; j < m_Trace->constantBlocks[i].members.count(); j++)
{
@@ -2040,7 +2181,7 @@ void ShaderViewer::updateDebugging()
RDTreeWidgetItem *child = new RDTreeWidgetItem(
{name, name, lit("Constant"), stringRep(m_Trace->constantBlocks[i].members[j])});
child->setTag(QVariant::fromValue(
VariableTag(name, DebugVariableReference(DebugVariableType::Constant, name))));
VariableTag(DebugVariableReference(DebugVariableType::Constant, name))));
node->addChild(child);
}
}
@@ -2067,7 +2208,7 @@ void ShaderViewer::updateDebugging()
RDTreeWidgetItem *node =
new RDTreeWidgetItem({input.name, input.name, lit("Input"), stringRep(input)});
node->setTag(QVariant::fromValue(
VariableTag(input.name, DebugVariableReference(DebugVariableType::Input, input.name))));
VariableTag(DebugVariableReference(DebugVariableType::Input, input.name))));
ui->constants->addTopLevelItem(node);
}
@@ -2104,8 +2245,8 @@ void ShaderViewer::updateDebugging()
RDTreeWidgetItem *node =
new RDTreeWidgetItem({m_ShaderDetails->readOnlyResources[i].name, ro.name,
lit("Resource"), ToQStr(roBind.resources[0].resourceId)});
node->setTag(QVariant::fromValue(VariableTag(
ro.name, DebugVariableReference(DebugVariableType::ReadOnlyResource, ro.name))));
node->setTag(QVariant::fromValue(
VariableTag(DebugVariableReference(DebugVariableType::ReadOnlyResource, ro.name))));
if(node)
ui->constants->addTopLevelItem(node);
}
@@ -2114,8 +2255,8 @@ void ShaderViewer::updateDebugging()
RDTreeWidgetItem *node =
new RDTreeWidgetItem({m_ShaderDetails->readOnlyResources[i].name, ro.name,
QFormatStr("[%1]").arg(bind.arraySize), QString()});
node->setTag(QVariant::fromValue(VariableTag(
ro.name, DebugVariableReference(DebugVariableType::ReadOnlyResource, ro.name))));
node->setTag(QVariant::fromValue(
VariableTag(DebugVariableReference(DebugVariableType::ReadOnlyResource, ro.name))));
for(uint32_t a = 0; a < bind.arraySize; a++)
{
@@ -2124,8 +2265,8 @@ void ShaderViewer::updateDebugging()
QFormatStr("%1[%2]").arg(m_ShaderDetails->readOnlyResources[i].name).arg(a),
childName, lit("Resource"), ToQStr(roBind.resources[a].resourceId),
});
child->setTag(QVariant::fromValue(VariableTag(
childName, DebugVariableReference(DebugVariableType::ReadOnlyResource, childName))));
child->setTag(QVariant::fromValue(
VariableTag(DebugVariableReference(DebugVariableType::ReadOnlyResource, childName))));
node->addChild(child);
}
@@ -2164,8 +2305,8 @@ void ShaderViewer::updateDebugging()
RDTreeWidgetItem *node =
new RDTreeWidgetItem({m_ShaderDetails->readWriteResources[i].name, rw.name,
lit("Resource"), ToQStr(rwBind.resources[0].resourceId)});
node->setTag(QVariant::fromValue(VariableTag(
rw.name, DebugVariableReference(DebugVariableType::ReadOnlyResource, rw.name))));
node->setTag(QVariant::fromValue(
VariableTag(DebugVariableReference(DebugVariableType::ReadOnlyResource, rw.name))));
if(node)
ui->constants->addTopLevelItem(node);
}
@@ -2174,8 +2315,8 @@ void ShaderViewer::updateDebugging()
RDTreeWidgetItem *node =
new RDTreeWidgetItem({m_ShaderDetails->readWriteResources[i].name, rw.name,
QFormatStr("[%1]").arg(bind.arraySize), QString()});
node->setTag(QVariant::fromValue(VariableTag(
rw.name, DebugVariableReference(DebugVariableType::ReadOnlyResource, rw.name))));
node->setTag(QVariant::fromValue(
VariableTag(DebugVariableReference(DebugVariableType::ReadOnlyResource, rw.name))));
for(uint32_t a = 0; a < bind.arraySize; a++)
{
@@ -2184,8 +2325,8 @@ void ShaderViewer::updateDebugging()
QFormatStr("%1[%2]").arg(m_ShaderDetails->readWriteResources[i].name).arg(a),
childName, lit("RW Resource"), ToQStr(rwBind.resources[a].resourceId),
});
child->setTag(QVariant::fromValue(VariableTag(
childName, DebugVariableReference(DebugVariableType::ReadWriteResource, childName))));
child->setTag(QVariant::fromValue(
VariableTag(DebugVariableReference(DebugVariableType::ReadWriteResource, childName))));
node->addChild(child);
}
@@ -2199,6 +2340,8 @@ void ShaderViewer::updateDebugging()
RDTreeViewExpansionState expansion;
ui->sourceVars->saveExpansion(expansion, 0);
ui->sourceVars->beginUpdate();
ui->sourceVars->clear();
RDTreeWidgetItem fakeroot;
@@ -2214,13 +2357,13 @@ void ShaderViewer::updateDebugging()
bool modified = false;
if(!l.variables.empty() && l.variables[0].type == DebugVariableType::Variable)
if(l.variables[0].type == DebugVariableType::Variable)
{
for(const DebugVariableReference &r : l.variables)
for(const DebugVariableReference &v : l.variables)
{
for(const DebugVariableReference &mr : state.modified)
for(const ShaderVariableChange &c : GetCurrentState().changes)
{
if(mr.name == r.name)
if(c.before.name == v.name || c.after.name == v.name)
{
modified = true;
break;
@@ -2246,74 +2389,40 @@ void ShaderViewer::updateDebugging()
while(fakeroot.childCount() > 0)
ui->sourceVars->addTopLevelItem(fakeroot.takeChild(0));
ui->sourceVars->endUpdate();
ui->sourceVars->applyExpansion(expansion, 0);
}
if(ui->debugVars->topLevelItemCount() == 0)
{
for(int i = 0; i < state.variables.count(); i++)
RDTreeViewExpansionState expansion;
ui->debugVars->saveExpansion(expansion, 0);
ui->debugVars->beginUpdate();
ui->debugVars->clear();
for(int i = 0; i < m_Variables.count(); i++)
{
RDTreeWidgetItem *node = new RDTreeWidgetItem({state.variables[i].name, QString()});
node->setTag(QVariant::fromValue(VariableTag(
state.variables[i].name,
DebugVariableReference(DebugVariableType::Variable, state.variables[i].name))));
for(int t = 0; t < state.variables[i].members.count(); t++)
bool modified = false;
for(const ShaderVariableChange &c : GetCurrentState().changes)
{
RDTreeWidgetItem *child =
new RDTreeWidgetItem({state.variables[i].members[t].name, QString()});
child->setTag(QVariant::fromValue(VariableTag(
state.variables[i].members[t].name,
DebugVariableReference(DebugVariableType::Variable, state.variables[i].members[t].name))));
node->addChild(child);
if(c.before.name == m_Variables[i].name || c.after.name == m_Variables[i].name)
{
modified = true;
break;
}
}
ui->debugVars->addTopLevelItem(node);
ui->debugVars->addTopLevelItem(makeDebugVariableNode(m_Variables[i], "", modified));
}
ui->debugVars->endUpdate();
ui->sourceVars->applyExpansion(expansion, 0);
}
ui->debugVars->beginUpdate();
for(int i = 0; i < state.variables.count(); i++)
{
RDTreeWidgetItem *node = ui->debugVars->topLevelItem(i);
bool modified = false;
for(const DebugVariableReference &mr : state.modified)
{
if(mr.name == state.variables[i].name)
{
modified = true;
break;
}
}
if(state.variables[i].members.empty())
{
node->setText(1, stringRep(state.variables[i]));
if(modified)
node->setForegroundColor(QColor(Qt::red));
else
node->setForeground(QBrush());
}
else
{
for(int t = 0; t < state.variables[i].members.count(); t++)
{
RDTreeWidgetItem *child = node->child(t);
if(modified)
child->setForegroundColor(QColor(Qt::red));
else
child->setForeground(QBrush());
child->setText(1, stringRep(state.variables[i].members[t]));
}
}
}
ui->debugVars->endUpdate();
updateWatchVariables();
ui->debugVars->resizeColumnToContents(0);
@@ -2324,8 +2433,6 @@ void ShaderViewer::updateDebugging()
void ShaderViewer::updateWatchVariables()
{
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
ui->watch->setUpdatesEnabled(false);
for(int i = 0; i < ui->watch->rowCount() - 1; i++)
@@ -2554,8 +2661,6 @@ void ShaderViewer::updateWatchVariables()
RDTreeWidgetItem *ShaderViewer::makeSourceVariableNode(const SourceVariableMapping &l,
int globalVarIdx, int localVarIdx)
{
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
const QString xyzw = lit("xyzw");
QString localName = l.name;
@@ -2712,6 +2817,27 @@ RDTreeWidgetItem *ShaderViewer::makeSourceVariableNode(const SourceVariableMappi
return node;
}
RDTreeWidgetItem *ShaderViewer::makeDebugVariableNode(const ShaderVariable &v, rdcstr prefix,
bool modified)
{
rdcstr basename = prefix + v.name;
RDTreeWidgetItem *node = new RDTreeWidgetItem({basename, stringRep(v)});
node->setTag(QVariant::fromValue(
VariableTag(DebugVariableReference(DebugVariableType::Variable, basename))));
for(const ShaderVariable &m : v.members)
{
rdcstr childprefix = basename + ".";
if(m.name.beginsWith(basename + "["))
childprefix = prefix;
node->addChild(makeDebugVariableNode(m, childprefix, modified));
}
if(modified)
node->setForegroundColor(QColor(Qt::red));
return node;
}
const ShaderVariable *ShaderViewer::GetRegisterVariable(const DebugVariableReference &r)
{
if(r.type == DebugVariableType::Input)
@@ -2756,17 +2882,15 @@ const ShaderVariable *ShaderViewer::GetRegisterVariable(const DebugVariableRefer
}
else if(r.type == DebugVariableType::Variable)
{
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
for(int i = 0; i < state.variables.count(); i++)
for(int i = 0; i < m_Variables.count(); i++)
{
if(state.variables[i].name == r.name)
return &state.variables[i];
if(m_Variables[i].name == r.name)
return &m_Variables[i];
for(int j = 0; j < state.variables[i].members.count(); j++)
for(int j = 0; j < m_Variables[i].members.count(); j++)
{
if(state.variables[i].members[j].name == r.name)
return &state.variables[i].members[j];
if(m_Variables[i].members[j].name == r.name)
return &m_Variables[i].members[j];
}
}
@@ -2785,19 +2909,34 @@ void ShaderViewer::ensureLineScrolled(ScintillaEdit *s, int line)
s->setFirstVisibleLine(qMax(0, line - linesVisible / 2));
}
int ShaderViewer::CurrentStep()
uint32_t ShaderViewer::CurrentStep()
{
return m_CurrentStep;
return (uint32_t)m_CurrentStateIdx;
}
void ShaderViewer::SetCurrentStep(int step)
void ShaderViewer::SetCurrentStep(uint32_t step)
{
if(m_Trace && !m_Trace->states.empty())
m_CurrentStep = qBound(0, step, m_Trace->states.count() - 1);
else
m_CurrentStep = 0;
while(GetCurrentState().stepIndex != step)
{
if(GetCurrentState().stepIndex < step)
{
// move forward if possible
if(!IsLastState())
applyForwardsChange();
else
break;
}
else
{
// move backward if possible
if(!IsFirstState())
applyBackwardsChange();
else
break;
}
}
updateDebugging();
updateDebugState();
}
void ShaderViewer::ToggleBreakpoint(int instruction)
@@ -3361,7 +3500,7 @@ bool ShaderViewer::eventFilter(QObject *watched, QEvent *event)
if(item)
{
VariableTag tag = item->tag().value<VariableTag>();
showVariableTooltip(tag.fullname);
showVariableTooltip(tag.debugVar.name);
}
}
@@ -3373,7 +3512,7 @@ bool ShaderViewer::eventFilter(QObject *watched, QEvent *event)
{
item = table->item(item->row(), 2);
VariableTag tag = item->data(Qt::UserRole).value<VariableTag>();
showVariableTooltip(tag.fullname);
showVariableTooltip(tag.debugVar.name);
}
}
}
@@ -3388,7 +3527,7 @@ bool ShaderViewer::eventFilter(QObject *watched, QEvent *event)
void ShaderViewer::disasm_tooltipShow(int x, int y)
{
// do nothing if there's no trace
if(!m_Trace || m_CurrentStep < 0 || m_CurrentStep >= m_Trace->states.count())
if(!m_Trace || m_States.empty())
return;
ScintillaEdit *sc = qobject_cast<ScintillaEdit *>(QObject::sender());
@@ -3442,11 +3581,9 @@ void ShaderViewer::showVariableTooltip(QString name)
void ShaderViewer::updateVariableTooltip()
{
if(!m_Trace || m_CurrentStep < 0 || m_CurrentStep >= m_Trace->states.count())
if(!m_Trace || m_States.empty())
return;
const ShaderDebugState &state = m_Trace->states[m_CurrentStep];
ShaderVariable var;
if(!findVar(m_TooltipName, &var))
@@ -3803,7 +3940,7 @@ void ShaderViewer::on_intView_clicked()
ui->intView->setChecked(true);
ui->floatView->setChecked(false);
updateDebugging();
updateDebugState();
}
void ShaderViewer::on_floatView_clicked()
@@ -3811,7 +3948,7 @@ void ShaderViewer::on_floatView_clicked()
ui->floatView->setChecked(true);
ui->intView->setChecked(false);
updateDebugging();
updateDebugState();
}
void ShaderViewer::on_debugToggle_clicked()
@@ -3821,7 +3958,7 @@ void ShaderViewer::on_debugToggle_clicked()
else
gotoSourceDebugging();
updateDebugging();
updateDebugState();
}
ScintillaEdit *ShaderViewer::currentScintilla()
+16 -4
View File
@@ -94,8 +94,8 @@ public:
// IShaderViewer
virtual QWidget *Widget() override { return this; }
virtual int CurrentStep() override;
virtual void SetCurrentStep(int step) override;
virtual uint32_t CurrentStep() override;
virtual void SetCurrentStep(uint32_t step) override;
virtual void ToggleBreakpoint(int instruction = -1) override;
@@ -232,7 +232,9 @@ private:
CloseCallback m_CloseCallback;
ShaderDebugTrace *m_Trace = NULL;
int m_CurrentStep;
rdcarray<ShaderDebugState> m_States;
size_t m_CurrentStateIdx = 0;
rdcarray<ShaderVariable> m_Variables;
QList<int> m_Breakpoints;
static const int CURRENT_MARKER = 0;
@@ -262,11 +264,18 @@ private:
int instructionForDisassemblyLine(sptr_t line);
void updateDebugging();
bool IsFirstState() const;
bool IsLastState() const;
const ShaderDebugState &GetPreviousState() const;
const ShaderDebugState &GetCurrentState() const;
const ShaderDebugState &GetNextState() const;
void updateDebugState();
void updateWatchVariables();
RDTreeWidgetItem *makeSourceVariableNode(const SourceVariableMapping &l, int globalVarIdx,
int localVarIdx);
RDTreeWidgetItem *makeDebugVariableNode(const ShaderVariable &v, rdcstr prefix, bool modified);
const ShaderVariable *GetRegisterVariable(const DebugVariableReference &r);
@@ -277,6 +286,9 @@ private:
void runTo(QVector<size_t> runToInstructions, bool forward,
ShaderEvents condition = ShaderEvents::NoEvent);
void applyBackwardsChange();
void applyForwardsChange();
QString stringRep(const ShaderVariable &var);
void combineStructures(RDTreeWidgetItem *root, int skipPrefixLength = 0);
RDTreeWidgetItem *findVarInTree(RDTreeWidgetItem *root, QString name, bool fullmatch, int maxDepth);
+1 -1
View File
@@ -3758,7 +3758,7 @@ void TextureViewer::on_debugPixelContext_clicked()
m_Ctx.Replay().AsyncInvoke([this, &trace, &done, x, y](IReplayController *r) {
trace = r->DebugPixel((uint32_t)x, (uint32_t)y, m_TexDisplay.subresource.sample, ~0U);
if(trace->states.isEmpty())
if(trace->debugger == NULL)
{
r->FreeTrace(trace);
trace = NULL;
+14
View File
@@ -874,6 +874,20 @@ bucket when the pixel values are divided between ``minval`` and ``maxval``.
)");
virtual ShaderDebugTrace *DebugThread(const uint32_t groupid[3], const uint32_t threadid[3]) = 0;
DOCUMENT(R"(Continue a shader's debugging with a given shader debugger instance. This will run an
implementation defined number of steps and then return those steps in a list. This may be a fixed
number of steps or it may run for a fixed length of time and return as many steps as can be
calculated in that time.
This will always perform at least one step. If the list is empty, the debugging process has
completed, further calls will return an empty list.
:param ShaderDebugger debugger: The shader debugger to continue running.
:return: A number of subsequent states.
:rtype: ``list`` of :class:`ShaderDebugTrace`
)");
virtual rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger) = 0;
DOCUMENT(R"(Free a debugging trace from running a shader invocation debug.
:param ShaderDebugTrace trace: The shader debugging trace to free.
+79 -22
View File
@@ -494,6 +494,39 @@ treated as covering the code.
};
DECLARE_REFLECTION_STRUCT(LineColumnInfo);
DOCUMENT("This stores the before and after state of a :class:`ShaderVariable`.");
struct ShaderVariableChange
{
DOCUMENT("");
ShaderVariableChange() = default;
ShaderVariableChange(const ShaderVariableChange &) = default;
ShaderVariableChange &operator=(const ShaderVariableChange &) = default;
bool operator==(const ShaderVariableChange &o) const
{
return before == o.before && after == o.after;
}
bool operator<(const ShaderVariableChange &o) const
{
if(!(before == o.before))
return before < o.before;
if(!(after == o.after))
return after < o.after;
return false;
}
DOCUMENT(R"(The value of the variable before the change. If this variable is uninitialised that
means the variable came into existance on this step.
)");
ShaderVariable before;
DOCUMENT(R"(The value of the variable after the change. If this variable is uninitialised that
means the variable stopped existing on this step.
)");
ShaderVariable after;
};
DECLARE_REFLECTION_STRUCT(ShaderVariableChange);
DOCUMENT(R"(This stores the current state of shader debugging at one particular step in the shader,
with all mutable variable contents.
)");
@@ -506,24 +539,42 @@ struct ShaderDebugState
bool operator==(const ShaderDebugState &o) const
{
return variables == o.variables && sourceVars == o.sourceVars &&
nextInstruction == o.nextInstruction && flags == o.flags;
return nextInstruction == o.nextInstruction && flags == o.flags && changes == o.changes &&
sourceVars == o.sourceVars && stepIndex == o.stepIndex;
}
bool operator<(const ShaderDebugState &o) const
{
if(!(variables == o.variables))
return variables < o.variables;
if(!(sourceVars == o.sourceVars))
return sourceVars < o.sourceVars;
if(!(nextInstruction == o.nextInstruction))
return nextInstruction < o.nextInstruction;
if(!(flags == o.flags))
return flags < o.flags;
if(!(stepIndex == o.stepIndex))
return stepIndex < o.stepIndex;
if(!(changes == o.changes))
return changes < o.changes;
if(!(sourceVars == o.sourceVars))
return sourceVars < o.sourceVars;
return false;
}
DOCUMENT("The mutable variables for this shader as a list of :class:`ShaderVariable`.");
rdcarray<ShaderVariable> variables;
DOCUMENT(R"(The next instruction to be executed after this state. The initial state before any
shader execution happened will have ``nextInstruction == 0``.
)");
uint32_t nextInstruction = 0;
DOCUMENT(R"(The program counter within the debug trace. The initial state will be index 0, and it
will increment linearly after that regardless of loops or branching.
)");
uint32_t stepIndex = 0;
DOCUMENT("A set of :class:`ShaderEvents` flags that indicate what events happened on this step.");
ShaderEvents flags = ShaderEvents::NoEvent;
DOCUMENT(R"(The changes in mutable variables for this shader as a list of
:class:`ShaderVariableChange`. The change documents the bidirectional change of variables, so that
a single state can be updated either forwards or backwards using the information.
)");
rdcarray<ShaderVariableChange> changes;
DOCUMENT(R"(An optional list of :class:`SourceVariableMapping` indicating which high-level source
variables map to which debug variables and including extra type information.
@@ -534,17 +585,6 @@ a different debug variable.
)");
rdcarray<SourceVariableMapping> sourceVars;
DOCUMENT("A list of ranges in :data:`variables` that were modified.");
rdcarray<DebugVariableReference> modified;
DOCUMENT(R"(The next instruction to be executed after this state. The initial state before any
shader execution happened will have ``nextInstruction == 0``.
)");
uint32_t nextInstruction;
DOCUMENT("A set of :class:`ShaderEvents` flags that indicate what events happened on this step.");
ShaderEvents flags;
DOCUMENT(R"(A ``list`` of ``str`` with each function call in the current callstack at this line.
The oldest/outer function is first in the list, the newest/inner function is last.
@@ -554,6 +594,21 @@ The oldest/outer function is first in the list, the newest/inner function is las
DECLARE_REFLECTION_STRUCT(ShaderDebugState);
DOCUMENT("An opaque structure that has internal state for shader debugging");
struct ShaderDebugger
{
protected:
DOCUMENT("");
ShaderDebugger() = default;
ShaderDebugger(const ShaderDebugger &) = default;
ShaderDebugger &operator=(const ShaderDebugger &) = default;
public:
virtual ~ShaderDebugger() = default;
};
DECLARE_REFLECTION_STRUCT(ShaderDebugger);
DOCUMENT(R"(This stores the whole state of a shader's execution from start to finish, with each
individual debugging step along the way, as well as the immutable global constant values that do not
change with shader execution.
@@ -602,10 +657,12 @@ be empty if there is no source variable mapping that extends to the life of the
)");
rdcarray<SourceVariableMapping> sourceVars;
DOCUMENT(R"(A list of :class:`ShaderDebugState` states representing the state after each
instruction was executed
DOCUMENT(R"(An opaque handle of :class:`ShaderDebugger` identifying by the undelying debugger,
which is used to simulate the shader and generate new debug states.
If this is ``None`` then the trace is invalid.
)");
rdcarray<ShaderDebugState> states;
ShaderDebugger *debugger = NULL;
DOCUMENT("A flag indicating whether this trace has source-variable mapping information");
bool hasSourceMapping = false;
+10 -15
View File
@@ -257,27 +257,22 @@ public:
{
return rdcarray<PixelModification>();
}
ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset)
ShaderDebugTrace *DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset)
{
ShaderDebugTrace ret;
RDCEraseEl(ret);
return ret;
return new ShaderDebugTrace();
}
ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
ShaderDebugTrace *DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
{
ShaderDebugTrace ret;
RDCEraseEl(ret);
return ret;
return new ShaderDebugTrace();
}
ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
ShaderDebugTrace *DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
{
ShaderDebugTrace ret;
RDCEraseEl(ret);
return ret;
return new ShaderDebugTrace();
}
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger) { return {}; }
void BuildTargetShader(ShaderEncoding sourceEncoding, const bytebuf &source, const rdcstr &entry,
const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id,
rdcstr &errors)
+65 -22
View File
@@ -93,6 +93,8 @@ rdcstr DoStringise(const ReplayProxyPacket &el)
STRINGISE_ENUM_NAMED(eReplayProxy_GetTargetShaderEncodings, "GetTargetShaderEncodings");
STRINGISE_ENUM_NAMED(eReplayProxy_GetDriverInfo, "GetDriverInfo");
STRINGISE_ENUM_NAMED(eReplayProxy_ContinueDebug, "ContinueDebug");
}
END_ENUM_STRINGISE();
}
@@ -1443,14 +1445,14 @@ rdcarray<PixelModification> ReplayProxy::PixelHistory(rdcarray<EventUsage> event
}
template <typename ParamSerialiser, typename ReturnSerialiser>
ShaderDebugTrace ReplayProxy::Proxied_DebugVertex(ParamSerialiser &paramser,
ReturnSerialiser &retser, uint32_t eventId,
uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset)
ShaderDebugTrace *ReplayProxy::Proxied_DebugVertex(ParamSerialiser &paramser,
ReturnSerialiser &retser, uint32_t eventId,
uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset)
{
const ReplayProxyPacket expectedPacket = eReplayProxy_DebugVertex;
ReplayProxyPacket packet = eReplayProxy_DebugVertex;
ShaderDebugTrace ret;
ShaderDebugTrace *ret;
{
BEGIN_PARAMS();
@@ -1467,27 +1469,29 @@ ShaderDebugTrace ReplayProxy::Proxied_DebugVertex(ParamSerialiser &paramser,
REMOTE_EXECUTION();
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
ret = m_Remote->DebugVertex(eventId, vertid, instid, idx, instOffset, vertOffset);
else
ret = new ShaderDebugTrace;
}
SERIALISE_RETURN(ret);
SERIALISE_RETURN(*ret);
return ret;
}
ShaderDebugTrace ReplayProxy::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
ShaderDebugTrace *ReplayProxy::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
{
PROXY_FUNCTION(DebugVertex, eventId, vertid, instid, idx, instOffset, vertOffset);
}
template <typename ParamSerialiser, typename ReturnSerialiser>
ShaderDebugTrace ReplayProxy::Proxied_DebugPixel(ParamSerialiser &paramser, ReturnSerialiser &retser,
uint32_t eventId, uint32_t x, uint32_t y,
uint32_t sample, uint32_t primitive)
ShaderDebugTrace *ReplayProxy::Proxied_DebugPixel(ParamSerialiser &paramser, ReturnSerialiser &retser,
uint32_t eventId, uint32_t x, uint32_t y,
uint32_t sample, uint32_t primitive)
{
const ReplayProxyPacket expectedPacket = eReplayProxy_DebugPixel;
ReplayProxyPacket packet = eReplayProxy_DebugPixel;
ShaderDebugTrace ret;
ShaderDebugTrace *ret;
{
BEGIN_PARAMS();
@@ -1503,27 +1507,30 @@ ShaderDebugTrace ReplayProxy::Proxied_DebugPixel(ParamSerialiser &paramser, Retu
REMOTE_EXECUTION();
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
ret = m_Remote->DebugPixel(eventId, x, y, sample, primitive);
else
ret = new ShaderDebugTrace;
}
SERIALISE_RETURN(ret);
SERIALISE_RETURN(*ret);
return ret;
}
ShaderDebugTrace ReplayProxy::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
ShaderDebugTrace *ReplayProxy::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
{
PROXY_FUNCTION(DebugPixel, eventId, x, y, sample, primitive);
}
template <typename ParamSerialiser, typename ReturnSerialiser>
ShaderDebugTrace ReplayProxy::Proxied_DebugThread(ParamSerialiser &paramser, ReturnSerialiser &retser,
uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
ShaderDebugTrace *ReplayProxy::Proxied_DebugThread(ParamSerialiser &paramser,
ReturnSerialiser &retser, uint32_t eventId,
const uint32_t groupid[3],
const uint32_t threadid[3])
{
const ReplayProxyPacket expectedPacket = eReplayProxy_DebugThread;
ReplayProxyPacket packet = eReplayProxy_DebugThread;
ShaderDebugTrace ret;
ShaderDebugTrace *ret;
uint32_t GroupID[3] = {groupid[0], groupid[1], groupid[2]};
uint32_t ThreadID[3] = {threadid[0], threadid[1], threadid[2]};
@@ -1540,6 +1547,42 @@ ShaderDebugTrace ReplayProxy::Proxied_DebugThread(ParamSerialiser &paramser, Ret
REMOTE_EXECUTION();
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
ret = m_Remote->DebugThread(eventId, GroupID, ThreadID);
else
ret = new ShaderDebugTrace;
}
SERIALISE_RETURN(*ret);
return ret;
}
ShaderDebugTrace *ReplayProxy::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
{
PROXY_FUNCTION(DebugThread, eventId, groupid, threadid);
}
template <typename ParamSerialiser, typename ReturnSerialiser>
rdcarray<ShaderDebugState> ReplayProxy::Proxied_ContinueDebug(ParamSerialiser &paramser,
ReturnSerialiser &retser,
ShaderDebugger *debugger)
{
const ReplayProxyPacket expectedPacket = eReplayProxy_GetDisassemblyTargets;
ReplayProxyPacket packet = eReplayProxy_GetDisassemblyTargets;
rdcarray<ShaderDebugState> ret;
{
BEGIN_PARAMS();
uint64_t debugger_ptr = (uint64_t)(uintptr_t)debugger;
SERIALISE_ELEMENT(debugger_ptr);
debugger = (ShaderDebugger *)(uintptr_t)debugger_ptr;
END_PARAMS();
}
{
REMOTE_EXECUTION();
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
ret = m_Remote->ContinueDebug(debugger);
}
SERIALISE_RETURN(ret);
@@ -1547,10 +1590,9 @@ ShaderDebugTrace ReplayProxy::Proxied_DebugThread(ParamSerialiser &paramser, Ret
return ret;
}
ShaderDebugTrace ReplayProxy::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
rdcarray<ShaderDebugState> ReplayProxy::ContinueDebug(ShaderDebugger *debugger)
{
PROXY_FUNCTION(DebugThread, eventId, groupid, threadid);
PROXY_FUNCTION(ContinueDebug, debugger);
}
template <typename ParamSerialiser, typename ReturnSerialiser>
@@ -2738,6 +2780,7 @@ bool ReplayProxy::Tick(int type)
DebugThread(0, dummy1, dummy2);
break;
}
case eReplayProxy_ContinueDebug: ContinueDebug(NULL); break;
case eReplayProxy_RenderOverlay:
RenderOverlay(ResourceId(), CompType::Typeless, FloatVector(), DebugOverlay::NoOverlay, 0,
rdcarray<uint32_t>());
+7 -4
View File
@@ -100,6 +100,8 @@ enum ReplayProxyPacket
eReplayProxy_GetDriverInfo,
eReplayProxy_GetAvailableGPUs,
eReplayProxy_ContinueDebug,
};
DECLARE_REFLECTION_ENUM(ReplayProxyPacket);
@@ -520,12 +522,13 @@ public:
IMPLEMENT_FUNCTION_PROXIED(rdcarray<PixelModification>, PixelHistory, rdcarray<EventUsage> events,
ResourceId target, uint32_t x, uint32_t y, const Subresource &sub,
CompType typeCast);
IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace, DebugVertex, uint32_t eventId, uint32_t vertid,
IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace *, DebugVertex, uint32_t eventId, uint32_t vertid,
uint32_t instid, uint32_t idx, uint32_t instOffset, uint32_t vertOffset);
IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace, DebugPixel, uint32_t eventId, uint32_t x, uint32_t y,
uint32_t sample, uint32_t primitive);
IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace, DebugThread, uint32_t eventId,
IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace *, DebugPixel, uint32_t eventId, uint32_t x,
uint32_t y, uint32_t sample, uint32_t primitive);
IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace *, DebugThread, uint32_t eventId,
const uint32_t groupid[3], const uint32_t threadid[3]);
IMPLEMENT_FUNCTION_PROXIED(rdcarray<ShaderDebugState>, ContinueDebug, ShaderDebugger *debugger);
IMPLEMENT_FUNCTION_PROXIED(rdcarray<ShaderEncoding>, GetTargetShaderEncodings);
IMPLEMENT_FUNCTION_PROXIED(void, BuildTargetShader, ShaderEncoding sourceEncoding,
-6
View File
@@ -40,12 +40,6 @@ class D3D11ResourceManager;
struct CopyPixelParams;
namespace DXBCDebug
{
struct GlobalState;
class State;
}
namespace DXBC
{
class DXBCContainer;
+8 -6
View File
@@ -231,12 +231,14 @@ public:
rdcarray<PixelModification> PixelHistory(rdcarray<EventUsage> events, ResourceId target, uint32_t x,
uint32_t y, const Subresource &sub, CompType typeCast);
ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]);
ShaderDebugTrace *DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace *DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace *DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]);
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg,
uint32_t x, uint32_t y);
+149 -353
View File
@@ -53,7 +53,7 @@ struct DebugHit
class D3D11DebugAPIWrapper : public DXBCDebug::DebugAPIWrapper
{
public:
D3D11DebugAPIWrapper(WrappedID3D11Device *device, DXBC::DXBCContainer *dxbc,
D3D11DebugAPIWrapper(WrappedID3D11Device *device, const DXBC::DXBCContainer *dxbc,
DXBCDebug::GlobalState &globalState);
void SetCurrentInstruction(uint32_t instruction) { m_instruction = instruction; }
@@ -82,12 +82,13 @@ public:
private:
DXBC::ShaderType GetShaderType() { return m_dxbc ? m_dxbc->m_Type : DXBC::ShaderType::Pixel; }
WrappedID3D11Device *m_pDevice;
DXBC::DXBCContainer *m_dxbc;
const DXBC::DXBCContainer *m_dxbc;
DXBCDebug::GlobalState &m_globalState;
uint32_t m_instruction;
};
D3D11DebugAPIWrapper::D3D11DebugAPIWrapper(WrappedID3D11Device *device, DXBC::DXBCContainer *dxbc,
D3D11DebugAPIWrapper::D3D11DebugAPIWrapper(WrappedID3D11Device *device,
const DXBC::DXBCContainer *dxbc,
DXBCDebug::GlobalState &globalState)
: m_pDevice(device), m_dxbc(dxbc), m_globalState(globalState), m_instruction(0)
{
@@ -1698,9 +1699,11 @@ bool D3D11DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod
return true;
}
void AddCBuffersToDebugTrace(const DXBCBytecode::Program &program, D3D11DebugManager &debugManager,
ShaderDebugTrace &trace, const D3D11RenderState::Shader &shader,
const ShaderReflection &refl, const ShaderBindpointMapping &mapping)
void AddCBuffersToGlobalState(const DXBCBytecode::Program &program, D3D11DebugManager &debugManager,
DXBCDebug::GlobalState &global,
rdcarray<SourceVariableMapping> &sourceVars,
const D3D11RenderState::Shader &shader, const ShaderReflection &refl,
const ShaderBindpointMapping &mapping)
{
bytebuf cbufData;
for(int i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++)
@@ -1712,22 +1715,20 @@ void AddCBuffersToDebugTrace(const DXBCBytecode::Program &program, D3D11DebugMan
debugManager.GetBufferData(shader.ConstantBuffers[i], shader.CBOffsets[i] * sizeof(Vec4f),
shader.CBCounts[i] * sizeof(Vec4f), cbufData);
AddCBufferToDebugTrace(program, trace, refl, mapping, slot, cbufData);
AddCBufferToGlobalState(program, global, sourceVars, refl, mapping, slot, cbufData);
}
}
}
ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
ShaderDebugTrace *D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
{
using namespace DXBCBytecode;
using namespace DXBCDebug;
D3D11MarkerRegion debugpixRegion(
D3D11MarkerRegion region(
StringFormat::Fmt("DebugVertex @ %u of (%u,%u,%u)", eventId, vertid, instid, idx));
ShaderDebugTrace empty;
const DrawcallDescription *draw = m_pDevice->GetDrawcall(eventId);
D3D11RenderStateTracker tracker(m_pImmediateContext);
@@ -1740,13 +1741,13 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
SAFE_RELEASE(stateVS);
if(!vs)
return empty;
return new ShaderDebugTrace;
DXBC::DXBCContainer *dxbc = vs->GetDXBC();
const ShaderReflection &refl = vs->GetDetails();
if(!dxbc)
return empty;
return new ShaderDebugTrace;
dxbc->GetDisassembly();
@@ -1811,19 +1812,15 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
}
}
ShaderDebugTrace ret;
InterpretDebugger *interpreter = new InterpretDebugger;
ShaderDebugTrace *ret = interpreter->BeginDebug(dxbc, refl, vs->GetMapping(), 0);
GlobalState &global = interpreter->global;
ThreadState &state = interpreter->activeLane();
GlobalState global;
global.PopulateGroupshared(dxbc->GetDXBCByteCode());
State initialState(-1, &global, dxbc);
CreateShaderDebugStateAndTrace(initialState, ret, dxbc, refl, vs->GetMapping());
AddCBuffersToGlobalState(*dxbc->GetDXBCByteCode(), *GetDebugManager(), global, ret->sourceVars,
rs->VS, refl, vs->GetMapping());
AddCBuffersToDebugTrace(*dxbc->GetDXBCByteCode(), *GetDebugManager(), ret, rs->VS, refl,
vs->GetMapping());
global.constantBlocks = ret.constantBlocks;
for(size_t i = 0; i < ret.inputs.size(); i++)
for(size_t i = 0; i < state.inputs.size(); i++)
{
if(dxbc->GetReflection()->InputSig[i].systemValue == ShaderBuiltin::Undefined ||
dxbc->GetReflection()->InputSig[i].systemValue ==
@@ -1894,17 +1891,17 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
// more data needed than is provided
if(dxbc->GetReflection()->InputSig[i].compCount > fmt.compCount)
{
ret.inputs[i].value.u.w = 1;
state.inputs[i].value.u.w = 1;
if(fmt.compType == CompType::Float)
ret.inputs[i].value.f.w = 1.0f;
state.inputs[i].value.f.w = 1.0f;
}
// interpret resource format types
if(fmt.Special())
{
Vec3f *v3 = (Vec3f *)ret.inputs[i].value.fv;
Vec4f *v4 = (Vec4f *)ret.inputs[i].value.fv;
Vec3f *v3 = (Vec3f *)state.inputs[i].value.fv;
Vec4f *v4 = (Vec4f *)state.inputs[i].value.fv;
// only pull in all or nothing from these,
// if there's only e.g. 3 bytes remaining don't read and unpack some of
@@ -1916,8 +1913,8 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
if(srcData == NULL || packedsize > dataSize)
{
ret.inputs[i].value.u.x = ret.inputs[i].value.u.y = ret.inputs[i].value.u.z =
ret.inputs[i].value.u.w = 0;
state.inputs[i].value.u.x = state.inputs[i].value.u.y = state.inputs[i].value.u.z =
state.inputs[i].value.u.w = 0;
}
else if(fmt.type == ResourceFormatType::R5G5B5A1)
{
@@ -1943,10 +1940,10 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
if(fmt.compType == CompType::UInt)
{
ret.inputs[i].value.u.z = (packed >> 0) & 0x3ff;
ret.inputs[i].value.u.y = (packed >> 10) & 0x3ff;
ret.inputs[i].value.u.x = (packed >> 20) & 0x3ff;
ret.inputs[i].value.u.w = (packed >> 30) & 0x003;
state.inputs[i].value.u.z = (packed >> 0) & 0x3ff;
state.inputs[i].value.u.y = (packed >> 10) & 0x3ff;
state.inputs[i].value.u.x = (packed >> 20) & 0x3ff;
state.inputs[i].value.u.w = (packed >> 30) & 0x003;
}
else
{
@@ -1965,7 +1962,7 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
{
if(srcData == NULL || fmt.compByteWidth > dataSize)
{
ret.inputs[i].value.uv[c] = 0;
state.inputs[i].value.uv[c] = 0;
continue;
}
@@ -1976,20 +1973,20 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
byte *src = srcData + c * fmt.compByteWidth;
if(fmt.compType == CompType::UInt)
ret.inputs[i].value.uv[c] = *src;
state.inputs[i].value.uv[c] = *src;
else if(fmt.compType == CompType::SInt)
ret.inputs[i].value.iv[c] = *((int8_t *)src);
state.inputs[i].value.iv[c] = *((int8_t *)src);
else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB)
ret.inputs[i].value.fv[c] = float(*src) / 255.0f;
state.inputs[i].value.fv[c] = float(*src) / 255.0f;
else if(fmt.compType == CompType::SNorm)
{
signed char *schar = (signed char *)src;
// -128 is mapped to -1, then -127 to -127 are mapped to -1 to 1
if(*schar == -128)
ret.inputs[i].value.fv[c] = -1.0f;
state.inputs[i].value.fv[c] = -1.0f;
else
ret.inputs[i].value.fv[c] = float(*schar) / 127.0f;
state.inputs[i].value.fv[c] = float(*schar) / 127.0f;
}
else
RDCERR("Unexpected component type");
@@ -1999,22 +1996,22 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
uint16_t *src = (uint16_t *)(srcData + c * fmt.compByteWidth);
if(fmt.compType == CompType::Float)
ret.inputs[i].value.fv[c] = ConvertFromHalf(*src);
state.inputs[i].value.fv[c] = ConvertFromHalf(*src);
else if(fmt.compType == CompType::UInt)
ret.inputs[i].value.uv[c] = *src;
state.inputs[i].value.uv[c] = *src;
else if(fmt.compType == CompType::SInt)
ret.inputs[i].value.iv[c] = *((int16_t *)src);
state.inputs[i].value.iv[c] = *((int16_t *)src);
else if(fmt.compType == CompType::UNorm || fmt.compType == CompType::UNormSRGB)
ret.inputs[i].value.fv[c] = float(*src) / float(UINT16_MAX);
state.inputs[i].value.fv[c] = float(*src) / float(UINT16_MAX);
else if(fmt.compType == CompType::SNorm)
{
int16_t *sint = (int16_t *)src;
// -32768 is mapped to -1, then -32767 to -32767 are mapped to -1 to 1
if(*sint == -32768)
ret.inputs[i].value.fv[c] = -1.0f;
state.inputs[i].value.fv[c] = -1.0f;
else
ret.inputs[i].value.fv[c] = float(*sint) / 32767.0f;
state.inputs[i].value.fv[c] = float(*sint) / 32767.0f;
}
else
RDCERR("Unexpected component type");
@@ -2025,7 +2022,7 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
if(fmt.compType == CompType::Float || fmt.compType == CompType::UInt ||
fmt.compType == CompType::SInt)
memcpy(&ret.inputs[i].value.uv[c], src, 4);
memcpy(&state.inputs[i].value.uv[c], src, 4);
else
RDCERR("Unexpected component type");
}
@@ -2034,7 +2031,7 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
if(fmt.BGRAOrder())
{
RDCASSERT(fmt.compCount == 4);
std::swap(ret.inputs[i].value.fv[2], ret.inputs[i].value.fv[0]);
std::swap(state.inputs[i].value.fv[2], state.inputs[i].value.fv[0]);
}
}
}
@@ -2046,20 +2043,20 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
sv_vertid = idx;
if(dxbc->GetReflection()->InputSig[i].compType == CompType::Float)
ret.inputs[i].value.f.x = ret.inputs[i].value.f.y = ret.inputs[i].value.f.z =
ret.inputs[i].value.f.w = (float)sv_vertid;
state.inputs[i].value.f.x = state.inputs[i].value.f.y = state.inputs[i].value.f.z =
state.inputs[i].value.f.w = (float)sv_vertid;
else
ret.inputs[i].value.u.x = ret.inputs[i].value.u.y = ret.inputs[i].value.u.z =
ret.inputs[i].value.u.w = sv_vertid;
state.inputs[i].value.u.x = state.inputs[i].value.u.y = state.inputs[i].value.u.z =
state.inputs[i].value.u.w = sv_vertid;
}
else if(dxbc->GetReflection()->InputSig[i].systemValue == ShaderBuiltin::InstanceIndex)
{
if(dxbc->GetReflection()->InputSig[i].compType == CompType::Float)
ret.inputs[i].value.f.x = ret.inputs[i].value.f.y = ret.inputs[i].value.f.z =
ret.inputs[i].value.f.w = (float)instid;
state.inputs[i].value.f.x = state.inputs[i].value.f.y = state.inputs[i].value.f.z =
state.inputs[i].value.f.w = (float)instid;
else
ret.inputs[i].value.u.x = ret.inputs[i].value.u.y = ret.inputs[i].value.u.z =
ret.inputs[i].value.u.w = instid;
state.inputs[i].value.u.x = state.inputs[i].value.u.y = state.inputs[i].value.u.z =
state.inputs[i].value.u.w = instid;
}
else
{
@@ -2067,56 +2064,26 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
}
}
ret->constantBlocks = global.constantBlocks;
ret->inputs = state.inputs;
ret->hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
delete[] instData;
rdcarray<ShaderDebugState> states;
dxbc->FillStateInstructionInfo(initialState);
states.push_back((State)initialState);
D3D11MarkerRegion simloop("Simulation Loop");
D3D11DebugAPIWrapper apiWrapper(m_pDevice, dxbc, global);
for(int cycleCounter = 0;; cycleCounter++)
{
if(initialState.Finished())
break;
initialState = initialState.GetNext(&apiWrapper, NULL);
dxbc->FillStateInstructionInfo(initialState);
states.push_back((State)initialState);
if(cycleCounter == SHADER_DEBUG_WARN_THRESHOLD)
{
if(PromptDebugTimeout(cycleCounter))
break;
}
}
ret.states = states;
ret.hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
dxbc->FillTraceLineInfo(ret);
dxbc->FillTraceLineInfo(*ret);
return ret;
}
ShaderDebugTrace D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
ShaderDebugTrace *D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
{
using namespace DXBCBytecode;
using namespace DXBCDebug;
D3D11MarkerRegion debugpixRegion(
D3D11MarkerRegion region(
StringFormat::Fmt("DebugPixel @ %u of (%u,%u) %u / %u", eventId, x, y, sample, primitive));
ShaderDebugTrace empty;
D3D11RenderStateTracker tracker(m_pImmediateContext);
ID3D11PixelShader *statePS = NULL;
@@ -2149,7 +2116,7 @@ ShaderDebugTrace D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
SAFE_RELEASE(stateVS);
if(!ps)
return empty;
return new ShaderDebugTrace;
D3D11RenderState *rs = m_pImmediateContext->GetCurrentPipelineState();
@@ -2157,7 +2124,7 @@ ShaderDebugTrace D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
const ShaderReflection &refl = ps->GetDetails();
if(!dxbc)
return empty;
return new ShaderDebugTrace;
dxbc->GetDisassembly();
@@ -2464,7 +2431,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(FAILED(hr))
{
RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str());
return empty;
return new ShaderDebugTrace;
}
ID3D11Buffer *evalBuf = NULL;
@@ -2479,7 +2446,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(FAILED(hr))
{
RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str());
return empty;
return new ShaderDebugTrace;
}
}
@@ -2496,7 +2463,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(FAILED(hr))
{
RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str());
return empty;
return new ShaderDebugTrace;
}
uint32_t evalStructStride = uint32_t(evalSampleCacheData.size() * sizeof(Vec4f));
@@ -2511,7 +2478,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(FAILED(hr))
{
RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str());
return empty;
return new ShaderDebugTrace;
}
}
@@ -2528,7 +2495,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(FAILED(hr))
{
RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str());
return empty;
return new ShaderDebugTrace;
}
ID3D11UnorderedAccessView *evalUAV = NULL;
@@ -2541,7 +2508,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(FAILED(hr))
{
RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str());
return empty;
return new ShaderDebugTrace;
}
}
@@ -2576,7 +2543,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(FAILED(hr))
{
RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str());
return empty;
return new ShaderDebugTrace;
}
byte *initialData = new byte[structStride * (overdrawLevels + 1)];
@@ -2594,7 +2561,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
{
RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str());
SAFE_DELETE_ARRAY(initialData);
return empty;
return new ShaderDebugTrace;
}
evalData = new byte[evalStructStride * (overdrawLevels + 1)];
@@ -2622,7 +2589,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
RDCLOG("No hit for this event");
SAFE_DELETE_ARRAY(initialData);
SAFE_DELETE_ARRAY(evalData);
return empty;
return new ShaderDebugTrace;
}
// if we encounter multiple hits at our destination pixel co-ord (or any other) we
@@ -2702,47 +2669,33 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
RDCLOG("Couldn't find any pixels that passed depth test at target co-ordinates");
SAFE_DELETE_ARRAY(initialData);
SAFE_DELETE_ARRAY(evalData);
return empty;
return new ShaderDebugTrace;
}
ShaderDebugTrace ret;
tracker.State().ApplyState(m_pImmediateContext);
GlobalState global;
global.PopulateGroupshared(dxbc->GetDXBCByteCode());
InterpretDebugger *interpreter = new InterpretDebugger;
ShaderDebugTrace *ret = interpreter->BeginDebug(dxbc, refl, ps->GetMapping(), destIdx);
GlobalState &global = interpreter->global;
ThreadState &state = interpreter->activeLane();
AddCBuffersToGlobalState(*dxbc->GetDXBCByteCode(), *GetDebugManager(), global, ret->sourceVars,
rs->PS, refl, ps->GetMapping());
global.sampleEvalRegisterMask = sampleEvalRegisterMask;
State quad[4] = {
// top-left
State(0, &global, dxbc),
// top-right
State(1, &global, dxbc),
// bottom-left
State(2, &global, dxbc),
// bottom-right
State(3, &global, dxbc),
};
CreateShaderDebugStateAndTrace(quad[destIdx], ret, dxbc, refl, ps->GetMapping());
AddCBuffersToDebugTrace(*dxbc->GetDXBCByteCode(), *GetDebugManager(), ret, rs->PS, refl,
ps->GetMapping());
global.constantBlocks = ret.constantBlocks;
{
DebugHit *hit = winner;
rdcarray<ShaderVariable> &ins = quad[destIdx].inputs;
rdcarray<ShaderVariable> &ins = state.inputs;
if(!ins.empty() &&
ins.back().name ==
dxbc->GetDXBCByteCode()->GetRegisterName(DXBCBytecode::TYPE_INPUT_COVERAGE_MASK, 0))
ins.back().value.u.x = hit->coverage;
quad[destIdx].semantics.coverage = hit->coverage;
quad[destIdx].semantics.primID = hit->primitive;
quad[destIdx].semantics.isFrontFace = hit->isFrontFace;
state.semantics.coverage = hit->coverage;
state.semantics.primID = hit->primitive;
state.semantics.isFrontFace = hit->isFrontFace;
uint32_t *data = &hit->rawdata;
@@ -2754,7 +2707,9 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
RDCERR("Derivatives invalid");
SAFE_DELETE_ARRAY(initialData);
SAFE_DELETE_ARRAY(evalData);
return empty;
delete interpreter;
delete ret;
return new ShaderDebugTrace;
}
data++;
@@ -2799,10 +2754,10 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
{
if(i != destIdx)
{
quad[i].inputs = quad[destIdx].inputs;
quad[i].semantics = quad[destIdx].semantics;
quad[i].variables = quad[destIdx].variables;
quad[i].SetHelper();
interpreter->workgroup[i].inputs = state.inputs;
interpreter->workgroup[i].semantics = state.semantics;
interpreter->workgroup[i].variables = state.variables;
interpreter->workgroup[i].SetHelper();
}
}
@@ -2810,7 +2765,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
for(const GlobalState::SampleEvalCacheKey &key : evalSampleCacheData)
{
// start with the basic input value
ShaderVariable var = ret.inputs[key.inputRegisterIndex];
ShaderVariable var = state.inputs[key.inputRegisterIndex];
// copy over the value into the variable
memcpy(var.value.fv, evalSampleCache, var.columns * sizeof(float));
@@ -2827,172 +2782,30 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
evalSampleCache += 4;
}
ApplyAllDerivatives(global, quad, destIdx, initialValues, (float *)data);
ApplyAllDerivatives(global, interpreter->workgroup, destIdx, initialValues, (float *)data);
}
ret.inputs = quad[destIdx].inputs;
ret->inputs = state.inputs;
ret->constantBlocks = global.constantBlocks;
ret->hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
SAFE_DELETE_ARRAY(initialData);
SAFE_DELETE_ARRAY(evalData);
rdcarray<ShaderDebugState> states;
dxbc->FillStateInstructionInfo(quad[destIdx]);
states.push_back((State)quad[destIdx]);
// ping pong between so that we can have 'current' quad to update into new one
State quad2[4] = {
State(0, &global, dxbc), State(1, &global, dxbc), State(2, &global, dxbc),
State(3, &global, dxbc),
};
State *curquad = quad;
State *newquad = quad2;
// marks any threads stalled waiting for others to catch up
bool activeMask[4] = {true, true, true, true};
int cycleCounter = 0;
D3D11MarkerRegion simloop("Simulation Loop");
D3D11DebugAPIWrapper apiWrapper(m_pDevice, dxbc, global);
// simulate lockstep until all threads are finished
bool finished = true;
do
{
for(size_t i = 0; i < 4; i++)
{
if(activeMask[i])
newquad[i] = curquad[i].GetNext(&apiWrapper, curquad);
else
newquad[i] = curquad[i];
}
State *a = curquad;
curquad = newquad;
newquad = a;
// if our destination quad is paused don't record multiple identical states.
if(activeMask[destIdx])
{
State &s = curquad[destIdx];
dxbc->FillStateInstructionInfo(s);
states.push_back(s);
}
// we need to make sure that control flow which converges stays in lockstep so that
// derivatives are still valid. While diverged, we don't have to keep threads in lockstep
// since using derivatives is invalid.
// Threads diverge either in ifs, loops, or switches. Due to the nature of the bytecode,
// all threads *must* pass through the same exit instruction for each, there's no jumping
// around with gotos. Note also for the same reason, the only time threads are on earlier
// instructions is if they are still catching up to a thread that has exited the control
// flow.
// So the scheme is as follows:
// * If all threads have the same nextInstruction, just continue we are still in lockstep.
// * If threads are out of lockstep, find any thread which has nextInstruction pointing
// immediately *after* an ENDIF, ENDLOOP or ENDSWITCH. Pointing directly at one is not
// an indication the thread is done, as the next step for an ENDLOOP will jump back to
// the matching LOOP and continue iterating.
// * Pause any thread matching the above until all threads are pointing to the same
// instruction. By the assumption above, all threads will eventually pass through this
// terminating instruction so we just pause any other threads and don't do anything
// until the control flow has converged and we can continue stepping in lockstep.
// mark all threads as active again.
// if we've converged, or we were never diverged, this keeps everything ticking
activeMask[0] = activeMask[1] = activeMask[2] = activeMask[3] = true;
if(curquad[0].nextInstruction != curquad[1].nextInstruction ||
curquad[0].nextInstruction != curquad[2].nextInstruction ||
curquad[0].nextInstruction != curquad[3].nextInstruction)
{
// this isn't *perfect* but it will still eventually continue. We look for the most
// advanced thread, and check to see if it's just finished a control flow. If it has
// then we assume it's at the convergence point and wait for every other thread to
// catch up, pausing any threads that reach the convergence point before others.
// Note this might mean we don't have any threads paused even within divergent flow.
// This is fine and all we care about is pausing to make sure threads don't run ahead
// into code that should be lockstep. We don't care at all about what they do within
// the code that is divergent.
// The reason this isn't perfect is that the most advanced thread could be on an
// inner loop or inner if, not the convergence point, and we could be pausing it
// fruitlessly. Worse still - it could be on a branch none of the other threads will
// take so they will never reach that exact instruction.
// But we know that all threads will eventually go through the convergence point, so
// even in that worst case if we didn't pick the right waiting point, another thread
// will overtake and become the new most advanced thread and the previous waiting
// thread will resume. So in this case we caused a thread to wait more than it should
// have but that's not a big deal as it's within divergent flow so they don't have to
// stay in lockstep. Also if all threads will eventually pass that point we picked,
// we just waited to converge even in technically divergent code which is also
// harmless.
// Phew!
uint32_t convergencePoint = 0;
// find which thread is most advanced
for(size_t i = 0; i < 4; i++)
if(curquad[i].nextInstruction > convergencePoint)
convergencePoint = curquad[i].nextInstruction;
if(convergencePoint > 0)
{
OpcodeType op = dxbc->GetDXBCByteCode()->GetInstruction(convergencePoint - 1).operation;
// if the most advnaced thread hasn't just finished control flow, then all
// threads are still running, so don't converge
if(op != OPCODE_ENDIF && op != OPCODE_ENDLOOP && op != OPCODE_ENDSWITCH)
convergencePoint = 0;
}
// pause any threads at that instruction (could be none)
for(size_t i = 0; i < 4; i++)
if(curquad[i].nextInstruction == convergencePoint)
activeMask[i] = false;
}
finished = curquad[destIdx].Finished();
cycleCounter++;
if(cycleCounter == SHADER_DEBUG_WARN_THRESHOLD)
{
if(PromptDebugTimeout(cycleCounter))
break;
}
} while(!finished);
ret.states = states;
ret.hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
dxbc->FillTraceLineInfo(ret);
dxbc->FillTraceLineInfo(*ret);
return ret;
}
ShaderDebugTrace D3D11Replay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
ShaderDebugTrace *D3D11Replay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
{
using namespace DXBCBytecode;
using namespace DXBCDebug;
D3D11MarkerRegion simloop(StringFormat::Fmt("DebugThread @ %u: [%u, %u, %u] (%u, %u, %u)",
eventId, groupid[0], groupid[1], groupid[2],
threadid[0], threadid[1], threadid[2]));
ShaderDebugTrace empty;
D3D11MarkerRegion region(StringFormat::Fmt("DebugThread @ %u: [%u, %u, %u] (%u, %u, %u)", eventId,
groupid[0], groupid[1], groupid[2], threadid[0],
threadid[1], threadid[2]));
D3D11RenderStateTracker tracker(m_pImmediateContext);
@@ -3004,68 +2817,38 @@ ShaderDebugTrace D3D11Replay::DebugThread(uint32_t eventId, const uint32_t group
SAFE_RELEASE(stateCS);
if(!cs)
return empty;
return new ShaderDebugTrace;
DXBC::DXBCContainer *dxbc = cs->GetDXBC();
const ShaderReflection &refl = cs->GetDetails();
if(!dxbc)
return empty;
return new ShaderDebugTrace;
dxbc->GetDisassembly();
D3D11RenderState *rs = m_pImmediateContext->GetCurrentPipelineState();
ShaderDebugTrace ret;
InterpretDebugger *interpreter = new InterpretDebugger;
ShaderDebugTrace *ret = interpreter->BeginDebug(dxbc, refl, cs->GetMapping(), 0);
GlobalState &global = interpreter->global;
ThreadState &state = interpreter->activeLane();
GlobalState global;
global.PopulateGroupshared(dxbc->GetDXBCByteCode());
State initialState(-1, &global, dxbc);
CreateShaderDebugStateAndTrace(initialState, ret, dxbc, refl, cs->GetMapping());
AddCBuffersToDebugTrace(*dxbc->GetDXBCByteCode(), *GetDebugManager(), ret, rs->CS, refl,
cs->GetMapping());
global.constantBlocks = ret.constantBlocks;
AddCBuffersToGlobalState(*dxbc->GetDXBCByteCode(), *GetDebugManager(), global, ret->sourceVars,
rs->PS, refl, cs->GetMapping());
for(int i = 0; i < 3; i++)
{
initialState.semantics.GroupID[i] = groupid[i];
initialState.semantics.ThreadID[i] = threadid[i];
state.semantics.GroupID[i] = groupid[i];
state.semantics.ThreadID[i] = threadid[i];
}
rdcarray<ShaderDebugState> states;
ret->constantBlocks = global.constantBlocks;
ret->hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
dxbc->FillStateInstructionInfo(initialState);
states.push_back((State)initialState);
D3D11DebugAPIWrapper apiWrapper(m_pDevice, dxbc, global);
for(int cycleCounter = 0;; cycleCounter++)
{
if(initialState.Finished())
break;
initialState = initialState.GetNext(&apiWrapper, NULL);
dxbc->FillStateInstructionInfo(initialState);
states.push_back((State)initialState);
if(cycleCounter == SHADER_DEBUG_WARN_THRESHOLD)
{
if(PromptDebugTimeout(cycleCounter))
break;
}
}
ret.states = states;
ret.hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
dxbc->FillTraceLineInfo(ret);
dxbc->FillTraceLineInfo(*ret);
// add fake inputs for semantics
for(size_t i = 0; i < dxbc->GetDXBCByteCode()->GetNumDeclarations(); i++)
{
const DXBCBytecode::Declaration &decl = dxbc->GetDXBCByteCode()->GetDeclaration(i);
@@ -3084,40 +2867,53 @@ ShaderDebugTrace D3D11Replay::DebugThread(uint32_t eventId, const uint32_t group
switch(decl.operand.type)
{
case TYPE_INPUT_THREAD_GROUP_ID:
memcpy(v.value.uv, initialState.semantics.GroupID, sizeof(uint32_t) * 3);
memcpy(v.value.uv, state.semantics.GroupID, sizeof(uint32_t) * 3);
v.columns = 3;
break;
case TYPE_INPUT_THREAD_ID_IN_GROUP:
memcpy(v.value.uv, initialState.semantics.ThreadID, sizeof(uint32_t) * 3);
memcpy(v.value.uv, state.semantics.ThreadID, sizeof(uint32_t) * 3);
v.columns = 3;
break;
case TYPE_INPUT_THREAD_ID:
v.value.u.x = initialState.semantics.GroupID[0] *
dxbc->GetReflection()->DispatchThreadsDimension[0] +
initialState.semantics.ThreadID[0];
v.value.u.y = initialState.semantics.GroupID[1] *
dxbc->GetReflection()->DispatchThreadsDimension[1] +
initialState.semantics.ThreadID[1];
v.value.u.z = initialState.semantics.GroupID[2] *
dxbc->GetReflection()->DispatchThreadsDimension[2] +
initialState.semantics.ThreadID[2];
v.value.u.x =
state.semantics.GroupID[0] * dxbc->GetReflection()->DispatchThreadsDimension[0] +
state.semantics.ThreadID[0];
v.value.u.y =
state.semantics.GroupID[1] * dxbc->GetReflection()->DispatchThreadsDimension[1] +
state.semantics.ThreadID[1];
v.value.u.z =
state.semantics.GroupID[2] * dxbc->GetReflection()->DispatchThreadsDimension[2] +
state.semantics.ThreadID[2];
v.columns = 3;
break;
case TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED:
v.value.u.x = initialState.semantics.ThreadID[2] *
dxbc->GetReflection()->DispatchThreadsDimension[0] *
dxbc->GetReflection()->DispatchThreadsDimension[1] +
initialState.semantics.ThreadID[1] *
dxbc->GetReflection()->DispatchThreadsDimension[0] +
initialState.semantics.ThreadID[0];
v.value.u.x =
state.semantics.ThreadID[2] * dxbc->GetReflection()->DispatchThreadsDimension[0] *
dxbc->GetReflection()->DispatchThreadsDimension[1] +
state.semantics.ThreadID[1] * dxbc->GetReflection()->DispatchThreadsDimension[0] +
state.semantics.ThreadID[0];
v.columns = 1;
break;
default: v.columns = 4; break;
}
ret.inputs.push_back(v);
ret->inputs.push_back(v);
}
}
return ret;
}
rdcarray<ShaderDebugState> D3D11Replay::ContinueDebug(ShaderDebugger *debugger)
{
DXBCDebug::InterpretDebugger *interpreter = (DXBCDebug::InterpretDebugger *)debugger;
if(!interpreter)
return NULL;
D3D11DebugAPIWrapper apiWrapper(m_pDevice, interpreter->dxbc, interpreter->global);
D3D11MarkerRegion region("ContinueDebug Simulation Loop");
return interpreter->ContinueDebug(&apiWrapper);
}
-6
View File
@@ -38,12 +38,6 @@ namespace DXBC
class DXBCContainer;
};
namespace DXBCDebug
{
struct GlobalState;
class State;
}
#define D3D12_MSAA_SAMPLECOUNT 4
// baked indices in descriptor heaps
+8 -6
View File
@@ -186,12 +186,14 @@ public:
rdcarray<PixelModification> PixelHistory(rdcarray<EventUsage> events, ResourceId target, uint32_t x,
uint32_t y, const Subresource &sub, CompType typeCast);
ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]);
ShaderDebugTrace *DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace *DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace *DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]);
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg,
uint32_t x, uint32_t y);
+100 -270
View File
@@ -64,7 +64,7 @@ static bool IsShaderParameterVisible(DXBC::ShaderType shaderType,
class D3D12DebugAPIWrapper : public DXBCDebug::DebugAPIWrapper
{
public:
D3D12DebugAPIWrapper(WrappedID3D12Device *device, DXBC::DXBCContainer *dxbc,
D3D12DebugAPIWrapper(WrappedID3D12Device *device, const DXBC::DXBCContainer *dxbc,
DXBCDebug::GlobalState &globalState);
void SetCurrentInstruction(uint32_t instruction) { m_instruction = instruction; }
@@ -94,12 +94,13 @@ public:
private:
DXBC::ShaderType GetShaderType() { return m_dxbc ? m_dxbc->m_Type : DXBC::ShaderType::Pixel; }
WrappedID3D12Device *m_pDevice;
DXBC::DXBCContainer *m_dxbc;
const DXBC::DXBCContainer *m_dxbc;
DXBCDebug::GlobalState &m_globalState;
uint32_t m_instruction;
};
D3D12DebugAPIWrapper::D3D12DebugAPIWrapper(WrappedID3D12Device *device, DXBC::DXBCContainer *dxbc,
D3D12DebugAPIWrapper::D3D12DebugAPIWrapper(WrappedID3D12Device *device,
const DXBC::DXBCContainer *dxbc,
DXBCDebug::GlobalState &globalState)
: m_pDevice(device), m_dxbc(dxbc), m_globalState(globalState), m_instruction(0)
{
@@ -1038,7 +1039,8 @@ bool D3D12DebugAPIWrapper::CalculateSampleGather(
void GatherConstantBuffers(WrappedID3D12Device *pDevice, const DXBCBytecode::Program &program,
const D3D12RenderState::RootSignature &rootsig,
const ShaderReflection &refl, const ShaderBindpointMapping &mapping,
ShaderDebugTrace &debugTrace)
DXBCDebug::GlobalState &global,
rdcarray<SourceVariableMapping> &sourceVars)
{
WrappedID3D12RootSignature *pD3D12RootSig =
pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(rootsig.rootsig);
@@ -1058,7 +1060,7 @@ void GatherConstantBuffers(WrappedID3D12Device *pDevice, const DXBCBytecode::Pro
UINT sizeBytes = sizeof(uint32_t) * RDCMIN(rootSigParam.Constants.Num32BitValues,
(UINT)element.constants.size());
bytebuf cbufData((const byte *)element.constants.data(), sizeBytes);
AddCBufferToDebugTrace(program, debugTrace, refl, mapping, slot, cbufData);
AddCBufferToGlobalState(program, global, sourceVars, refl, mapping, slot, cbufData);
}
else if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV && element.type == eRootCBV)
{
@@ -1067,7 +1069,7 @@ void GatherConstantBuffers(WrappedID3D12Device *pDevice, const DXBCBytecode::Pro
ID3D12Resource *cbv = pDevice->GetResourceManager()->GetCurrentAs<ID3D12Resource>(element.id);
bytebuf cbufData;
pDevice->GetDebugManager()->GetBufferData(cbv, element.offset, 0, cbufData);
AddCBufferToDebugTrace(program, debugTrace, refl, mapping, slot, cbufData);
AddCBufferToGlobalState(program, global, sourceVars, refl, mapping, slot, cbufData);
}
else if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE &&
element.type == eRootTable)
@@ -1122,7 +1124,7 @@ void GatherConstantBuffers(WrappedID3D12Device *pDevice, const DXBCBytecode::Pro
pDevice->GetResourceManager()->GetCurrentAs<ID3D12Resource>(resId);
cbufData.clear();
pDevice->GetDebugManager()->GetBufferData(pCbvResource, element.offset, 0, cbufData);
AddCBufferToDebugTrace(program, debugTrace, refl, mapping, slot, cbufData);
AddCBufferToGlobalState(program, global, sourceVars, refl, mapping, slot, cbufData);
}
}
}
@@ -1131,28 +1133,26 @@ void GatherConstantBuffers(WrappedID3D12Device *pDevice, const DXBCBytecode::Pro
}
}
ShaderDebugTrace D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
{
RDCUNIMPLEMENTED("Vertex debugging not yet implemented for D3D12");
ShaderDebugTrace ret;
return ret;
return new ShaderDebugTrace();
}
#if D3D12SHADERDEBUG_PIXEL == 0
ShaderDebugTrace D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
{
RDCUNIMPLEMENTED("Pixel debugging not yet implemented for D3D12");
ShaderDebugTrace ret;
return ret;
return new ShaderDebugTrace();
}
#else
ShaderDebugTrace D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
{
using namespace DXBC;
using namespace DXBCBytecode;
@@ -1164,20 +1164,18 @@ ShaderDebugTrace D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
const D3D12Pipe::State *pipelineState = GetD3D12PipelineState();
ShaderDebugTrace empty;
// Fetch the disassembly info from the pixel shader
const D3D12Pipe::Shader &pixelShader = pipelineState->pixelShader;
WrappedID3D12Shader *ps =
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12Shader>(pixelShader.resourceId);
if(!ps)
return empty;
return new ShaderDebugTrace;
DXBCContainer *dxbc = ps->GetDXBC();
const ShaderReflection &refl = ps->GetDetails();
if(!dxbc)
return empty;
return new ShaderDebugTrace;
dxbc->GetDisassembly();
@@ -1230,7 +1228,7 @@ ShaderDebugTrace D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
if(outputSampleCount > 1)
{
RDCUNIMPLEMENTED("MSAA debugging not yet implemented for D3D12");
return empty;
return new ShaderDebugTrace;
}
extractHlsl += R"(
@@ -1298,7 +1296,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
"ps_5_0", &psBlob) != "")
{
RDCERR("Failed to create shader to extract inputs");
return empty;
return new ShaderDebugTrace;
}
uint32_t structStride = sizeof(uint32_t) // uint hit;
@@ -1343,7 +1341,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
{
RDCERR("Failed to create buffer for pixel shader debugging HRESULT: %s", ToStr(hr).c_str());
SAFE_RELEASE(psBlob);
return empty;
return new ShaderDebugTrace;
}
// Create UAV of initial values buffer
@@ -1410,7 +1408,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
SAFE_RELEASE(root);
SAFE_RELEASE(psBlob);
SAFE_RELEASE(pInitialValuesBuffer);
return empty;
return new ShaderDebugTrace;
}
SAFE_RELEASE(root);
@@ -1435,7 +1433,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
SAFE_RELEASE(psBlob);
SAFE_RELEASE(pInitialValuesBuffer);
SAFE_RELEASE(pRootSignature);
return empty;
return new ShaderDebugTrace;
}
// Add the descriptor for our UAV, then clear it
@@ -1459,7 +1457,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
SAFE_RELEASE(pInitialValuesBuffer);
SAFE_RELEASE(pRootSignature);
SAFE_RELEASE(initialPso);
return empty;
return new ShaderDebugTrace;
}
{
@@ -1500,7 +1498,7 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(buf[0].numHits == 0)
{
RDCLOG("No hit for this event");
return empty;
return new ShaderDebugTrace;
}
// if we encounter multiple hits at our destination pixel co-ord (or any other) we
@@ -1567,43 +1565,28 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(pWinnerHit == NULL)
{
RDCLOG("Couldn't find any pixels that passed depth test at target coordinates");
return empty;
return new ShaderDebugTrace;
}
ShaderDebugTrace ret;
GlobalState global;
global.PopulateGroupshared(dxbc->GetDXBCByteCode());
State quad[4] = {
// top-left
State(0, &global, dxbc),
// top-right
State(1, &global, dxbc),
// bottom-left
State(2, &global, dxbc),
// bottom-right
State(3, &global, dxbc),
};
CreateShaderDebugStateAndTrace(quad[destIdx], ret, dxbc, refl, origPSO->PS()->GetMapping());
InterpretDebugger *interpreter = new InterpretDebugger;
ShaderDebugTrace *ret = interpreter->BeginDebug(dxbc, refl, origPSO->PS()->GetMapping(), destIdx);
GlobalState &global = interpreter->global;
ThreadState &state = interpreter->activeLane();
// Fetch constant buffer data from root signature
GatherConstantBuffers(m_pDevice, *dxbc->GetDXBCByteCode(), rs.graphics, refl,
origPSO->PS()->GetMapping(), ret);
global.constantBlocks = ret.constantBlocks;
origPSO->PS()->GetMapping(), global, ret->sourceVars);
{
DebugHit *pHit = pWinnerHit;
rdcarray<ShaderVariable> &ins = quad[destIdx].inputs;
rdcarray<ShaderVariable> &ins = state.inputs;
if(!ins.empty() && ins.back().name == "vCoverage")
ins.back().value.u.x = pHit->coverage;
quad[destIdx].semantics.coverage = pHit->coverage;
quad[destIdx].semantics.primID = pHit->primitive;
quad[destIdx].semantics.isFrontFace = pHit->isFrontFace;
state.semantics.coverage = pHit->coverage;
state.semantics.primID = pHit->primitive;
state.semantics.isFrontFace = pHit->isFrontFace;
uint32_t *data = &pHit->rawdata;
@@ -1613,7 +1596,9 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
if(*pos_ddx != 1.0f)
{
RDCERR("Derivatives invalid");
return empty;
delete interpreter;
delete ret;
return new ShaderDebugTrace;
}
data++;
@@ -1656,162 +1641,26 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
for(int i = 0; i < 4; i++)
{
quad[i].inputs = quad[destIdx].inputs;
quad[i].semantics = quad[destIdx].semantics;
quad[i].variables = quad[destIdx].variables;
quad[i].SetHelper();
if(i != destIdx)
{
interpreter->workgroup[i].inputs = state.inputs;
interpreter->workgroup[i].semantics = state.semantics;
interpreter->workgroup[i].variables = state.variables;
interpreter->workgroup[i].SetHelper();
}
}
// TODO: Handle inputs that were evaluated at sample granularity (MSAA)
ApplyAllDerivatives(global, quad, destIdx, initialValues, (float *)data);
ApplyAllDerivatives(global, interpreter->workgroup, destIdx, initialValues, (float *)data);
}
ret.inputs = quad[destIdx].inputs;
ret->constantBlocks = global.constantBlocks;
ret->inputs = state.inputs;
rdcarray<ShaderDebugState> states;
ret->hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
dxbc->FillStateInstructionInfo(quad[destIdx]);
states.push_back(quad[destIdx]);
// ping pong between so that we can have 'current' quad to update into new one
State quad2[4] = {
State(0, &global, dxbc), State(1, &global, dxbc), State(2, &global, dxbc),
State(3, &global, dxbc),
};
State *curquad = quad;
State *newquad = quad2;
// marks any threads stalled waiting for others to catch up
bool activeMask[4] = {true, true, true, true};
int cycleCounter = 0;
D3D12MarkerRegion simloop(m_pDevice->GetQueue()->GetReal(), "Simulation Loop");
D3D12DebugAPIWrapper apiWrapper(m_pDevice, dxbc, global);
// simulate lockstep until all threads are finished
bool finished = true;
do
{
for(size_t i = 0; i < 4; i++)
{
if(activeMask[i])
newquad[i] = curquad[i].GetNext(&apiWrapper, curquad);
else
newquad[i] = curquad[i];
}
State *a = curquad;
curquad = newquad;
newquad = a;
// if our destination quad is paused don't record multiple identical states.
if(activeMask[destIdx])
{
State &s = curquad[destIdx];
dxbc->FillStateInstructionInfo(s);
states.push_back(s);
}
// we need to make sure that control flow which converges stays in lockstep so that
// derivatives are still valid. While diverged, we don't have to keep threads in lockstep
// since using derivatives is invalid.
// Threads diverge either in ifs, loops, or switches. Due to the nature of the bytecode,
// all threads *must* pass through the same exit instruction for each, there's no jumping
// around with gotos. Note also for the same reason, the only time threads are on earlier
// instructions is if they are still catching up to a thread that has exited the control
// flow.
// So the scheme is as follows:
// * If all threads have the same nextInstruction, just continue we are still in lockstep.
// * If threads are out of lockstep, find any thread which has nextInstruction pointing
// immediately *after* an ENDIF, ENDLOOP or ENDSWITCH. Pointing directly at one is not
// an indication the thread is done, as the next step for an ENDLOOP will jump back to
// the matching LOOP and continue iterating.
// * Pause any thread matching the above until all threads are pointing to the same
// instruction. By the assumption above, all threads will eventually pass through this
// terminating instruction so we just pause any other threads and don't do anything
// until the control flow has converged and we can continue stepping in lockstep.
// mark all threads as active again.
// if we've converged, or we were never diverged, this keeps everything ticking
activeMask[0] = activeMask[1] = activeMask[2] = activeMask[3] = true;
if(curquad[0].nextInstruction != curquad[1].nextInstruction ||
curquad[0].nextInstruction != curquad[2].nextInstruction ||
curquad[0].nextInstruction != curquad[3].nextInstruction)
{
// this isn't *perfect* but it will still eventually continue. We look for the most
// advanced thread, and check to see if it's just finished a control flow. If it has
// then we assume it's at the convergence point and wait for every other thread to
// catch up, pausing any threads that reach the convergence point before others.
// Note this might mean we don't have any threads paused even within divergent flow.
// This is fine and all we care about is pausing to make sure threads don't run ahead
// into code that should be lockstep. We don't care at all about what they do within
// the code that is divergent.
// The reason this isn't perfect is that the most advanced thread could be on an
// inner loop or inner if, not the convergence point, and we could be pausing it
// fruitlessly. Worse still - it could be on a branch none of the other threads will
// take so they will never reach that exact instruction.
// But we know that all threads will eventually go through the convergence point, so
// even in that worst case if we didn't pick the right waiting point, another thread
// will overtake and become the new most advanced thread and the previous waiting
// thread will resume. So in this case we caused a thread to wait more than it should
// have but that's not a big deal as it's within divergent flow so they don't have to
// stay in lockstep. Also if all threads will eventually pass that point we picked,
// we just waited to converge even in technically divergent code which is also
// harmless.
// Phew!
uint32_t convergencePoint = 0;
// find which thread is most advanced
for(size_t i = 0; i < 4; i++)
if(curquad[i].nextInstruction > convergencePoint)
convergencePoint = curquad[i].nextInstruction;
if(convergencePoint > 0)
{
OpcodeType op = dxbc->GetDXBCByteCode()->GetInstruction(convergencePoint - 1).operation;
// if the most advnaced thread hasn't just finished control flow, then all
// threads are still running, so don't converge
if(op != OPCODE_ENDIF && op != OPCODE_ENDLOOP && op != OPCODE_ENDSWITCH)
convergencePoint = 0;
}
// pause any threads at that instruction (could be none)
for(size_t i = 0; i < 4; i++)
if(curquad[i].nextInstruction == convergencePoint)
activeMask[i] = false;
}
finished = curquad[destIdx].Finished();
cycleCounter++;
if(cycleCounter == SHADER_DEBUG_WARN_THRESHOLD)
{
if(PromptDebugTimeout(cycleCounter))
break;
}
} while(!finished);
ret.states = states;
ret.hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
dxbc->FillTraceLineInfo(ret);
dxbc->FillTraceLineInfo(*ret);
return ret;
}
@@ -1820,18 +1669,17 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
#if D3D12SHADERDEBUG_THREAD == 0
ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
{
RDCUNIMPLEMENTED("Compute shader debugging not yet implemented for D3D12");
ShaderDebugTrace ret;
return ret;
return new ShaderDebugTrace();
}
#else
ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
{
using namespace DXBCBytecode;
using namespace DXBCDebug;
@@ -1841,78 +1689,47 @@ ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventId, const uint32_t group
StringFormat::Fmt("DebugThread @ %u: [%u, %u, %u] (%u, %u, %u)", eventId, groupid[0],
groupid[1], groupid[2], threadid[0], threadid[1], threadid[2]));
ShaderDebugTrace empty;
const D3D12Pipe::State *pipelineState = GetD3D12PipelineState();
const D3D12Pipe::Shader &computeShader = pipelineState->computeShader;
WrappedID3D12Shader *cs =
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12Shader>(computeShader.resourceId);
if(!cs)
return empty;
return new ShaderDebugTrace;
DXBC::DXBCContainer *dxbc = cs->GetDXBC();
const ShaderReflection &refl = cs->GetDetails();
if(!dxbc)
return empty;
return new ShaderDebugTrace;
dxbc->GetDisassembly();
D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState;
ShaderDebugTrace ret;
WrappedID3D12PipelineState *pso =
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12PipelineState>(rs.pipe);
GlobalState global;
global.PopulateGroupshared(dxbc->GetDXBCByteCode());
State initialState(-1, &global, dxbc);
CreateShaderDebugStateAndTrace(initialState, ret, dxbc, refl, pso->CS()->GetMapping());
InterpretDebugger *interpreter = new InterpretDebugger;
ShaderDebugTrace *ret = interpreter->BeginDebug(dxbc, refl, pso->CS()->GetMapping(), 0);
GlobalState &global = interpreter->global;
ThreadState &state = interpreter->activeLane();
GatherConstantBuffers(m_pDevice, *dxbc->GetDXBCByteCode(), rs.compute, refl,
pso->CS()->GetMapping(), ret);
global.constantBlocks = ret.constantBlocks;
pso->CS()->GetMapping(), global, ret->sourceVars);
for(int i = 0; i < 3; i++)
{
initialState.semantics.GroupID[i] = groupid[i];
initialState.semantics.ThreadID[i] = threadid[i];
state.semantics.GroupID[i] = groupid[i];
state.semantics.ThreadID[i] = threadid[i];
}
rdcarray<ShaderDebugState> states;
ret->constantBlocks = global.constantBlocks;
dxbc->FillStateInstructionInfo(initialState);
ret->hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
states.push_back((State)initialState);
D3D12DebugAPIWrapper apiWrapper(m_pDevice, dxbc, global);
for(int cycleCounter = 0;; cycleCounter++)
{
if(initialState.Finished())
break;
initialState = initialState.GetNext(&apiWrapper, NULL);
dxbc->FillStateInstructionInfo(initialState);
states.push_back((State)initialState);
if(cycleCounter == SHADER_DEBUG_WARN_THRESHOLD)
{
if(PromptDebugTimeout(cycleCounter))
break;
}
}
ret.states = states;
ret.hasSourceMapping = dxbc->GetDebugInfo() && dxbc->GetDebugInfo()->HasSourceMapping();
dxbc->FillTraceLineInfo(ret);
dxbc->FillTraceLineInfo(*ret);
// add fake inputs for semantics
for(size_t i = 0; i < dxbc->GetDXBCByteCode()->GetNumDeclarations(); i++)
{
const DXBCBytecode::Declaration &decl = dxbc->GetDXBCByteCode()->GetDeclaration(i);
@@ -1931,38 +1748,37 @@ ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventId, const uint32_t group
switch(decl.operand.type)
{
case TYPE_INPUT_THREAD_GROUP_ID:
memcpy(v.value.uv, initialState.semantics.GroupID, sizeof(uint32_t) * 3);
memcpy(v.value.uv, state.semantics.GroupID, sizeof(uint32_t) * 3);
v.columns = 3;
break;
case TYPE_INPUT_THREAD_ID_IN_GROUP:
memcpy(v.value.uv, initialState.semantics.ThreadID, sizeof(uint32_t) * 3);
memcpy(v.value.uv, state.semantics.ThreadID, sizeof(uint32_t) * 3);
v.columns = 3;
break;
case TYPE_INPUT_THREAD_ID:
v.value.u.x = initialState.semantics.GroupID[0] *
dxbc->GetReflection()->DispatchThreadsDimension[0] +
initialState.semantics.ThreadID[0];
v.value.u.y = initialState.semantics.GroupID[1] *
dxbc->GetReflection()->DispatchThreadsDimension[1] +
initialState.semantics.ThreadID[1];
v.value.u.z = initialState.semantics.GroupID[2] *
dxbc->GetReflection()->DispatchThreadsDimension[2] +
initialState.semantics.ThreadID[2];
v.value.u.x =
state.semantics.GroupID[0] * dxbc->GetReflection()->DispatchThreadsDimension[0] +
state.semantics.ThreadID[0];
v.value.u.y =
state.semantics.GroupID[1] * dxbc->GetReflection()->DispatchThreadsDimension[1] +
state.semantics.ThreadID[1];
v.value.u.z =
state.semantics.GroupID[2] * dxbc->GetReflection()->DispatchThreadsDimension[2] +
state.semantics.ThreadID[2];
v.columns = 3;
break;
case TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED:
v.value.u.x = initialState.semantics.ThreadID[2] *
dxbc->GetReflection()->DispatchThreadsDimension[0] *
dxbc->GetReflection()->DispatchThreadsDimension[1] +
initialState.semantics.ThreadID[1] *
dxbc->GetReflection()->DispatchThreadsDimension[0] +
initialState.semantics.ThreadID[0];
v.value.u.x =
state.semantics.ThreadID[2] * dxbc->GetReflection()->DispatchThreadsDimension[0] *
dxbc->GetReflection()->DispatchThreadsDimension[1] +
state.semantics.ThreadID[1] * dxbc->GetReflection()->DispatchThreadsDimension[0] +
state.semantics.ThreadID[0];
v.columns = 1;
break;
default: v.columns = 4; break;
}
ret.inputs.push_back(v);
ret->inputs.push_back(v);
}
}
@@ -1970,3 +1786,17 @@ ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventId, const uint32_t group
}
#endif // D3D12SHADERDEBUG_THREAD
rdcarray<ShaderDebugState> D3D12Replay::ContinueDebug(ShaderDebugger *debugger)
{
DXBCDebug::InterpretDebugger *interpreter = (DXBCDebug::InterpretDebugger *)debugger;
if(!interpreter)
return NULL;
D3D12DebugAPIWrapper apiWrapper(m_pDevice, interpreter->dxbc, interpreter->global);
D3D12MarkerRegion region(m_pDevice->GetQueue()->GetReal(), "ContinueDebug Simulation Loop");
return interpreter->ContinueDebug(&apiWrapper);
}
+15 -9
View File
@@ -3453,25 +3453,31 @@ rdcarray<PixelModification> GLReplay::PixelHistory(rdcarray<EventUsage> events,
return {};
}
ShaderDebugTrace GLReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
ShaderDebugTrace *GLReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
{
GLNOTIMP("DebugVertex");
return ShaderDebugTrace();
return new ShaderDebugTrace();
}
ShaderDebugTrace GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
{
GLNOTIMP("DebugPixel");
return ShaderDebugTrace();
return new ShaderDebugTrace();
}
ShaderDebugTrace GLReplay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
ShaderDebugTrace *GLReplay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
{
GLNOTIMP("DebugThread");
return ShaderDebugTrace();
return new ShaderDebugTrace();
}
rdcarray<ShaderDebugState> GLReplay::ContinueDebug(ShaderDebugger *debugger)
{
GLNOTIMP("ContinueDebug");
return {};
}
void GLReplay::MakeCurrentReplayContext(GLWindowingData *ctx)
+7 -6
View File
@@ -217,12 +217,13 @@ public:
rdcarray<PixelModification> PixelHistory(rdcarray<EventUsage> events, ResourceId target, uint32_t x,
uint32_t y, const Subresource &sub, CompType typeCast);
ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]);
ShaderDebugTrace *DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace *DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace *DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]);
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg,
uint32_t x, uint32_t y);
File diff suppressed because it is too large Load Diff
+44 -29
View File
@@ -179,9 +179,6 @@ public:
rdcarray<ShaderVariable> constantBlocks;
};
#define SHADER_DEBUG_WARN_THRESHOLD 100000
bool PromptDebugTimeout(uint32_t cycleCounter);
struct PSInputElement
{
PSInputElement(int regster, int element, int numWords, ShaderBuiltin attr, bool inc)
@@ -272,10 +269,10 @@ public:
ShaderVariable &output) = 0;
};
class State : public ShaderDebugState
class ThreadState
{
public:
State(int quadIdx, GlobalState *globalState, const DXBC::DXBCContainer *dxbc);
ThreadState(int workgroupIdx, GlobalState &globalState, const DXBC::DXBCContainer *dxbc);
void SetHelper() { done = true; }
struct
@@ -287,26 +284,28 @@ public:
uint32_t isFrontFace;
} semantics;
uint32_t nextInstruction;
GlobalState &global;
rdcarray<ShaderVariable> inputs;
rdcarray<ShaderVariable> variables;
bool Finished() const;
State GetNext(DebugAPIWrapper *apiWrapper, State quad[4]) const;
rdcarray<ShaderVariable> inputs;
GlobalState *global;
void StepNext(ShaderDebugState *prevState, DebugAPIWrapper *apiWrapper,
const rdcarray<ThreadState> &prevWorkgroup);
private:
// index in the pixel quad
int quadIndex;
int workgroupIndex;
bool done;
// validates assignment for generation of non-normal values
bool AssignValue(ShaderVariable &dst, uint32_t dstIndex, const ShaderVariable &src,
uint32_t srcIndex, bool flushDenorm);
ShaderEvents AssignValue(ShaderVariable &dst, uint32_t dstIndex, const ShaderVariable &src,
uint32_t srcIndex, bool flushDenorm);
// sets the destination operand by looking up in the register
// file and applying any masking or swizzling
void SetDst(const DXBCBytecode::Operand &dstoper, const DXBCBytecode::Operation &op,
const ShaderVariable &val);
void SetDst(ShaderDebugState *state, const DXBCBytecode::Operand &dstoper,
const DXBCBytecode::Operation &op, const ShaderVariable &val);
// retrieves the value of the operand, by looking up
// in the register file and performing any swizzling and
@@ -314,26 +313,42 @@ private:
ShaderVariable GetSrc(const DXBCBytecode::Operand &oper, const DXBCBytecode::Operation &op,
bool allowFlushing = true) const;
ShaderVariable DDX(bool fine, State quad[4], const DXBCBytecode::Operand &oper,
const DXBCBytecode::Operation &op) const;
ShaderVariable DDY(bool fine, State quad[4], const DXBCBytecode::Operand &oper,
const DXBCBytecode::Operation &op) const;
VarType OperationType(const DXBCBytecode::OpcodeType &op) const;
bool OperationFlushing(const DXBCBytecode::OpcodeType &op) const;
ShaderVariable DDX(bool fine, const rdcarray<ThreadState> &quad,
const DXBCBytecode::Operand &oper, const DXBCBytecode::Operation &op) const;
ShaderVariable DDY(bool fine, const rdcarray<ThreadState> &quad,
const DXBCBytecode::Operand &oper, const DXBCBytecode::Operation &op) const;
const DXBC::Reflection *reflection;
const DXBCBytecode::Program *program;
};
void ApplyAllDerivatives(GlobalState &global, State quad[4], int destIdx,
struct InterpretDebugger : public ShaderDebugger
{
ShaderDebugTrace *BeginDebug(const DXBC::DXBCContainer *dxbcContainer, const ShaderReflection &refl,
const ShaderBindpointMapping &mapping, int activeIndex);
GlobalState global;
rdcarray<ThreadState> workgroup;
// convenience for access to active lane
ThreadState &activeLane() { return workgroup[activeLaneIndex]; }
int activeLaneIndex = 0;
int steps = 0;
const DXBC::DXBCContainer *dxbc;
void CalcActiveMask(rdcarray<bool> &activeMask);
rdcarray<ShaderDebugState> ContinueDebug(DebugAPIWrapper *apiWrapper);
};
void ApplyAllDerivatives(GlobalState &global, rdcarray<ThreadState> &quad, int destIdx,
const rdcarray<PSInputElement> &initialValues, float *data);
void CreateShaderDebugStateAndTrace(State &initialState, ShaderDebugTrace &trace,
DXBC::DXBCContainer *dxbc, const ShaderReflection &refl,
const ShaderBindpointMapping &mapping);
void AddCBufferToDebugTrace(const DXBCBytecode::Program &program, ShaderDebugTrace &trace,
const ShaderReflection &refl, const ShaderBindpointMapping &mapping,
const BindingSlot &slot, bytebuf &cbufData);
void AddCBufferToGlobalState(const DXBCBytecode::Program &program, GlobalState &global,
rdcarray<SourceVariableMapping> &sourceVars,
const ShaderReflection &refl, const ShaderBindpointMapping &mapping,
const BindingSlot &slot, bytebuf &cbufData);
}; // namespace ShaderDebug
+15 -9
View File
@@ -3871,25 +3871,31 @@ void VulkanReplay::RefreshDerivedReplacements()
m_pDriver->vkDestroyPipeline(dev, pipe, NULL);
}
ShaderDebugTrace VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
{
VULKANNOTIMP("DebugVertex");
return ShaderDebugTrace();
return new ShaderDebugTrace();
}
ShaderDebugTrace VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
uint32_t sample, uint32_t primitive)
{
VULKANNOTIMP("DebugPixel");
return ShaderDebugTrace();
return new ShaderDebugTrace();
}
ShaderDebugTrace VulkanReplay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
ShaderDebugTrace *VulkanReplay::DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3])
{
VULKANNOTIMP("DebugThread");
return ShaderDebugTrace();
return new ShaderDebugTrace();
}
rdcarray<ShaderDebugState> VulkanReplay::ContinueDebug(ShaderDebugger *debugger)
{
VULKANNOTIMP("ContinueDebug");
return {};
}
ResourceId VulkanReplay::CreateProxyTexture(const TextureDescription &templateTex)
+8 -6
View File
@@ -367,12 +367,14 @@ public:
rdcarray<PixelModification> PixelHistory(rdcarray<EventUsage> events, ResourceId target, uint32_t x,
uint32_t y, const Subresource &sub, CompType typeCast);
ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]);
ShaderDebugTrace *DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace *DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace *DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]);
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg,
uint32_t x, uint32_t y);
+23 -7
View File
@@ -375,17 +375,26 @@ void DoSerialise(SerialiserType &ser, LineColumnInfo &el)
SIZE_CHECK(24);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, ShaderVariableChange &el)
{
SERIALISE_MEMBER(before);
SERIALISE_MEMBER(after);
SIZE_CHECK(384);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, ShaderDebugState &el)
{
SERIALISE_MEMBER(variables);
SERIALISE_MEMBER(sourceVars);
SERIALISE_MEMBER(modified);
SERIALISE_MEMBER(nextInstruction);
SERIALISE_MEMBER(stepIndex);
SERIALISE_MEMBER(flags);
SERIALISE_MEMBER(changes);
SERIALISE_MEMBER(sourceVars);
SERIALISE_MEMBER(callstack);
SIZE_CHECK(104);
SIZE_CHECK(88);
}
template <typename SerialiserType>
@@ -396,11 +405,18 @@ void DoSerialise(SerialiserType &ser, ShaderDebugTrace &el)
SERIALISE_MEMBER(readOnlyResources);
SERIALISE_MEMBER(readWriteResources);
SERIALISE_MEMBER(sourceVars);
SERIALISE_MEMBER(states);
SERIALISE_MEMBER(hasSourceMapping);
SERIALISE_MEMBER(lineInfo);
SERIALISE_MEMBER(hasSourceMapping);
SIZE_CHECK(176);
// serialise the debugger pointer entirely opaquely, this is only used for replay proxying
uint64_t debugger = 0;
if(ser.IsWriting())
debugger = (uint64_t)(uintptr_t)el.debugger;
SERIALISE_ELEMENT(debugger);
if(ser.IsReading())
el.debugger = (ShaderDebugger *)debugger;
SIZE_CHECK(160);
}
template <typename SerialiserType>
+19 -9
View File
@@ -1626,9 +1626,8 @@ ShaderDebugTrace *ReplayController::DebugVertex(uint32_t vertid, uint32_t instid
{
CHECK_REPLAY_THREAD();
ShaderDebugTrace *ret = new ShaderDebugTrace;
*ret = m_pDevice->DebugVertex(m_EventID, vertid, instid, idx, instOffset, vertOffset);
ShaderDebugTrace *ret =
m_pDevice->DebugVertex(m_EventID, vertid, instid, idx, instOffset, vertOffset);
SetFrameEvent(m_EventID, true);
@@ -1640,9 +1639,7 @@ ShaderDebugTrace *ReplayController::DebugPixel(uint32_t x, uint32_t y, uint32_t
{
CHECK_REPLAY_THREAD();
ShaderDebugTrace *ret = new ShaderDebugTrace;
*ret = m_pDevice->DebugPixel(m_EventID, x, y, sample, primitive);
ShaderDebugTrace *ret = m_pDevice->DebugPixel(m_EventID, x, y, sample, primitive);
SetFrameEvent(m_EventID, true);
@@ -1653,9 +1650,18 @@ ShaderDebugTrace *ReplayController::DebugThread(const uint32_t groupid[3], const
{
CHECK_REPLAY_THREAD();
ShaderDebugTrace *ret = new ShaderDebugTrace;
ShaderDebugTrace *ret = m_pDevice->DebugThread(m_EventID, groupid, threadid);
*ret = m_pDevice->DebugThread(m_EventID, groupid, threadid);
SetFrameEvent(m_EventID, true);
return ret;
}
rdcarray<ShaderDebugState> ReplayController::ContinueDebug(ShaderDebugger *debugger)
{
CHECK_REPLAY_THREAD();
rdcarray<ShaderDebugState> ret = m_pDevice->ContinueDebug(debugger);
SetFrameEvent(m_EventID, true);
@@ -1666,7 +1672,11 @@ void ReplayController::FreeTrace(ShaderDebugTrace *trace)
{
CHECK_REPLAY_THREAD();
delete trace;
if(trace)
{
SAFE_DELETE(trace->debugger);
delete trace;
}
}
rdcarray<ShaderVariable> ReplayController::GetCBufferVariableContents(
+1
View File
@@ -189,6 +189,7 @@ public:
uint32_t vertOffset);
ShaderDebugTrace *DebugPixel(uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive);
ShaderDebugTrace *DebugThread(const uint32_t groupid[3], const uint32_t threadid[3]);
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
void FreeTrace(ShaderDebugTrace *trace);
MeshFormat GetPostVSData(uint32_t instID, uint32_t viewID, MeshDataStage stage);
+7 -6
View File
@@ -179,12 +179,13 @@ public:
virtual rdcarray<PixelModification> PixelHistory(rdcarray<EventUsage> events, ResourceId target,
uint32_t x, uint32_t y, const Subresource &sub,
CompType typeCast) = 0;
virtual ShaderDebugTrace DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset) = 0;
virtual ShaderDebugTrace DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive) = 0;
virtual ShaderDebugTrace DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]) = 0;
virtual ShaderDebugTrace *DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset) = 0;
virtual ShaderDebugTrace *DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive) = 0;
virtual ShaderDebugTrace *DebugThread(uint32_t eventId, const uint32_t groupid[3],
const uint32_t threadid[3]) = 0;
virtual rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger) = 0;
virtual ResourceId RenderOverlay(ResourceId texid, CompType typeCast, FloatVector clearCol,
DebugOverlay overlay, uint32_t eventId,