Make event selection 'soft' blocking instead of hard blocking

* Normally SetEventID is synchronous and blocking, and will stall the UI while
  it is processing. However we can at least pop up a progress dialog and allow
  the UI to function (if not be interactive due to the blocking progress dialog)
  when some other long-running task is delaying the processing on the replay
  thread.
This commit is contained in:
baldurk
2020-12-03 15:09:29 +00:00
parent 6bc4e007a0
commit 60409caf8d
3 changed files with 32 additions and 1 deletions
+22 -1
View File
@@ -1478,15 +1478,36 @@ void CaptureContext::SetEventID(const rdcarray<ICaptureViewer *> &exclude, uint3
uint32_t prevEventID = m_EventID;
m_EventID = eventId;
m_Replay.BlockInvoke([this, eventId, force](IReplayController *r) {
bool done = false;
QString tag = lit("replaySetEvent");
// we can't return until the event is selected, but a blocking invoke on the UI thread can cause
// the UI to stall. We ideally want to have at least an interactive UI and a progress bar.
m_Replay.AsyncInvoke(tag, [this, eventId, force, &done](IReplayController *r) {
r->SetFrameEvent(eventId, force);
m_CurD3D11PipelineState = r->GetD3D11PipelineState();
m_CurD3D12PipelineState = r->GetD3D12PipelineState();
m_CurGLPipelineState = r->GetGLPipelineState();
m_CurVulkanPipelineState = r->GetVulkanPipelineState();
m_CurPipelineState = &r->GetPipelineState();
done = true;
});
// wait a short while before displaying the progress dialog (which won't show if we're already
// done by the time we reach it).
// Keep waiting if the current tag is a set event, we don't want to be popping up progress bars
// when the user is browsing the frame if it's going slow. If that's the case we'll just block the
// UI thread. Instead only pop up the progress bar if some other large task is blocking.
for(int i = 0; !done && (i < 100 || m_Replay.GetCurrentProcessingTag().isEmpty() ||
m_Replay.GetCurrentProcessingTag() == tag);
i++)
QThread::msleep(5);
ShowProgressDialog(m_MainWindow->Widget(), tr("Please wait, working..."),
[&done]() { return done; });
bool updateSelectedEvent = force || prevSelectedEventID != selectedEventID;
bool updateEvent = force || prevEventID != eventId;
+8
View File
@@ -240,6 +240,12 @@ float ReplayManager::GetCurrentProcessingTime()
return m_CommandTimer.isValid() ? double(m_CommandTimer.elapsed()) / 1000.0 : 0.0;
}
QString ReplayManager::GetCurrentProcessingTag()
{
QMutexLocker lock(&m_TimerLock);
return m_CommandTag;
}
void ReplayManager::AsyncInvoke(const rdcstr &tag, ReplayManager::InvokeCallback m)
{
QString qtag(tag);
@@ -486,6 +492,7 @@ void ReplayManager::run(int proxyRenderer, const QString &capturefile, const Rep
{
QMutexLocker lock(&m_TimerLock);
m_CommandTimer.start();
m_CommandTag = cmd->tag;
}
cmd->method(m_Renderer);
@@ -493,6 +500,7 @@ void ReplayManager::run(int proxyRenderer, const QString &capturefile, const Rep
{
QMutexLocker lock(&m_TimerLock);
m_CommandTimer.invalidate();
m_CommandTag = QString();
}
}
+2
View File
@@ -55,6 +55,7 @@ public:
bool IsRunning();
ReplayStatus GetCreateStatus() { return m_CreateStatus; }
float GetCurrentProcessingTime();
QString GetCurrentProcessingTag();
// this tagged version is for cases when we might send a request - e.g. to pick a vertex or pixel
// - and want to pre-empt it with a new request before the first has returned. Either because some
// other work is taking a while or because we're sending requests faster than they can be
@@ -119,6 +120,7 @@ private:
QMutex m_TimerLock;
QElapsedTimer m_CommandTimer;
QString m_CommandTag;
QMutex m_RenderLock;
QQueue<InvokeHandle *> m_RenderQueue;