mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Add notion of UI modifications to a capture, saved in .rdc sections
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>&Save Capture</string>
|
||||
</property>
|
||||
@@ -409,6 +410,11 @@
|
||||
<string>&Resource Inspector</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Save_Capture_As">
|
||||
<property name="text">
|
||||
<string>Sa&ve Capture As</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
Reference in New Issue
Block a user