mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
GUIInvoke takes a QObject* to avoid callbacks after object lifetime
* The GUIInvoke object takes a QObject, and uses QPointer to check that it hasn't been deleted when the callback fires. This prevents delayed callbacks from executing after the object has been deleted and crashing. * In most cases the pointer is just 'this'.
This commit is contained in:
@@ -193,7 +193,7 @@ void CaptureContext::LoadCapture(const rdcstr &captureFile, const rdcstr &origFi
|
||||
else if(!m_Drawcalls.empty())
|
||||
SetEventID(viewers, m_Drawcalls.back().eventId, true);
|
||||
|
||||
GUIInvoke::blockcall([&viewers]() {
|
||||
GUIInvoke::blockcall(m_MainWindow, [&viewers]() {
|
||||
// notify all the registers viewers that a capture has been loaded
|
||||
for(ICaptureViewer *viewer : viewers)
|
||||
{
|
||||
@@ -1062,7 +1062,7 @@ void CaptureContext::AddMessages(const rdcarray<DebugMessage> &msgs)
|
||||
|
||||
if(m_DebugMessageView)
|
||||
{
|
||||
GUIInvoke::call([this]() { m_DebugMessageView->RefreshMessageList(); });
|
||||
GUIInvoke::call(m_DebugMessageView, [this]() { m_DebugMessageView->RefreshMessageList(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ rdcstr SPIRVDisassembler::DisassembleShader(QWidget *window, const ShaderReflect
|
||||
|
||||
if(process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0)
|
||||
{
|
||||
GUIInvoke::call([window]() {
|
||||
GUIInvoke::call(window, [window]() {
|
||||
RDDialog::critical(
|
||||
window, QApplication::translate("SPIRVDisassembler", "Error running disassembler"),
|
||||
QApplication::translate(
|
||||
|
||||
@@ -808,37 +808,39 @@ int GUIInvoke::methodIndex = -1;
|
||||
|
||||
void GUIInvoke::init()
|
||||
{
|
||||
GUIInvoke *invoke = new GUIInvoke();
|
||||
GUIInvoke *invoke = new GUIInvoke(NULL, {});
|
||||
methodIndex = invoke->metaObject()->indexOfMethod(QMetaObject::normalizedSignature("doInvoke()"));
|
||||
}
|
||||
|
||||
void GUIInvoke::call(const std::function<void()> &f)
|
||||
void GUIInvoke::call(QObject *obj, const std::function<void()> &f)
|
||||
{
|
||||
if(onUIThread())
|
||||
{
|
||||
f();
|
||||
if(obj)
|
||||
f();
|
||||
return;
|
||||
}
|
||||
|
||||
defer(f);
|
||||
defer(obj, f);
|
||||
}
|
||||
|
||||
void GUIInvoke::defer(const std::function<void()> &f)
|
||||
void GUIInvoke::defer(QObject *obj, const std::function<void()> &f)
|
||||
{
|
||||
GUIInvoke *invoke = new GUIInvoke(f);
|
||||
GUIInvoke *invoke = new GUIInvoke(obj, f);
|
||||
invoke->moveToThread(qApp->thread());
|
||||
invoke->metaObject()->method(methodIndex).invoke(invoke, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void GUIInvoke::blockcall(const std::function<void()> &f)
|
||||
void GUIInvoke::blockcall(QObject *obj, const std::function<void()> &f)
|
||||
{
|
||||
if(onUIThread())
|
||||
{
|
||||
f();
|
||||
if(obj)
|
||||
f();
|
||||
return;
|
||||
}
|
||||
|
||||
GUIInvoke *invoke = new GUIInvoke(f);
|
||||
GUIInvoke *invoke = new GUIInvoke(obj, f);
|
||||
invoke->moveToThread(qApp->thread());
|
||||
invoke->metaObject()->method(methodIndex).invoke(invoke, Qt::BlockingQueuedConnection);
|
||||
}
|
||||
@@ -906,7 +908,7 @@ QMessageBox::StandardButton RDDialog::messageBox(QMessageBox::Icon icon, QWidget
|
||||
QMessageBox::StandardButton ret = defaultButton;
|
||||
|
||||
// if we're already on the right thread, this boils down to a function call
|
||||
GUIInvoke::blockcall([&]() {
|
||||
GUIInvoke::blockcall(parent, [&]() {
|
||||
QMessageBox mb(icon, title, text, buttons, parent);
|
||||
mb.setDefaultButton(defaultButton);
|
||||
show(&mb);
|
||||
@@ -924,7 +926,7 @@ QMessageBox::StandardButton RDDialog::messageBoxChecked(QMessageBox::Icon icon,
|
||||
QMessageBox::StandardButton ret = defaultButton;
|
||||
|
||||
// if we're already on the right thread, this boils down to a function call
|
||||
GUIInvoke::blockcall([&]() {
|
||||
GUIInvoke::blockcall(parent, [&]() {
|
||||
QMessageBox mb(icon, title, text, buttons, parent);
|
||||
mb.setDefaultButton(defaultButton);
|
||||
mb.setCheckBox(checkBox);
|
||||
@@ -1321,7 +1323,7 @@ bool IsRunningAsAdmin()
|
||||
}
|
||||
|
||||
bool RunProcessAsAdmin(const QString &fullExecutablePath, const QStringList ¶ms,
|
||||
std::function<void()> finishedCallback)
|
||||
QWidget *parent, std::function<void()> finishedCallback)
|
||||
{
|
||||
#if defined(Q_OS_WIN32)
|
||||
|
||||
@@ -1352,10 +1354,10 @@ bool RunProcessAsAdmin(const QString &fullExecutablePath, const QStringList &par
|
||||
HANDLE h = info.hProcess;
|
||||
|
||||
// do the wait on another thread
|
||||
LambdaThread *thread = new LambdaThread([h, finishedCallback]() {
|
||||
LambdaThread *thread = new LambdaThread([h, parent, finishedCallback]() {
|
||||
WaitForSingleObject(h, 30000);
|
||||
CloseHandle(h);
|
||||
GUIInvoke::call(finishedCallback);
|
||||
GUIInvoke::call(parent, finishedCallback);
|
||||
});
|
||||
thread->selfDelete(true);
|
||||
thread->start();
|
||||
@@ -1582,15 +1584,15 @@ void ShowProgressDialog(QWidget *window, const QString &labelText, ProgressFinis
|
||||
QThread::msleep(30);
|
||||
|
||||
if(update)
|
||||
GUIInvoke::call([update, &dialog]() { dialog.setPercentage(update()); });
|
||||
GUIInvoke::call(&dialog, [update, &dialog]() { dialog.setPercentage(update()); });
|
||||
|
||||
GUIInvoke::call([finished, &tickerSemaphore]() {
|
||||
GUIInvoke::call(&dialog, [finished, &tickerSemaphore]() {
|
||||
if(finished())
|
||||
tickerSemaphore.tryAcquire();
|
||||
});
|
||||
}
|
||||
|
||||
GUIInvoke::call([&dialog]() { dialog.closeAndReset(); });
|
||||
GUIInvoke::call(&dialog, [&dialog]() { dialog.closeAndReset(); });
|
||||
});
|
||||
progressTickerThread.start();
|
||||
|
||||
|
||||
@@ -228,29 +228,32 @@ struct OverloadedSlot
|
||||
// wise not to require a higher version that necessary.
|
||||
#include <functional>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
class GUIInvoke : public QObject
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
GUIInvoke(const std::function<void()> &f) : func(f) {}
|
||||
GUIInvoke() {}
|
||||
GUIInvoke(QObject *obj, const std::function<void()> &f) : ptr(obj), func(f) {}
|
||||
QPointer<QObject> ptr;
|
||||
std::function<void()> func;
|
||||
|
||||
static int methodIndex;
|
||||
|
||||
public:
|
||||
static void init();
|
||||
static void call(const std::function<void()> &f);
|
||||
static void blockcall(const std::function<void()> &f);
|
||||
static void call(QObject *obj, const std::function<void()> &f);
|
||||
static void blockcall(QObject *obj, const std::function<void()> &f);
|
||||
static bool onUIThread();
|
||||
|
||||
// same as call() above, but it doesn't check for an instant call on the UI thread
|
||||
static void defer(const std::function<void()> &f);
|
||||
static void defer(QObject *obj, const std::function<void()> &f);
|
||||
|
||||
protected slots:
|
||||
void doInvoke()
|
||||
{
|
||||
func();
|
||||
if(ptr)
|
||||
func();
|
||||
deleteLater();
|
||||
}
|
||||
};
|
||||
@@ -526,6 +529,7 @@ typedef std::function<bool()> ProgressFinishedMethod;
|
||||
QStringList ParseArgsList(const QString &args);
|
||||
bool IsRunningAsAdmin();
|
||||
bool RunProcessAsAdmin(const QString &fullExecutablePath, const QStringList ¶ms,
|
||||
QWidget *parent = NULL,
|
||||
std::function<void()> finishedCallback = std::function<void()>());
|
||||
|
||||
void RevealFilenameInExternalFileBrowser(const QString &filePath);
|
||||
|
||||
@@ -805,7 +805,7 @@ void PythonContext::outstream_del(PyObject *self)
|
||||
PythonContext *context = redirector->context;
|
||||
|
||||
// delete the context on the UI thread.
|
||||
GUIInvoke::call([context]() { delete context; });
|
||||
GUIInvoke::call(context, [context]() { delete context; });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -483,13 +483,10 @@ void RDHeaderView::setRootIndex(const QModelIndex &index)
|
||||
// *before* the root index changes).
|
||||
if(!m_sectionStretchHints.isEmpty())
|
||||
{
|
||||
QPointer<RDHeaderView> ptr;
|
||||
GUIInvoke::defer([ptr]() {
|
||||
if(ptr)
|
||||
{
|
||||
ptr->cacheSectionMinSizes();
|
||||
ptr->resizeSectionsWithHints();
|
||||
}
|
||||
QPointer<RDHeaderView> ptr = this;
|
||||
GUIInvoke::defer(this, [this]() {
|
||||
cacheSectionMinSizes();
|
||||
resizeSectionsWithHints();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ void APIInspector::on_apiEvents_itemSelectionChanged()
|
||||
m_Ctx.Replay().AsyncInvoke([this, ev](IReplayController *) {
|
||||
rdcarray<rdcstr> stack = m_Ctx.Replay().GetCaptureAccess()->GetResolve(ev.callstack);
|
||||
|
||||
GUIInvoke::call([this, stack]() { addCallstack(stack); });
|
||||
GUIInvoke::call(this, [this, stack]() { addCallstack(stack); });
|
||||
});
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1511,7 +1511,7 @@ void BufferViewer::OnEventChanged(uint32_t eventId)
|
||||
buf->end = buf->data + data.size();
|
||||
}
|
||||
|
||||
GUIInvoke::call([this, buf, vsinHoriz, vsoutHoriz, gsoutHoriz] {
|
||||
GUIInvoke::call(this, [this, buf, vsinHoriz, vsoutHoriz, gsoutHoriz] {
|
||||
|
||||
if(buf)
|
||||
{
|
||||
@@ -1850,7 +1850,7 @@ void BufferViewer::RT_FetchMeshData(IReplayController *r)
|
||||
LambdaThread *thread = new LambdaThread([this, bbox] {
|
||||
calcBoundingData(*bbox);
|
||||
|
||||
GUIInvoke::call([this, bbox]() { updateBoundingBox(*bbox); });
|
||||
GUIInvoke::call(this, [this, bbox]() { updateBoundingBox(*bbox); });
|
||||
});
|
||||
thread->selfDelete(true);
|
||||
thread->start();
|
||||
@@ -2002,7 +2002,7 @@ void BufferViewer::resetArcball()
|
||||
|
||||
m_Arcball->Reset(mid, len * 0.7f);
|
||||
|
||||
GUIInvoke::call([this, len]() { ui->camSpeed->setValue(len / 200.0f); });
|
||||
GUIInvoke::call(this, [this, len]() { ui->camSpeed->setValue(len / 200.0f); });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2661,7 +2661,7 @@ void BufferViewer::render_clicked(QMouseEvent *e)
|
||||
|
||||
if(vertSelected != ~0U)
|
||||
{
|
||||
GUIInvoke::call([this, vertSelected, instanceSelected] {
|
||||
GUIInvoke::call(this, [this, vertSelected, instanceSelected] {
|
||||
int row = (int)vertSelected;
|
||||
|
||||
if(instanceSelected != m_Config.curInstance)
|
||||
@@ -2784,7 +2784,7 @@ void BufferViewer::RT_UpdateAndDisplay(IReplayController *)
|
||||
m_Output->SetMeshDisplay(m_Config);
|
||||
}
|
||||
|
||||
GUIInvoke::call([this]() { ui->render->update(); });
|
||||
GUIInvoke::call(this, [this]() { ui->render->update(); });
|
||||
}
|
||||
|
||||
RDTableView *BufferViewer::tableForStage(MeshDataStage stage)
|
||||
@@ -3297,7 +3297,7 @@ void BufferViewer::debugVertex()
|
||||
|
||||
if(!idx.isValid())
|
||||
{
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
RDDialog::critical(this, tr("Error debugging"),
|
||||
tr("Error debugging vertex - make sure a valid vertex is selected"));
|
||||
});
|
||||
@@ -3318,14 +3318,14 @@ void BufferViewer::debugVertex()
|
||||
{
|
||||
r->FreeTrace(trace);
|
||||
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
RDDialog::critical(this, tr("Error debugging"),
|
||||
tr("Error debugging vertex - make sure a valid vertex is selected"));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
GUIInvoke::call([this, vertid, trace]() {
|
||||
GUIInvoke::call(this, [this, vertid, trace]() {
|
||||
QString debugContext = tr("Vertex %1").arg(vertid);
|
||||
|
||||
if(m_Ctx.CurDrawcall()->numInstances > 1)
|
||||
|
||||
@@ -120,7 +120,7 @@ void ConstantBufferPreviewer::OnEventChanged(uint32_t eventId)
|
||||
m_Ctx.Replay().AsyncInvoke([this, offs, size, wasEmpty](IReplayController *r) {
|
||||
bytebuf data = r->GetBufferData(m_cbuffer, offs, size);
|
||||
rdcarray<ShaderVariable> vars = applyFormatOverride(data);
|
||||
GUIInvoke::call([this, vars, wasEmpty] {
|
||||
GUIInvoke::call(this, [this, vars, wasEmpty] {
|
||||
setVariables(vars);
|
||||
if(wasEmpty)
|
||||
{
|
||||
@@ -135,7 +135,7 @@ void ConstantBufferPreviewer::OnEventChanged(uint32_t eventId)
|
||||
m_Ctx.Replay().AsyncInvoke([this, entryPoint, offs, wasEmpty](IReplayController *r) {
|
||||
rdcarray<ShaderVariable> vars = r->GetCBufferVariableContents(
|
||||
m_shader, entryPoint.toUtf8().data(), m_slot, m_cbuffer, offs);
|
||||
GUIInvoke::call([this, vars, wasEmpty] {
|
||||
GUIInvoke::call(this, [this, vars, wasEmpty] {
|
||||
setVariables(vars);
|
||||
if(wasEmpty)
|
||||
{
|
||||
|
||||
@@ -402,7 +402,7 @@ void CaptureDialog::vulkanLayerWarn_mouseClick()
|
||||
if(admin)
|
||||
{
|
||||
RunProcessAsAdmin(qApp->applicationFilePath(),
|
||||
QStringList() << lit("--install_vulkan_layer") << lit("root"),
|
||||
QStringList() << lit("--install_vulkan_layer") << lit("root"), this,
|
||||
[this]() { ui->vulkanLayerWarn->setVisible(false); });
|
||||
return;
|
||||
}
|
||||
@@ -435,7 +435,7 @@ void CaptureDialog::CheckAndroidSetup(QString &filename)
|
||||
if(!debuggable && !hasroot)
|
||||
{
|
||||
// Check failed - set the warning visible
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
ui->androidScan->setVisible(false);
|
||||
ui->androidWarn->setVisible(true);
|
||||
});
|
||||
@@ -443,7 +443,7 @@ void CaptureDialog::CheckAndroidSetup(QString &filename)
|
||||
else
|
||||
{
|
||||
// Check passed, either app is debuggable or we have root - no warnings needed
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
ui->androidScan->setVisible(false);
|
||||
ui->androidWarn->setVisible(false);
|
||||
});
|
||||
|
||||
@@ -1078,7 +1078,7 @@ void LiveCapture::connectionThreadEntry()
|
||||
|
||||
if(!m_Connection || !m_Connection->Connected())
|
||||
{
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
setTitle(tr("Connection failed"));
|
||||
ui->connectionStatus->setText(tr("Failed"));
|
||||
ui->connectionIcon->setPixmap(Pixmaps::del(ui->connectionIcon));
|
||||
@@ -1089,7 +1089,7 @@ void LiveCapture::connectionThreadEntry()
|
||||
return;
|
||||
}
|
||||
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
uint32_t pid = m_Connection->GetPID();
|
||||
QString target = QString::fromUtf8(m_Connection->GetTarget());
|
||||
if(pid)
|
||||
@@ -1149,7 +1149,7 @@ void LiveCapture::connectionThreadEntry()
|
||||
QString api = msg.apiUse.name;
|
||||
bool presenting = msg.apiUse.presenting;
|
||||
bool supported = msg.apiUse.supported;
|
||||
GUIInvoke::call([this, api, presenting, supported]() {
|
||||
GUIInvoke::call(this, [this, api, presenting, supported]() {
|
||||
m_APIs[api] = APIStatus(presenting, supported);
|
||||
|
||||
if(presenting && supported)
|
||||
@@ -1165,7 +1165,7 @@ void LiveCapture::connectionThreadEntry()
|
||||
if(msg.type == TargetControlMessageType::CaptureProgress)
|
||||
{
|
||||
float progress = msg.capProgress;
|
||||
GUIInvoke::call([this, progress]() {
|
||||
GUIInvoke::call(this, [this, progress]() {
|
||||
|
||||
if(progress >= 0.0f && progress < 1.0f)
|
||||
{
|
||||
@@ -1194,7 +1194,7 @@ void LiveCapture::connectionThreadEntry()
|
||||
QString path = msg.newCapture.path;
|
||||
bool local = msg.newCapture.local;
|
||||
|
||||
GUIInvoke::call([this, capID, timestamp, thumb, thumbWidth, thumbHeight, path, local]() {
|
||||
GUIInvoke::call(this, [this, capID, timestamp, thumb, thumbWidth, thumbHeight, path, local]() {
|
||||
QString target = QString::fromUtf8(m_Connection->GetTarget());
|
||||
QString api = QString::fromUtf8(m_Connection->GetAPI());
|
||||
|
||||
@@ -1207,7 +1207,7 @@ void LiveCapture::connectionThreadEntry()
|
||||
uint32_t capID = msg.newCapture.captureId;
|
||||
QString path = msg.newCapture.path;
|
||||
|
||||
GUIInvoke::call([this, capID, path]() { captureCopied(capID, path); });
|
||||
GUIInvoke::call(this, [this, capID, path]() { captureCopied(capID, path); });
|
||||
}
|
||||
|
||||
if(msg.type == TargetControlMessageType::NewChild)
|
||||
@@ -1226,7 +1226,7 @@ void LiveCapture::connectionThreadEntry()
|
||||
}
|
||||
}
|
||||
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
ui->connectionStatus->setText(tr("Closed"));
|
||||
ui->connectionIcon->setPixmap(Pixmaps::disconnect(ui->connectionIcon));
|
||||
|
||||
|
||||
@@ -241,14 +241,14 @@ PerformanceCounterSelection::PerformanceCounterSelection(ICaptureContext &ctx,
|
||||
|
||||
ui->counterTree->setMouseTracking(true);
|
||||
|
||||
ctx.Replay().AsyncInvoke([this, selectedCounters](IReplayController *controller) -> void {
|
||||
ctx.Replay().AsyncInvoke([this, selectedCounters](IReplayController *controller) {
|
||||
QVector<CounterDescription> counterDescriptions;
|
||||
for(const GPUCounter counter : controller->EnumerateCounters())
|
||||
{
|
||||
counterDescriptions.append(controller->DescribeCounter(counter));
|
||||
}
|
||||
|
||||
GUIInvoke::call([counterDescriptions, selectedCounters, this]() -> void {
|
||||
GUIInvoke::call(this, [counterDescriptions, selectedCounters, this]() {
|
||||
SetCounters(counterDescriptions);
|
||||
SetSelectedCounters(selectedCounters);
|
||||
});
|
||||
|
||||
@@ -233,7 +233,7 @@ void RemoteManager::refreshHost(RDTreeWidgetItem *node)
|
||||
host->CheckStatus();
|
||||
|
||||
GUIInvoke::call(
|
||||
[this, node, host]() { setRemoteServerLive(node, host->serverRunning, host->busy); });
|
||||
this, [this, node, host]() { setRemoteServerLive(node, host->serverRunning, host->busy); });
|
||||
|
||||
uint32_t nextIdent = 0;
|
||||
|
||||
@@ -265,7 +265,7 @@ void RemoteManager::refreshHost(RDTreeWidgetItem *node)
|
||||
|
||||
RemoteConnect tag(host->hostname, host->Name(), nextIdent);
|
||||
|
||||
GUIInvoke::call([this, node, target, running, tag]() {
|
||||
GUIInvoke::call(this, [this, node, target, running, tag]() {
|
||||
RDTreeWidgetItem *child = new RDTreeWidgetItem({target, running});
|
||||
setRemoteConnect(child, tag);
|
||||
node->addChild(child);
|
||||
@@ -276,11 +276,11 @@ void RemoteManager::refreshHost(RDTreeWidgetItem *node)
|
||||
}
|
||||
}
|
||||
|
||||
GUIInvoke::call([node]() { node->setItalic(false); });
|
||||
GUIInvoke::call(this, [node]() { node->setItalic(false); });
|
||||
|
||||
m_Lookups.acquire();
|
||||
|
||||
GUIInvoke::call([this]() { updateStatus(); });
|
||||
GUIInvoke::call(this, [this]() { updateStatus(); });
|
||||
});
|
||||
th->selfDelete(true);
|
||||
th->start();
|
||||
|
||||
@@ -436,7 +436,7 @@ void EventBrowser::on_timeDraws_clicked()
|
||||
|
||||
m_Times = r->FetchCounters({GPUCounter::EventGPUDuration});
|
||||
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
SetDrawcallTimes(ui->events->topLevelItem(0), m_Times);
|
||||
ui->events->update();
|
||||
});
|
||||
|
||||
@@ -230,7 +230,7 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
|
||||
if(diff > 2 * 24 * 60 * 60)
|
||||
{
|
||||
// update the check date on the stored bug
|
||||
GUIInvoke::call([this, b, now]() {
|
||||
GUIInvoke::call(this, [this, b, now]() {
|
||||
for(BugReport &bug : m_Ctx.Config().CrashReport_ReportedBugs)
|
||||
{
|
||||
if(bug.reportId == b.reportId)
|
||||
@@ -510,7 +510,7 @@ void MainWindow::OnCaptureTrigger(const QString &exe, const QString &workingDir,
|
||||
ExecuteResult ret =
|
||||
m_Ctx.Replay().ExecuteAndInject(exe, workingDir, cmdLine, env, capturefile, opts);
|
||||
|
||||
GUIInvoke::call([this, exe, ret, callback]() {
|
||||
GUIInvoke::call(this, [this, exe, ret, callback]() {
|
||||
|
||||
if(ret.status == ReplayStatus::JDWPFailure)
|
||||
{
|
||||
@@ -568,7 +568,7 @@ void MainWindow::OnInjectTrigger(uint32_t PID, const rdcarray<EnvironmentModific
|
||||
ExecuteResult ret =
|
||||
RENDERDOC_InjectIntoProcess(PID, env, capturefile.toUtf8().data(), opts, false);
|
||||
|
||||
GUIInvoke::call([this, PID, ret, callback]() {
|
||||
GUIInvoke::call(this, [this, PID, ret, callback]() {
|
||||
|
||||
if(ret.status == ReplayStatus::JDWPFailure)
|
||||
{
|
||||
@@ -1513,7 +1513,7 @@ void MainWindow::remoteProbe()
|
||||
{
|
||||
if(!m_Ctx.IsCaptureLoaded() && !m_Ctx.IsCaptureLoading())
|
||||
{
|
||||
GUIInvoke::call([this] { m_Ctx.Config().AddAndroidHosts(); });
|
||||
GUIInvoke::call(this, [this] { m_Ctx.Config().AddAndroidHosts(); });
|
||||
|
||||
for(RemoteHost *host : m_Ctx.Config().RemoteHosts)
|
||||
{
|
||||
@@ -1559,7 +1559,7 @@ void MainWindow::messageCheck()
|
||||
disconnected = true;
|
||||
}
|
||||
|
||||
GUIInvoke::call([this, disconnected, msgs] {
|
||||
GUIInvoke::call(this, [this, disconnected, msgs] {
|
||||
// if we just got disconnected while replaying a capture, alert the user.
|
||||
if(disconnected)
|
||||
{
|
||||
@@ -1592,7 +1592,7 @@ void MainWindow::messageCheck()
|
||||
if(m_Ctx.Replay().CurrentRemote())
|
||||
m_Ctx.Replay().PingRemote();
|
||||
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
if(m_Ctx.Replay().CurrentRemote() && !m_Ctx.Replay().CurrentRemote()->serverRunning)
|
||||
{
|
||||
contextChooser->setIcon(Icons::cross());
|
||||
@@ -1735,7 +1735,7 @@ void MainWindow::switchContext()
|
||||
|
||||
if(!host->serverRunning && !host->runCommand.isEmpty())
|
||||
{
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
statusText->setText(tr("Running remote server command..."));
|
||||
statusProgress->setVisible(true);
|
||||
statusProgress->setMaximum(0);
|
||||
@@ -1746,7 +1746,7 @@ void MainWindow::switchContext()
|
||||
// check if it's running now
|
||||
host->CheckStatus();
|
||||
|
||||
GUIInvoke::call([this]() { statusProgress->setVisible(false); });
|
||||
GUIInvoke::call(this, [this]() { statusProgress->setVisible(false); });
|
||||
}
|
||||
|
||||
ReplayStatus status = ReplayStatus::Succeeded;
|
||||
@@ -1756,7 +1756,7 @@ void MainWindow::switchContext()
|
||||
status = m_Ctx.Replay().ConnectToRemoteServer(host);
|
||||
}
|
||||
|
||||
GUIInvoke::call([this, host, status]() {
|
||||
GUIInvoke::call(this, [this, host, status]() {
|
||||
contextChooser->setIcon(host->serverRunning && !host->busy ? Icons::connect()
|
||||
: Icons::disconnect());
|
||||
|
||||
@@ -1834,7 +1834,7 @@ void MainWindow::OnCaptureLoaded()
|
||||
m_Ctx.Replay().AsyncInvoke([this](IReplayController *) {
|
||||
bool hasResolver = m_Ctx.Replay().GetCaptureAccess()->HasCallstacks();
|
||||
|
||||
GUIInvoke::call([this, hasResolver]() {
|
||||
GUIInvoke::call(this, [this, hasResolver]() {
|
||||
ui->action_Resolve_Symbols->setEnabled(hasResolver);
|
||||
ui->action_Resolve_Symbols->setText(hasResolver ? tr("Resolve Symbols")
|
||||
: tr("Resolve Symbols - None in capture"));
|
||||
@@ -2311,9 +2311,9 @@ void MainWindow::on_action_Create_RGP_Profile_triggered()
|
||||
|
||||
rdcstr path;
|
||||
|
||||
m_Ctx.Replay().AsyncInvoke([winData, &popup, &path](IReplayController *r) {
|
||||
m_Ctx.Replay().AsyncInvoke([this, winData, &popup, &path](IReplayController *r) {
|
||||
path = r->CreateRGPProfile(winData);
|
||||
GUIInvoke::call([&popup]() { popup.close(); });
|
||||
GUIInvoke::call(this, [&popup]() { popup.close(); });
|
||||
});
|
||||
|
||||
RDDialog::show(&popup);
|
||||
@@ -2571,7 +2571,7 @@ void MainWindow::dropEvent(QDropEvent *event)
|
||||
{
|
||||
// we defer this so we can return immediately and unblock whichever application dropped the
|
||||
// item.
|
||||
GUIInvoke::defer([this, fn]() { LoadFromFilename(fn, false); });
|
||||
GUIInvoke::defer(this, [this, fn]() { LoadFromFilename(fn, false); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ void PerformanceCounterViewer::CaptureCounters()
|
||||
|
||||
const rdcarray<CounterResult> results = controller->FetchCounters(counters);
|
||||
|
||||
GUIInvoke::call([this, results, counterDescriptions, counterIndex]() -> void {
|
||||
GUIInvoke::call(this, [this, results, counterDescriptions, counterIndex]() {
|
||||
ui->counterResults->clear();
|
||||
|
||||
QStringList headers;
|
||||
|
||||
@@ -3135,7 +3135,7 @@ void D3D11PipelineStateViewer::on_debugThread_clicked()
|
||||
{
|
||||
r->FreeTrace(trace);
|
||||
|
||||
GUIInvoke::call([this]() {
|
||||
GUIInvoke::call(this, [this]() {
|
||||
RDDialog::critical(
|
||||
this, tr("Error debugging"),
|
||||
tr("Error debugging thread - make sure a valid group and thread is selected"));
|
||||
@@ -3151,7 +3151,7 @@ void D3D11PipelineStateViewer::on_debugThread_clicked()
|
||||
.arg(thread.t[1])
|
||||
.arg(thread.t[2]);
|
||||
|
||||
GUIInvoke::call([this, debugContext, trace]() {
|
||||
GUIInvoke::call(this, [this, debugContext, trace]() {
|
||||
|
||||
const ShaderReflection *shaderDetails =
|
||||
m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Compute);
|
||||
|
||||
@@ -841,16 +841,16 @@ void PipelineStateViewer::EditShader(ShaderStage shaderType, ResourceId id,
|
||||
std::tie(to, errs) = r->BuildTargetShader(
|
||||
entryFunc.toUtf8().data(), compileSource.toUtf8().data(), flags, shaderType);
|
||||
|
||||
GUIInvoke::call([viewer, errs]() { viewer->ShowErrors(errs); });
|
||||
GUIInvoke::call(viewer->Widget(), [viewer, errs]() { viewer->ShowErrors(errs); });
|
||||
if(to == ResourceId())
|
||||
{
|
||||
r->RemoveReplacement(from);
|
||||
GUIInvoke::call([ctx]() { ctx->RefreshStatus(); });
|
||||
GUIInvoke::call(viewer->Widget(), [ctx]() { ctx->RefreshStatus(); });
|
||||
}
|
||||
else
|
||||
{
|
||||
r->ReplaceResource(from, to);
|
||||
GUIInvoke::call([ctx]() { ctx->RefreshStatus(); });
|
||||
GUIInvoke::call(viewer->Widget(), [ctx]() { ctx->RefreshStatus(); });
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -861,7 +861,7 @@ void PipelineStateViewer::EditShader(ShaderStage shaderType, ResourceId id,
|
||||
// was a place to control replaced resources/shaders).
|
||||
ctx->Replay().AsyncInvoke([ctx, id](IReplayController *r) {
|
||||
r->RemoveReplacement(id);
|
||||
GUIInvoke::call([ctx] { ctx->RefreshStatus(); });
|
||||
GUIInvoke::call(ctx->GetMainWindow()->Widget(), [ctx] { ctx->RefreshStatus(); });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2401,7 +2401,7 @@ void VulkanPipelineStateViewer::shaderEdit_clicked()
|
||||
m_Ctx.Replay().AsyncInvoke([this, stage, pipe, shaderDetails, entryFunc](IReplayController *r) {
|
||||
rdcstr disasm = r->DisassembleShader(pipe, shaderDetails, "");
|
||||
|
||||
GUIInvoke::call([this, stage, shaderDetails, entryFunc, disasm]() {
|
||||
GUIInvoke::call(this, [this, stage, shaderDetails, entryFunc, disasm]() {
|
||||
rdcstrpairs fileMap;
|
||||
fileMap.push_back(make_rdcpair<rdcstr, rdcstr>("generated.glsl", disasm));
|
||||
m_Common.EditShader(stage->stage, stage->resourceId, shaderDetails, entryFunc, fileMap);
|
||||
|
||||
@@ -694,7 +694,7 @@ void PixelHistoryView::startDebug(EventTag tag)
|
||||
return;
|
||||
}
|
||||
|
||||
GUIInvoke::call([this, trace]() {
|
||||
GUIInvoke::call(this, [this, trace]() {
|
||||
QString debugContext = QFormatStr("Pixel %1,%2").arg(m_Pixel.x()).arg(m_Pixel.y());
|
||||
|
||||
const ShaderReflection *shaderDetails =
|
||||
|
||||
@@ -39,8 +39,9 @@
|
||||
// on the python thread.
|
||||
struct CaptureContextInvoker : ICaptureContext
|
||||
{
|
||||
PythonShell *m_Shell;
|
||||
ICaptureContext &m_Ctx;
|
||||
CaptureContextInvoker(ICaptureContext &ctx) : m_Ctx(ctx) {}
|
||||
CaptureContextInvoker(PythonShell *shell, ICaptureContext &ctx) : m_Shell(shell), m_Ctx(ctx) {}
|
||||
virtual ~CaptureContextInvoker() {}
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@@ -140,7 +141,7 @@ struct CaptureContextInvoker : ICaptureContext
|
||||
{
|
||||
if(!GUIInvoke::onUIThread())
|
||||
{
|
||||
GUIInvoke::blockcall([this, ptr, params...]() { (m_Ctx.*ptr)(params...); });
|
||||
GUIInvoke::blockcall(m_Shell, [this, ptr, params...]() { (m_Ctx.*ptr)(params...); });
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -154,7 +155,8 @@ struct CaptureContextInvoker : ICaptureContext
|
||||
if(!GUIInvoke::onUIThread())
|
||||
{
|
||||
R ret;
|
||||
GUIInvoke::blockcall([this, &ret, ptr, params...]() { ret = (m_Ctx.*ptr)(params...); });
|
||||
GUIInvoke::blockcall(m_Shell,
|
||||
[this, &ret, ptr, params...]() { ret = (m_Ctx.*ptr)(params...); });
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -447,7 +449,7 @@ PythonShell::PythonShell(ICaptureContext &ctx, QWidget *parent)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_ThreadCtx = new CaptureContextInvoker(m_Ctx);
|
||||
m_ThreadCtx = new CaptureContextInvoker(this, m_Ctx);
|
||||
|
||||
QObject::connect(ui->lineInput, &RDLineEdit::keyPress, this, &PythonShell::interactive_keypress);
|
||||
QObject::connect(ui->helpSearch, &RDLineEdit::keyPress, this, &PythonShell::helpSearch_keypress);
|
||||
@@ -681,7 +683,7 @@ void PythonShell::on_runScript_clicked()
|
||||
context->executeString(lit("script.py"), script);
|
||||
scriptContext = NULL;
|
||||
|
||||
GUIInvoke::call([this, context]() {
|
||||
GUIInvoke::call(this, [this, context]() {
|
||||
context->Finish();
|
||||
enableButtons(true);
|
||||
});
|
||||
|
||||
@@ -218,7 +218,7 @@ void ResourceInspector::Inspect(ResourceId id)
|
||||
|
||||
rdcarray<ShaderEntryPoint> entries = r->GetShaderEntryPoints(id);
|
||||
|
||||
GUIInvoke::call([this, entries, usage] {
|
||||
GUIInvoke::call(this, [this, entries, usage] {
|
||||
|
||||
if(!entries.isEmpty())
|
||||
{
|
||||
@@ -450,13 +450,13 @@ void ResourceInspector::on_viewContents_clicked()
|
||||
|
||||
ResourceId id = m_Resource;
|
||||
ICaptureContext *ctx = &m_Ctx;
|
||||
m_Ctx.Replay().AsyncInvoke([ctx, id, entry](IReplayController *r) {
|
||||
m_Ctx.Replay().AsyncInvoke([this, ctx, id, entry](IReplayController *r) {
|
||||
ShaderReflection *refl = r->GetShader(id, entry);
|
||||
|
||||
if(!refl)
|
||||
return;
|
||||
|
||||
GUIInvoke::call([ctx, refl] {
|
||||
GUIInvoke::call(this, [ctx, refl] {
|
||||
IShaderViewer *viewer = ctx->ViewShader(refl, ResourceId());
|
||||
|
||||
ctx->AddDockWindow(viewer->Widget(), DockReference::MainToolArea, NULL);
|
||||
|
||||
@@ -312,7 +312,7 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
|
||||
|
||||
rdcstr disasm = r->DisassembleShader(m_Pipeline, m_ShaderDetails, "");
|
||||
|
||||
GUIInvoke::call([this, targets, disasm]() {
|
||||
GUIInvoke::call(this, [this, targets, disasm]() {
|
||||
QStringList targetNames;
|
||||
for(const rdcstr &t : targets)
|
||||
{
|
||||
@@ -909,7 +909,7 @@ void ShaderViewer::disassemble_typeChanged(int index)
|
||||
m_Ctx.Replay().AsyncInvoke([this, target](IReplayController *r) {
|
||||
rdcstr disasm = r->DisassembleShader(m_Pipeline, m_ShaderDetails, target.data());
|
||||
|
||||
GUIInvoke::call([this, disasm]() {
|
||||
GUIInvoke::call(this, [this, disasm]() {
|
||||
m_DisassemblyView->setReadOnly(false);
|
||||
m_DisassemblyView->setText(disasm.c_str());
|
||||
m_DisassemblyView->setReadOnly(true);
|
||||
|
||||
@@ -733,7 +733,7 @@ void TextureViewer::RT_PickPixelsAndUpdate(IReplayController *)
|
||||
m_CurPixelValue = pickValue;
|
||||
m_CurRealValue = realValue;
|
||||
|
||||
GUIInvoke::call([this]() { UI_UpdateStatusText(); });
|
||||
GUIInvoke::call(this, [this]() { UI_UpdateStatusText(); });
|
||||
}
|
||||
|
||||
void TextureViewer::RT_PickHoverAndUpdate(IReplayController *)
|
||||
@@ -747,7 +747,7 @@ void TextureViewer::RT_PickHoverAndUpdate(IReplayController *)
|
||||
|
||||
m_CurHoverValue = pickValue;
|
||||
|
||||
GUIInvoke::call([this]() { UI_UpdateStatusText(); });
|
||||
GUIInvoke::call(this, [this]() { UI_UpdateStatusText(); });
|
||||
}
|
||||
|
||||
void TextureViewer::RT_UpdateAndDisplay(IReplayController *)
|
||||
@@ -755,7 +755,7 @@ void TextureViewer::RT_UpdateAndDisplay(IReplayController *)
|
||||
if(m_Output != NULL)
|
||||
m_Output->SetTextureDisplay(m_TexDisplay);
|
||||
|
||||
GUIInvoke::call([this]() { ui->render->update(); });
|
||||
GUIInvoke::call(this, [this]() { ui->render->update(); });
|
||||
}
|
||||
|
||||
void TextureViewer::RT_UpdateVisualRange(IReplayController *)
|
||||
@@ -784,7 +784,7 @@ void TextureViewer::RT_UpdateVisualRange(IReplayController *)
|
||||
if(!histogram.isEmpty())
|
||||
memcpy(histogramVec.data(), histogram.data(), histogram.byteSize());
|
||||
|
||||
GUIInvoke::call([this, histogramVec]() {
|
||||
GUIInvoke::call(this, [this, histogramVec]() {
|
||||
ui->rangeHistogram->setHistogramRange(ui->rangeHistogram->rangeMin(),
|
||||
ui->rangeHistogram->rangeMax());
|
||||
ui->rangeHistogram->setHistogramData(histogramVec);
|
||||
@@ -1710,7 +1710,7 @@ void TextureViewer::ViewTexture(ResourceId ID, bool focus)
|
||||
{
|
||||
if(QThread::currentThread() != QCoreApplication::instance()->thread())
|
||||
{
|
||||
GUIInvoke::call([this, ID, focus] { this->ViewTexture(ID, focus); });
|
||||
GUIInvoke::call(this, [this, ID, focus] { this->ViewTexture(ID, focus); });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2108,7 +2108,7 @@ void TextureViewer::thumb_clicked(QMouseEvent *e)
|
||||
m_Ctx.Replay().AsyncInvoke([this, id](IReplayController *r) {
|
||||
rdcarray<EventUsage> usage = r->GetUsage(id);
|
||||
|
||||
GUIInvoke::call([this, id, usage]() { OpenResourceContextMenu(id, usage); });
|
||||
GUIInvoke::call(this, [this, id, usage]() { OpenResourceContextMenu(id, usage); });
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2496,7 +2496,7 @@ void TextureViewer::OnCaptureLoaded()
|
||||
|
||||
RT_UpdateAndDisplay(r);
|
||||
|
||||
GUIInvoke::call([this]() { OnEventChanged(m_Ctx.CurEvent()); });
|
||||
GUIInvoke::call(this, [this]() { OnEventChanged(m_Ctx.CurEvent()); });
|
||||
});
|
||||
|
||||
m_Watcher = new QFileSystemWatcher({configFilePath(QString())}, this);
|
||||
@@ -3131,7 +3131,7 @@ void TextureViewer::AutoFitRange()
|
||||
|
||||
if(changeRange)
|
||||
{
|
||||
GUIInvoke::call([this, minval, maxval]() {
|
||||
GUIInvoke::call(this, [this, minval, maxval]() {
|
||||
ui->rangeHistogram->setRange(minval, maxval);
|
||||
INVOKE_MEMFN(RT_UpdateVisualRange);
|
||||
});
|
||||
@@ -3479,11 +3479,11 @@ void TextureViewer::on_debugPixelContext_clicked()
|
||||
r->FreeTrace(trace);
|
||||
|
||||
// if we couldn't debug the pixel on this event, open up a pixel history
|
||||
GUIInvoke::call([this]() { on_pixelHistory_clicked(); });
|
||||
GUIInvoke::call(this, [this]() { on_pixelHistory_clicked(); });
|
||||
return;
|
||||
}
|
||||
|
||||
GUIInvoke::call([this, x, y, trace]() {
|
||||
GUIInvoke::call(this, [this, x, y, trace]() {
|
||||
QString debugContext = tr("Pixel %1,%2").arg(x).arg(y);
|
||||
|
||||
const ShaderReflection *shaderDetails =
|
||||
@@ -3535,7 +3535,7 @@ void TextureViewer::on_pixelHistory_clicked()
|
||||
r->PixelHistory(texptr->resourceId, (uint32_t)x, (int32_t)y, m_TexDisplay.sliceFace,
|
||||
m_TexDisplay.mip, m_TexDisplay.sampleIdx, m_TexDisplay.typeHint);
|
||||
|
||||
GUIInvoke::call([hist, histWidget, history] {
|
||||
GUIInvoke::call(this, [hist, histWidget, history] {
|
||||
if(histWidget)
|
||||
hist->SetHistory(history);
|
||||
});
|
||||
@@ -3694,10 +3694,10 @@ void TextureViewer::reloadCustomShaders(const QString &filter)
|
||||
if(m_CustomShaderEditor.contains(key))
|
||||
{
|
||||
IShaderViewer *editor = m_CustomShaderEditor[key];
|
||||
GUIInvoke::call([editor, errors]() { editor->ShowErrors(errors); });
|
||||
GUIInvoke::call(editor->Widget(), [editor, errors]() { editor->ShowErrors(errors); });
|
||||
}
|
||||
|
||||
GUIInvoke::call([this, fn, key, id]() {
|
||||
GUIInvoke::call(this, [this, fn, key, id]() {
|
||||
QString prevtext = ui->customShader->currentText();
|
||||
ui->customShader->addItem(fn);
|
||||
ui->customShader->setCurrentText(prevtext);
|
||||
|
||||
@@ -140,7 +140,7 @@ void TimelineBar::HighlightResourceUsage(ResourceId id)
|
||||
m_Ctx.Replay().AsyncInvoke([this, id](IReplayController *r) {
|
||||
rdcarray<EventUsage> usage = r->GetUsage(id);
|
||||
|
||||
GUIInvoke::call([this, usage]() {
|
||||
GUIInvoke::call(this, [this, usage]() {
|
||||
for(const EventUsage &u : usage)
|
||||
m_UsageEvents << u;
|
||||
qSort(m_UsageEvents);
|
||||
|
||||
Reference in New Issue
Block a user