Process render commands 1 by 1 to allow pre-empting high frequency cmds

This commit is contained in:
baldurk
2017-02-17 13:43:19 +00:00
parent 24c1042f06
commit 1e65762e93
4 changed files with 57 additions and 22 deletions
+42 -18
View File
@@ -231,6 +231,31 @@ bool RenderManager::IsRunning()
return m_Thread && m_Thread->isRunning() && m_Running;
}
void RenderManager::AsyncInvoke(const QString &tag, RenderManager::InvokeMethod m)
{
{
QMutexLocker autolock(&m_RenderLock);
for(int i = 0; i < m_RenderQueue.count();)
{
if(m_RenderQueue[i]->tag == tag)
{
InvokeHandle *cmd = m_RenderQueue.takeAt(i);
if(cmd->selfdelete)
delete cmd;
}
else
{
i++;
}
}
}
InvokeHandle *cmd = new InvokeHandle(m, tag);
cmd->selfdelete = true;
PushInvoke(cmd);
}
void RenderManager::AsyncInvoke(RenderManager::InvokeMethod m)
{
InvokeHandle *cmd = new InvokeHandle(m);
@@ -373,7 +398,7 @@ void RenderManager::PushInvoke(RenderManager::InvokeHandle *cmd)
}
QMutexLocker autolock(&m_RenderLock);
m_RenderQueue.push_back(cmd);
m_RenderQueue.enqueue(cmd);
m_RenderCondition.wakeAll();
}
@@ -396,31 +421,30 @@ void RenderManager::run()
// main render command loop
while(m_Running)
{
QQueue<InvokeHandle *> queue;
InvokeHandle *cmd = NULL;
// wait for the condition to be woken, grab current queue,
// wait for the condition to be woken, grab top of current queue,
// unlock again.
{
QMutexLocker autolock(&m_RenderLock);
m_RenderCondition.wait(&m_RenderLock, 10);
m_RenderQueue.swap(queue);
if(m_RenderQueue.isEmpty())
m_RenderCondition.wait(&m_RenderLock, 10);
if(!m_RenderQueue.isEmpty())
cmd = m_RenderQueue.dequeue();
}
// process all the commands
for(InvokeHandle *cmd : queue)
{
if(cmd == NULL)
continue;
if(cmd == NULL)
continue;
if(cmd->method != NULL)
cmd->method(renderer);
if(cmd->method != NULL)
cmd->method(renderer);
// if it's a throwaway command, delete it
if(cmd->selfdelete)
delete cmd;
else
cmd->processed.release();
}
// if it's a throwaway command, delete it
if(cmd->selfdelete)
delete cmd;
else
cmd->processed.release();
}
// clean up anything left in the queue
+10 -1
View File
@@ -131,6 +131,13 @@ public:
bool IsRunning();
ReplayCreateStatus GetCreateStatus() { return m_CreateStatus; }
// 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
// processed.
// the manager processes only the request on the top of the queue, so when a new tagged invoke
// comes in, we remove any other requests in the queue before it that have the same tag
void AsyncInvoke(const QString &tag, InvokeMethod m);
void AsyncInvoke(InvokeMethod m);
void BlockInvoke(InvokeMethod m);
@@ -155,12 +162,14 @@ public:
private:
struct InvokeHandle
{
InvokeHandle(InvokeMethod m)
InvokeHandle(InvokeMethod m, const QString &t = QString())
{
tag = t;
method = m;
selfdelete = false;
}
QString tag;
InvokeMethod method;
QSemaphore processed;
bool selfdelete;
+1 -1
View File
@@ -1889,7 +1889,7 @@ void BufferViewer::render_clicked(QMouseEvent *e)
if((e->buttons() & Qt::RightButton) && m_Output)
{
m_Ctx.Renderer().AsyncInvoke([this, curpos](IReplayRenderer *r) {
m_Ctx.Renderer().AsyncInvoke("PickVertex", [this, curpos](IReplayRenderer *r) {
uint32_t instanceSelected = 0;
uint32_t vertSelected = m_Output->PickVertex(m_Ctx.CurEvent(), (uint32_t)curpos.x(),
(uint32_t)curpos.y(), &instanceSelected);
+4 -2
View File
@@ -2185,11 +2185,13 @@ void TextureViewer::render_mouseMove(QMouseEvent *e)
m_PickedPoint.setX(qBound(0, m_PickedPoint.x(), (int)texptr->width - 1));
m_PickedPoint.setY(qBound(0, m_PickedPoint.y(), (int)texptr->height - 1));
INVOKE_MEMFN(RT_PickPixelsAndUpdate);
m_Ctx.Renderer().AsyncInvoke("PickPixelClick",
[this](IReplayRenderer *r) { RT_PickPixelsAndUpdate(r); });
}
else if(e->buttons() == Qt::NoButton)
{
INVOKE_MEMFN(RT_PickHoverAndUpdate);
m_Ctx.Renderer().AsyncInvoke("PickPixelHover",
[this](IReplayRenderer *r) { RT_PickHoverAndUpdate(r); });
}
}
}