Add functionality to reset an edited shader to original. Closes #2334

* We also add the ability to toggle on/off the replacement being active without
  needing to intentionally add a compile error (and this also makes it more
  explicitly clear when the shader replacement is enabled or not. This could be
  useful for quick A/B testing between the edited version and the original.
This commit is contained in:
baldurk
2021-11-02 14:09:50 +00:00
parent de38cf7b9c
commit d4a5592780
8 changed files with 161 additions and 38 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ Using the built-in shader editor
When you have launched the shader editor, the main window will be filled with the source of your shader. In here you can make edits and changes with the basic controls and syntax highlighting available with the Scintilla editor.
To compile the shader and apply your changes, either click the refresh button in the toolbar or press :kbd:`F5`. This will compile the shader and apply it, any warnings and errors will be added to the errors panel below the main source.
To compile the shader and apply your changes, either click the Apply changes button in the toolbar or press :kbd:`F5`. This will compile the shader and apply it, any warnings and errors will be added to the errors panel below the main source.
You can choose the tool used to compile in the lower section, as well as configure any parameters to it. See above for more information about shader processing tools.
+17 -11
View File
@@ -1973,14 +1973,14 @@ void CaptureContext::LoadEdits(const QString &data)
ApplyShaderEdit(viewer, id, stage, shaderEncoding, flags, entryFunc, shaderBytes);
};
auto replaceCloseCallback = [this](ICaptureContext *ctx, IShaderViewer *view, ResourceId id) {
auto replaceRevertCallback = [this](ICaptureContext *ctx, IShaderViewer *view, ResourceId id) {
RevertShaderEdit(view, id);
};
for(QVariant e : editors)
{
ShaderViewer *edit =
ShaderViewer::LoadEditor(*this, e.toMap(), replaceSaveCallback, replaceCloseCallback,
ShaderViewer::LoadEditor(*this, e.toMap(), replaceSaveCallback, replaceRevertCallback,
[this](ShaderViewer *view, bool closed) {
SetModification(CaptureModifications::EditedShaders);
if(closed)
@@ -2457,7 +2457,7 @@ IShaderViewer *CaptureContext::EditShader(ResourceId id, ShaderStage stage,
const rdcstr &entryPoint, const rdcstrpairs &files,
ShaderEncoding shaderEncoding, ShaderCompileFlags flags,
IShaderViewer::SaveCallback saveCallback,
IShaderViewer::CloseCallback closeCallback)
IShaderViewer::RevertCallback revertCallback)
{
ShaderViewer *viewer = NULL;
@@ -2474,16 +2474,16 @@ IShaderViewer *CaptureContext::EditShader(ResourceId id, ShaderStage stage,
saveCallback(ctx, viewer, id, stage, shaderEncoding, flags, entryFunc, shaderBytes);
};
auto replaceCloseCallback = [this, closeCallback](ICaptureContext *ctx, IShaderViewer *view,
ResourceId id) {
auto replaceRevertCallback = [this, revertCallback](ICaptureContext *ctx, IShaderViewer *view,
ResourceId id) {
RevertShaderEdit(view, id);
if(closeCallback)
closeCallback(ctx, view, id);
if(revertCallback)
revertCallback(ctx, view, id);
};
viewer = ShaderViewer::EditShader(*this, id, stage, entryPoint, files, shaderEncoding, flags,
replaceSaveCallback, replaceCloseCallback,
replaceSaveCallback, replaceRevertCallback,
[this](ShaderViewer *view, bool closed) {
SetModification(CaptureModifications::EditedShaders);
if(closed)
@@ -2497,7 +2497,7 @@ IShaderViewer *CaptureContext::EditShader(ResourceId id, ShaderStage stage,
else
{
viewer = ShaderViewer::EditShader(*this, id, stage, entryPoint, files, shaderEncoding, flags,
saveCallback, closeCallback, NULL, m_MainWindow->Widget());
saveCallback, revertCallback, NULL, m_MainWindow->Widget());
}
return viewer;
@@ -2546,12 +2546,18 @@ void CaptureContext::ApplyShaderEdit(IShaderViewer *viewer, ResourceId id, Shade
void CaptureContext::RevertShaderEdit(IShaderViewer *viewer, ResourceId id)
{
QPointer<QObject> ptr(viewer->Widget());
// remove the replacement on close (we could make this more sophisticated if there
// was a place to control replaced resources/shaders).
Replay().AsyncInvoke([this, id](IReplayController *r) {
Replay().AsyncInvoke([this, viewer, id, ptr](IReplayController *r) {
if(IsCaptureLoaded())
r->RemoveReplacement(id);
GUIInvoke::call(GetMainWindow()->Widget(), [this, id] { UnregisterReplacement(id); });
GUIInvoke::call(GetMainWindow()->Widget(), [this, viewer, id, ptr] {
UnregisterReplacement(id);
if(ptr)
viewer->ShowErrors(rdcstr());
});
});
}
+1 -1
View File
@@ -245,7 +245,7 @@ public:
IShaderViewer *EditShader(ResourceId id, ShaderStage stage, const rdcstr &entryPoint,
const rdcstrpairs &files, ShaderEncoding shaderEncoding,
ShaderCompileFlags flags, IShaderViewer::SaveCallback saveCallback,
IShaderViewer::CloseCallback closeCallback) override;
IShaderViewer::RevertCallback revertCallback) override;
void ApplyShaderEdit(IShaderViewer *viewer, ResourceId id, ShaderStage stage,
ShaderEncoding shaderEncoding, ShaderCompileFlags flags,
+6 -6
View File
@@ -1096,9 +1096,9 @@ DOCUMENT(R"(A shader window used for viewing, editing, or debugging.
:param bytes source: The byte buffer containing the source - may just be text depending on the
encoding.
.. function:: CloseCallback(context)
.. function:: RevertCallback(context)
Not a member function - the signature for any ``CloseCallback`` callbacks.
Not a member function - the signature for any ``RevertCallback`` callbacks.
Called whenever a shader viewer that was open for editing is closed.
@@ -1111,7 +1111,7 @@ struct IShaderViewer
typedef std::function<void(ICaptureContext *, IShaderViewer *, ResourceId, ShaderStage,
ShaderEncoding, ShaderCompileFlags, rdcstr, bytebuf)>
SaveCallback;
typedef std::function<void(ICaptureContext *, IShaderViewer *, ResourceId)> CloseCallback;
typedef std::function<void(ICaptureContext *, IShaderViewer *, ResourceId)> RevertCallback;
DOCUMENT(R"(Retrieves the PySide2 QWidget for this :class:`ShaderViewer` if PySide2 is available, or otherwise
returns a unique opaque pointer that can be passed back to any RenderDoc functions expecting a
@@ -2483,8 +2483,8 @@ place if needed.
:param renderdoc.ShaderCompileFlags flags: The flags originally used to compile the shader.
:param ShaderViewer.SaveCallback saveCallback: The callback function to call when a save/update is
triggered.
:param ShaderViewer.CloseCallback closeCallback: The callback function to call when the shader
viewer is closed.
:param ShaderViewer.RevertCallback revertCallback: The callback function to call when the shader
is to be reverted - either by user request or because the shader viewer was closed.
:return: The new :class:`ShaderViewer` window opened but not shown for editing.
:rtype: ShaderViewer
)");
@@ -2492,7 +2492,7 @@ place if needed.
const rdcstrpairs &files, ShaderEncoding shaderEncoding,
ShaderCompileFlags flags,
IShaderViewer::SaveCallback saveCallback,
IShaderViewer::CloseCallback closeCallback) = 0;
IShaderViewer::RevertCallback revertCallback) = 0;
DOCUMENT(R"(Show a new :class:`ShaderViewer` window, showing a read-only view of a debug trace
through the execution of a given shader.
+2 -2
View File
@@ -747,11 +747,11 @@ struct CaptureContextInvoker : ObjectForwarder<ICaptureContext>
const rdcstrpairs &files, ShaderEncoding shaderEncoding,
ShaderCompileFlags flags,
IShaderViewer::SaveCallback saveCallback,
IShaderViewer::CloseCallback closeCallback) override
IShaderViewer::RevertCallback revertCallback) override
{
return InvokeRetFunction<IShaderViewer *>(&ICaptureContext::EditShader, id, stage, entryPoint,
files, shaderEncoding, flags, saveCallback,
closeCallback);
revertCallback);
}
virtual IShaderViewer *DebugShader(const ShaderBindpointMapping *bind,
+73 -9
View File
@@ -322,6 +322,7 @@ void ShaderViewer::editShader(ResourceId id, ShaderStage stage, const QString &e
QWidget *w = (QWidget *)scintilla;
w->setProperty("filename", kv.first);
w->setProperty("origText", kv.second);
if(text.contains(entryPoint))
sel = scintilla;
@@ -526,6 +527,9 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
// hide edit buttons
ui->refresh->hide();
ui->unrefresh->hide();
ui->resetEdits->hide();
ui->editStatusLabel->hide();
ui->snippets->hide();
ui->editSep->hide();
@@ -1130,7 +1134,7 @@ void ShaderViewer::gotoDisassemblyDebugging()
ShaderViewer *ShaderViewer::LoadEditor(ICaptureContext &ctx, QVariantMap data,
IShaderViewer::SaveCallback saveCallback,
IShaderViewer::CloseCallback closeCallback,
IShaderViewer::RevertCallback revertCallback,
ModifyCallback modifyCallback, QWidget *parent)
{
if(data.isEmpty())
@@ -1181,7 +1185,7 @@ ShaderViewer *ShaderViewer::LoadEditor(ICaptureContext &ctx, QVariantMap data,
}
ShaderViewer *view = EditShader(ctx, id, stage, entryPoint, files, encoding, flags, saveCallback,
closeCallback, modifyCallback, parent);
revertCallback, modifyCallback, parent);
int toolIndex = -1;
@@ -1266,8 +1270,8 @@ ShaderViewer::~ShaderViewer()
m_Ctx.Replay().AsyncInvoke([trace](IReplayController *r) { r->FreeTrace(trace); });
if(m_CloseCallback)
m_CloseCallback(&m_Ctx, this, m_EditingShader);
if(m_RevertCallback)
m_RevertCallback(&m_Ctx, this, m_EditingShader);
if(m_ModifyCallback)
m_ModifyCallback(this, true);
@@ -2645,12 +2649,35 @@ bool ShaderViewer::getVar(RDTreeWidgetItem *item, ShaderVariable *var, QString *
}
}
void ShaderViewer::setEditorWindowTitle()
void ShaderViewer::updateEditState()
{
if(m_EditingShader != ResourceId())
{
if(!m_Ctx.IsResourceReplaced(m_EditingShader))
m_Modified = true;
QString statusString, statusTooltip;
// check if the shader is replaced and update the status
if(m_Ctx.IsResourceReplaced(m_EditingShader))
{
statusString = tr("Status: Edited Shader Active");
statusTooltip = tr("The replay currently has the original shader active");
}
else
{
statusString = tr("Status: Original Shader Active");
statusTooltip = tr("The replay currently has an edited version of the shader active");
// if we expected it to be saved something went wrong
if(m_Saved)
{
// we're still 'modified' as in have unsaved changes
m_Modified = true;
statusTooltip.append(tr("\n\nSomething went wrong applying changes."));
}
}
ui->editStatusLabel->setText(statusString);
ui->editStatusLabel->setToolTip(statusTooltip);
if(m_Modified)
{
@@ -4257,7 +4284,7 @@ void ShaderViewer::ShowErrors(const rdcstr &errors)
ToolWindowManager::raiseToolWindow(m_Errors);
}
setEditorWindowTitle();
updateEditState();
}
void ShaderViewer::AddWatch(const rdcstr &variable)
@@ -4760,7 +4787,7 @@ void ShaderViewer::MarkModification()
m_Modified = true;
setEditorWindowTitle();
updateEditState();
}
void ShaderViewer::disasm_tooltipShow(int x, int y)
@@ -5095,6 +5122,41 @@ bool ShaderViewer::ProcessIncludeDirectives(QString &source, const rdcstrpairs &
return true;
}
void ShaderViewer::on_resetEdits_clicked()
{
QMessageBox::StandardButton res = RDDialog::question(
this, tr("Are you sure?"), tr("Are you sure you want to reset all edits and restore the "
"shader source back to the original?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if(res != QMessageBox::Yes)
return;
for(ScintillaEdit *s : m_Scintillas)
{
QWidget *w = (QWidget *)s;
s->selectAll();
s->replaceSel(w->property("origText").toString().toUtf8().data());
}
m_RevertCallback(&m_Ctx, this, m_EditingShader);
m_Modified = false;
m_Saved = false;
updateEditState();
}
void ShaderViewer::on_unrefresh_clicked()
{
m_RevertCallback(&m_Ctx, this, m_EditingShader);
m_Modified = true;
m_Saved = false;
updateEditState();
}
void ShaderViewer::on_refresh_clicked()
{
if(m_Trace)
@@ -5134,6 +5196,8 @@ void ShaderViewer::on_refresh_clicked()
return;
}
m_Saved = true;
bytebuf shaderBytes(source.toUtf8());
rdcarray<ShaderEncoding> accepted = m_Ctx.TargetShaderEncodings();
+8 -5
View File
@@ -78,7 +78,7 @@ public:
static ShaderViewer *LoadEditor(ICaptureContext &ctx, QVariantMap data,
IShaderViewer::SaveCallback saveCallback,
IShaderViewer::CloseCallback closeCallback,
IShaderViewer::RevertCallback revertCallback,
ModifyCallback modifyCallback, QWidget *parent);
QVariantMap SaveEditor();
@@ -86,12 +86,12 @@ public:
const QString &entryPoint, const rdcstrpairs &files,
ShaderEncoding shaderEncoding, ShaderCompileFlags flags,
IShaderViewer::SaveCallback saveCallback,
IShaderViewer::CloseCallback closeCallback,
IShaderViewer::RevertCallback revertCallback,
ModifyCallback modifyCallback, QWidget *parent)
{
ShaderViewer *ret = new ShaderViewer(ctx, parent);
ret->m_SaveCallback = saveCallback;
ret->m_CloseCallback = closeCallback;
ret->m_RevertCallback = revertCallback;
ret->m_ModifyCallback = modifyCallback;
ret->editShader(id, stage, entryPoint, files, shaderEncoding, flags);
return ret;
@@ -140,6 +140,8 @@ private slots:
// automatic slots
void on_findReplace_clicked();
void on_refresh_clicked();
void on_unrefresh_clicked();
void on_resetEdits_clicked();
void on_intView_clicked();
void on_floatView_clicked();
void on_debugToggle_clicked();
@@ -261,10 +263,11 @@ private:
} m_FindState;
SaveCallback m_SaveCallback;
CloseCallback m_CloseCallback;
RevertCallback m_RevertCallback;
ModifyCallback m_ModifyCallback;
bool m_Modified = true;
bool m_Saved = false;
ShaderDebugTrace *m_Trace = NULL;
rdcarray<ShaderDebugState> m_States;
@@ -338,7 +341,7 @@ private:
void find(bool down);
void setEditorWindowTitle();
void updateEditState();
enum StepMode
{
+53 -3
View File
@@ -327,12 +327,32 @@
</widget>
</item>
<item>
<widget class="QToolButton" name="refresh">
<widget class="QToolButton" name="resetEdits">
<property name="toolTip">
<string>Compile Shader &amp; Refresh changes</string>
<string>Remove all source edits and restore original shader</string>
</property>
<property name="text">
<string>Refresh</string>
<string>Reset</string>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/del.png</normaloff>:/del.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="refresh">
<property name="toolTip">
<string>Compile shader &amp; apply changes</string>
</property>
<property name="text">
<string>Apply changes</string>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
@@ -346,6 +366,36 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="unrefresh">
<property name="toolTip">
<string>Use original shader</string>
</property>
<property name="text">
<string>Remove changes</string>
</property>
<property name="icon">
<iconset resource="../Resources/resources.qrc">
<normaloff>:/arrow_undo.png</normaloff>:/arrow_undo.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="editStatusLabel">
<property name="text">
<string>Status: Original Shader Active</string>
</property>
<property name="toolTip">
<string>The replay currently has the original shader active</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="snippets">
<property name="toolTip">