mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-08 08:40:55 +00:00
Mesh Shader Debugging
This commit is contained in:
committed by
Baldur Karlsson
parent
a48f11d2b5
commit
3ea9735866
@@ -65,6 +65,21 @@ ComputeDebugSelector::~ComputeDebugSelector()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ComputeDebugSelector::SetDefaultDispatch(const rdcfixedarray<uint32_t, 3> &group,
|
||||
const rdcfixedarray<uint32_t, 3> &thread)
|
||||
{
|
||||
QSignalBlocker blockers[6] = {QSignalBlocker(ui->groupX), QSignalBlocker(ui->groupY),
|
||||
QSignalBlocker(ui->groupZ), QSignalBlocker(ui->threadX),
|
||||
QSignalBlocker(ui->threadY), QSignalBlocker(ui->threadZ)};
|
||||
|
||||
ui->groupX->setValue(group[0]);
|
||||
ui->groupY->setValue(group[1]);
|
||||
ui->groupZ->setValue(group[2]);
|
||||
ui->threadX->setValue(thread[0]);
|
||||
ui->threadY->setValue(thread[1]);
|
||||
ui->threadZ->setValue(thread[2]);
|
||||
}
|
||||
|
||||
void ComputeDebugSelector::SetThreadBounds(const rdcfixedarray<uint32_t, 3> &group,
|
||||
const rdcfixedarray<uint32_t, 3> &thread)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
explicit ComputeDebugSelector(QWidget *parent = 0);
|
||||
~ComputeDebugSelector();
|
||||
|
||||
void SetDefaultDispatch(const rdcfixedarray<uint32_t, 3> &group,
|
||||
const rdcfixedarray<uint32_t, 3> &thread);
|
||||
void SetThreadBounds(const rdcfixedarray<uint32_t, 3> &group,
|
||||
const rdcfixedarray<uint32_t, 3> &thread);
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "Code/Resources.h"
|
||||
#include "Widgets/CollapseGroupBox.h"
|
||||
#include "Widgets/ComputeDebugSelector.h"
|
||||
#include "Widgets/Extended/RDLabel.h"
|
||||
#include "Widgets/Extended/RDSplitter.h"
|
||||
#include "Windows/Dialogs/AxisMappingDialog.h"
|
||||
@@ -2361,6 +2362,8 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)
|
||||
m_ModelOut1 = new BufferItemModel(ui->out1Table, false, meshview, this);
|
||||
m_ModelOut2 = new BufferItemModel(ui->out2Table, false, meshview, this);
|
||||
|
||||
m_MeshDebugSelector = new ComputeDebugSelector(this);
|
||||
|
||||
// we keep the old UI names for serialised layouts compatibility
|
||||
QString containerNames[] = {
|
||||
lit("vsinData"),
|
||||
@@ -2440,6 +2443,9 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)
|
||||
m_DebugVert = new QAction(tr("&Debug this Vertex"), this);
|
||||
m_DebugVert->setIcon(Icons::wrench());
|
||||
|
||||
m_DebugMeshThread = new QAction(tr("&Debug Mesh Thread"), this);
|
||||
m_DebugMeshThread->setIcon(Icons::wrench());
|
||||
|
||||
m_FilterMesh = new QAction(tr("&Filter to this Meshlet"), this);
|
||||
m_FilterMesh->setIcon(Icons::filter());
|
||||
|
||||
@@ -2458,6 +2464,7 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)
|
||||
QObject::connect(m_ExportBytes, &QAction::triggered,
|
||||
[this] { exportData(BufferExport(BufferExport::RawBytes)); });
|
||||
QObject::connect(m_DebugVert, &QAction::triggered, this, &BufferViewer::debugVertex);
|
||||
QObject::connect(m_DebugMeshThread, &QAction::triggered, this, &BufferViewer::debugMeshThread);
|
||||
QObject::connect(m_RemoveFilter, &QAction::triggered,
|
||||
[this]() { SetMeshFilter(MeshFilter::None); });
|
||||
QObject::connect(m_FilterMesh, &QAction::triggered, [this]() {
|
||||
@@ -2624,6 +2631,9 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)
|
||||
ui->fixedVars->setTooltipElidedItems(false);
|
||||
ui->fixedVars->installEventFilter(this);
|
||||
|
||||
QObject::connect(m_MeshDebugSelector, &ComputeDebugSelector::beginDebug, this,
|
||||
&BufferViewer::meshDebugSelector_beginDebug);
|
||||
|
||||
Reset();
|
||||
|
||||
m_Ctx.AddCaptureViewer(this);
|
||||
@@ -3093,6 +3103,37 @@ void BufferViewer::stageRowMenu(MeshDataStage stage, QMenu *menu, const QPoint &
|
||||
menu->addAction(m_RemoveFilter);
|
||||
menu->addAction(m_FilterMesh);
|
||||
menu->addAction(m_GotoTask);
|
||||
|
||||
const ShaderReflection *shaderDetails =
|
||||
m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Mesh);
|
||||
|
||||
m_DebugMeshThread->setEnabled(false);
|
||||
|
||||
if(!m_Ctx.APIProps().shaderDebugging)
|
||||
{
|
||||
m_DebugMeshThread->setToolTip(tr("This API does not support shader debugging"));
|
||||
}
|
||||
else if(!m_Ctx.CurAction() ||
|
||||
!(m_Ctx.CurAction()->flags & (ActionFlags::Drawcall | ActionFlags::MeshDispatch)))
|
||||
{
|
||||
m_DebugMeshThread->setToolTip(tr("No draw call selected"));
|
||||
}
|
||||
else if(!shaderDetails)
|
||||
{
|
||||
m_DebugMeshThread->setToolTip(tr("No mesh shader bound"));
|
||||
}
|
||||
else if(!shaderDetails->debugInfo.debuggable)
|
||||
{
|
||||
m_DebugMeshThread->setToolTip(
|
||||
tr("This shader doesn't support debugging: %1").arg(shaderDetails->debugInfo.debugStatus));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DebugMeshThread->setEnabled(true);
|
||||
m_DebugMeshThread->setToolTip(QString());
|
||||
}
|
||||
menu->addAction(m_DebugMeshThread);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
m_GotoTask->setEnabled(m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Task));
|
||||
@@ -6638,6 +6679,135 @@ void BufferViewer::debugVertex()
|
||||
m_Ctx.AddDockWindow(s->Widget(), DockReference::AddTo, this);
|
||||
}
|
||||
|
||||
void BufferViewer::debugMeshThread()
|
||||
{
|
||||
if(!m_Ctx.IsCaptureLoaded())
|
||||
return;
|
||||
|
||||
const ActionDescription *action = m_Ctx.CurAction();
|
||||
if(!action)
|
||||
return;
|
||||
|
||||
if(!m_CurView)
|
||||
return;
|
||||
|
||||
QModelIndex idx = m_CurView->selectionModel()->currentIndex();
|
||||
|
||||
if(!idx.isValid())
|
||||
{
|
||||
GUIInvoke::call(this, [this]() {
|
||||
RDDialog::critical(this, tr("Error debugging"),
|
||||
tr("Error debugging meshlet - make sure a valid meshlet is selected"));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t taskIndex = 0, meshletIndex = 0;
|
||||
GetIndicesForMeshRow((uint32_t)idx.row(), taskIndex, meshletIndex);
|
||||
|
||||
const ShaderReflection *shaderDetails =
|
||||
m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Mesh);
|
||||
|
||||
if(!shaderDetails)
|
||||
return;
|
||||
|
||||
rdcfixedarray<uint32_t, 3> threadGroupSize = action->dispatchThreadsDimension[0] == 0
|
||||
? shaderDetails->dispatchThreadsDimension
|
||||
: action->dispatchThreadsDimension;
|
||||
m_MeshDebugSelector->SetThreadBounds(action->dispatchDimension, threadGroupSize);
|
||||
|
||||
// Calculate 3d group id from 1d meshlet index and dispatch dimensions
|
||||
// Imagine 8x2x4 with idx 60
|
||||
// 8x2 = 16
|
||||
// 8x2x4 = 64
|
||||
// 60 % x = 4
|
||||
// 60 % (x * y) = 12 / x = 1
|
||||
// 60 / (x * y) = 3
|
||||
// index 60 is id (4,1,3)
|
||||
// 4 + (8 * 1) + (16 * 3) = 60
|
||||
uint32_t xDim = action->dispatchDimension[0];
|
||||
uint32_t yDim = action->dispatchDimension[1];
|
||||
uint32_t zDim = action->dispatchDimension[2];
|
||||
rdcfixedarray<uint32_t, 3> meshletGroup = {
|
||||
meshletIndex % xDim,
|
||||
(meshletIndex % (xDim * yDim)) / xDim,
|
||||
meshletIndex / (xDim * yDim),
|
||||
};
|
||||
m_MeshDebugSelector->SetDefaultDispatch(meshletGroup, {0, 0, 0});
|
||||
|
||||
RDDialog::show(m_MeshDebugSelector);
|
||||
}
|
||||
|
||||
void BufferViewer::meshDebugSelector_beginDebug(const rdcfixedarray<uint32_t, 3> &group,
|
||||
const rdcfixedarray<uint32_t, 3> &thread)
|
||||
{
|
||||
const ActionDescription *action = m_Ctx.CurAction();
|
||||
|
||||
if(!action)
|
||||
return;
|
||||
|
||||
const ShaderReflection *shaderDetails =
|
||||
m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Mesh);
|
||||
|
||||
if(!shaderDetails)
|
||||
return;
|
||||
|
||||
struct threadSelect
|
||||
{
|
||||
rdcfixedarray<uint32_t, 3> g;
|
||||
rdcfixedarray<uint32_t, 3> t;
|
||||
} debugThread = {
|
||||
// g[]
|
||||
{group[0], group[1], group[2]},
|
||||
// t[]
|
||||
{thread[0], thread[1], thread[2]},
|
||||
};
|
||||
|
||||
bool done = false;
|
||||
ShaderDebugTrace *trace = NULL;
|
||||
|
||||
m_Ctx.Replay().AsyncInvoke([&trace, &done, debugThread](IReplayController *r) {
|
||||
trace = r->DebugMeshThread(debugThread.g, debugThread.t);
|
||||
|
||||
if(trace->debugger == NULL)
|
||||
{
|
||||
r->FreeTrace(trace);
|
||||
trace = NULL;
|
||||
}
|
||||
|
||||
done = true;
|
||||
});
|
||||
|
||||
QString debugContext = lit("Mesh Group [%1,%2,%3] Thread [%4,%5,%6]")
|
||||
.arg(group[0])
|
||||
.arg(group[1])
|
||||
.arg(group[2])
|
||||
.arg(thread[0])
|
||||
.arg(thread[1])
|
||||
.arg(thread[2]);
|
||||
|
||||
// wait a short while before displaying the progress dialog (which won't show if we're already
|
||||
// done by the time we reach it)
|
||||
for(int i = 0; !done && i < 100; i++)
|
||||
QThread::msleep(5);
|
||||
|
||||
ShowProgressDialog(this, tr("Debugging %1").arg(debugContext), [&done]() { return done; });
|
||||
|
||||
if(!trace)
|
||||
{
|
||||
RDDialog::critical(
|
||||
this, tr("Error debugging"),
|
||||
tr("Error debugging thread - make sure a valid group and thread is selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
// viewer takes ownership of the trace
|
||||
IShaderViewer *s = m_Ctx.DebugShader(
|
||||
shaderDetails, m_Ctx.CurPipelineState().GetComputePipelineObject(), trace, debugContext);
|
||||
|
||||
m_Ctx.AddDockWindow(s->Widget(), DockReference::AddTo, this);
|
||||
}
|
||||
|
||||
void BufferViewer::SyncViews(RDTableView *primary, bool selection, bool scroll)
|
||||
{
|
||||
if(!ui->syncViews->isChecked())
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Ui
|
||||
class BufferViewer;
|
||||
}
|
||||
|
||||
class ComputeDebugSelector;
|
||||
class RDSpinBox64;
|
||||
class QItemSelection;
|
||||
class QMenu;
|
||||
@@ -164,12 +165,16 @@ private slots:
|
||||
void updateExportActionNames();
|
||||
void exportData(const BufferExport ¶ms);
|
||||
void debugVertex();
|
||||
void debugMeshThread();
|
||||
void meshDebugSelector_beginDebug(const rdcfixedarray<uint32_t, 3> &group,
|
||||
const rdcfixedarray<uint32_t, 3> &thread);
|
||||
void fixedVars_contextMenu(const QPoint &pos);
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
Ui::BufferViewer *ui;
|
||||
ICaptureContext &m_Ctx;
|
||||
ComputeDebugSelector *m_MeshDebugSelector;
|
||||
|
||||
IReplayOutput *m_Output;
|
||||
|
||||
@@ -323,6 +328,7 @@ private:
|
||||
QAction *m_ExportCSV = NULL;
|
||||
QAction *m_ExportBytes = NULL;
|
||||
QAction *m_DebugVert = NULL;
|
||||
QAction *m_DebugMeshThread = NULL;
|
||||
QAction *m_FilterMesh = NULL;
|
||||
QAction *m_RemoveFilter = NULL;
|
||||
QAction *m_GotoTask = NULL;
|
||||
|
||||
@@ -266,6 +266,10 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s
|
||||
inputs.view = msg.location.pixel.view;
|
||||
trace = r->DebugPixel(msg.location.pixel.x, msg.location.pixel.y, inputs);
|
||||
}
|
||||
else if(msg.stage == ShaderStage::Mesh)
|
||||
{
|
||||
trace = r->DebugMeshThread(msg.location.mesh.meshGroup, msg.location.mesh.thread);
|
||||
}
|
||||
|
||||
if(trace && trace->debugger == NULL)
|
||||
{
|
||||
|
||||
@@ -1021,6 +1021,17 @@ bucket when the pixel values are divided between ``minval`` and ``maxval``.
|
||||
virtual ShaderDebugTrace *DebugThread(const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid) = 0;
|
||||
|
||||
DOCUMENT(R"(Retrieve a debugging trace from running a mesh shader.
|
||||
|
||||
:param Tuple[int,int,int] groupid: A list containing the 3D workgroup index.
|
||||
:param Tuple[int,int,int] threadid: A list containing the 3D thread index within the workgroup.
|
||||
:return: The resulting trace resulting from debugging. Destroy with
|
||||
:meth:`FreeTrace`.
|
||||
:rtype: ShaderDebugTrace
|
||||
)");
|
||||
virtual ShaderDebugTrace *DebugMeshThread(const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid) = 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
|
||||
|
||||
@@ -357,6 +357,11 @@ public:
|
||||
{
|
||||
return new ShaderDebugTrace();
|
||||
}
|
||||
ShaderDebugTrace *DebugMeshThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
return new ShaderDebugTrace();
|
||||
}
|
||||
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger) { return {}; }
|
||||
void FreeDebugger(ShaderDebugger *debugger) { delete debugger; }
|
||||
void BuildTargetShader(ShaderEncoding sourceEncoding, const bytebuf &source, const rdcstr &entry,
|
||||
|
||||
@@ -1684,6 +1684,44 @@ ShaderDebugTrace *ReplayProxy::DebugThread(uint32_t eventId,
|
||||
PROXY_FUNCTION(DebugThread, eventId, groupid, threadid);
|
||||
}
|
||||
|
||||
template <typename ParamSerialiser, typename ReturnSerialiser>
|
||||
ShaderDebugTrace *ReplayProxy::Proxied_DebugMeshThread(ParamSerialiser ¶mser,
|
||||
ReturnSerialiser &retser, uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
const ReplayProxyPacket expectedPacket = eReplayProxy_DebugMeshThread;
|
||||
ReplayProxyPacket packet = eReplayProxy_DebugMeshThread;
|
||||
ShaderDebugTrace *ret;
|
||||
|
||||
{
|
||||
BEGIN_PARAMS();
|
||||
SERIALISE_ELEMENT(eventId);
|
||||
SERIALISE_ELEMENT(groupid);
|
||||
SERIALISE_ELEMENT(threadid);
|
||||
END_PARAMS();
|
||||
}
|
||||
|
||||
{
|
||||
REMOTE_EXECUTION();
|
||||
if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored)
|
||||
ret = m_Remote->DebugMeshThread(eventId, groupid, threadid);
|
||||
else
|
||||
ret = new ShaderDebugTrace;
|
||||
}
|
||||
|
||||
SERIALISE_RETURN(*ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *ReplayProxy::DebugMeshThread(uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
PROXY_FUNCTION(DebugMeshThread, eventId, groupid, threadid);
|
||||
}
|
||||
|
||||
template <typename ParamSerialiser, typename ReturnSerialiser>
|
||||
rdcarray<ShaderDebugState> ReplayProxy::Proxied_ContinueDebug(ParamSerialiser ¶mser,
|
||||
ReturnSerialiser &retser,
|
||||
|
||||
@@ -89,6 +89,7 @@ enum ReplayProxyPacket
|
||||
eReplayProxy_DebugVertex,
|
||||
eReplayProxy_DebugPixel,
|
||||
eReplayProxy_DebugThread,
|
||||
eReplayProxy_DebugMeshThread,
|
||||
|
||||
eReplayProxy_RenderOverlay,
|
||||
|
||||
@@ -552,6 +553,9 @@ public:
|
||||
IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace *, DebugThread, uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
IMPLEMENT_FUNCTION_PROXIED(ShaderDebugTrace *, DebugMeshThread, uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
IMPLEMENT_FUNCTION_PROXIED(rdcarray<ShaderDebugState>, ContinueDebug, ShaderDebugger *debugger);
|
||||
IMPLEMENT_FUNCTION_PROXIED(void, FreeDebugger, ShaderDebugger *debugger);
|
||||
|
||||
|
||||
@@ -288,6 +288,8 @@ public:
|
||||
const DebugPixelInputs &inputs);
|
||||
ShaderDebugTrace *DebugThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
ShaderDebugTrace *DebugMeshThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
|
||||
void FreeDebugger(ShaderDebugger *debugger);
|
||||
|
||||
|
||||
@@ -2688,6 +2688,14 @@ ShaderDebugTrace *D3D11Replay::DebugThread(uint32_t eventId,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *D3D11Replay::DebugMeshThread(uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
// Not supported
|
||||
return new ShaderDebugTrace;
|
||||
}
|
||||
|
||||
rdcarray<ShaderDebugState> D3D11Replay::ContinueDebug(ShaderDebugger *debugger)
|
||||
{
|
||||
DXBCDebug::InterpretDebugger *interpreter = (DXBCDebug::InterpretDebugger *)debugger;
|
||||
|
||||
@@ -251,6 +251,8 @@ public:
|
||||
const DebugPixelInputs &inputs);
|
||||
ShaderDebugTrace *DebugThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
ShaderDebugTrace *DebugMeshThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
|
||||
void FreeDebugger(ShaderDebugger *debugger);
|
||||
|
||||
|
||||
@@ -3377,6 +3377,14 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *D3D12Replay::DebugMeshThread(uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
// Not implemented yet
|
||||
return new ShaderDebugTrace;
|
||||
}
|
||||
|
||||
rdcarray<ShaderDebugState> D3D12Replay::ContinueDebug(ShaderDebugger *debugger)
|
||||
{
|
||||
if(!debugger)
|
||||
|
||||
@@ -4300,6 +4300,14 @@ ShaderDebugTrace *GLReplay::DebugThread(uint32_t eventId, const rdcfixedarray<ui
|
||||
return new ShaderDebugTrace();
|
||||
}
|
||||
|
||||
ShaderDebugTrace *GLReplay::DebugMeshThread(uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
GLNOTIMP("DebugMeshThread");
|
||||
return new ShaderDebugTrace();
|
||||
}
|
||||
|
||||
rdcarray<ShaderDebugState> GLReplay::ContinueDebug(ShaderDebugger *debugger)
|
||||
{
|
||||
GLNOTIMP("ContinueDebug");
|
||||
|
||||
@@ -260,6 +260,8 @@ public:
|
||||
const DebugPixelInputs &inputs);
|
||||
ShaderDebugTrace *DebugThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
ShaderDebugTrace *DebugMeshThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
|
||||
void FreeDebugger(ShaderDebugger *debugger);
|
||||
uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg,
|
||||
|
||||
@@ -3521,6 +3521,12 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
|
||||
break;
|
||||
}
|
||||
|
||||
case Op::SetMeshOutputsEXT:
|
||||
{
|
||||
// Ignore mesh outputs, nothing to do, really
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO sparse sampling
|
||||
case Op::ImageSparseSampleImplicitLod:
|
||||
case Op::ImageSparseSampleExplicitLod:
|
||||
@@ -3750,7 +3756,6 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
|
||||
case Op::ConvertSampledImageToUNV:
|
||||
case Op::SamplerImageAddressingModeNV:
|
||||
case Op::EmitMeshTasksEXT:
|
||||
case Op::SetMeshOutputsEXT:
|
||||
case Op::HitObjectRecordHitMotionNV:
|
||||
case Op::HitObjectRecordHitWithIndexMotionNV:
|
||||
case Op::HitObjectRecordMissMotionNV:
|
||||
|
||||
@@ -437,6 +437,7 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
|
||||
"SPV_GOOGLE_user_type",
|
||||
"SPV_KHR_physical_storage_buffer",
|
||||
"SPV_KHR_relaxed_extended_instruction",
|
||||
"SPV_EXT_mesh_shader",
|
||||
};
|
||||
|
||||
// whitelist supported extensions
|
||||
@@ -554,6 +555,7 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
|
||||
case Capability::UniformDecoration:
|
||||
case Capability::SignedZeroInfNanPreserve:
|
||||
case Capability::PhysicalStorageBufferAddresses:
|
||||
case Capability::MeshShadingEXT:
|
||||
{
|
||||
supported = true;
|
||||
break;
|
||||
@@ -646,13 +648,6 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
|
||||
break;
|
||||
}
|
||||
|
||||
// mesh shading
|
||||
case Capability::MeshShadingEXT:
|
||||
{
|
||||
supported = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// no plans to support these - mostly Kernel/OpenCL related or vendor extensions
|
||||
case Capability::Addresses:
|
||||
case Capability::Linkage:
|
||||
|
||||
@@ -451,6 +451,8 @@ public:
|
||||
const DebugPixelInputs &inputs);
|
||||
ShaderDebugTrace *DebugThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
ShaderDebugTrace *DebugMeshThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
|
||||
void FreeDebugger(ShaderDebugger *debugger);
|
||||
|
||||
|
||||
@@ -5080,6 +5080,89 @@ ShaderDebugTrace *VulkanReplay::DebugThread(uint32_t eventId,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *VulkanReplay::DebugMeshThread(uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
const VulkanRenderState &state = m_pDriver->GetRenderState();
|
||||
VulkanCreationInfo &c = m_pDriver->m_CreationInfo;
|
||||
|
||||
rdcstr regionName =
|
||||
StringFormat::Fmt("DebugMeshThread @ %u of (%u,%u,%u) (%u,%u,%u)", eventId, groupid[0],
|
||||
groupid[1], groupid[2], threadid[0], threadid[1], threadid[2]);
|
||||
|
||||
VkMarkerRegion region(regionName);
|
||||
|
||||
if(Vulkan_Debug_ShaderDebugLogging())
|
||||
RDCLOG("%s", regionName.c_str());
|
||||
|
||||
const ActionDescription *action = m_pDriver->GetAction(eventId);
|
||||
|
||||
if(!(action->flags & ActionFlags::MeshDispatch))
|
||||
{
|
||||
RDCLOG("No mesh dispatch selected");
|
||||
return new ShaderDebugTrace();
|
||||
}
|
||||
|
||||
// get ourselves in pristine state before this dispatch (without any side effects it may have had)
|
||||
m_pDriver->ReplayLog(0, eventId, eReplay_WithoutDraw);
|
||||
|
||||
const VulkanCreationInfo::Pipeline &pipe = c.m_Pipeline[state.graphics.pipeline];
|
||||
const VulkanCreationInfo::ShaderEntry &shaderEntry =
|
||||
state.graphics.shaderObject
|
||||
? c.m_ShaderObject[state.shaderObjects[(size_t)ShaderStage::Mesh]].shad
|
||||
: pipe.shaders[(size_t)ShaderStage::Mesh];
|
||||
VulkanCreationInfo::ShaderModule &shader = c.m_ShaderModule[shaderEntry.module];
|
||||
rdcstr entryPoint = shaderEntry.entryPoint;
|
||||
const rdcarray<SpecConstant> &spec = shaderEntry.specialization;
|
||||
|
||||
VulkanCreationInfo::ShaderModuleReflection &shadRefl =
|
||||
shader.GetReflection(ShaderStage::Mesh, entryPoint, state.graphics.pipeline);
|
||||
|
||||
if(!shadRefl.refl->debugInfo.debuggable)
|
||||
{
|
||||
RDCLOG("Shader is not debuggable: %s", shadRefl.refl->debugInfo.debugStatus.c_str());
|
||||
return new ShaderDebugTrace();
|
||||
}
|
||||
|
||||
shadRefl.PopulateDisassembly(shader.spirv);
|
||||
|
||||
VulkanAPIWrapper *apiWrapper =
|
||||
new VulkanAPIWrapper(m_pDriver, c, ShaderStage::Mesh, eventId, shadRefl.refl->resourceId);
|
||||
|
||||
uint32_t threadDim[3];
|
||||
threadDim[0] = shadRefl.refl->dispatchThreadsDimension[0];
|
||||
threadDim[1] = shadRefl.refl->dispatchThreadsDimension[1];
|
||||
threadDim[2] = shadRefl.refl->dispatchThreadsDimension[2];
|
||||
|
||||
std::map<ShaderBuiltin, ShaderVariable> &builtins = apiWrapper->builtin_inputs;
|
||||
builtins[ShaderBuiltin::DispatchSize] =
|
||||
ShaderVariable(rdcstr(), action->dispatchDimension[0], action->dispatchDimension[1],
|
||||
action->dispatchDimension[2], 0U);
|
||||
builtins[ShaderBuiltin::DispatchThreadIndex] = ShaderVariable(
|
||||
rdcstr(), groupid[0] * threadDim[0] + threadid[0], groupid[1] * threadDim[1] + threadid[1],
|
||||
groupid[2] * threadDim[2] + threadid[2], 0U);
|
||||
builtins[ShaderBuiltin::GroupIndex] =
|
||||
ShaderVariable(rdcstr(), groupid[0], groupid[1], groupid[2], 0U);
|
||||
builtins[ShaderBuiltin::GroupSize] =
|
||||
ShaderVariable(rdcstr(), threadDim[0], threadDim[1], threadDim[2], 0U);
|
||||
builtins[ShaderBuiltin::GroupThreadIndex] =
|
||||
ShaderVariable(rdcstr(), threadid[0], threadid[1], threadid[2], 0U);
|
||||
builtins[ShaderBuiltin::GroupFlatIndex] = ShaderVariable(
|
||||
rdcstr(), threadid[2] * threadDim[0] * threadDim[1] + threadid[1] * threadDim[0] + threadid[0],
|
||||
0U, 0U, 0U);
|
||||
builtins[ShaderBuiltin::DeviceIndex] = ShaderVariable(rdcstr(), 0U, 0U, 0U, 0U);
|
||||
builtins[ShaderBuiltin::DrawIndex] = ShaderVariable(rdcstr(), action->drawIndex, 0U, 0U, 0U);
|
||||
|
||||
rdcspv::Debugger *debugger = new rdcspv::Debugger;
|
||||
debugger->Parse(shader.spirv.GetSPIRV());
|
||||
ShaderDebugTrace *ret = debugger->BeginDebug(apiWrapper, ShaderStage::Mesh, entryPoint, spec,
|
||||
shadRefl.instructionLines, shadRefl.patchData, 0);
|
||||
apiWrapper->ResetReplay();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdcarray<ShaderDebugState> VulkanReplay::ContinueDebug(ShaderDebugger *debugger)
|
||||
{
|
||||
rdcspv::Debugger *spvDebugger = (rdcspv::Debugger *)debugger;
|
||||
|
||||
@@ -296,6 +296,13 @@ ShaderDebugTrace *DummyDriver::DebugVertex(uint32_t eventId, uint32_t vertid, ui
|
||||
return new ShaderDebugTrace;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *DummyDriver::DebugMeshThread(uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
return new ShaderDebugTrace;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *DummyDriver::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
|
||||
const DebugPixelInputs &inputs)
|
||||
{
|
||||
|
||||
@@ -114,6 +114,8 @@ public:
|
||||
const DebugPixelInputs &inputs);
|
||||
ShaderDebugTrace *DebugThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
ShaderDebugTrace *DebugMeshThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
|
||||
void FreeDebugger(ShaderDebugger *debugger);
|
||||
|
||||
|
||||
@@ -1698,6 +1698,24 @@ ShaderDebugTrace *ReplayController::DebugThread(const rdcfixedarray<uint32_t, 3>
|
||||
return ret;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *ReplayController::DebugMeshThread(const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
CHECK_REPLAY_THREAD();
|
||||
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
ShaderDebugTrace *ret = m_pDevice->DebugMeshThread(m_EventID, groupid, threadid);
|
||||
FatalErrorCheck();
|
||||
|
||||
SetFrameEvent(m_EventID, true);
|
||||
|
||||
if(ret->debugger)
|
||||
m_Debuggers.push_back(ret->debugger);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdcarray<ShaderDebugState> ReplayController::ContinueDebug(ShaderDebugger *debugger)
|
||||
{
|
||||
CHECK_REPLAY_THREAD();
|
||||
|
||||
@@ -214,6 +214,8 @@ public:
|
||||
ShaderDebugTrace *DebugPixel(uint32_t x, uint32_t y, const DebugPixelInputs &inputs);
|
||||
ShaderDebugTrace *DebugThread(const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
ShaderDebugTrace *DebugMeshThread(const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
|
||||
void FreeTrace(ShaderDebugTrace *trace);
|
||||
|
||||
|
||||
@@ -231,6 +231,9 @@ public:
|
||||
const DebugPixelInputs &inputs) = 0;
|
||||
virtual ShaderDebugTrace *DebugThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid) = 0;
|
||||
virtual ShaderDebugTrace *DebugMeshThread(uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid) = 0;
|
||||
virtual rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger) = 0;
|
||||
virtual void FreeDebugger(ShaderDebugger *debugger) = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user