mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-28 18:31:40 +00:00
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:
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ¶mser,
|
||||
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 ¶mser,
|
||||
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 ¶mser,
|
||||
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 ¶mser, ReturnSerialiser &retser,
|
||||
uint32_t eventId, uint32_t x, uint32_t y,
|
||||
uint32_t sample, uint32_t primitive)
|
||||
ShaderDebugTrace *ReplayProxy::Proxied_DebugPixel(ParamSerialiser ¶mser, 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 ¶mser, 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 ¶mser, ReturnSerialiser &retser,
|
||||
uint32_t eventId, const uint32_t groupid[3],
|
||||
const uint32_t threadid[3])
|
||||
ShaderDebugTrace *ReplayProxy::Proxied_DebugThread(ParamSerialiser ¶mser,
|
||||
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 ¶mser, 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 ¶mser,
|
||||
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 ¶mser, 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>());
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -40,12 +40,6 @@ class D3D11ResourceManager;
|
||||
|
||||
struct CopyPixelParams;
|
||||
|
||||
namespace DXBCDebug
|
||||
{
|
||||
struct GlobalState;
|
||||
class State;
|
||||
}
|
||||
|
||||
namespace DXBC
|
||||
{
|
||||
class DXBCContainer;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -38,12 +38,6 @@ namespace DXBC
|
||||
class DXBCContainer;
|
||||
};
|
||||
|
||||
namespace DXBCDebug
|
||||
{
|
||||
struct GlobalState;
|
||||
class State;
|
||||
}
|
||||
|
||||
#define D3D12_MSAA_SAMPLECOUNT 4
|
||||
|
||||
// baked indices in descriptor heaps
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user