mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 09:00:44 +00:00
Improve workflow for capture import/export
* If the export doesn't need buffers, we export directly from the loaded capture file instead of re-loading it. * Add progress bars for the load step so it shows what's happening instead of looking stalled. * Reduce compression rate on XML+ZIP buffers as it took too long trying to compress when exporting large captures.
This commit is contained in:
@@ -135,6 +135,8 @@ rdcstr CaptureContext::TempCaptureFilename(const rdcstr &appname)
|
||||
void CaptureContext::LoadCapture(const rdcstr &captureFile, const rdcstr &origFilename,
|
||||
bool temporary, bool local)
|
||||
{
|
||||
CloseCapture();
|
||||
|
||||
m_LoadInProgress = true;
|
||||
|
||||
if(local)
|
||||
@@ -662,7 +664,7 @@ void CaptureContext::RecompressCapture()
|
||||
{
|
||||
// for remote files we open a new short-lived handle on the temporary file
|
||||
tempCap = cap = RENDERDOC_OpenCaptureFile();
|
||||
cap->OpenFile(tempFilename.toUtf8().data(), "rdc");
|
||||
cap->OpenFile(tempFilename.toUtf8().data(), "rdc", NULL);
|
||||
}
|
||||
|
||||
if(!cap)
|
||||
@@ -691,7 +693,7 @@ void CaptureContext::RecompressCapture()
|
||||
float progress = 0.0f;
|
||||
|
||||
LambdaThread *th = new LambdaThread([this, cap, destFilename, &progress]() {
|
||||
cap->Convert(destFilename.toUtf8().data(), "rdc", [&progress](float p) { progress = p; });
|
||||
cap->Convert(destFilename.toUtf8().data(), "rdc", NULL, [&progress](float p) { progress = p; });
|
||||
});
|
||||
th->start();
|
||||
// wait a few ms before popping up a progress bar
|
||||
@@ -709,7 +711,7 @@ void CaptureContext::RecompressCapture()
|
||||
// the original, then re-open.
|
||||
|
||||
// this releases the hold over the real desired location.
|
||||
cap->OpenFile("", "");
|
||||
cap->OpenFile("", "", NULL);
|
||||
|
||||
// now remove the old capture
|
||||
QFile::remove(GetCaptureFilename());
|
||||
@@ -718,7 +720,7 @@ void CaptureContext::RecompressCapture()
|
||||
QFile::rename(destFilename, GetCaptureFilename());
|
||||
|
||||
// and re-open
|
||||
cap->OpenFile(GetCaptureFilename().c_str(), "rdc");
|
||||
cap->OpenFile(GetCaptureFilename().c_str(), "rdc", NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -869,6 +871,141 @@ void CaptureContext::CloseCapture()
|
||||
}
|
||||
}
|
||||
|
||||
bool CaptureContext::ImportCapture(const CaptureFileFormat &fmt, const rdcstr &importfile,
|
||||
const rdcstr &rdcfile)
|
||||
{
|
||||
CloseCapture();
|
||||
|
||||
QString ext = fmt.extension;
|
||||
|
||||
ReplayStatus status = ReplayStatus::UnknownError;
|
||||
QString message;
|
||||
|
||||
// shorten the filename after here for error messages
|
||||
QString filename = QFileInfo(importfile).fileName();
|
||||
|
||||
float progress = 0.0f;
|
||||
|
||||
LambdaThread *th = new LambdaThread([rdcfile, importfile, ext, &message, &progress, &status]() {
|
||||
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
status = file->OpenFile(importfile.c_str(), ext.toUtf8().data(),
|
||||
[&progress](float p) { progress = p * 0.5f; });
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
message = file->ErrorString();
|
||||
file->Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
status = file->Convert(rdcfile.c_str(), "rdc", NULL,
|
||||
[&progress](float p) { progress = 0.5f + p * 0.5f; });
|
||||
file->Shutdown();
|
||||
});
|
||||
th->start();
|
||||
// wait a few ms before popping up a progress bar
|
||||
th->wait(500);
|
||||
if(th->isRunning())
|
||||
{
|
||||
ShowProgressDialog(m_MainWindow, tr("Importing from %1, please wait...").arg(filename),
|
||||
[th]() { return !th->isRunning(); }, [&progress]() { return progress; });
|
||||
}
|
||||
th->deleteLater();
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
QString text = tr("Couldn't convert file '%1'\n").arg(filename);
|
||||
if(message.isEmpty())
|
||||
text += tr("%1").arg(ToQStr(status));
|
||||
else
|
||||
text += tr("%1: %2").arg(ToQStr(status)).arg(message);
|
||||
|
||||
RDDialog::critical(m_MainWindow, tr("Error converting capture"), text);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CaptureContext::ExportCapture(const CaptureFileFormat &fmt, const rdcstr &exportfile)
|
||||
{
|
||||
if(!m_CaptureLocal)
|
||||
return;
|
||||
|
||||
QString ext = fmt.extension;
|
||||
|
||||
ICaptureFile *local = NULL;
|
||||
ICaptureFile *file = NULL;
|
||||
ReplayStatus status = ReplayStatus::Succeeded;
|
||||
|
||||
const SDFile *sdfile = NULL;
|
||||
|
||||
// if we don't need buffers, we can export directly from our existing capture file
|
||||
if(!fmt.requiresBuffers)
|
||||
{
|
||||
file = Replay().GetCaptureFile();
|
||||
sdfile = m_StructuredFile;
|
||||
}
|
||||
|
||||
if(!file)
|
||||
{
|
||||
local = file = RENDERDOC_OpenCaptureFile();
|
||||
status = file->OpenFile(m_CaptureFile.toUtf8().data(), "rdc", NULL);
|
||||
}
|
||||
|
||||
QString filename = QFileInfo(m_CaptureFile).fileName();
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
QString text = tr("Couldn't open file '%1' for export\n").arg(filename);
|
||||
QString message = local->ErrorString();
|
||||
if(message.isEmpty())
|
||||
text += tr("%1").arg(ToQStr(status));
|
||||
else
|
||||
text += tr("%1: %2").arg(ToQStr(status)).arg(message);
|
||||
|
||||
RDDialog::critical(m_MainWindow, tr("Error opening file"), text);
|
||||
|
||||
if(local)
|
||||
local->Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
float progress = 0.0f;
|
||||
|
||||
LambdaThread *th = new LambdaThread([this, file, sdfile, ext, exportfile, &progress, &status]() {
|
||||
status = file->Convert(exportfile.c_str(), ext.toUtf8().data(), sdfile,
|
||||
[&progress](float p) { progress = p; });
|
||||
});
|
||||
th->start();
|
||||
// wait a few ms before popping up a progress bar
|
||||
th->wait(500);
|
||||
if(th->isRunning())
|
||||
{
|
||||
ShowProgressDialog(m_MainWindow,
|
||||
tr("Exporting %1 to %2, please wait...").arg(filename).arg(QString(fmt.name)),
|
||||
[th]() { return !th->isRunning(); }, [&progress]() { return progress; });
|
||||
}
|
||||
th->deleteLater();
|
||||
|
||||
QString message = file->ErrorString();
|
||||
if(local)
|
||||
local->Shutdown();
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
QString text = tr("Couldn't convert file '%1'\n").arg(filename);
|
||||
if(message.isEmpty())
|
||||
text += tr("%1").arg(ToQStr(status));
|
||||
else
|
||||
text += tr("%1: %2").arg(ToQStr(status)).arg(message);
|
||||
|
||||
RDDialog::critical(m_MainWindow, tr("Error converting capture"), text);
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureContext::SetEventID(const rdcarray<ICaptureViewer *> &exclude, uint32_t selectedEventID,
|
||||
uint32_t eventId, bool force)
|
||||
{
|
||||
|
||||
@@ -73,7 +73,9 @@ public:
|
||||
bool SaveCaptureTo(const rdcstr &captureFile) override;
|
||||
void RecompressCapture() override;
|
||||
void CloseCapture() override;
|
||||
|
||||
bool ImportCapture(const CaptureFileFormat &fmt, const rdcstr &importfile,
|
||||
const rdcstr &rdcfile) override;
|
||||
void ExportCapture(const CaptureFileFormat &fmt, const rdcstr &exportfile) override;
|
||||
void SetEventID(const rdcarray<ICaptureViewer *> &exclude, uint32_t selectedEventID,
|
||||
uint32_t eventId, bool force = false) override;
|
||||
|
||||
|
||||
@@ -1006,6 +1006,30 @@ time.
|
||||
DOCUMENT("Close the currently open capture file.");
|
||||
virtual void CloseCapture() = 0;
|
||||
|
||||
DOCUMENT(R"(Imports a capture file from a non-native format, via conversion to temporary rdc.
|
||||
|
||||
This converts the file to a specified temporary .rdc and loads it, closing any existing capture.
|
||||
|
||||
The capture must be available locally, if it's not this function will fail.
|
||||
|
||||
:param CaptureFileFormat fmt: The capture file format to import from.
|
||||
:param str importfile: The path to import from.
|
||||
:param str rdcfile: The temporary path to save the rdc file to.
|
||||
:return: ``True`` if the import operation was successful and the capture was loaded.
|
||||
:rtype: ``bool``
|
||||
)");
|
||||
virtual bool ImportCapture(const CaptureFileFormat &fmt, const rdcstr &importfile,
|
||||
const rdcstr &rdcfile) = 0;
|
||||
|
||||
DOCUMENT(R"(Exports the current capture file to a given path with a specified capture file format.
|
||||
|
||||
The capture must be available locally, if it's not this function will fail.
|
||||
|
||||
:param CaptureFileFormat fmt: The capture file format to export to.
|
||||
:param str exportfile: The path to export the capture file to.
|
||||
)");
|
||||
virtual void ExportCapture(const CaptureFileFormat &fmt, const rdcstr &exportfile) = 0;
|
||||
|
||||
DOCUMENT(R"(Move the current replay to a new event in the capture.
|
||||
|
||||
:param list exclude: A list of :class:`CaptureViewer` to exclude from being notified of this, to stop
|
||||
|
||||
@@ -369,7 +369,7 @@ void ReplayManager::ReopenCaptureFile(const QString &path)
|
||||
{
|
||||
if(!m_CaptureFile)
|
||||
m_CaptureFile = RENDERDOC_OpenCaptureFile();
|
||||
m_CaptureFile->OpenFile(path.toUtf8().data(), "rdc");
|
||||
m_CaptureFile->OpenFile(path.toUtf8().data(), "rdc", NULL);
|
||||
}
|
||||
|
||||
uint32_t ReplayManager::ExecuteAndInject(const rdcstr &exe, const rdcstr &workingDir,
|
||||
@@ -423,7 +423,7 @@ void ReplayManager::run(int proxyRenderer, const QString &capturefile,
|
||||
{
|
||||
m_CaptureFile = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
m_CreateStatus = m_CaptureFile->OpenFile(capturefile.toUtf8().data(), "rdc");
|
||||
m_CreateStatus = m_CaptureFile->OpenFile(capturefile.toUtf8().data(), "rdc", NULL);
|
||||
|
||||
if(m_CreateStatus == ReplayStatus::Succeeded)
|
||||
std::tie(m_CreateStatus, m_Renderer) = m_CaptureFile->OpenCapture(progress);
|
||||
|
||||
@@ -76,7 +76,7 @@ CrashDialog::CrashDialog(PersistantConfig &cfg, QVariantMap crashReportJSON, QWi
|
||||
|
||||
ICaptureFile *cap = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
ReplayStatus status = cap->OpenFile(capInfo.absoluteFilePath().toUtf8().data(), "");
|
||||
ReplayStatus status = cap->OpenFile(capInfo.absoluteFilePath().toUtf8().data(), "", NULL);
|
||||
|
||||
if(status == ReplayStatus::Succeeded)
|
||||
{
|
||||
|
||||
@@ -338,39 +338,29 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
|
||||
|
||||
for(const CaptureFileFormat &fmt : formats)
|
||||
{
|
||||
QString name = fmt.name;
|
||||
if(name == lit("rdc"))
|
||||
if(fmt.extension == "rdc")
|
||||
continue;
|
||||
|
||||
QString desc = fmt.description;
|
||||
|
||||
int idx = desc.indexOf(QLatin1Char('\n'));
|
||||
|
||||
QString title = idx >= 0 ? desc.mid(0, idx).trimmed() : desc.trimmed();
|
||||
QString tooltip = idx >= 0 ? desc.mid(idx).trimmed() : QString();
|
||||
|
||||
if(fmt.openSupported)
|
||||
{
|
||||
QAction *action = new QAction(title, this);
|
||||
QAction *action = new QAction(fmt.name, this);
|
||||
|
||||
QObject::connect(action, &QAction::triggered,
|
||||
[this, name, title]() { importCapture(name, title); });
|
||||
QObject::connect(action, &QAction::triggered, [this, fmt]() { importCapture(fmt); });
|
||||
|
||||
if(!tooltip.isEmpty())
|
||||
action->setToolTip(tooltip);
|
||||
if(!fmt.description.isEmpty())
|
||||
action->setToolTip(fmt.description);
|
||||
|
||||
ui->menu_Import_From->addAction(action);
|
||||
}
|
||||
|
||||
if(fmt.convertSupported)
|
||||
{
|
||||
QAction *action = new QAction(title, this);
|
||||
QAction *action = new QAction(fmt.name, this);
|
||||
|
||||
QObject::connect(action, &QAction::triggered,
|
||||
[this, name, title]() { exportCapture(name, title); });
|
||||
QObject::connect(action, &QAction::triggered, [this, fmt]() { exportCapture(fmt); });
|
||||
|
||||
if(!tooltip.isEmpty())
|
||||
action->setToolTip(tooltip);
|
||||
if(!fmt.description.isEmpty())
|
||||
action->setToolTip(fmt.description);
|
||||
|
||||
ui->menu_Export_As->addAction(action);
|
||||
}
|
||||
@@ -444,75 +434,30 @@ void MainWindow::on_action_Open_Capture_triggered()
|
||||
LoadFromFilename(filename, false);
|
||||
}
|
||||
|
||||
void MainWindow::importCapture(QString ext, QString title)
|
||||
void MainWindow::importCapture(const CaptureFileFormat &fmt)
|
||||
{
|
||||
if(!PromptCloseCapture())
|
||||
return;
|
||||
|
||||
QString ext = fmt.extension;
|
||||
QString title = fmt.name;
|
||||
|
||||
QString filename =
|
||||
RDDialog::getOpenFileName(this, tr("Select file to open"), m_Ctx.Config().LastCaptureFilePath,
|
||||
tr("%1 Files (*.%2);;All Files (*)").arg(title).arg(ext));
|
||||
|
||||
if(!filename.isEmpty())
|
||||
{
|
||||
QString rdcfile = m_Ctx.TempCaptureFilename("imported");
|
||||
QString rdcfile = m_Ctx.TempCaptureFilename(lit("imported_") + ext);
|
||||
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
bool success = m_Ctx.ImportCapture(fmt, filename, rdcfile);
|
||||
|
||||
ReplayStatus status = file->OpenFile(filename.toUtf8().data(), ext.toUtf8().data());
|
||||
|
||||
filename = QFileInfo(filename).fileName();
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
if(success)
|
||||
{
|
||||
QString text = tr("Couldn't open file '%1'\n").arg(filename);
|
||||
QString message = file->ErrorString();
|
||||
if(message.isEmpty())
|
||||
text += tr("%1").arg(ToQStr(status));
|
||||
else
|
||||
text += tr("%1: %2").arg(ToQStr(status)).arg(message);
|
||||
|
||||
RDDialog::critical(this, tr("Error opening file"), text);
|
||||
|
||||
file->Shutdown();
|
||||
return;
|
||||
// open file as temporary, in case the user wants to save the imported rdc
|
||||
LoadFromFilename(rdcfile, true);
|
||||
takeCaptureOwnership();
|
||||
}
|
||||
|
||||
float progress = 0.0f;
|
||||
|
||||
LambdaThread *th = new LambdaThread([file, rdcfile, &progress, &status]() {
|
||||
status = file->Convert(rdcfile.toUtf8().data(), "rdc", [&progress](float p) { progress = p; });
|
||||
});
|
||||
th->start();
|
||||
// wait a few ms before popping up a progress bar
|
||||
th->wait(500);
|
||||
if(th->isRunning())
|
||||
{
|
||||
ShowProgressDialog(this, tr("Importing from %1, please wait...").arg(filename),
|
||||
[th]() { return !th->isRunning(); }, [&progress]() { return progress; });
|
||||
}
|
||||
th->deleteLater();
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
QString text = tr("Couldn't convert file '%1'\n").arg(filename);
|
||||
QString message = file->ErrorString();
|
||||
if(message.isEmpty())
|
||||
text += tr("%1").arg(ToQStr(status));
|
||||
else
|
||||
text += tr("%1: %2").arg(ToQStr(status)).arg(message);
|
||||
|
||||
RDDialog::critical(this, tr("Error converting capture"), text);
|
||||
|
||||
file->Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
file->Shutdown();
|
||||
|
||||
// open file as temporary, in case the user wants to save the imported rdc
|
||||
LoadFromFilename(rdcfile, true);
|
||||
takeCaptureOwnership();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -647,7 +592,7 @@ void MainWindow::LoadCapture(const QString &filename, bool temporary, bool local
|
||||
{
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
ReplayStatus status = file->OpenFile(filename.toUtf8().data(), "rdc");
|
||||
ReplayStatus status = file->OpenFile(filename.toUtf8().data(), "rdc", NULL);
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
@@ -880,9 +825,9 @@ bool MainWindow::PromptSaveCaptureAs()
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainWindow::exportCapture(QString ext, QString title)
|
||||
void MainWindow::exportCapture(const CaptureFileFormat &fmt)
|
||||
{
|
||||
if(m_Ctx.Replay().CurrentRemote())
|
||||
if(!m_Ctx.IsCaptureLocal())
|
||||
{
|
||||
RDDialog::information(
|
||||
this, tr("Save changes to capture?"),
|
||||
@@ -892,62 +837,11 @@ void MainWindow::exportCapture(QString ext, QString title)
|
||||
}
|
||||
|
||||
QString saveFilename =
|
||||
GetSavePath(tr("Export Capture As"), tr("%1 Files (*.%2)").arg(title).arg(ext));
|
||||
GetSavePath(tr("Export Capture As"),
|
||||
tr("%1 Files (*.%2)").arg(QString(fmt.name)).arg(QString(fmt.extension)));
|
||||
|
||||
if(!saveFilename.isEmpty())
|
||||
{
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
ReplayStatus status = file->OpenFile(m_Ctx.GetCaptureFilename().c_str(), "rdc");
|
||||
|
||||
QString filename = QFileInfo(QString(m_Ctx.GetCaptureFilename())).fileName();
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
QString text = tr("Couldn't open file '%1' for export\n").arg(filename);
|
||||
QString message = file->ErrorString();
|
||||
if(message.isEmpty())
|
||||
text += tr("%1").arg(ToQStr(status));
|
||||
else
|
||||
text += tr("%1: %2").arg(ToQStr(status)).arg(message);
|
||||
|
||||
RDDialog::critical(this, tr("Error opening file"), text);
|
||||
|
||||
file->Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
float progress = 0.0f;
|
||||
|
||||
LambdaThread *th = new LambdaThread([file, ext, saveFilename, &progress, &status]() {
|
||||
status = file->Convert(saveFilename.toUtf8().data(), ext.toUtf8().data(),
|
||||
[&progress](float p) { progress = p; });
|
||||
});
|
||||
th->start();
|
||||
// wait a few ms before popping up a progress bar
|
||||
th->wait(500);
|
||||
if(th->isRunning())
|
||||
{
|
||||
ShowProgressDialog(this, tr("Exporting %1 to %2, please wait...").arg(filename).arg(title),
|
||||
[th]() { return !th->isRunning(); }, [&progress]() { return progress; });
|
||||
}
|
||||
th->deleteLater();
|
||||
|
||||
QString message = file->ErrorString();
|
||||
file->Shutdown();
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
QString text = tr("Couldn't convert file '%1'\n").arg(filename);
|
||||
if(message.isEmpty())
|
||||
text += tr("%1").arg(ToQStr(status));
|
||||
else
|
||||
text += tr("%1: %2").arg(ToQStr(status)).arg(message);
|
||||
|
||||
RDDialog::critical(this, tr("Error converting capture"), text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_Ctx.ExportCapture(fmt, saveFilename);
|
||||
}
|
||||
|
||||
bool MainWindow::PromptCloseCapture()
|
||||
|
||||
@@ -162,8 +162,8 @@ private:
|
||||
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
void importCapture(QString ext, QString title);
|
||||
void exportCapture(QString ext, QString title);
|
||||
void importCapture(const CaptureFileFormat &fmt);
|
||||
void exportCapture(const CaptureFileFormat &fmt);
|
||||
|
||||
QString dragFilename(const QMimeData *mimeData);
|
||||
|
||||
|
||||
@@ -183,6 +183,15 @@ struct CaptureContextInvoker : ICaptureContext
|
||||
InvokeVoidFunction(&ICaptureContext::RecompressCapture);
|
||||
}
|
||||
virtual void CloseCapture() override { InvokeVoidFunction(&ICaptureContext::CloseCapture); }
|
||||
virtual bool ImportCapture(const CaptureFileFormat &fmt, const rdcstr &importfile,
|
||||
const rdcstr &rdcfile) override
|
||||
{
|
||||
return InvokeRetFunction<bool>(&ICaptureContext::ImportCapture, fmt, importfile, rdcfile);
|
||||
}
|
||||
virtual void ExportCapture(const CaptureFileFormat &fmt, const rdcstr &exportfile) override
|
||||
{
|
||||
InvokeVoidFunction(&ICaptureContext::ExportCapture, fmt, exportfile);
|
||||
}
|
||||
virtual void SetEventID(const rdcarray<ICaptureViewer *> &exclude, uint32_t selectedEventID,
|
||||
uint32_t eventId, bool force = false) override
|
||||
{
|
||||
|
||||
@@ -536,34 +536,48 @@ struct CaptureFileFormat
|
||||
DOCUMENT("");
|
||||
bool operator==(const CaptureFileFormat &o) const
|
||||
{
|
||||
return name == o.name && description == o.description && openSupported == o.openSupported &&
|
||||
return extension == o.extension && name == o.name && description == o.description &&
|
||||
requiresBuffers == o.requiresBuffers && openSupported == o.openSupported &&
|
||||
convertSupported == o.convertSupported;
|
||||
}
|
||||
bool operator<(const CaptureFileFormat &o) const
|
||||
{
|
||||
if(!(extension == o.extension))
|
||||
return extension < o.extension;
|
||||
if(!(name == o.name))
|
||||
return name < o.name;
|
||||
if(!(description == o.description))
|
||||
return description < o.description;
|
||||
if(!(requiresBuffers == o.requiresBuffers))
|
||||
return requiresBuffers < o.requiresBuffers;
|
||||
if(!(openSupported == o.openSupported))
|
||||
return openSupported < o.openSupported;
|
||||
if(!(convertSupported == o.convertSupported))
|
||||
return convertSupported < o.convertSupported;
|
||||
return false;
|
||||
}
|
||||
DOCUMENT("The name of the format as a single minimal string, e.g. ``rdc``.");
|
||||
DOCUMENT("The file of the format as a single minimal string, e.g. ``rdc``.");
|
||||
rdcstr extension;
|
||||
|
||||
DOCUMENT("A human readable short phrase naming the file format.");
|
||||
rdcstr name;
|
||||
|
||||
DOCUMENT("A human readable description of the file format, e.g. ``RenderDoc native capture``.");
|
||||
DOCUMENT("A human readable long-form description of the file format.");
|
||||
rdcstr description;
|
||||
|
||||
DOCUMENT(R"(Indicates whether exporting to this format requires buffers or just structured data.
|
||||
If it doesn't require buffers then it can be exported directly from an opened capture, which by
|
||||
default has structured data but no buffers available.
|
||||
)");
|
||||
bool requiresBuffers;
|
||||
|
||||
DOCUMENT(R"(Indicates whether or not files in this format can be opened and processed as
|
||||
structured data.
|
||||
)");
|
||||
bool openSupported = false;
|
||||
bool openSupported;
|
||||
|
||||
DOCUMENT("Indicates whether captures or structured data can be saved out in this format.");
|
||||
bool convertSupported = true;
|
||||
bool convertSupported;
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(CaptureFileFormat);
|
||||
|
||||
@@ -1486,10 +1486,13 @@ empty or unrecognised.
|
||||
|
||||
:param str filename: The filename of the file to open.
|
||||
:param str filetype: The format of the given file.
|
||||
:param ProgressCallback progress: A callback that will be repeatedly called with an updated progress
|
||||
value if an import step occurs. Can be ``None`` if no progress is desired.
|
||||
:return: The status of the open operation, whether it succeeded or failed (and how it failed).
|
||||
:rtype: ReplayStatus
|
||||
)");
|
||||
virtual ReplayStatus OpenFile(const char *filename, const char *filetype) = 0;
|
||||
virtual ReplayStatus OpenFile(const char *filename, const char *filetype,
|
||||
RENDERDOC_ProgressCallback progress) = 0;
|
||||
|
||||
DOCUMENT(R"(Initialises the file handle from a raw memory buffer.
|
||||
|
||||
@@ -1499,10 +1502,13 @@ For the :paramref:`OpenBuffer.filetype` parameter, see :meth:`OpenFile`.
|
||||
|
||||
:param bytes buffer: The buffer containing the data to process.
|
||||
:param str filetype: The format of the given file.
|
||||
:param ProgressCallback progress: A callback that will be repeatedly called with an updated progress
|
||||
value if an import step occurs. Can be ``None`` if no progress is desired.
|
||||
:return: The status of the open operation, whether it succeeded or failed (and how it failed).
|
||||
:rtype: ReplayStatus
|
||||
)");
|
||||
virtual ReplayStatus OpenBuffer(const bytebuf &buffer, const char *filetype) = 0;
|
||||
virtual ReplayStatus OpenBuffer(const bytebuf &buffer, const char *filetype,
|
||||
RENDERDOC_ProgressCallback progress) = 0;
|
||||
|
||||
DOCUMENT(R"(When a capture file is opened, an exclusive lock is held on the file on disk. This
|
||||
makes it impossible to copy the file to another location at the user's request. Calling this
|
||||
@@ -1525,12 +1531,16 @@ representation back to native RDC.
|
||||
|
||||
:param str filename: The filename to save to.
|
||||
:param str filetype: The format to convert to.
|
||||
:param SDFile file: An optional :class:`SDFile` with the structured data to source from. This is
|
||||
useful in case the format specifies that it doesn't need buffers, and you already have a
|
||||
:class:`ReplayController` open with the structured data. This saves the need to load the file
|
||||
again. If ``None`` then structured data will be fetched if not already present and used.
|
||||
:param ProgressCallback progress: A callback that will be repeatedly called with an updated progress
|
||||
value for the conversion. Can be ``None`` if no progress is desired.
|
||||
:return: The status of the conversion operation, whether it succeeded or failed (and how it failed).
|
||||
:rtype: ReplayStatus
|
||||
)");
|
||||
virtual ReplayStatus Convert(const char *filename, const char *filetype,
|
||||
virtual ReplayStatus Convert(const char *filename, const char *filetype, const SDFile *file,
|
||||
RENDERDOC_ProgressCallback progress) = 0;
|
||||
|
||||
DOCUMENT(R"(Returns the human-readable error string for the last error received.
|
||||
|
||||
+38
-26
@@ -788,22 +788,45 @@ void RenderDoc::RegisterStructuredProcessor(RDCDriver driver, StructuredProcesso
|
||||
m_StructProcesssors[driver] = provider;
|
||||
}
|
||||
|
||||
void RenderDoc::RegisterCaptureExporter(const char *filetype, const char *description,
|
||||
CaptureExporter exporter)
|
||||
void RenderDoc::RegisterCaptureExporter(CaptureExporter exporter, CaptureFileFormat description)
|
||||
{
|
||||
RDCASSERT(m_ImportExportFormats.find(filetype) == m_ImportExportFormats.end());
|
||||
std::string filetype = description.extension;
|
||||
|
||||
m_ImportExportFormats[filetype] = description;
|
||||
for(const CaptureFileFormat &fmt : m_ImportExportFormats)
|
||||
{
|
||||
if(fmt.extension == filetype)
|
||||
{
|
||||
RDCERR("Duplicate exporter for '%s' found", filetype.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
description.openSupported = false;
|
||||
description.convertSupported = true;
|
||||
|
||||
m_ImportExportFormats.push_back(description);
|
||||
|
||||
m_Exporters[filetype] = exporter;
|
||||
}
|
||||
|
||||
void RenderDoc::RegisterCaptureImportExporter(const char *filetype, const char *description,
|
||||
CaptureImporter importer, CaptureExporter exporter)
|
||||
void RenderDoc::RegisterCaptureImportExporter(CaptureImporter importer, CaptureExporter exporter,
|
||||
CaptureFileFormat description)
|
||||
{
|
||||
RDCASSERT(m_ImportExportFormats.find(filetype) == m_ImportExportFormats.end());
|
||||
std::string filetype = description.extension;
|
||||
|
||||
m_ImportExportFormats[filetype] = description;
|
||||
for(const CaptureFileFormat &fmt : m_ImportExportFormats)
|
||||
{
|
||||
if(fmt.extension == filetype)
|
||||
{
|
||||
RDCERR("Duplicate import/exporter for '%s' found", filetype.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
description.openSupported = true;
|
||||
description.convertSupported = true;
|
||||
|
||||
m_ImportExportFormats.push_back(description);
|
||||
|
||||
m_Importers[filetype] = importer;
|
||||
m_Exporters[filetype] = exporter;
|
||||
@@ -847,30 +870,19 @@ CaptureImporter RenderDoc::GetCaptureImporter(const char *filetype)
|
||||
|
||||
std::vector<CaptureFileFormat> RenderDoc::GetCaptureFileFormats()
|
||||
{
|
||||
std::vector<CaptureFileFormat> ret;
|
||||
std::vector<CaptureFileFormat> ret = m_ImportExportFormats;
|
||||
|
||||
std::sort(ret.begin(), ret.end());
|
||||
|
||||
{
|
||||
CaptureFileFormat rdc;
|
||||
rdc.name = "rdc";
|
||||
rdc.description = "Native RDC capture file format.";
|
||||
rdc.extension = "rdc";
|
||||
rdc.name = "Native RDC capture file format.";
|
||||
rdc.description = "The format produced by frame-captures from applications directly.";
|
||||
rdc.openSupported = true;
|
||||
rdc.convertSupported = true;
|
||||
|
||||
ret.push_back(rdc);
|
||||
}
|
||||
|
||||
for(auto it = m_ImportExportFormats.begin(); it != m_ImportExportFormats.end(); ++it)
|
||||
{
|
||||
CaptureFileFormat fmt;
|
||||
fmt.name = it->first;
|
||||
fmt.description = it->second;
|
||||
|
||||
fmt.openSupported = m_Importers.find(it->first) != m_Importers.end();
|
||||
fmt.convertSupported = m_Exporters.find(it->first) != m_Exporters.end();
|
||||
|
||||
RDCASSERT(fmt.openSupported || fmt.convertSupported);
|
||||
|
||||
ret.push_back(fmt);
|
||||
ret.insert(ret.begin(), rdc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
+9
-12
@@ -312,8 +312,6 @@ class IReplayDriver;
|
||||
class StreamReader;
|
||||
class RDCFile;
|
||||
|
||||
class RDCFile;
|
||||
|
||||
typedef ReplayStatus (*RemoteDriverProvider)(RDCFile *rdc, IRemoteDriver **driver);
|
||||
typedef ReplayStatus (*ReplayDriverProvider)(RDCFile *rdc, IReplayDriver **driver);
|
||||
|
||||
@@ -430,10 +428,9 @@ public:
|
||||
|
||||
void RegisterStructuredProcessor(RDCDriver driver, StructuredProcessor provider);
|
||||
|
||||
void RegisterCaptureExporter(const char *filetype, const char *description,
|
||||
CaptureExporter exporter);
|
||||
void RegisterCaptureImportExporter(const char *filetype, const char *description,
|
||||
CaptureImporter importer, CaptureExporter exporter);
|
||||
void RegisterCaptureExporter(CaptureExporter exporter, CaptureFileFormat description);
|
||||
void RegisterCaptureImportExporter(CaptureImporter importer, CaptureExporter exporter,
|
||||
CaptureFileFormat description);
|
||||
|
||||
StructuredProcessor GetStructuredProcessor(RDCDriver driver);
|
||||
|
||||
@@ -584,7 +581,7 @@ private:
|
||||
|
||||
std::map<RDCDriver, StructuredProcessor> m_StructProcesssors;
|
||||
|
||||
std::map<std::string, std::string> m_ImportExportFormats;
|
||||
std::vector<CaptureFileFormat> m_ImportExportFormats;
|
||||
std::map<std::string, CaptureImporter> m_Importers;
|
||||
std::map<std::string, CaptureExporter> m_Exporters;
|
||||
|
||||
@@ -674,13 +671,13 @@ struct StructuredProcessRegistration
|
||||
|
||||
struct ConversionRegistration
|
||||
{
|
||||
ConversionRegistration(const char *filetype, const char *description, CaptureImporter importer,
|
||||
CaptureExporter exporter)
|
||||
ConversionRegistration(CaptureImporter importer, CaptureExporter exporter,
|
||||
CaptureFileFormat description)
|
||||
{
|
||||
RenderDoc::Inst().RegisterCaptureImportExporter(filetype, description, importer, exporter);
|
||||
RenderDoc::Inst().RegisterCaptureImportExporter(importer, exporter, description);
|
||||
}
|
||||
ConversionRegistration(const char *filetype, const char *description, CaptureExporter exporter)
|
||||
ConversionRegistration(CaptureExporter exporter, CaptureFileFormat description)
|
||||
{
|
||||
RenderDoc::Inst().RegisterCaptureExporter(filetype, description, exporter);
|
||||
RenderDoc::Inst().RegisterCaptureExporter(exporter, description);
|
||||
}
|
||||
};
|
||||
@@ -179,7 +179,7 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli
|
||||
bytebuf buf;
|
||||
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
if(file->OpenFile(captures.back().path.c_str(), "rdc") == ReplayStatus::Succeeded)
|
||||
if(file->OpenFile(captures.back().path.c_str(), "rdc", NULL) == ReplayStatus::Succeeded)
|
||||
{
|
||||
buf = file->GetThumbnail(FileType::JPG, 0).data;
|
||||
}
|
||||
|
||||
@@ -1552,7 +1552,7 @@ ReplayStatus WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStruct
|
||||
|
||||
// only set progress after we've initialised the debug manager, to prevent progress jumping
|
||||
// backwards.
|
||||
if(m_DebugManager)
|
||||
if(m_DebugManager || IsStructuredExporting(m_State))
|
||||
{
|
||||
RenderDoc::Inst().SetProgress(LoadProgress::FileInitialRead,
|
||||
float(offsetEnd) / float(reader->GetSize()));
|
||||
|
||||
@@ -112,8 +112,10 @@ public:
|
||||
CaptureFile();
|
||||
virtual ~CaptureFile();
|
||||
|
||||
ReplayStatus OpenFile(const char *filename, const char *filetype);
|
||||
ReplayStatus OpenBuffer(const bytebuf &buffer, const char *filetype);
|
||||
ReplayStatus OpenFile(const char *filename, const char *filetype,
|
||||
RENDERDOC_ProgressCallback progress);
|
||||
ReplayStatus OpenBuffer(const bytebuf &buffer, const char *filetype,
|
||||
RENDERDOC_ProgressCallback progress);
|
||||
bool CopyFileTo(const char *filename);
|
||||
rdcstr ErrorString() { return m_ErrorString; }
|
||||
void Shutdown() { delete this; }
|
||||
@@ -125,7 +127,7 @@ public:
|
||||
void SetMetadata(const char *driverName, uint64_t machineIdent, FileType thumbType,
|
||||
uint32_t thumbWidth, uint32_t thumbHeight, const bytebuf &thumbData);
|
||||
|
||||
ReplayStatus Convert(const char *filename, const char *filetype,
|
||||
ReplayStatus Convert(const char *filename, const char *filetype, const SDFile *file,
|
||||
RENDERDOC_ProgressCallback progress);
|
||||
|
||||
rdcarray<CaptureFileFormat> GetCaptureFileFormats()
|
||||
@@ -135,16 +137,8 @@ public:
|
||||
|
||||
const SDFile &GetStructuredData()
|
||||
{
|
||||
if(m_StructuredData.chunks.empty() && m_RDC && m_RDC->SectionIndex(SectionType::FrameCapture) >= 0)
|
||||
{
|
||||
// decompile to structured data on demand.
|
||||
StructuredProcessor proc = RenderDoc::Inst().GetStructuredProcessor(m_RDC->GetDriver());
|
||||
|
||||
if(proc)
|
||||
proc(m_RDC, m_StructuredData);
|
||||
else
|
||||
RDCERR("Can't get structured data for driver %s", m_RDC->GetDriverName().c_str());
|
||||
}
|
||||
// decompile to structured data on demand.
|
||||
InitStructuredData();
|
||||
|
||||
return m_StructuredData;
|
||||
}
|
||||
@@ -182,6 +176,8 @@ public:
|
||||
private:
|
||||
ReplayStatus Init();
|
||||
|
||||
void InitStructuredData(RENDERDOC_ProgressCallback progress = RENDERDOC_ProgressCallback());
|
||||
|
||||
RDCFile *m_RDC = NULL;
|
||||
Callstack::StackResolver *m_Resolver = NULL;
|
||||
|
||||
@@ -201,7 +197,8 @@ CaptureFile::~CaptureFile()
|
||||
SAFE_DELETE(m_Resolver);
|
||||
}
|
||||
|
||||
ReplayStatus CaptureFile::OpenFile(const char *filename, const char *filetype)
|
||||
ReplayStatus CaptureFile::OpenFile(const char *filename, const char *filetype,
|
||||
RENDERDOC_ProgressCallback progress)
|
||||
{
|
||||
CaptureImporter importer = RenderDoc::Inst().GetCaptureImporter(filetype);
|
||||
|
||||
@@ -213,7 +210,7 @@ ReplayStatus CaptureFile::OpenFile(const char *filename, const char *filetype)
|
||||
StreamReader reader(FileIO::fopen(filename, "rb"));
|
||||
delete m_RDC;
|
||||
m_RDC = new RDCFile;
|
||||
ret = importer(filename, reader, m_RDC, m_StructuredData, NULL);
|
||||
ret = importer(filename, reader, m_RDC, m_StructuredData, progress);
|
||||
}
|
||||
|
||||
if(ret != ReplayStatus::Succeeded)
|
||||
@@ -228,15 +225,22 @@ ReplayStatus CaptureFile::OpenFile(const char *filename, const char *filetype)
|
||||
if(filetype != NULL && strcmp(filetype, "") && strcmp(filetype, "rdc"))
|
||||
RDCWARN("Opening file with unrecognised filetype '%s' - treating as 'rdc'", filetype);
|
||||
|
||||
if(progress)
|
||||
progress(0.0f);
|
||||
|
||||
delete m_RDC;
|
||||
m_RDC = new RDCFile;
|
||||
m_RDC->Open(filename);
|
||||
|
||||
if(progress)
|
||||
progress(1.0f);
|
||||
}
|
||||
|
||||
return Init();
|
||||
}
|
||||
|
||||
ReplayStatus CaptureFile::OpenBuffer(const bytebuf &buffer, const char *filetype)
|
||||
ReplayStatus CaptureFile::OpenBuffer(const bytebuf &buffer, const char *filetype,
|
||||
RENDERDOC_ProgressCallback progress)
|
||||
{
|
||||
CaptureImporter importer = RenderDoc::Inst().GetCaptureImporter(filetype);
|
||||
|
||||
@@ -249,7 +253,7 @@ ReplayStatus CaptureFile::OpenBuffer(const bytebuf &buffer, const char *filetype
|
||||
{
|
||||
StreamReader reader(vec);
|
||||
m_RDC = new RDCFile;
|
||||
ret = importer(NULL, reader, m_RDC, m_StructuredData, NULL);
|
||||
ret = importer(NULL, reader, m_RDC, m_StructuredData, progress);
|
||||
}
|
||||
|
||||
if(ret != ReplayStatus::Succeeded)
|
||||
@@ -264,8 +268,14 @@ ReplayStatus CaptureFile::OpenBuffer(const bytebuf &buffer, const char *filetype
|
||||
if(filetype != NULL && strcmp(filetype, "") && strcmp(filetype, "rdc"))
|
||||
RDCWARN("Opening file with unrecognised filetype '%s' - treating as 'rdc'", filetype);
|
||||
|
||||
if(progress)
|
||||
progress(0.0f);
|
||||
|
||||
m_RDC = new RDCFile;
|
||||
m_RDC->Open(vec);
|
||||
|
||||
if(progress)
|
||||
progress(1.0f);
|
||||
}
|
||||
|
||||
return Init();
|
||||
@@ -325,6 +335,23 @@ ReplayStatus CaptureFile::Init()
|
||||
return ReplayStatus::InternalError;
|
||||
}
|
||||
|
||||
void CaptureFile::InitStructuredData(RENDERDOC_ProgressCallback progress /*= RENDERDOC_ProgressCallback()*/)
|
||||
{
|
||||
if(m_StructuredData.chunks.empty() && m_RDC && m_RDC->SectionIndex(SectionType::FrameCapture) >= 0)
|
||||
{
|
||||
StructuredProcessor proc = RenderDoc::Inst().GetStructuredProcessor(m_RDC->GetDriver());
|
||||
|
||||
RenderDoc::Inst().SetProgressCallback<LoadProgress>(progress);
|
||||
|
||||
if(proc)
|
||||
proc(m_RDC, m_StructuredData);
|
||||
else
|
||||
RDCERR("Can't get structured data for driver %s", m_RDC->GetDriverName().c_str());
|
||||
|
||||
RenderDoc::Inst().SetProgressCallback<LoadProgress>(RENDERDOC_ProgressCallback());
|
||||
}
|
||||
}
|
||||
|
||||
rdcpair<ReplayStatus, IReplayController *> CaptureFile::OpenCapture(RENDERDOC_ProgressCallback progress)
|
||||
{
|
||||
if(!m_RDC || m_RDC->ErrorCode() != ContainerError::NoError)
|
||||
@@ -377,7 +404,7 @@ void CaptureFile::SetMetadata(const char *driverName, uint64_t machineIdent, Fil
|
||||
free((void *)th.pixels);
|
||||
}
|
||||
|
||||
ReplayStatus CaptureFile::Convert(const char *filename, const char *filetype,
|
||||
ReplayStatus CaptureFile::Convert(const char *filename, const char *filetype, const SDFile *file,
|
||||
RENDERDOC_ProgressCallback progress)
|
||||
{
|
||||
if(!m_RDC)
|
||||
@@ -386,10 +413,30 @@ ReplayStatus CaptureFile::Convert(const char *filename, const char *filetype,
|
||||
return ReplayStatus::FileCorrupted;
|
||||
}
|
||||
|
||||
// make sure progress is valid so we don't have to check it everywhere
|
||||
if(!progress)
|
||||
progress = [](float) {};
|
||||
|
||||
// we have two separate steps that can take time - fetching the structured data, and then
|
||||
// exporting or writing to RDC
|
||||
RENDERDOC_ProgressCallback fetchProgress = [progress](float p) { progress(p * 0.5f); };
|
||||
RENDERDOC_ProgressCallback exportProgress = [progress](float p) { progress(0.5f + p * 0.5f); };
|
||||
|
||||
CaptureExporter exporter = RenderDoc::Inst().GetCaptureExporter(filetype);
|
||||
|
||||
if(exporter)
|
||||
return exporter(filename, *m_RDC, GetStructuredData(), progress);
|
||||
{
|
||||
if(file)
|
||||
{
|
||||
return exporter(filename, *m_RDC, *file, exportProgress);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitStructuredData(fetchProgress);
|
||||
|
||||
return exporter(filename, *m_RDC, GetStructuredData(), exportProgress);
|
||||
}
|
||||
}
|
||||
|
||||
if(filetype != NULL && strcmp(filetype, "") && strcmp(filetype, "rdc"))
|
||||
RDCWARN("Converting file to unrecognised filetype '%s' - treating as 'rdc'", filetype);
|
||||
@@ -419,17 +466,23 @@ ReplayStatus CaptureFile::Convert(const char *filename, const char *filetype,
|
||||
|
||||
if(frameCaptureIndex == -1)
|
||||
{
|
||||
if(file == NULL)
|
||||
{
|
||||
InitStructuredData(fetchProgress);
|
||||
file = &m_StructuredData;
|
||||
}
|
||||
|
||||
SectionProperties frameCapture;
|
||||
frameCapture.flags = SectionFlags::ZstdCompressed;
|
||||
frameCapture.type = SectionType::FrameCapture;
|
||||
frameCapture.name = ToStr(frameCapture.type);
|
||||
frameCapture.version = GetStructuredData().version;
|
||||
frameCapture.version = file->version;
|
||||
|
||||
StreamWriter *writer = output.WriteSection(frameCapture);
|
||||
|
||||
WriteSerialiser ser(writer, Ownership::Nothing);
|
||||
|
||||
ser.WriteStructuredFile(GetStructuredData(), progress);
|
||||
ser.WriteStructuredFile(*file, exportProgress);
|
||||
|
||||
writer->Finish();
|
||||
|
||||
|
||||
@@ -92,9 +92,11 @@ ReplayStatus exportChrome(const char *filename, const RDCFile &rdc, const SDFile
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
static ConversionRegistration XMLConversionRegistration("chrome.json", R"(Chrome profiler JSON
|
||||
|
||||
Exports the chunk threadID, timestamp and duration data to a JSON format that can be loaded by
|
||||
chrome's profiler at chrome://tracing
|
||||
)",
|
||||
&exportChrome);
|
||||
static ConversionRegistration XMLConversionRegistration(
|
||||
&exportChrome,
|
||||
{
|
||||
"chrome.json", "Chrome profiler JSON",
|
||||
R"(Exports the chunk threadID, timestamp and duration data to a JSON format that can be loaded
|
||||
by chrome's profiler at chrome://tracing)",
|
||||
false,
|
||||
});
|
||||
@@ -289,6 +289,9 @@ static ReplayStatus Structured2XML(const char *filename, const RDCFile &file, ui
|
||||
}
|
||||
}
|
||||
|
||||
if(progress)
|
||||
progress(StructuredProgress(0.1f));
|
||||
|
||||
// write all other sections
|
||||
for(int i = 0; i < file.NumSections(); i++)
|
||||
{
|
||||
@@ -340,6 +343,9 @@ static ReplayStatus Structured2XML(const char *filename, const RDCFile &file, ui
|
||||
delete reader;
|
||||
}
|
||||
|
||||
if(progress)
|
||||
progress(StructuredProgress(0.2f));
|
||||
|
||||
pugi::xml_node xChunks = xRoot.append_child("chunks");
|
||||
|
||||
xChunks.append_attribute("version") = version;
|
||||
@@ -382,6 +388,9 @@ static ReplayStatus Structured2XML(const char *filename, const RDCFile &file, ui
|
||||
for(size_t o = 0; o < chunk->data.children.size(); o++)
|
||||
Obj2XML(xChunk, *chunk->data.children[o]);
|
||||
}
|
||||
|
||||
if(progress)
|
||||
progress(StructuredProgress(0.2f + 0.8f * (float(c) / float(chunks.size()))));
|
||||
}
|
||||
|
||||
xml_file_writer writer(filename);
|
||||
@@ -712,8 +721,7 @@ static ReplayStatus Buffers2ZIP(const std::string &filename, const RDCFile &file
|
||||
|
||||
for(size_t i = 0; i < buffers.size(); i++)
|
||||
{
|
||||
mz_zip_writer_add_mem(&zip, GetBufferName(i).c_str(), buffers[i]->data(), buffers[i]->size(),
|
||||
MZ_BEST_COMPRESSION);
|
||||
mz_zip_writer_add_mem(&zip, GetBufferName(i).c_str(), buffers[i]->data(), buffers[i]->size(), 2);
|
||||
|
||||
if(progress)
|
||||
progress(BufferProgress(float(i) / float(buffers.size())));
|
||||
@@ -729,13 +737,17 @@ static ReplayStatus Buffers2ZIP(const std::string &filename, const RDCFile &file
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
static void ZIP2Buffers(const std::string &filename, StructuredBufferList &buffers,
|
||||
static bool ZIP2Buffers(const std::string &filename, StructuredBufferList &buffers,
|
||||
RENDERDOC_ProgressCallback progress)
|
||||
{
|
||||
std::string zipFile = filename + ".zip";
|
||||
std::string zipFile = filename;
|
||||
zipFile.erase(zipFile.size() - 4); // remove the .xml, leave only the .zip
|
||||
|
||||
if(!FileIO::exists(zipFile.c_str()))
|
||||
return;
|
||||
{
|
||||
RDCERR("Expected to file zip for %s at %s", filename.c_str(), zipFile.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
mz_zip_archive zip;
|
||||
memset(&zip, 0, sizeof(zip));
|
||||
@@ -780,13 +792,22 @@ static void ZIP2Buffers(const std::string &filename, StructuredBufferList &buffe
|
||||
}
|
||||
|
||||
mz_zip_reader_end(&zip);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ReplayStatus importXMLZ(const char *filename, StreamReader &reader, RDCFile *rdc,
|
||||
SDFile &structData, RENDERDOC_ProgressCallback progress)
|
||||
{
|
||||
if(filename)
|
||||
ZIP2Buffers(filename, structData.buffers, progress);
|
||||
{
|
||||
bool success = ZIP2Buffers(filename, structData.buffers, progress);
|
||||
if(!success)
|
||||
{
|
||||
RDCERR("Couldn't load zip to go with %s", filename);
|
||||
return ReplayStatus::FileCorrupted;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t len = reader.GetSize();
|
||||
char *buf = new char[(size_t)len + 1];
|
||||
@@ -814,16 +835,20 @@ ReplayStatus exportXMLOnly(const char *filename, const RDCFile &rdc, const SDFil
|
||||
return Structured2XML(filename, rdc, structData.version, structData.chunks, progress);
|
||||
}
|
||||
|
||||
static ConversionRegistration XMLZIPConversionRegistration("zip.xml", R"(XML+ZIP capture
|
||||
static ConversionRegistration XMLZIPConversionRegistration(
|
||||
&importXMLZ, &exportXMLZ,
|
||||
{
|
||||
"zip.xml", "XML+ZIP capture",
|
||||
R"(Stores the structured data in an xml tree, with large buffer data stored in indexed blobs in
|
||||
similarly named zip file.)",
|
||||
true,
|
||||
});
|
||||
|
||||
Stores the structured data in an xml tree, with large buffer data stored in indexed blobs in
|
||||
similarly named zip file.
|
||||
)",
|
||||
&importXMLZ, &exportXMLZ);
|
||||
|
||||
static ConversionRegistration XMLOnlyConversionRegistration("xml", R"(XML capture
|
||||
|
||||
Stores the structured data in an xml tree, with large buffer data omitted - that makes it easier to
|
||||
work with but it cannot then be imported.
|
||||
)",
|
||||
&exportXMLOnly);
|
||||
static ConversionRegistration XMLOnlyConversionRegistration(
|
||||
&exportXMLOnly,
|
||||
{
|
||||
"xml", "XML capture",
|
||||
R"(Stores the structured data in an xml tree, with large buffer data omitted - that makes it
|
||||
easier to work with but it cannot then be imported.)",
|
||||
false,
|
||||
});
|
||||
@@ -282,7 +282,7 @@ struct ThumbCommand : public Command
|
||||
bytebuf buf;
|
||||
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
ReplayStatus st = file->OpenFile(filename.c_str(), "rdc");
|
||||
ReplayStatus st = file->OpenFile(filename.c_str(), "rdc", NULL);
|
||||
if(st == ReplayStatus::Succeeded)
|
||||
{
|
||||
buf = file->GetThumbnail(type, maxsize).data;
|
||||
@@ -591,7 +591,7 @@ struct ReplayCommand : public Command
|
||||
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
if(file->OpenFile(filename.c_str(), "rdc") != ReplayStatus::Succeeded)
|
||||
if(file->OpenFile(filename.c_str(), "rdc", NULL) != ReplayStatus::Succeeded)
|
||||
{
|
||||
std::cerr << "Couldn't load '" << filename << "'." << std::endl;
|
||||
return 1;
|
||||
@@ -657,7 +657,9 @@ struct ConvertCommand : public Command
|
||||
{
|
||||
std::cout << "Available formats:" << std::endl;
|
||||
for(CaptureFileFormat f : m_Formats)
|
||||
std::cout << "'" << (std::string)f.name << "': " << (std::string)f.description << std::endl;
|
||||
std::cout << "'" << (std::string)f.name << "': " << (std::string)f.name << std::endl
|
||||
<< std::endl
|
||||
<< (std::string)f.description << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -687,11 +689,11 @@ struct ConvertCommand : public Command
|
||||
for(CaptureFileFormat f : m_Formats)
|
||||
{
|
||||
string extension = ".";
|
||||
extension += f.name;
|
||||
extension += f.extension;
|
||||
|
||||
if(infile.find(extension.c_str()) != string::npos)
|
||||
{
|
||||
infmt = f.name;
|
||||
infmt = f.extension;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -710,11 +712,11 @@ struct ConvertCommand : public Command
|
||||
for(CaptureFileFormat f : m_Formats)
|
||||
{
|
||||
string extension = ".";
|
||||
extension += f.name;
|
||||
extension += f.extension;
|
||||
|
||||
if(outfile.find(extension.c_str()) != string::npos)
|
||||
{
|
||||
outfmt = f.name;
|
||||
outfmt = f.extension;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -729,7 +731,7 @@ struct ConvertCommand : public Command
|
||||
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
ReplayStatus st = file->OpenFile(infile.c_str(), infmt.c_str());
|
||||
ReplayStatus st = file->OpenFile(infile.c_str(), infmt.c_str(), NULL);
|
||||
|
||||
if(st != ReplayStatus::Succeeded)
|
||||
{
|
||||
@@ -738,7 +740,7 @@ struct ConvertCommand : public Command
|
||||
return 1;
|
||||
}
|
||||
|
||||
st = file->Convert(outfile.c_str(), outfmt.c_str(), NULL);
|
||||
st = file->Convert(outfile.c_str(), outfmt.c_str(), NULL, NULL);
|
||||
|
||||
if(st != ReplayStatus::Succeeded)
|
||||
{
|
||||
@@ -956,7 +958,7 @@ struct EmbeddedSectionCommand : public Command
|
||||
|
||||
ICaptureFile *capfile = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
ReplayStatus status = capfile->OpenFile(rdc.c_str(), "");
|
||||
ReplayStatus status = capfile->OpenFile(rdc.c_str(), "", NULL);
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user