diff --git a/qrenderdoc/Code/Core.h b/qrenderdoc/Code/Core.h index 4eec44428..f77d8eb41 100644 --- a/qrenderdoc/Code/Core.h +++ b/qrenderdoc/Code/Core.h @@ -1,12 +1,18 @@ #ifndef CORE_H #define CORE_H +#include "RenderManager.h" class Core { public: Core(); ~Core(); + + const RenderManager *Renderer() { return &m_Renderer; } + + private: + RenderManager m_Renderer; }; #endif // CORE_H diff --git a/qrenderdoc/Code/RenderManager.cpp b/qrenderdoc/Code/RenderManager.cpp new file mode 100644 index 000000000..a4da9f8e0 --- /dev/null +++ b/qrenderdoc/Code/RenderManager.cpp @@ -0,0 +1,162 @@ +#include "RenderManager.h" + +#include + +RenderManager::RenderManager() +{ + m_Running = false; +} + +RenderManager::~RenderManager() +{ + +} + +void RenderManager::Init(int proxyRenderer, QString replayHost, QString logfile, float *progress) +{ + if(m_Running) + return; + + m_ProxyRenderer = proxyRenderer; + m_ReplayHost = replayHost; + m_Logfile = logfile; + m_Progress = progress; + + *progress = 0.0f; + + start(HighestPriority); + + while (!isRunning()) {} +} + +void RenderManager::AsyncInvoke(RenderManager::InvokeMethod m) +{ + InvokeHandle *cmd = new InvokeHandle(m); + cmd->selfdelete = true; + + PushInvoke(cmd); +} + +void RenderManager::BlockInvoke(RenderManager::InvokeMethod m) +{ + InvokeHandle *cmd = new InvokeHandle(m); + + PushInvoke(cmd); + + while(!cmd->processed) {} +} + +void RenderManager::CloseThread() +{ + m_Running = false; + + m_RenderCondition.wakeAll(); + + // wait for the thread to close and clean up + while(isRunning()) {} +} + +void RenderManager::PushInvoke(RenderManager::InvokeHandle *cmd) +{ + if(!isRunning() || !m_Running) + { + cmd->processed = true; + if(cmd->selfdelete) delete cmd; + return; + } + + m_RenderLock.lock(); + m_RenderQueue.push_back(cmd); + m_RenderLock.unlock(); + + m_RenderCondition.wakeAll(); +} + +void RenderManager::run() +{ + IReplayRenderer *renderer = NULL; + IRemoteRenderer *remote = NULL; + + if (m_ProxyRenderer < 0) + { + m_CreateStatus = RENDERDOC_CreateReplayRenderer(m_Logfile.toUtf8(), m_Progress, &renderer); + } + else + { + m_CreateStatus = RENDERDOC_CreateRemoteReplayConnection(m_ReplayHost.toUtf8(), &remote); + + if(remote == NULL) + { + return; + } + + m_CreateStatus = remote->CreateProxyRenderer(m_ProxyRenderer, m_Logfile.toUtf8(), m_Progress, &renderer); + + if(renderer == NULL) + { + remote->Shutdown(); + remote = NULL; + return; + } + } + + if(renderer == NULL) + return; + + RENDERDOC_LogText(QString("QRenderDoc - renderer created for %1").arg(m_Logfile).toUtf8()); + + m_Running = true; + + // main render command loop + while(m_Running) + { + QQueue queue; + + // wait for the condition to be woken, grab current queue, + // unlock again. + { + m_RenderLock.lock(); + m_RenderCondition.wait(&m_RenderLock); + m_RenderQueue.swap(queue); + m_RenderLock.unlock(); + } + + // process all the commands + for(InvokeHandle *cmd : queue) + { + if(cmd == NULL) continue; + + if(cmd->method != NULL) + cmd->method(renderer); + + cmd->processed = true; + + // if it's a throwaway command, delete it + if(cmd->selfdelete) + delete cmd; + } + } + + // clean up anything left in the queue + { + QQueue queue; + + m_RenderLock.lock(); + m_RenderQueue.swap(queue); + m_RenderLock.unlock(); + + for(InvokeHandle *cmd : queue) + { + if(cmd == NULL) continue; + + cmd->processed = true; + + if(cmd->selfdelete) + delete cmd; + } + } + + // close the core renderer + renderer->Shutdown(); + if(remote) remote->Shutdown(); +} diff --git a/qrenderdoc/Code/RenderManager.h b/qrenderdoc/Code/RenderManager.h new file mode 100644 index 000000000..f0de7c959 --- /dev/null +++ b/qrenderdoc/Code/RenderManager.h @@ -0,0 +1,65 @@ +#ifndef RENDERMANAGER_H +#define RENDERMANAGER_H + +#include "renderdoc_replay.h" + +#include +#include +#include +#include +#include + +struct IReplayRenderer; + +class RenderManager : public QThread +{ + Q_OBJECT + void run(); + + public: + typedef void (*InvokeMethod)(IReplayRenderer *r); + + RenderManager(); + ~RenderManager(); + + void Init(int proxyRenderer, QString replayHost, QString logfile, float *progress); + + bool IsRunning() { return isRunning() && m_Running; } + ReplayCreateStatus GetCreateStatus() { return m_CreateStatus; } + + void AsyncInvoke(InvokeMethod m); + void BlockInvoke(InvokeMethod m); + + void CloseThread(); + private: + + struct InvokeHandle + { + InvokeHandle(InvokeMethod m) + { + method = m; + processed = false; + selfdelete = true; + } + + InvokeMethod method; + bool processed; + bool selfdelete; + }; + + QMutex m_RenderLock; + QQueue m_RenderQueue; + QWaitCondition m_RenderCondition; + + void PushInvoke(InvokeHandle *cmd); + + int m_ProxyRenderer; + QString m_ReplayHost; + QString m_Logfile; + float *m_Progress; + + volatile bool m_Running; + ReplayCreateStatus m_CreateStatus; +}; + +#endif // RENDERMANAGER_H diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index 5585527b2..34b07d2ab 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -59,7 +59,8 @@ SOURCES += Code/main.cpp \ Widgets/CustomPaintWidget.cpp \ 3rdparty/toolwindowmanager/ToolWindowManager.cpp \ 3rdparty/toolwindowmanager/ToolWindowManagerArea.cpp \ - 3rdparty/toolwindowmanager/ToolWindowManagerWrapper.cpp + 3rdparty/toolwindowmanager/ToolWindowManagerWrapper.cpp \ + Code/RenderManager.cpp HEADERS += Windows/MainWindow.h \ Windows/EventBrowser.h \ @@ -68,7 +69,8 @@ HEADERS += Windows/MainWindow.h \ 3rdparty/toolwindowmanager/ToolWindowManager.h \ 3rdparty/toolwindowmanager/ToolWindowManagerArea.h \ 3rdparty/toolwindowmanager/ToolWindowManagerWrapper.h \ - Code/Core.h + Code/Core.h \ + Code/RenderManager.h FORMS += Windows/MainWindow.ui \ Windows/EventBrowser.ui \