Implement location tracking and goto for GS printfs

* We can't debug geometry shaders but we can scroll to them, as long as we have
  the primitive. We can't differentiate instances currently without passing that
  data through from the VS (and through tessellation, if it exists).
* This also disables the debug and goto buttons for printfs from shader stages
  that don't support those operations.
This commit is contained in:
baldurk
2022-07-11 13:02:23 +01:00
parent d39197a499
commit 7bdf26d329
8 changed files with 150 additions and 10 deletions
+6
View File
@@ -778,6 +778,12 @@ QWidget.
)");
virtual void ScrollToColumn(int32_t column, MeshDataStage stage = MeshDataStage::VSIn) = 0;
DOCUMENT(R"(Ensure the given stage's data is visible and raised, if it wasn't before.
:param renderdoc.MeshDataStage stage: The stage of the geometry pipeline to show data for.
)");
virtual void ShowMeshData(MeshDataStage stage) = 0;
DOCUMENT(R"(For a mesh view, set the current instance. This is ignored when called on a raw buffer
view.
+10
View File
@@ -4150,6 +4150,16 @@ void BufferViewer::ScrollToColumn(RDTableView *view, int column)
view->verticalScrollBar()->setValue(vs);
}
void BufferViewer::ShowMeshData(MeshDataStage stage)
{
if(stage == MeshDataStage::VSIn)
ToolWindowManager::raiseToolWindow(ui->vsinData);
else if(stage == MeshDataStage::VSOut)
ToolWindowManager::raiseToolWindow(ui->vsoutData);
else if(stage == MeshDataStage::GSOut)
ToolWindowManager::raiseToolWindow(ui->gsoutData);
}
void BufferViewer::SetCurrentInstance(int32_t instance)
{
if(ui->instance->isVisible() && ui->instance->isEnabled())
+1
View File
@@ -104,6 +104,7 @@ public:
QWidget *Widget() override { return this; }
void ScrollToRow(int32_t row, MeshDataStage stage = MeshDataStage::VSIn) override;
void ScrollToColumn(int32_t column, MeshDataStage stage = MeshDataStage::VSIn) override;
void ShowMeshData(MeshDataStage stage) override;
void SetCurrentInstance(int32_t instance) override;
void SetCurrentView(int32_t view) override;
void SetPreviewStage(MeshDataStage stage) override;
+65 -8
View File
@@ -34,8 +34,11 @@
#include "toolwindowmanager/ToolWindowManager.h"
#include "ui_ShaderMessageViewer.h"
ButtonDelegate::ButtonDelegate(const QIcon &icon, QWidget *parent)
: m_Icon(icon), QStyledItemDelegate(parent)
static const int debuggableRole = Qt::UserRole + 1;
static const int gotoableRole = Qt::UserRole + 2;
ButtonDelegate::ButtonDelegate(const QIcon &icon, int enableRole, QWidget *parent)
: m_Icon(icon), m_EnableRole(enableRole), QStyledItemDelegate(parent)
{
}
@@ -54,7 +57,9 @@ void ButtonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option
button.rect.setSize(sz);
button.icon = m_Icon;
button.iconSize = sz;
button.state = QStyle::State_Enabled;
if(m_EnableRole == 0 || index.data(m_EnableRole).toBool())
button.state = QStyle::State_Enabled;
if(m_ClickedIndex == index)
button.state |= QStyle::State_Sunken;
@@ -77,7 +82,8 @@ bool ButtonDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
{
if(event->type() == QEvent::MouseButtonPress)
{
m_ClickedIndex = index;
if(m_EnableRole == 0 || index.data(m_EnableRole).toBool())
m_ClickedIndex = index;
}
else if(event->type() == QEvent::MouseMove)
{
@@ -105,7 +111,7 @@ bool ButtonDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
}
else if(event->type() == QEvent::MouseButtonRelease)
{
if(m_ClickedIndex == index)
if(m_ClickedIndex == index && index != QModelIndex())
{
m_ClickedIndex = QModelIndex();
@@ -200,7 +206,7 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s
int sortColumn = 0;
m_debugDelegate = new ButtonDelegate(Icons::wrench(), this);
m_debugDelegate = new ButtonDelegate(Icons::wrench(), debuggableRole, this);
if(m_Action && (m_Action->flags & ActionFlags::Dispatch))
{
@@ -218,7 +224,7 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s
ui->messages->setColumns({lit("Debug"), lit("Go to"), tr("Location"), lit("Message")});
sortColumn = 2;
m_gotoDelegate = new ButtonDelegate(Icons::find(), this);
m_gotoDelegate = new ButtonDelegate(Icons::find(), gotoableRole, this);
ui->messages->setItemDelegateForColumn(0, m_debugDelegate);
ui->messages->setItemDelegateForColumn(1, m_gotoDelegate);
@@ -389,6 +395,9 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s
m_Ctx.ShowMeshPreview();
m_Ctx.GetMeshPreview()->SetCurrentInstance(msg.location.vertex.instance);
m_Ctx.GetMeshPreview()->SetCurrentView(msg.location.vertex.view);
m_Ctx.GetMeshPreview()->ShowMeshData(MeshDataStage::VSOut);
m_Ctx.GetMeshPreview()->ScrollToRow(msg.location.vertex.vertexIndex, MeshDataStage::VSOut);
m_Ctx.GetMeshPreview()->ShowMeshData(MeshDataStage::VSIn);
// TODO, not accurate for indices
m_Ctx.GetMeshPreview()->ScrollToRow(msg.location.vertex.vertexIndex, MeshDataStage::VSIn);
}
@@ -415,6 +424,17 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s
ShaderStage::Pixel, 0, 0);
m_Ctx.GetTextureViewer()->GotoLocation(msg.location.pixel.x, msg.location.pixel.y);
}
else if(msg.stage == ShaderStage::Geometry)
{
m_Ctx.ShowMeshPreview();
m_Ctx.GetMeshPreview()->SetCurrentView(msg.location.geometry.view);
m_Ctx.GetMeshPreview()->ShowMeshData(MeshDataStage::GSOut);
// TODO, instances not supported
m_Ctx.GetMeshPreview()->ScrollToRow(
RENDERDOC_VertexOffset(m_Ctx.CurPipelineState().GetPrimitiveTopology(),
msg.location.geometry.primitive),
MeshDataStage::GSOut);
}
else
{
qCritical() << "Can't go to a compute thread";
@@ -496,6 +516,15 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s
// column 2 is the thread column for compute
return am.location.compute.thread < bm.location.compute.thread;
}
else if(am.stage == ShaderStage::Geometry)
{
const ShaderGeometryMessageLocation &aloc = am.location.geometry;
const ShaderGeometryMessageLocation &bloc = bm.location.geometry;
if(aloc.view != bloc.view)
return aloc.view < bloc.view;
return am.location.geometry.primitive < bm.location.geometry.primitive;
}
else
{
// can't sort these, pretend they're all equal
@@ -735,6 +764,10 @@ void ShaderMessageViewer::refreshMessages()
QString filter = ui->filter->text().trimmed();
const ShaderReflection *vsrefl = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Vertex);
const ShaderReflection *psrefl = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Pixel);
const ShaderReflection *csrefl = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Compute);
for(int i = 0; i < m_Messages.count(); i++)
{
const ShaderMessage &msg = m_Messages[i];
@@ -745,9 +778,13 @@ void ShaderMessageViewer::refreshMessages()
QString text(msg.message);
const ShaderReflection *refl = NULL;
QString location;
if(msg.stage == ShaderStage::Vertex)
{
refl = vsrefl;
// only show the view if the draw has multiview enabled
if(m_Multiview)
{
@@ -771,6 +808,8 @@ void ShaderMessageViewer::refreshMessages()
}
else if(msg.stage == ShaderStage::Pixel)
{
refl = psrefl;
location = QFormatStr("%1 %2,%3")
.arg(IsD3D(m_API) ? lit("Pixel") : lit("Frag"))
.arg(msg.location.pixel.x)
@@ -794,11 +833,22 @@ void ShaderMessageViewer::refreshMessages()
}
else if(msg.stage == ShaderStage::Compute)
{
refl = csrefl;
}
else if(msg.stage == ShaderStage::Geometry)
{
location = lit("Geometry Prim %1").arg(msg.location.geometry.primitive);
// only show the view if the draw has multiview enabled
if(m_Multiview)
{
location += lit(", View %1").arg(msg.location.geometry.view);
}
}
else
{
// no location info for other stages
location = tr("Unknown shader");
location = tr("Unknown %1").arg(ToQStr(msg.stage, m_Ctx.APIProps().pipelineType));
}
// filter by text on location and messag
@@ -821,10 +871,17 @@ void ShaderMessageViewer::refreshMessages()
.arg(msg.location.compute.thread[2]),
text,
});
node->setData(0, debuggableRole, refl && refl->debugInfo.debuggable);
}
else
{
node = new RDTreeWidgetItem({QString(), QString(), location, text});
node->setData(0, debuggableRole, refl && refl->debugInfo.debuggable);
node->setData(1, gotoableRole, msg.stage == ShaderStage::Vertex ||
msg.stage == ShaderStage::Pixel ||
msg.stage == ShaderStage::Geometry);
}
if(node)
+2 -1
View File
@@ -40,9 +40,10 @@ private:
QModelIndex m_ClickedIndex;
QIcon m_Icon;
int m_EnableRole;
public:
ButtonDelegate(const QIcon &icon, QWidget *parent);
ButtonDelegate(const QIcon &icon, int enableRole, QWidget *parent);
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+29
View File
@@ -632,6 +632,29 @@ struct ShaderPixelMessageLocation
DECLARE_REFLECTION_STRUCT(ShaderPixelMessageLocation);
DOCUMENT(R"(A geometry shader message's location.
.. data:: NoLocation
No frame number is available.
)");
struct ShaderGeometryMessageLocation
{
DOCUMENT(R"(The primitive index
:type: int
)");
uint32_t primitive;
DOCUMENT(R"(The multiview view for this primitive, or ``0`` if multiview is disabled.
:type: int
)");
uint32_t view;
};
DECLARE_REFLECTION_STRUCT(ShaderGeometryMessageLocation);
DOCUMENT("A shader message's location.");
union ShaderMessageLocation
{
@@ -652,6 +675,12 @@ union ShaderMessageLocation
:type: ShaderPixelMessageLocation
)");
ShaderPixelMessageLocation pixel;
DOCUMENT(R"(The location if the shader is a geometry shader.
:type: ShaderGeometryMessageLocation
)");
ShaderGeometryMessageLocation geometry;
};
DECLARE_REFLECTION_STRUCT(ShaderMessageLocation);
+29 -1
View File
@@ -357,7 +357,8 @@ void AnnotateShader(const ShaderReflection &refl, const SPIRVPatchData &patchDat
rdcspv::Id bufferAddressConst, ssboVar, uint32ptrtype;
if(usesMultiview && (stage == ShaderStage::Pixel || stage == ShaderStage::Vertex))
if(usesMultiview &&
(stage == ShaderStage::Pixel || stage == ShaderStage::Vertex || stage == ShaderStage::Geometry))
{
editor.AddCapability(rdcspv::Capability::MultiView);
editor.AddExtension("SPV_KHR_multiview");
@@ -683,6 +684,28 @@ void AnnotateShader(const ShaderReflection &refl, const SPIRVPatchData &patchDat
rdcspv::OpCompositeConstruct(uvec3Type, editor.MakeId(), {coord, view, prim}));
}
}
else if(stage == ShaderStage::Geometry)
{
rdcspv::Id prim = fetchOrAddGlobalInput("rdoc_primitiveIndex", ShaderBuiltin::PrimitiveIndex,
rdcspv::BuiltIn::PrimitiveId, uint32Type);
rdcspv::Id view;
// only search for the view index is the multiview capability is declared, otherwise it's
// invalid and we just set 0. Valid for both Vertex and Pixel shaders
if(editor.HasCapability(rdcspv::Capability::MultiView))
{
view = fetchOrAddGlobalInput("rdoc_viewIndex", ShaderBuiltin::ViewportIndex,
rdcspv::BuiltIn::ViewIndex, uint32Type);
}
else
{
view = editor.AddConstantImmediate<uint32_t>(0U);
}
location = locationGather.add(
rdcspv::OpCompositeConstruct(uvec3Type, editor.MakeId(), {prim, view, zero}));
}
else
{
RDCWARN("No identifier stored for %s stage", ToStr(stage).c_str());
@@ -1900,6 +1923,11 @@ void VulkanReplay::FetchShaderFeedback(uint32_t eventId)
msg.location.vertex.instance = location[1] - action->instanceOffset;
msg.location.vertex.view = location[2];
}
else if(stage == ShaderStage::Geometry)
{
msg.location.geometry.primitive = location[0];
msg.location.geometry.view = location[1];
}
else
{
msg.location.pixel.x = location[0] >> 16U;
+8
View File
@@ -1045,6 +1045,14 @@ void DoSerialise(SerialiserType &ser, ShaderPixelMessageLocation &el)
SIZE_CHECK(20);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, ShaderGeometryMessageLocation &el)
{
SERIALISE_MEMBER(primitive);
SIZE_CHECK(4);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, ShaderMessageLocation &el)
{