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:
baldurk
2018-05-08 11:54:34 +01:00
parent c880def5ef
commit 082ab4d75d
25 changed files with 113 additions and 108 deletions
+2 -2
View File
@@ -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(
+19 -17
View File
@@ -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 &params,
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();
+10 -6
View File
@@ -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 &params,
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; });
}
}
+4 -7
View File
@@ -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();
});
}
}
+1 -1
View File
@@ -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
+8 -8
View File
@@ -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)
{
+3 -3
View File
@@ -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);
});
+7 -7
View File
@@ -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);
});
+4 -4
View File
@@ -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();
+1 -1
View File
@@ -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();
});
+13 -13
View File
@@ -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);
+1 -1
View File
@@ -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 =
+7 -5
View File
@@ -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);
});
+3 -3
View File
@@ -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);
+2 -2
View File
@@ -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);
+13 -13
View File
@@ -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);
+1 -1
View File
@@ -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);