mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 17:40:39 +00:00
Don't launch blocking execute call on UI thread, pop up progress ticker
* This most commonly happens launching an Android program that takes a while to launch, or if you're launching a program with the delay for debugger option set. * Instead of the whole UI hanging, you'll get a progress dialog to appear while it's waiting.
This commit is contained in:
@@ -685,11 +685,14 @@ CaptureDialog *CaptureContext::captureDialog()
|
||||
m_CaptureDialog = new CaptureDialog(
|
||||
*this,
|
||||
[this](const QString &exe, const QString &workingDir, const QString &cmdLine,
|
||||
const QList<EnvironmentModification> &env, CaptureOptions opts) {
|
||||
return m_MainWindow->OnCaptureTrigger(exe, workingDir, cmdLine, env, opts);
|
||||
const QList<EnvironmentModification> &env, CaptureOptions opts,
|
||||
std::function<void(LiveCapture *)> callback) {
|
||||
return m_MainWindow->OnCaptureTrigger(exe, workingDir, cmdLine, env, opts, callback);
|
||||
},
|
||||
[this](uint32_t PID, const QList<EnvironmentModification> &env, const QString &name,
|
||||
CaptureOptions opts) { return m_MainWindow->OnInjectTrigger(PID, env, name, opts); },
|
||||
CaptureOptions opts, std::function<void(LiveCapture *)> callback) {
|
||||
return m_MainWindow->OnInjectTrigger(PID, env, name, opts, callback);
|
||||
},
|
||||
m_MainWindow);
|
||||
m_CaptureDialog->setObjectName("capDialog");
|
||||
m_CaptureDialog->setWindowIcon(*m_Icon);
|
||||
|
||||
@@ -745,10 +745,11 @@ void CaptureDialog::triggerCapture()
|
||||
QString name = m_ProcessModel->data(m_ProcessModel->index(item.row(), 0)).toString();
|
||||
uint32_t PID = m_ProcessModel->data(m_ProcessModel->index(item.row(), 1)).toUInt();
|
||||
|
||||
LiveCapture *live = m_InjectCallback(PID, settings().Environment, name, settings().Options);
|
||||
|
||||
if(ui->queueFrameCap->isChecked() && live != NULL)
|
||||
live->QueueCapture((int)ui->queuedFrame->value());
|
||||
m_InjectCallback(PID, settings().Environment, name, settings().Options,
|
||||
[this](LiveCapture *live) {
|
||||
if(ui->queueFrameCap->isChecked())
|
||||
live->QueueCapture((int)ui->queuedFrame->value());
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -781,10 +782,10 @@ void CaptureDialog::triggerCapture()
|
||||
|
||||
QString cmdLine = ui->cmdline->text();
|
||||
|
||||
LiveCapture *live =
|
||||
m_CaptureCallback(exe, workingDir, cmdLine, settings().Environment, settings().Options);
|
||||
|
||||
if(ui->queueFrameCap->isChecked() && live != NULL)
|
||||
live->QueueCapture((int)ui->queuedFrame->value());
|
||||
m_CaptureCallback(exe, workingDir, cmdLine, settings().Environment, settings().Options,
|
||||
[this](LiveCapture *live) {
|
||||
if(ui->queueFrameCap->isChecked())
|
||||
live->QueueCapture((int)ui->queuedFrame->value());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,11 +57,12 @@ class CaptureDialog : public QFrame
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef std::function<LiveCapture *(const QString &exe, const QString &workingDir, const QString &cmdLine,
|
||||
const QList<EnvironmentModification> &env, CaptureOptions opts)>
|
||||
typedef std::function<void(const QString &exe, const QString &workingDir, const QString &cmdLine,
|
||||
const QList<EnvironmentModification> &env, CaptureOptions opts,
|
||||
std::function<void(LiveCapture *)> callback)>
|
||||
OnCaptureMethod;
|
||||
typedef std::function<LiveCapture *(uint32_t PID, const QList<EnvironmentModification> &env,
|
||||
const QString &name, CaptureOptions opts)>
|
||||
typedef std::function<void(uint32_t PID, const QList<EnvironmentModification> &env, const QString &name,
|
||||
CaptureOptions opts, std::function<void(LiveCapture *)> callback)>
|
||||
OnInjectMethod;
|
||||
|
||||
explicit CaptureDialog(CaptureContext &ctx, OnCaptureMethod captureCallback,
|
||||
|
||||
@@ -324,63 +324,91 @@ void MainWindow::LoadFromFilename(const QString &filename)
|
||||
}
|
||||
}
|
||||
|
||||
LiveCapture *MainWindow::OnCaptureTrigger(const QString &exe, const QString &workingDir,
|
||||
const QString &cmdLine,
|
||||
const QList<EnvironmentModification> &env,
|
||||
CaptureOptions opts)
|
||||
void MainWindow::OnCaptureTrigger(const QString &exe, const QString &workingDir,
|
||||
const QString &cmdLine, const QList<EnvironmentModification> &env,
|
||||
CaptureOptions opts, std::function<void(LiveCapture *)> callback)
|
||||
{
|
||||
if(!PromptCloseLog())
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
QString logfile = m_Ctx.TempLogFilename(QFileInfo(exe).baseName());
|
||||
LambdaThread *th = new LambdaThread([this, exe, workingDir, cmdLine, env, opts, callback]() {
|
||||
QString logfile = m_Ctx.TempLogFilename(QFileInfo(exe).baseName());
|
||||
|
||||
uint32_t ret = m_Ctx.Renderer().ExecuteAndInject(exe, workingDir, cmdLine, env, logfile, opts);
|
||||
uint32_t ret = m_Ctx.Renderer().ExecuteAndInject(exe, workingDir, cmdLine, env, logfile, opts);
|
||||
|
||||
if(ret == 0)
|
||||
GUIInvoke::call([this, exe, ret, callback]() {
|
||||
if(ret == 0)
|
||||
{
|
||||
RDDialog::critical(this, tr("Error kicking capture"),
|
||||
tr("Error launching %1 for capture.\n\nCheck diagnostic log in Help "
|
||||
"menu for more details.")
|
||||
.arg(exe));
|
||||
return;
|
||||
}
|
||||
|
||||
LiveCapture *live = new LiveCapture(
|
||||
m_Ctx, m_Ctx.Renderer().remote() ? m_Ctx.Renderer().remote()->Hostname : "", ret, this,
|
||||
this);
|
||||
ShowLiveCapture(live);
|
||||
callback(live);
|
||||
});
|
||||
});
|
||||
th->start();
|
||||
// wait a few ms before popping up a progress bar
|
||||
th->wait(500);
|
||||
if(th->isRunning())
|
||||
{
|
||||
RDDialog::critical(
|
||||
this, tr("Error kicking capture"),
|
||||
tr("Error launching %1 for capture.\n\nCheck diagnostic log in Help menu for more details.")
|
||||
.arg(exe));
|
||||
return NULL;
|
||||
ShowProgressDialog(this, tr("Launching %1, please wait...").arg(exe),
|
||||
[th]() { return !th->isRunning(); });
|
||||
}
|
||||
|
||||
LiveCapture *live = new LiveCapture(
|
||||
m_Ctx, m_Ctx.Renderer().remote() ? m_Ctx.Renderer().remote()->Hostname : "", ret, this, this);
|
||||
ShowLiveCapture(live);
|
||||
return live;
|
||||
th->deleteLater();
|
||||
}
|
||||
|
||||
LiveCapture *MainWindow::OnInjectTrigger(uint32_t PID, const QList<EnvironmentModification> &env,
|
||||
const QString &name, CaptureOptions opts)
|
||||
void MainWindow::OnInjectTrigger(uint32_t PID, const QList<EnvironmentModification> &env,
|
||||
const QString &name, CaptureOptions opts,
|
||||
std::function<void(LiveCapture *)> callback)
|
||||
{
|
||||
if(!PromptCloseLog())
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
QString logfile = m_Ctx.TempLogFilename(name);
|
||||
LambdaThread *th = new LambdaThread([this, PID, env, name, opts, callback]() {
|
||||
QString logfile = m_Ctx.TempLogFilename(name);
|
||||
|
||||
void *envList = RENDERDOC_MakeEnvironmentModificationList(env.size());
|
||||
void *envList = RENDERDOC_MakeEnvironmentModificationList(env.size());
|
||||
|
||||
for(int i = 0; i < env.size(); i++)
|
||||
RENDERDOC_SetEnvironmentModification(envList, i, env[i].variable.toUtf8().data(),
|
||||
env[i].value.toUtf8().data(), env[i].type, env[i].separator);
|
||||
for(int i = 0; i < env.size(); i++)
|
||||
RENDERDOC_SetEnvironmentModification(envList, i, env[i].variable.toUtf8().data(),
|
||||
env[i].value.toUtf8().data(), env[i].type,
|
||||
env[i].separator);
|
||||
|
||||
uint32_t ret = RENDERDOC_InjectIntoProcess(PID, envList, logfile.toUtf8().data(), &opts, false);
|
||||
uint32_t ret = RENDERDOC_InjectIntoProcess(PID, envList, logfile.toUtf8().data(), &opts, false);
|
||||
|
||||
RENDERDOC_FreeEnvironmentModificationList(envList);
|
||||
RENDERDOC_FreeEnvironmentModificationList(envList);
|
||||
|
||||
if(ret == 0)
|
||||
GUIInvoke::call([this, PID, ret, callback]() {
|
||||
if(ret == 0)
|
||||
{
|
||||
RDDialog::critical(
|
||||
this, tr("Error kicking capture"),
|
||||
tr("Error injecting into process %1 for capture.\n\nCheck diagnostic log in "
|
||||
"Help menu for more details.")
|
||||
.arg(PID));
|
||||
return;
|
||||
}
|
||||
|
||||
LiveCapture *live = new LiveCapture(m_Ctx, "", ret, this, this);
|
||||
ShowLiveCapture(live);
|
||||
});
|
||||
});
|
||||
th->start();
|
||||
// wait a few ms before popping up a progress bar
|
||||
th->wait(500);
|
||||
if(th->isRunning())
|
||||
{
|
||||
RDDialog::critical(this, tr("Error kicking capture"),
|
||||
tr("Error injecting into process %1 for capture.\n\nCheck diagnostic log in "
|
||||
"Help menu for more details.")
|
||||
.arg(PID));
|
||||
return NULL;
|
||||
ShowProgressDialog(this, tr("Injecting into %1, please wait...").arg(PID),
|
||||
[th]() { return !th->isRunning(); });
|
||||
}
|
||||
|
||||
LiveCapture *live = new LiveCapture(m_Ctx, "", ret, this, this);
|
||||
ShowLiveCapture(live);
|
||||
return live;
|
||||
th->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::LoadLogfile(const QString &filename, bool temporary, bool local)
|
||||
|
||||
@@ -63,10 +63,11 @@ public:
|
||||
void CloseLogfile();
|
||||
QString GetSavePath();
|
||||
|
||||
LiveCapture *OnCaptureTrigger(const QString &exe, const QString &workingDir, const QString &cmdLine,
|
||||
const QList<EnvironmentModification> &env, CaptureOptions opts);
|
||||
LiveCapture *OnInjectTrigger(uint32_t PID, const QList<EnvironmentModification> &env,
|
||||
const QString &name, CaptureOptions opts);
|
||||
void OnCaptureTrigger(const QString &exe, const QString &workingDir, const QString &cmdLine,
|
||||
const QList<EnvironmentModification> &env, CaptureOptions opts,
|
||||
std::function<void(LiveCapture *)> callback);
|
||||
void OnInjectTrigger(uint32_t PID, const QList<EnvironmentModification> &env, const QString &name,
|
||||
CaptureOptions opts, std::function<void(LiveCapture *)> callback);
|
||||
|
||||
void PopulateRecentFiles();
|
||||
|
||||
|
||||
@@ -259,8 +259,10 @@ namespace renderdocui.Windows.Dialogs
|
||||
|
||||
#region Callbacks
|
||||
|
||||
public delegate LiveCapture OnCaptureMethod(string exe, string workingDir, string cmdLine, EnvironmentModification[] env, CaptureOptions opts);
|
||||
public delegate LiveCapture OnInjectMethod(UInt32 PID, EnvironmentModification[] env, string name, CaptureOptions opts);
|
||||
public delegate void OnConnectionEstablishedMethod(LiveCapture live);
|
||||
|
||||
public delegate void OnCaptureMethod(string exe, string workingDir, string cmdLine, EnvironmentModification[] env, CaptureOptions opts, OnConnectionEstablishedMethod cb);
|
||||
public delegate void OnInjectMethod(UInt32 PID, EnvironmentModification[] env, string name, CaptureOptions opts, OnConnectionEstablishedMethod cb);
|
||||
|
||||
private OnCaptureMethod m_CaptureCallback = null;
|
||||
private OnInjectMethod m_InjectCallback = null;
|
||||
@@ -430,10 +432,11 @@ namespace renderdocui.Windows.Dialogs
|
||||
|
||||
string cmdLine = cmdline.Text;
|
||||
|
||||
var live = m_CaptureCallback(exe, workingDir, cmdLine, GetSettings().Environment, GetSettings().Options);
|
||||
|
||||
if (queueFrameCap.Checked && live != null)
|
||||
live.QueueCapture((int)queuedCapFrame.Value);
|
||||
m_CaptureCallback(exe, workingDir, cmdLine, GetSettings().Environment, GetSettings().Options, (LiveCapture live) =>
|
||||
{
|
||||
if (queueFrameCap.Checked)
|
||||
live.QueueCapture((int)queuedCapFrame.Value);
|
||||
});
|
||||
}
|
||||
|
||||
private void OnInject()
|
||||
@@ -445,10 +448,11 @@ namespace renderdocui.Windows.Dialogs
|
||||
string name = item.SubItems[1].Text;
|
||||
UInt32 PID = (UInt32)item.Tag;
|
||||
|
||||
var live = m_InjectCallback(PID, GetSettings().Environment, name, GetSettings().Options);
|
||||
|
||||
if (queueFrameCap.Checked && live != null)
|
||||
live.QueueCapture((int)queuedCapFrame.Value);
|
||||
m_InjectCallback(PID, GetSettings().Environment, name, GetSettings().Options, (LiveCapture live) =>
|
||||
{
|
||||
if (queueFrameCap.Checked)
|
||||
live.QueueCapture((int)queuedCapFrame.Value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1019,48 +1019,90 @@ namespace renderdocui.Windows
|
||||
return "";
|
||||
}
|
||||
|
||||
private LiveCapture OnCaptureTrigger(string exe, string workingDir, string cmdLine, EnvironmentModification[] env, CaptureOptions opts)
|
||||
private void OnCaptureTrigger(string exe, string workingDir, string cmdLine, EnvironmentModification[] env, CaptureOptions opts, Dialogs.CaptureDialog.OnConnectionEstablishedMethod callback)
|
||||
{
|
||||
if (!PromptCloseLog())
|
||||
return null;
|
||||
return;
|
||||
|
||||
string logfile = m_Core.TempLogFilename(Path.GetFileNameWithoutExtension(exe));
|
||||
|
||||
StaticExports.SetConfigSetting("MaxConnectTimeout", m_Core.Config.MaxConnectTimeout.ToString());
|
||||
|
||||
UInt32 ret = m_Core.Renderer.ExecuteAndInject(exe, workingDir, cmdLine, env, logfile, opts);
|
||||
|
||||
if (ret == 0)
|
||||
Thread th = Helpers.NewThread(new ThreadStart(() =>
|
||||
{
|
||||
MessageBox.Show(string.Format("Error launching {0} for capture.\n\nCheck diagnostic log in Help menu for more details.", exe),
|
||||
"Error kicking capture", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return null;
|
||||
}
|
||||
UInt32 ret = m_Core.Renderer.ExecuteAndInject(exe, workingDir, cmdLine, env, logfile, opts);
|
||||
|
||||
var live = new LiveCapture(m_Core, m_Core.Renderer.Remote == null ? "" : m_Core.Renderer.Remote.Hostname, ret, this);
|
||||
ShowLiveCapture(live);
|
||||
return live;
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (ret == 0)
|
||||
{
|
||||
MessageBox.Show(string.Format("Error launching {0} for capture.\n\nCheck diagnostic log in Help menu for more details.", exe),
|
||||
"Error kicking capture", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var live = new LiveCapture(m_Core, m_Core.Renderer.Remote == null ? "" : m_Core.Renderer.Remote.Hostname, ret, this);
|
||||
ShowLiveCapture(live);
|
||||
callback(live);
|
||||
}));
|
||||
}));
|
||||
th.Start();
|
||||
|
||||
// wait a few ms before popping up a progress bar
|
||||
th.Join(500);
|
||||
|
||||
if (th.IsAlive)
|
||||
{
|
||||
ProgressPopup modal = new ProgressPopup((ModalCloseCallback)delegate
|
||||
{
|
||||
return !th.IsAlive;
|
||||
}, false);
|
||||
modal.SetModalText(String.Format("Launching {0}, please wait...", exe));
|
||||
|
||||
modal.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private LiveCapture OnInjectTrigger(UInt32 PID, EnvironmentModification[] env, string name, CaptureOptions opts)
|
||||
private void OnInjectTrigger(UInt32 PID, EnvironmentModification[] env, string name, CaptureOptions opts, Dialogs.CaptureDialog.OnConnectionEstablishedMethod callback)
|
||||
{
|
||||
if (!PromptCloseLog())
|
||||
return null;
|
||||
return;
|
||||
|
||||
string logfile = m_Core.TempLogFilename(name);
|
||||
|
||||
UInt32 ret = StaticExports.InjectIntoProcess(PID, env, logfile, opts);
|
||||
|
||||
if (ret == 0)
|
||||
Thread th = Helpers.NewThread(new ThreadStart(() =>
|
||||
{
|
||||
MessageBox.Show(string.Format("Error injecting into process {0} for capture.\n\nCheck diagnostic log in Help menu for more details.", PID),
|
||||
"Error kicking capture", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return null;
|
||||
}
|
||||
UInt32 ret = StaticExports.InjectIntoProcess(PID, env, logfile, opts);
|
||||
|
||||
var live = new LiveCapture(m_Core, "", ret, this);
|
||||
ShowLiveCapture(live);
|
||||
return live;
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (ret == 0)
|
||||
{
|
||||
MessageBox.Show(string.Format("Error injecting into process {0} for capture.\n\nCheck diagnostic log in Help menu for more details.", PID),
|
||||
"Error kicking capture", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var live = new LiveCapture(m_Core, m_Core.Renderer.Remote == null ? "" : m_Core.Renderer.Remote.Hostname, ret, this);
|
||||
ShowLiveCapture(live);
|
||||
callback(live);
|
||||
}));
|
||||
}));
|
||||
th.Start();
|
||||
|
||||
// wait a few ms before popping up a progress bar
|
||||
th.Join(500);
|
||||
|
||||
if (th.IsAlive)
|
||||
{
|
||||
ProgressPopup modal = new ProgressPopup((ModalCloseCallback)delegate
|
||||
{
|
||||
return !th.IsAlive;
|
||||
}, false);
|
||||
modal.SetModalText(String.Format("Injecting into {0}, please wait...", PID));
|
||||
|
||||
modal.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void captureLogToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user