diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index e0d769a38..6416b2419 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -758,8 +758,8 @@ blocking fashion on the current thread. DOCUMENT(R"(Copy a capture from the local machine to the remote host. :param str localpath: The path on the local machine to copy from. -:return: The path on the local machine where the file was saved, or empty if something went wrong. :param QWidget window: A handle to the window to use when showing a progress bar. +:return: The path on the local machine where the file was saved, or empty if something went wrong. :rtype: ``str`` )"); virtual rdcstr CopyCaptureToRemote(const rdcstr &localpath, QWidget *window) = 0; @@ -773,6 +773,17 @@ blocking fashion on the current thread. virtual void CopyCaptureFromRemote(const rdcstr &remotepath, const rdcstr &localpath, QWidget *window) = 0; + DOCUMENT(R"(Return the amount of time that the currently active command on the replay thread has +been executing for. + +This can be used to identify if a command is long-running to display a progress bar or notification. + +:return: The time in seconds that the current command has been executing for, or 0.0 if no command + is executing. +:rtype: ``float`` +)"); + virtual float GetCurrentProcessingTime() = 0; + DOCUMENT(R"(Make a tagged non-blocking invoke call onto the replay thread. This tagged function is for cases when we might send a request - e.g. to pick a vertex or pixel - diff --git a/qrenderdoc/Code/ReplayManager.cpp b/qrenderdoc/Code/ReplayManager.cpp index 02ce5da69..193f093a6 100644 --- a/qrenderdoc/Code/ReplayManager.cpp +++ b/qrenderdoc/Code/ReplayManager.cpp @@ -230,6 +230,12 @@ bool ReplayManager::IsRunning() return m_Thread && m_Thread->isRunning() && m_Running; } +float ReplayManager::GetCurrentProcessingTime() +{ + QMutexLocker lock(&m_TimerLock); + return m_CommandTimer.isValid() ? double(m_CommandTimer.elapsed()) / 1000.0 : 0.0; +} + void ReplayManager::AsyncInvoke(const rdcstr &tag, ReplayManager::InvokeCallback m) { QString qtag(tag); @@ -462,8 +468,20 @@ void ReplayManager::run(int proxyRenderer, const QString &capturefile, continue; if(cmd->method != NULL) + { + { + QMutexLocker lock(&m_TimerLock); + m_CommandTimer.start(); + } + cmd->method(m_Renderer); + { + QMutexLocker lock(&m_TimerLock); + m_CommandTimer.invalidate(); + } + } + // if it's a throwaway command, delete it if(cmd->selfdelete) delete cmd; diff --git a/qrenderdoc/Code/ReplayManager.h b/qrenderdoc/Code/ReplayManager.h index c8cb10d3f..88697c325 100644 --- a/qrenderdoc/Code/ReplayManager.h +++ b/qrenderdoc/Code/ReplayManager.h @@ -24,6 +24,7 @@ #pragma once +#include #include #include #include @@ -52,6 +53,7 @@ public: bool IsRunning(); ReplayStatus GetCreateStatus() { return m_CreateStatus; } + float GetCurrentProcessingTime(); // 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 @@ -113,6 +115,9 @@ private: void run(int proxyRenderer, const QString &capturefile, RENDERDOC_ProgressCallback progress); + QMutex m_TimerLock; + QElapsedTimer m_CommandTimer; + QMutex m_RenderLock; QQueue m_RenderQueue; QWaitCondition m_RenderCondition; diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index 799e78239..f8ebea1a2 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -154,7 +154,7 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai QObject::connect(&m_MessageTick, &QTimer::timeout, this, &MainWindow::messageCheck); m_MessageTick.setSingleShot(false); - m_MessageTick.setInterval(500); + m_MessageTick.setInterval(175); m_MessageTick.start(); m_RemoteProbeSemaphore.release(); @@ -1482,10 +1482,7 @@ void MainWindow::setCaptureHasErrors(bool errors) statusIcon->setPixmap(m_messageAlternate ? empty : del); QString text; - text = tr("%1 loaded. Capture has %2 errors, warnings or performance notes. " - "See the 'Errors and Warnings' window.") - .arg(filename) - .arg(m_Ctx.DebugMessages().size()); + text = tr("%1 loaded. Capture has %2 issues.").arg(filename).arg(m_Ctx.DebugMessages().size()); if(m_Ctx.UnreadMessageCount() > 0) text += tr(" %1 Unread.").arg(m_Ctx.UnreadMessageCount()); statusText->setText(text); @@ -1522,6 +1519,16 @@ void MainWindow::messageCheck() { if(m_Ctx.IsCaptureLoaded()) { + if(m_Ctx.Replay().GetCurrentProcessingTime() >= 1.5f) + { + statusProgress->setVisible(true); + statusProgress->setMaximum(0); + } + else + { + statusProgress->hide(); + } + m_Ctx.Replay().AsyncInvoke([this](IReplayController *r) { rdcarray msgs = r->GetDebugMessages();