diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index 6868f8713..842977289 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -1478,15 +1478,36 @@ void CaptureContext::SetEventID(const rdcarray &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; diff --git a/qrenderdoc/Code/ReplayManager.cpp b/qrenderdoc/Code/ReplayManager.cpp index 839ecbc04..6042f78ef 100644 --- a/qrenderdoc/Code/ReplayManager.cpp +++ b/qrenderdoc/Code/ReplayManager.cpp @@ -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(); } } diff --git a/qrenderdoc/Code/ReplayManager.h b/qrenderdoc/Code/ReplayManager.h index 0c89b7ab3..62fb58c53 100644 --- a/qrenderdoc/Code/ReplayManager.h +++ b/qrenderdoc/Code/ReplayManager.h @@ -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 m_RenderQueue;