Add UI to vulkan pipeline state viewer to allow compute debugging

This commit is contained in:
baldurk
2020-04-29 11:41:43 +01:00
parent 2cb546686b
commit 2eaeb96799
3 changed files with 342 additions and 73 deletions
@@ -30,6 +30,7 @@
#include <QXmlStreamWriter>
#include "Code/Resources.h"
#include "Widgets/Extended/RDHeaderView.h"
#include "flowlayout/FlowLayout.h"
#include "toolwindowmanager/ToolWindowManager.h"
#include "PipelineStateViewer.h"
#include "ui_VulkanPipelineStateViewer.h"
@@ -135,6 +136,23 @@ VulkanPipelineStateViewer::VulkanPipelineStateViewer(ICaptureContext &ctx,
ui->vsUBOs, ui->tcsUBOs, ui->tesUBOs, ui->gsUBOs, ui->fsUBOs, ui->csUBOs,
};
// setup FlowLayout for CS shader group, with debugging controls
{
QLayout *oldLayout = ui->csShaderGroup->layout();
QObjectList childs = ui->csShaderGroup->children();
childs.removeOne((QObject *)oldLayout);
delete oldLayout;
FlowLayout *csShaderFlow = new FlowLayout(ui->csShaderGroup, -1, 3, 3);
for(QObject *o : childs)
csShaderFlow->addWidget(qobject_cast<QWidget *>(o));
ui->csShaderGroup->setLayout(csShaderFlow);
}
for(QToolButton *b : viewButtons)
QObject::connect(b, &QToolButton::clicked, this, &VulkanPipelineStateViewer::shaderView_clicked);
@@ -749,6 +767,18 @@ void VulkanPipelineStateViewer::clearState()
ui->stencils->clear();
{
ui->groupX->setEnabled(false);
ui->groupY->setEnabled(false);
ui->groupZ->setEnabled(false);
ui->threadX->setEnabled(false);
ui->threadY->setEnabled(false);
ui->threadZ->setEnabled(false);
ui->debugThread->setEnabled(false);
}
ui->conditionalRenderingGroup->setVisible(false);
ui->csConditionalRenderingGroup->setVisible(false);
}
@@ -2501,6 +2531,51 @@ void VulkanPipelineStateViewer::setState()
ui->stencils->clearSelection();
ui->stencils->endUpdate();
// set up thread debugging inputs
if(m_Ctx.APIProps().shaderDebugging && state.computeShader.reflection && draw &&
(draw->flags & DrawFlags::Dispatch))
{
ui->groupX->setEnabled(true);
ui->groupY->setEnabled(true);
ui->groupZ->setEnabled(true);
ui->threadX->setEnabled(true);
ui->threadY->setEnabled(true);
ui->threadZ->setEnabled(true);
ui->debugThread->setEnabled(true);
// set maximums for CS debugging
ui->groupX->setMaximum((int)draw->dispatchDimension[0] - 1);
ui->groupY->setMaximum((int)draw->dispatchDimension[1] - 1);
ui->groupZ->setMaximum((int)draw->dispatchDimension[2] - 1);
if(draw->dispatchThreadsDimension[0] == 0)
{
ui->threadX->setMaximum((int)state.computeShader.reflection->dispatchThreadsDimension[0] - 1);
ui->threadY->setMaximum((int)state.computeShader.reflection->dispatchThreadsDimension[1] - 1);
ui->threadZ->setMaximum((int)state.computeShader.reflection->dispatchThreadsDimension[2] - 1);
}
else
{
ui->threadX->setMaximum((int)draw->dispatchThreadsDimension[0] - 1);
ui->threadY->setMaximum((int)draw->dispatchThreadsDimension[1] - 1);
ui->threadZ->setMaximum((int)draw->dispatchThreadsDimension[2] - 1);
}
}
else
{
ui->groupX->setEnabled(false);
ui->groupY->setEnabled(false);
ui->groupZ->setEnabled(false);
ui->threadX->setEnabled(false);
ui->threadY->setEnabled(false);
ui->threadZ->setEnabled(false);
ui->debugThread->setEnabled(false);
}
// highlight the appropriate stages in the flowchart
if(draw == NULL)
{
@@ -3722,3 +3797,94 @@ void VulkanPipelineStateViewer::on_meshView_clicked()
m_Ctx.ShowMeshPreview();
ToolWindowManager::raiseToolWindow(m_Ctx.GetMeshPreview()->Widget());
}
void VulkanPipelineStateViewer::on_debugThread_clicked()
{
if(!m_Ctx.APIProps().shaderDebugging)
return;
if(!m_Ctx.IsCaptureLoaded())
return;
const DrawcallDescription *draw = m_Ctx.CurDrawcall();
if(!draw || !(draw->flags & DrawFlags::Dispatch))
return;
ShaderReflection *shaderDetails = m_Ctx.CurVulkanPipelineState()->computeShader.reflection;
const ShaderBindpointMapping &bindMapping =
m_Ctx.CurVulkanPipelineState()->computeShader.bindpointMapping;
if(!shaderDetails)
return;
uint32_t groupdim[3] = {};
for(int i = 0; i < 3; i++)
groupdim[i] = draw->dispatchDimension[i];
uint32_t threadsdim[3] = {};
for(int i = 0; i < 3; i++)
threadsdim[i] = draw->dispatchThreadsDimension[i];
if(threadsdim[0] == 0)
{
for(int i = 0; i < 3; i++)
threadsdim[i] = shaderDetails->dispatchThreadsDimension[i];
}
struct threadSelect
{
uint32_t g[3];
uint32_t t[3];
} thread = {
// g[]
{(uint32_t)ui->groupX->value(), (uint32_t)ui->groupY->value(), (uint32_t)ui->groupZ->value()},
// t[]
{(uint32_t)ui->threadX->value(), (uint32_t)ui->threadY->value(), (uint32_t)ui->threadZ->value()},
};
bool done = false;
ShaderDebugTrace *trace = NULL;
m_Ctx.Replay().AsyncInvoke([&trace, &done, thread](IReplayController *r) {
trace = r->DebugThread(thread.g, thread.t);
if(trace->debugger == NULL)
{
r->FreeTrace(trace);
trace = NULL;
}
done = true;
});
QString debugContext = lit("Group [%1,%2,%3] Thread [%4,%5,%6]")
.arg(thread.g[0])
.arg(thread.g[1])
.arg(thread.g[2])
.arg(thread.t[0])
.arg(thread.t[1])
.arg(thread.t[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(&bindMapping, shaderDetails, ResourceId(), trace, debugContext);
m_Ctx.AddDockWindow(s->Widget(), DockReference::AddTo, this);
}
@@ -82,6 +82,8 @@ private slots:
void ubo_itemActivated(RDTreeWidgetItem *item, int column);
void vertex_leave(QEvent *e);
void on_debugThread_clicked();
private:
Ui::VulkanPipelineStateViewer *ui;
ICaptureContext &m_Ctx;
@@ -3546,90 +3546,191 @@
<number>4</number>
</property>
<item>
<widget class="RDLabel" name="csShader">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="text">
<string/>
</property>
<widget class="QFrame" name="csShaderControlsFrame">
<layout class="QHBoxLayout" name="horizontalLayout_29">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="RDLabel" name="csShader">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="csShaderViewButton">
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Open Shader Source</string>
</property>
<property name="text">
<string>View</string>
</property>
<property name="icon">
<iconset resource="../../Resources/resources.qrc">
<normaloff>:/action.png</normaloff>:/action.png
</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="csShaderEditButton">
<property name="toolTip">
<string>Edit Shader</string>
</property>
<property name="text">
<string>Edit</string>
</property>
<property name="icon">
<iconset resource="../../Resources/resources.qrc">
<normaloff>:/page_white_edit.png</normaloff>:/page_white_edit.png
</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::MenuButtonPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="csShaderSaveButton">
<property name="toolTip">
<string>Save Shader DXBC</string>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="icon">
<iconset resource="../../Resources/resources.qrc">
<normaloff>:/save.png</normaloff>:/save.png
</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QToolButton" name="csShaderViewButton">
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Open Shader Source</string>
</property>
<property name="text">
<string>View</string>
</property>
<property name="icon">
<iconset resource="../../Resources/resources.qrc">
<normaloff>:/action.png</normaloff>:/action.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
<widget class="QFrame" name="csDebugFrame">
<layout class="QHBoxLayout" name="horizontalLayout_34">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="groupDebugLabel">
<property name="text">
<string>Debug Group:</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="groupX"/>
</item>
<item>
<widget class="QSpinBox" name="groupY"/>
</item>
<item>
<widget class="QSpinBox" name="groupZ"/>
</item>
<item>
<widget class="QLabel" name="threadDebugLabel">
<property name="text">
<string>Thread:</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="threadX"/>
</item>
<item>
<widget class="QSpinBox" name="threadY"/>
</item>
<item>
<widget class="QSpinBox" name="threadZ"/>
</item>
<item>
<widget class="QToolButton" name="debugThread">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../Resources/resources.qrc">
<normaloff>:/wrench.png</normaloff>:/wrench.png
</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QToolButton" name="csShaderEditButton">
<property name="toolTip">
<string>Edit Shader</string>
</property>
<property name="text">
<string>Edit</string>
</property>
<property name="icon">
<iconset resource="../../Resources/resources.qrc">
<normaloff>:/page_white_edit.png</normaloff>:/page_white_edit.png</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::MenuButtonPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="csShaderSaveButton">
<property name="toolTip">
<string>Save Shader SPIR-V</string>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="icon">
<iconset resource="../../Resources/resources.qrc">
<normaloff>:/save.png</normaloff>:/save.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="csShaderSpacer">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>