Update shader viewer to support editing and debugging of shaders

This commit is contained in:
baldurk
2017-02-10 21:48:50 +00:00
parent 235167f6df
commit 8630f82db3
12 changed files with 1741 additions and 124 deletions
@@ -2149,11 +2149,13 @@ void D3D11PipelineStateViewer::shaderView_clicked()
{
ShaderStageType shaderStage = eShaderStage_Vertex;
ShaderReflection *shaderDetails = NULL;
const ShaderBindpointMapping *bindMap = NULL;
QWidget *sender = qobject_cast<QWidget *>(QObject::sender());
if(sender == ui->iaBytecode || sender == ui->iaBytecodeViewButton)
{
shaderDetails = m_Ctx.CurD3D11PipelineState.m_IA.Bytecode;
bindMap = NULL;
}
else
{
@@ -2162,11 +2164,13 @@ void D3D11PipelineStateViewer::shaderView_clicked()
if(stage == NULL || stage->Shader == ResourceId())
return;
bindMap = &stage->BindpointMapping;
shaderDetails = stage->ShaderDetails;
shaderStage = stage->stage;
}
ShaderViewer *shad = new ShaderViewer(m_Ctx, shaderDetails, shaderStage, NULL, "");
ShaderViewer *shad =
ShaderViewer::viewShader(m_Ctx, bindMap, shaderDetails, shaderStage, m_Ctx.mainWindow());
m_Ctx.setupDockWindow(shad);
@@ -2178,6 +2182,38 @@ void D3D11PipelineStateViewer::shaderView_clicked()
void D3D11PipelineStateViewer::shaderEdit_clicked()
{
QWidget *sender = qobject_cast<QWidget *>(QObject::sender());
const D3D11PipelineState::ShaderStage *stage = stageForSender(sender);
if(!stage || stage->Shader == ResourceId())
return;
const ShaderReflection *shaderDetails = stage->ShaderDetails;
if(!shaderDetails)
return;
QString entryFunc = QString("EditedShader%1S").arg(ToQStr(stage->stage, eGraphicsAPI_D3D11)[0]);
QString mainfile = "";
QStringMap files;
bool hasOrigSource = m_Common.PrepareShaderEditing(shaderDetails, entryFunc, files, mainfile);
if(!hasOrigSource)
{
QString hlsl = "// TODO - generate stub HLSL";
mainfile = "generated.hlsl";
files[mainfile] = hlsl;
}
if(files.empty())
return;
m_Common.EditShader(stage->stage, stage->Shader, shaderDetails, entryFunc, files, mainfile);
}
void D3D11PipelineStateViewer::shaderSave_clicked()
@@ -2160,7 +2160,8 @@ void D3D12PipelineStateViewer::shaderView_clicked()
if(stage == NULL || stage->Shader == ResourceId())
return;
ShaderViewer *shad = new ShaderViewer(m_Ctx, stage->ShaderDetails, stage->stage, NULL, "");
ShaderViewer *shad = ShaderViewer::viewShader(
m_Ctx, &stage->BindpointMapping, stage->ShaderDetails, stage->stage, m_Ctx.mainWindow());
m_Ctx.setupDockWindow(shad);
@@ -2172,6 +2173,38 @@ void D3D12PipelineStateViewer::shaderView_clicked()
void D3D12PipelineStateViewer::shaderEdit_clicked()
{
QWidget *sender = qobject_cast<QWidget *>(QObject::sender());
const D3D12PipelineState::ShaderStage *stage = stageForSender(sender);
if(!stage || stage->Shader == ResourceId())
return;
const ShaderReflection *shaderDetails = stage->ShaderDetails;
if(!shaderDetails)
return;
QString entryFunc = QString("EditedShader%1S").arg(ToQStr(stage->stage, eGraphicsAPI_D3D12)[0]);
QString mainfile = "";
QStringMap files;
bool hasOrigSource = m_Common.PrepareShaderEditing(shaderDetails, entryFunc, files, mainfile);
if(!hasOrigSource)
{
QString hlsl = "// TODO - generate stub HLSL";
mainfile = "generated.hlsl";
files[mainfile] = hlsl;
}
if(files.empty())
return;
m_Common.EditShader(stage->stage, stage->Shader, shaderDetails, entryFunc, files, mainfile);
}
void D3D12PipelineStateViewer::shaderSave_clicked()
@@ -2257,7 +2257,8 @@ void GLPipelineStateViewer::shaderView_clicked()
ShaderReflection *shaderDetails = stage->ShaderDetails;
ShaderViewer *shad = new ShaderViewer(m_Ctx, shaderDetails, stage->stage, NULL, "");
ShaderViewer *shad = ShaderViewer::viewShader(m_Ctx, &stage->BindpointMapping, shaderDetails,
stage->stage, m_Ctx.mainWindow());
m_Ctx.setupDockWindow(shad);
@@ -2269,6 +2270,38 @@ void GLPipelineStateViewer::shaderView_clicked()
void GLPipelineStateViewer::shaderEdit_clicked()
{
QWidget *sender = qobject_cast<QWidget *>(QObject::sender());
const GLPipelineState::ShaderStage *stage = stageForSender(sender);
if(!stage || stage->Shader == ResourceId())
return;
const ShaderReflection *shaderDetails = stage->ShaderDetails;
if(!shaderDetails)
return;
QString entryFunc = QString("EditedShader%1S").arg(ToQStr(stage->stage, eGraphicsAPI_OpenGL)[0]);
QString mainfile = "";
QStringMap files;
bool hasOrigSource = m_Common.PrepareShaderEditing(shaderDetails, entryFunc, files, mainfile);
if(!hasOrigSource)
{
QString glsl = "// TODO - disassemble SPIR-V";
mainfile = "generated.glsl";
files[mainfile] = glsl;
}
if(files.empty())
return;
m_Common.EditShader(stage->stage, stage->Shader, shaderDetails, entryFunc, files, mainfile);
}
void GLPipelineStateViewer::shaderSave_clicked()
@@ -23,6 +23,9 @@
******************************************************************************/
#include "PipelineStateViewer.h"
#include "3rdparty/toolwindowmanager/ToolWindowManager.h"
#include "Windows/MainWindow.h"
#include "Windows/ShaderViewer.h"
#include "D3D11PipelineStateViewer.h"
#include "D3D12PipelineStateViewer.h"
#include "GLPipelineStateViewer.h"
@@ -183,6 +186,188 @@ void PipelineStateViewer::setToVulkan()
ui->layout->addWidget(m_Vulkan);
m_Current = m_Vulkan;
m_Ctx.CurPipelineState.DefaultType = eGraphicsAPI_Vulkan;
}
bool PipelineStateViewer::PrepareShaderEditing(const ShaderReflection *shaderDetails,
QString &entryFunc, QStringMap &files,
QString &mainfile)
{
if(!shaderDetails->DebugInfo.entryFunc.empty() && !shaderDetails->DebugInfo.files.empty())
{
entryFunc = ToQStr(shaderDetails->DebugInfo.entryFunc);
QStringList uniqueFiles;
for(auto &s : shaderDetails->DebugInfo.files)
{
QString filename = ToQStr(s.first);
if(uniqueFiles.contains(filename.toLower()))
{
qWarning() << "Duplicate full filename" << ToQStr(s.first);
continue;
}
uniqueFiles.push_back(filename.toLower());
files[filename] = ToQStr(s.second);
}
int entryFile = shaderDetails->DebugInfo.entryFile;
if(entryFile < 0 || entryFile >= shaderDetails->DebugInfo.files.count)
entryFile = 0;
mainfile = ToQStr(shaderDetails->DebugInfo.files[entryFile].first);
return true;
}
return false;
}
void PipelineStateViewer::EditShader(ShaderStageType shaderType, ResourceId id,
const ShaderReflection *shaderDetails, const QString &entryFunc,
const QStringMap &files, const QString &mainfile)
{
ShaderViewer *sv = ShaderViewer::editShader(
m_Ctx, false, entryFunc, files,
// save callback
[entryFunc, mainfile, shaderType, id, shaderDetails](
CaptureContext *ctx, ShaderViewer *viewer, const QStringMap &updatedfiles) {
QString compileSource = updatedfiles[mainfile];
// try and match up #includes against the files that we have. This isn't always
// possible as fxc only seems to include the source for files if something in
// that file was included in the compiled output. So you might end up with
// dangling #includes - we just have to ignore them
int offs = compileSource.indexOf("#include");
while(offs >= 0)
{
// search back to ensure this is a valid #include (ie. not in a comment).
// Must only see whitespace before, then a newline.
int ws = qMax(0, offs - 1);
while(ws >= 0 && (compileSource[ws] == ' ' || compileSource[ws] == '\t'))
ws--;
// not valid? jump to next.
if(ws > 0 && compileSource[ws] != '\n')
{
offs = compileSource.indexOf("#include", offs + 1);
continue;
}
int start = ws + 1;
bool tail = true;
int lineEnd = compileSource.indexOf("\n", start + 1);
if(lineEnd == -1)
{
lineEnd = compileSource.length();
tail = false;
}
ws = offs + sizeof("#include") - 1;
while(compileSource[ws] == ' ' || compileSource[ws] == '\t')
ws++;
QString line = compileSource.mid(offs, lineEnd - offs + 1);
if(compileSource[ws] != '<' && compileSource[ws] != '"')
{
viewer->showErrors("Invalid #include directive found:\r\n" + line);
return;
}
// find matching char, either <> or "";
int end = compileSource.indexOf(compileSource[ws] == '"' ? '"' : '>', ws + 1);
if(end == -1)
{
viewer->showErrors("Invalid #include directive found:\r\n" + line);
return;
}
QString fname = compileSource.mid(ws + 1, end - ws - 1);
QString fileText;
// look for exact match first
if(updatedfiles.contains(fname))
{
fileText = updatedfiles[fname];
}
else
{
QString search = QFileInfo(fname).fileName();
// if not, try and find the same filename (this is not proper include handling!)
for(const QString &k : updatedfiles.keys())
{
if(QFileInfo(k).fileName().compare(search, Qt::CaseInsensitive) == 0)
{
fileText = updatedfiles[k];
break;
}
}
if(fileText == "")
fileText = "// Can't find file " + fname + "\n";
}
compileSource = compileSource.left(offs) + "\n\n" + fileText + "\n\n" +
(tail ? compileSource.mid(lineEnd + 1) : "");
// need to start searching from the beginning - wasteful but allows nested includes to
// work
offs = compileSource.indexOf("#include");
}
if(updatedfiles.contains("@cmdline"))
compileSource = updatedfiles["@cmdline"] + "\n\n" + compileSource;
// invoke off to the ReplayRenderer to replace the log's shader
// with our edited one
ctx->Renderer().AsyncInvoke([ctx, entryFunc, compileSource, shaderType, id, shaderDetails,
viewer](IReplayRenderer *r) {
rdctype::str errs;
uint flags = shaderDetails->DebugInfo.compileFlags;
ResourceId from = id;
ResourceId to = r->BuildTargetShader(
entryFunc.toUtf8().data(), compileSource.toUtf8().data(), flags, shaderType, &errs);
GUIInvoke::call([viewer, errs]() { viewer->showErrors(ToQStr(errs)); });
if(to == ResourceId())
{
r->RemoveReplacement(from);
GUIInvoke::call([ctx]() { ctx->RefreshStatus(); });
}
else
{
r->ReplaceResource(from, to);
GUIInvoke::call([ctx]() { ctx->RefreshStatus(); });
}
});
},
// Close Callback
[id](CaptureContext *ctx) {
// remove the replacement on close (we could make this more sophisticated if there
// was a place to control replaced resources/shaders).
ctx->Renderer().AsyncInvoke([ctx, id](IReplayRenderer *r) {
r->RemoveReplacement(id);
GUIInvoke::call([ctx] { ctx->RefreshStatus(); });
});
},
m_Ctx.mainWindow());
m_Ctx.setupDockWindow(sv);
ToolWindowManager *manager = ToolWindowManager::managerOf(this);
ToolWindowManager::AreaReference ref(ToolWindowManager::AddTo, manager->areaOf(this));
manager->addToolWindow(sv, ref);
}
bool PipelineStateViewer::SaveShaderFile(const ShaderReflection *shader)
{
@@ -56,6 +56,10 @@ public:
void setPersistData(const QVariant &persistData);
bool SaveShaderFile(const ShaderReflection *shader);
bool PrepareShaderEditing(const ShaderReflection *shaderDetails, QString &entryFunc,
QStringMap &files, QString &mainfile);
void EditShader(ShaderStageType shaderType, ResourceId id, const ShaderReflection *shaderDetails,
const QString &entryFunc, const QStringMap &files, const QString &mainfile);
private:
Ui::PipelineStateViewer *ui;
@@ -2359,7 +2359,8 @@ void VulkanPipelineStateViewer::shaderView_clicked()
ShaderReflection *shaderDetails = stage->ShaderDetails;
ShaderViewer *shad = new ShaderViewer(m_Ctx, shaderDetails, stage->stage, NULL, "");
ShaderViewer *shad = ShaderViewer::viewShader(m_Ctx, &stage->BindpointMapping, shaderDetails,
stage->stage, m_Ctx.mainWindow());
m_Ctx.setupDockWindow(shad);
@@ -2371,6 +2372,38 @@ void VulkanPipelineStateViewer::shaderView_clicked()
void VulkanPipelineStateViewer::shaderEdit_clicked()
{
QWidget *sender = qobject_cast<QWidget *>(QObject::sender());
const VulkanPipelineState::ShaderStage *stage = stageForSender(sender);
if(!stage || stage->Shader == ResourceId())
return;
const ShaderReflection *shaderDetails = stage->ShaderDetails;
if(!shaderDetails)
return;
QString entryFunc = QString("EditedShader%1S").arg(ToQStr(stage->stage, eGraphicsAPI_Vulkan)[0]);
QString mainfile = "";
QStringMap files;
bool hasOrigSource = m_Common.PrepareShaderEditing(shaderDetails, entryFunc, files, mainfile);
if(!hasOrigSource)
{
QString glsl = "// TODO - disassemble SPIR-V";
mainfile = "generated.glsl";
files[mainfile] = glsl;
}
if(files.empty())
return;
m_Common.EditShader(stage->stage, stage->Shader, shaderDetails, entryFunc, files, mainfile);
}
void VulkanPipelineStateViewer::shaderSave_clicked()
+37 -1
View File
@@ -29,6 +29,7 @@
#include <QMenu>
#include "3rdparty/toolwindowmanager/ToolWindowManager.h"
#include "Windows/BufferViewer.h"
#include "Windows/ShaderViewer.h"
#include "ui_PixelHistoryView.h"
struct EventTag
@@ -635,7 +636,42 @@ void PixelHistoryView::setHistory(const rdctype::array<PixelModification> &histo
void PixelHistoryView::startDebug(EventTag tag)
{
m_Ctx.SetEventID({this}, tag.eventID, tag.eventID);
// TODO Shader debugging
ShaderDebugTrace *trace = new ShaderDebugTrace;
bool success = false;
m_Ctx.Renderer().BlockInvoke([this, &success, trace](IReplayRenderer *r) {
success =
r->DebugPixel((uint32_t)m_Pixel.x(), (uint32_t)m_Pixel.y(), m_Display.sampleIdx, ~0U, trace);
});
if(!success || trace->states.count == 0)
{
RDDialog::critical(this, tr("Debug Error"), tr("Error debugging pixel."));
delete trace;
return;
}
GUIInvoke::call([this, trace]() {
QString debugContext = QString("Pixel %1,%2").arg(m_Pixel.x()).arg(m_Pixel.y());
const ShaderReflection *shaderDetails =
m_Ctx.CurPipelineState.GetShaderReflection(eShaderStage_Pixel);
const ShaderBindpointMapping &bindMapping =
m_Ctx.CurPipelineState.GetBindpointMapping(eShaderStage_Pixel);
// viewer takes ownership of the trace
ShaderViewer *s = ShaderViewer::debugShader(m_Ctx, &bindMapping, shaderDetails,
eShaderStage_Pixel, trace, debugContext, this);
m_Ctx.setupDockWindow(s);
ToolWindowManager *manager = ToolWindowManager::managerOf(this);
ToolWindowManager::AreaReference ref(ToolWindowManager::AddTo, manager->areaOf(this));
manager->addToolWindow(s, ref);
});
}
void PixelHistoryView::jumpToPrimitive(EventTag tag)
File diff suppressed because it is too large Load Diff
+87 -8
View File
@@ -37,13 +37,45 @@ struct ShaderDebugTrace;
struct ShaderReflection;
class ScintillaEdit;
// from Scintilla
typedef intptr_t sptr_t;
class ShaderViewer : public QFrame, public ILogViewerForm
{
Q_OBJECT
public:
explicit ShaderViewer(CaptureContext &ctx, ShaderReflection *shader, ShaderStageType stage,
ShaderDebugTrace *trace, const QString &debugContext, QWidget *parent = 0);
typedef std::function<void(CaptureContext *ctx, ShaderViewer *, const QStringMap &)> SaveMethod;
typedef std::function<void(CaptureContext *ctx)> CloseMethod;
static ShaderViewer *editShader(CaptureContext &ctx, bool customShader, const QString &entryPoint,
const QStringMap &files, SaveMethod saveCallback,
CloseMethod closeCallback, QWidget *parent)
{
ShaderViewer *ret = new ShaderViewer(ctx, parent);
ret->m_SaveCallback = saveCallback;
ret->m_CloseCallback = closeCallback;
ret->editShader(customShader, entryPoint, files);
return ret;
}
static ShaderViewer *debugShader(CaptureContext &ctx, const ShaderBindpointMapping *bind,
const ShaderReflection *shader, ShaderStageType stage,
ShaderDebugTrace *trace, const QString &debugContext,
QWidget *parent)
{
ShaderViewer *ret = new ShaderViewer(ctx, parent);
ret->debugShader(bind, shader, stage, trace, debugContext);
return ret;
}
static ShaderViewer *viewShader(CaptureContext &ctx, const ShaderBindpointMapping *bind,
const ShaderReflection *shader, ShaderStageType stage,
QWidget *parent)
{
return ShaderViewer::debugShader(ctx, bind, shader, stage, NULL, "", parent);
}
~ShaderViewer();
void OnLogfileLoaded();
@@ -51,22 +83,69 @@ public:
void OnSelectedEventChanged(uint32_t eventID) {}
void OnEventChanged(uint32_t eventID);
int currentStep();
void setCurrentStep(int step);
void toggleBreakpoint(int instruction = -1);
void showErrors(const QString &errors);
private slots:
// automatic slots
void on_findReplace_clicked();
void on_save_clicked();
void on_intView_clicked();
void on_floatView_clicked();
// manual slots
void disassembly_keyPressed(QKeyEvent *event);
void readonly_keyPressed(QKeyEvent *event);
void editable_keyPressed(QKeyEvent *event);
void disassembly_buttonReleased(QMouseEvent *event);
public slots:
bool stepBack();
bool stepNext();
void runToCursor();
void runToSample();
void runToNanOrInf();
void runBack();
void run();
private:
explicit ShaderViewer(CaptureContext &ctx, QWidget *parent = 0);
void editShader(bool customShader, const QString &entryPoint, const QStringMap &files);
void debugShader(const ShaderBindpointMapping *bind, const ShaderReflection *shader,
ShaderStageType stage, ShaderDebugTrace *trace, const QString &debugContext);
Ui::ShaderViewer *ui;
CaptureContext &m_Ctx;
ShaderDebugTrace *m_Trace;
ShaderReflection *m_ShaderDetails;
ScintillaEdit *m_DisassemblyView;
const ShaderBindpointMapping *m_Mapping = NULL;
const ShaderReflection *m_ShaderDetails = NULL;
ShaderStageType m_Stage;
ScintillaEdit *m_DisassemblyView = NULL;
ScintillaEdit *m_Errors = NULL;
QList<ScintillaEdit *> m_Scintillas;
SaveMethod m_SaveCallback;
CloseMethod m_CloseCallback;
ShaderDebugTrace *m_Trace = NULL;
int m_CurrentStep;
QList<int> m_Breakpoints;
static const int CURRENT_MARKER = 0;
static const int BREAKPOINT_MARKER = 1;
static const int FINISHED_MARKER = 2;
static const int BREAKPOINT_MARKER = 2;
static const int FINISHED_MARKER = 4;
ScintillaEdit *MakeEditor(const QString &name, const QString &text, bool src);
ScintillaEdit *AddFileScintilla(const QString &name, const QString &text);
int instructionForLine(sptr_t line);
void updateDebugging();
void runTo(int runToInstruction, bool forward, ShaderDebugStateFlags condition = eShaderDbg_None);
QString stringRep(const ShaderVariable &var, bool useType);
QTreeWidgetItem *makeResourceRegister(const BindpointMap &bind, uint32_t idx,
const BoundResource &ro, const ShaderResource &resources);
};
+396 -11
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>691</width>
<height>427</height>
<width>963</width>
<height>574</height>
</rect>
</property>
<property name="windowTitle">
@@ -16,18 +16,18 @@
<widget class="ToolWindowManager" name="docking" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
<x>80</x>
<y>90</y>
<width>351</width>
<height>301</height>
</rect>
</property>
</widget>
<widget class="QTreeWidget" name="inputSig">
<property name="geometry">
<rect>
<x>60</x>
<y>200</y>
<x>570</x>
<y>160</y>
<width>256</width>
<height>192</height>
</rect>
@@ -107,8 +107,8 @@
<widget class="QTreeWidget" name="outputSig">
<property name="geometry">
<rect>
<x>360</x>
<y>200</y>
<x>590</x>
<y>360</y>
<width>256</width>
<height>192</height>
</rect>
@@ -185,14 +185,399 @@
</property>
</column>
</widget>
<widget class="RDTreeWidget" name="constants">
<property name="geometry">
<rect>
<x>20</x>
<y>310</y>
<width>256</width>
<height>192</height>
</rect>
</property>
<property name="contextMenuPolicy">
<enum>Qt::PreventContextMenu</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
</widget>
<widget class="RDTreeWidget" name="variables">
<property name="geometry">
<rect>
<x>310</x>
<y>310</y>
<width>256</width>
<height>192</height>
</rect>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
</widget>
<widget class="QFrame" name="toolbar">
<property name="geometry">
<rect>
<x>40</x>
<y>10</y>
<width>291</width>
<height>28</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QToolButton" name="findReplace">
<property name="toolTip">
<string>Find &amp; Replace</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/find.png</normaloff>:/find.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="editSep">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="save">
<property name="toolTip">
<string>Compile &amp; Save changes</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/save.png</normaloff>:/save.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="snippets">
<property name="toolTip">
<string>Insert built-in snippets</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/plugin_add.png</normaloff>:/plugin_add.png</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="debugSep">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="stepBack">
<property name="toolTip">
<string>Step Back (Shift-F10)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/stepprev.png</normaloff>:/stepprev.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="stepNext">
<property name="toolTip">
<string>Step Next (F10)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/stepnext.png</normaloff>:/stepnext.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="runToCursor">
<property name="minimumSize">
<size>
<width>23</width>
<height>22</height>
</size>
</property>
<property name="toolTip">
<string>Run to Cursor (Ctrl-F10)</string>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/runcursor.png</normaloff>:/runcursor.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="runToSample">
<property name="minimumSize">
<size>
<width>23</width>
<height>22</height>
</size>
</property>
<property name="toolTip">
<string>Run to Sample/Load/Gather</string>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/runsample.png</normaloff>:/runsample.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="runToNaNOrInf">
<property name="minimumSize">
<size>
<width>23</width>
<height>22</height>
</size>
</property>
<property name="toolTip">
<string>Run to NaN or Inf</string>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/runnaninf.png</normaloff>:/runnaninf.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="regFormatSep">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="intView">
<property name="text">
<string>int</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="floatView">
<property name="text">
<string>float</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="RDTableWidget" name="watch">
<property name="geometry">
<rect>
<x>710</x>
<y>20</y>
<width>151</width>
<height>131</height>
</rect>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>RDTreeWidget</class>
<extends>QTreeWidget</extends>
<header>Widgets/Extended/RDTreeWidget.h</header>
</customwidget>
<customwidget>
<class>ToolWindowManager</class>
<extends>QWidget</extends>
<header>3rdparty/toolwindowmanager/ToolWindowManager.h</header>
</customwidget>
<customwidget>
<class>RDTableWidget</class>
<extends>QTableWidget</extends>
<header>Widgets/Extended/RDTableWidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<resources>
<include location="../Resources/resources.qrc"/>
</resources>
<connections/>
</ui>
+47
View File
@@ -43,6 +43,7 @@
#include "BufferViewer.h"
#include "MainWindow.h"
#include "PixelHistoryView.h"
#include "ShaderViewer.h"
#include "ui_TextureViewer.h"
float area(const QSizeF &s)
@@ -3267,6 +3268,52 @@ void TextureViewer::on_saveTex_clicked()
}
}
void TextureViewer::on_debugPixelContext_clicked()
{
ShaderDebugTrace *trace = new ShaderDebugTrace;
if(m_PickedPoint.x() < 0 || m_PickedPoint.y() < 0)
return;
int x = m_PickedPoint.x() >> (int)m_TexDisplay.mip;
int y = m_PickedPoint.y() >> (int)m_TexDisplay.mip;
bool success = false;
m_Ctx.Renderer().BlockInvoke([this, x, y, &success, trace](IReplayRenderer *r) {
success = r->DebugPixel((uint32_t)x, (uint32_t)y, m_TexDisplay.sampleIdx, ~0U, trace);
});
if(!success || trace->states.count == 0)
{
delete trace;
// if we couldn't debug the pixel on this event, open up a pixel history
on_pixelHistory_clicked();
return;
}
GUIInvoke::call([this, x, y, trace]() {
QString debugContext = tr("Pixel %1,%2").arg(x).arg(y);
const ShaderReflection *shaderDetails =
m_Ctx.CurPipelineState.GetShaderReflection(eShaderStage_Pixel);
const ShaderBindpointMapping &bindMapping =
m_Ctx.CurPipelineState.GetBindpointMapping(eShaderStage_Pixel);
// viewer takes ownership of the trace
ShaderViewer *s = ShaderViewer::debugShader(m_Ctx, &bindMapping, shaderDetails,
eShaderStage_Pixel, trace, debugContext, this);
m_Ctx.setupDockWindow(s);
ToolWindowManager *manager = ToolWindowManager::managerOf(this);
ToolWindowManager::AreaReference ref(ToolWindowManager::AddTo, manager->areaOf(this));
manager->addToolWindow(s, ref);
});
}
void TextureViewer::on_pixelHistory_clicked()
{
FetchTexture *texptr = GetCurrentTexture();
+1
View File
@@ -159,6 +159,7 @@ private slots:
void on_viewTexBuffer_clicked();
void on_texListShow_clicked();
void on_saveTex_clicked();
void on_debugPixelContext_clicked();
void on_pixelHistory_clicked();
void on_cancelTextureListFilter_clicked();