Add notion of UI modifications to a capture, saved in .rdc sections

This commit is contained in:
baldurk
2017-11-15 19:28:19 +00:00
parent bb6452c334
commit c00a6ca8ef
8 changed files with 227 additions and 10 deletions
+70
View File
@@ -147,6 +147,8 @@ void CaptureContext::LoadCapture(const QString &captureFile, const QString &orig
{
m_CaptureTemporary = temporary;
m_CaptureMods = CaptureModifications::NoModifications;
QVector<ICaptureViewer *> viewers(m_CaptureViewers);
// make sure we're on a consistent event before invoking viewer forms
@@ -311,6 +313,18 @@ void CaptureContext::LoadCaptureThreaded(const QString &captureFile, const QStri
.arg(origFilename));
}
ICaptureAccess *access = Replay().GetCaptureAccess();
if(access)
{
int idx = access->FindSectionByType(SectionType::ResourceRenames);
if(idx >= 0)
{
bytebuf buf = access->GetSectionContents(idx);
LoadRenames(QString::fromUtf8((const char *)buf.data(), buf.count()));
}
}
m_LoadInProgress = false;
m_CaptureLoaded = true;
}
@@ -596,6 +610,17 @@ bool CaptureContext::SaveCaptureTo(const QString &captureFile)
Replay().ReopenCaptureFile(captureFile);
if(m_CaptureMods & CaptureModifications::Renames)
{
SectionProperties props;
props.type = SectionType::ResourceRenames;
props.version = 1;
Replay().GetCaptureAccess()->WriteSection(props, SaveRenames().toUtf8());
}
m_CaptureMods = CaptureModifications::NoModifications;
return true;
}
@@ -697,6 +722,48 @@ void CaptureContext::AddMessages(const rdcarray<DebugMessage> &msgs)
}
}
QString CaptureContext::SaveRenames()
{
QVariantMap resources;
for(ResourceId id : m_CustomNames.keys())
{
resources[ToQStr(id)] = m_CustomNames[id];
}
QVariantMap root;
root[lit("CustomResourceNames")] = resources;
return VariantToJSON(root);
}
void CaptureContext::LoadRenames(const QString &data)
{
QVariantMap root = JSONToVariant(data);
if(root.contains(lit("CustomResourceNames")))
{
QVariantMap resources = root[lit("CustomResourceNames")].toMap();
for(const QString &str : resources.keys())
{
ResourceId id;
if(str.startsWith(lit("resourceid::")))
{
qulonglong num = str.mid(sizeof("resourceid::") - 1).toULongLong();
memcpy(&id, &num, sizeof(num));
}
else
{
qCritical() << "Unrecognised resourceid encoding" << str;
}
if(id != ResourceId())
m_CustomNames[id] = resources[str].toString();
}
}
}
QString CaptureContext::GetResourceName(ResourceId id)
{
if(id == ResourceId())
@@ -748,6 +815,9 @@ void CaptureContext::SetResourceCustomName(ResourceId id, const QString &name)
m_CustomNameCachedID++;
m_CaptureMods |= CaptureModifications::Renames;
m_MainWindow->captureModified();
RefreshUIStatus({}, true, true);
}
+5
View File
@@ -103,6 +103,7 @@ public:
bool IsCaptureTemporary() override { return m_CaptureTemporary; }
bool IsCaptureLoading() override { return m_LoadInProgress; }
QString GetCaptureFilename() override { return m_CaptureFile; }
CaptureModifications GetCaptureModifications() override { return m_CaptureMods; }
const FrameDescription &FrameInfo() override { return m_FrameInfo; }
const APIProperties &APIProps() override { return m_APIProps; }
uint32_t CurSelectedEvent() override { return m_SelectedEventID; }
@@ -233,6 +234,7 @@ private:
bool m_CaptureLoaded = false, m_LoadInProgress = false, m_CaptureLocal = false,
m_CaptureTemporary = false;
QString m_CaptureFile;
CaptureModifications m_CaptureMods = CaptureModifications::NoModifications;
QVector<DebugMessage> m_DebugMessages;
int m_UnreadMessageCount = 0;
@@ -241,6 +243,9 @@ private:
bool ContainsMarker(const rdcarray<DrawcallDescription> &m_Drawcalls);
void AddFakeProfileMarkers();
QString SaveRenames();
void LoadRenames(const QString &data);
float m_LoadProgress = 0.0f;
float m_PostloadProgress = 0.0f;
float UpdateLoadProgress();
+42
View File
@@ -871,6 +871,40 @@ enum class DockReference : int
ConstantBufferArea,
};
DOCUMENT(R"(Details any changes that have been made to a capture in the UI which can be saved to
disk but currently aren't. Note that detection is conservative - e.g. if a change is made, then
cancelled out by reversing the change, this will still count as 'modified' even if the end result is
the same data. In that sense it's analogous to adding and then deleting some characters in a text
editor, since there is no actual undo system.
This is a bitmask, so several values can be present at once.
.. data:: NoModifications
Fixed value of 0 indicating no modifications have been made.
.. data:: Renames
One or more resources have been given a custom name which hasn't been saved.
.. data:: Bookmarks
Event bookmarks have been added or removed.
.. data:: Notes
The general notes field has been changed.
)");
enum class CaptureModifications : uint32_t
{
NoModifications = 0x0000,
Renames = 0x0001,
Bookmarks = 0x0002,
Notes = 0x0004,
};
BITMASK_OPERATORS(CaptureModifications);
DOCUMENT("The capture context that the python script is running in.")
struct ICaptureContext
{
@@ -998,6 +1032,14 @@ temporary and treated like any other capture.
)");
virtual QString GetCaptureFilename() = 0;
DOCUMENT(R"(Get a bitmask indicating which modifications (if any) have been made to the capture in
the UI which aren't reflected in the capture file on disk.
:return: The modifications (if any) that have been made to the capture.
:rtype: CaptureModifications
)");
virtual CaptureModifications GetCaptureModifications() = 0;
DOCUMENT(R"(Retrieve the :class:`~renderdoc.FrameDescription` for the currently loaded capture.
:return: The frame information.
+88 -7
View File
@@ -220,7 +220,8 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
m_Ctx.AddCaptureViewer(this);
ui->action_Save_Capture->setEnabled(false);
ui->action_Save_Capture_Inplace->setEnabled(false);
ui->action_Save_Capture_As->setEnabled(false);
ui->action_Close_Capture->setEnabled(false);
QList<QAction *> actions = ui->menuBar->actions();
@@ -282,6 +283,14 @@ void MainWindow::on_action_Open_Capture_triggered()
LoadFromFilename(filename, false);
}
void MainWindow::captureModified()
{
// once the capture is modified, enable the save-in-place option. It might already have been
// enabled if this capture was a temporary one
if(m_Ctx.IsCaptureLoaded())
ui->action_Save_Capture_Inplace->setEnabled(true);
}
void MainWindow::LoadFromFilename(const QString &filename, bool temporary)
{
QFileInfo path(filename);
@@ -652,6 +661,53 @@ bool MainWindow::PromptCloseCapture()
deletepath = temppath;
m_OwnTempCapture = false;
}
else if(m_Ctx.GetCaptureModifications() != CaptureModifications::NoModifications)
{
QMessageBox::StandardButton res = QMessageBox::No;
QString text = tr("This capture has the following modifications:\n\n");
CaptureModifications mods = m_Ctx.GetCaptureModifications();
if(mods & CaptureModifications::Renames)
text += tr("Resources have been renamed.\n");
if(mods & CaptureModifications::Bookmarks)
text += tr("Bookmarks have been changed.\n");
if(mods & CaptureModifications::Notes)
text += tr("Capture notes have been changed.\n");
bool saveas = false;
if(m_Ctx.IsCaptureLocal())
{
text += tr("\nWould you like to save those changes to '%1'?").arg(m_Ctx.GetCaptureFilename());
}
else
{
saveas = true;
text +=
tr("\nThe capture is on a remote host, would you like to save these changes locally?");
}
res = RDDialog::question(NULL, tr("Save changes to capture?"), text,
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if(res == QMessageBox::Cancel)
return false;
if(res == QMessageBox::Yes)
{
bool success = false;
if(saveas)
success = PromptSaveCaptureAs();
else
success = m_Ctx.SaveCaptureTo(m_Ctx.GetCaptureFilename());
if(!success)
return false;
}
}
CloseCapture();
@@ -665,7 +721,8 @@ void MainWindow::CloseCapture()
{
m_Ctx.CloseCapture();
ui->action_Save_Capture->setEnabled(false);
ui->action_Save_Capture_Inplace->setEnabled(false);
ui->action_Save_Capture_As->setEnabled(false);
}
void MainWindow::SetTitle(const QString &filename)
@@ -1226,7 +1283,11 @@ void MainWindow::statusDoubleClicked(QMouseEvent *event)
void MainWindow::OnCaptureLoaded()
{
ui->action_Save_Capture->setEnabled(true);
// at first only allow the default save for temporary captures. It should be disabled if we have
// loaded a 'permanent' capture from disk and haven't made any changes. It will be enabled as soon
// as any changes are made.
ui->action_Save_Capture_Inplace->setEnabled(m_Ctx.IsCaptureTemporary());
ui->action_Save_Capture_As->setEnabled(true);
ui->action_Close_Capture->setEnabled(true);
// don't allow changing context while capture is open
@@ -1247,8 +1308,6 @@ void MainWindow::OnCaptureLoaded()
ui->action_Resolve_Symbols->setEnabled(hasResolver);
ui->action_Resolve_Symbols->setText(hasResolver ? tr("Resolve Symbols")
: tr("Resolve Symbols - None in capture"));
ui->action_Save_Capture->setEnabled(true);
});
});
@@ -1261,7 +1320,8 @@ void MainWindow::OnCaptureLoaded()
void MainWindow::OnCaptureClosed()
{
ui->action_Save_Capture->setEnabled(false);
ui->action_Save_Capture_Inplace->setEnabled(false);
ui->action_Save_Capture_As->setEnabled(false);
ui->action_Close_Capture->setEnabled(false);
ui->action_Start_Replay_Loop->setEnabled(false);
@@ -1361,7 +1421,28 @@ void MainWindow::on_action_Close_Capture_triggered()
PromptCloseCapture();
}
void MainWindow::on_action_Save_Capture_triggered()
void MainWindow::on_action_Save_Capture_Inplace_triggered()
{
bool saved = false;
if(m_Ctx.IsCaptureTemporary() || !m_Ctx.IsCaptureLocal())
{
saved = PromptSaveCaptureAs();
}
else
{
if(m_Ctx.GetCaptureModifications() != CaptureModifications::NoModifications &&
m_Ctx.IsCaptureLocal())
{
saved = m_Ctx.SaveCaptureTo(m_Ctx.GetCaptureFilename());
}
}
if(saved)
ui->action_Save_Capture_Inplace->setEnabled(false);
}
void MainWindow::on_action_Save_Capture_As_triggered()
{
PromptSaveCaptureAs();
}
+3 -1
View File
@@ -68,6 +68,7 @@ public:
void setProgress(float val);
void takeCaptureOwnership() { m_OwnTempCapture = true; }
void captureModified();
void LoadFromFilename(const QString &filename, bool temporary);
void LoadCapture(const QString &filename, bool temporary, bool local);
void CloseCapture();
@@ -101,7 +102,8 @@ private slots:
void on_action_Exit_triggered();
void on_action_About_triggered();
void on_action_Open_Capture_triggered();
void on_action_Save_Capture_triggered();
void on_action_Save_Capture_Inplace_triggered();
void on_action_Save_Capture_As_triggered();
void on_action_Close_Capture_triggered();
void on_action_Mesh_Output_triggered();
void on_action_API_Inspector_triggered();
+8 -2
View File
@@ -79,7 +79,8 @@
<addaction name="action_Inject_into_Process"/>
<addaction name="separator"/>
<addaction name="action_Open_Capture"/>
<addaction name="action_Save_Capture"/>
<addaction name="action_Save_Capture_Inplace"/>
<addaction name="action_Save_Capture_As"/>
<addaction name="action_Close_Capture"/>
<addaction name="separator"/>
<addaction name="menu_Recent_Capture_Files"/>
@@ -181,7 +182,7 @@
<string>Ctrl+O</string>
</property>
</action>
<action name="action_Save_Capture">
<action name="action_Save_Capture_Inplace">
<property name="text">
<string>&amp;Save Capture</string>
</property>
@@ -409,6 +410,11 @@
<string>&amp;Resource Inspector</string>
</property>
</action>
<action name="action_Save_Capture_As">
<property name="text">
<string>Sa&amp;ve Capture As</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
+4
View File
@@ -60,6 +60,10 @@ struct CaptureContextInvoker : ICaptureContext
virtual bool IsCaptureTemporary() override { return m_Ctx.IsCaptureTemporary(); }
virtual bool IsCaptureLoading() override { return m_Ctx.IsCaptureLoading(); }
virtual QString GetCaptureFilename() override { return m_Ctx.GetCaptureFilename(); }
virtual CaptureModifications GetCaptureModifications() override
{
return m_Ctx.GetCaptureModifications();
}
virtual const FrameDescription &FrameInfo() override { return m_Ctx.FrameInfo(); }
virtual const APIProperties &APIProps() override { return m_Ctx.APIProps(); }
virtual uint32_t CurSelectedEvent() override { return m_Ctx.CurSelectedEvent(); }
+7
View File
@@ -597,4 +597,11 @@ struct bytebuf : public rdcarray<byte>
{
bytebuf() : rdcarray<byte>() {}
bytebuf(const std::vector<byte> &in) : rdcarray<byte>(in) {}
#if defined(RENDERDOC_QT_COMPAT)
bytebuf(const QByteArray &in)
{
resize(in.size());
memcpy(elems, in.data(), in.size());
}
#endif
};