Backport 'tagged' render invokes from qrenderdoc

* This is a possible fix for a case where render work triggered by mouse
  movements (such as pixel and vertex picking) can happen faster than it
  executes, leading to a backlog of render commands and a noticeable lag
  which only gets worse the more you move the mouse until everything
  seems to be unresponsive or laggy (especially if you then trigger a
  blocking command like event change, which will block the whole UI
  until the queued picks happen).
* Since a new pick coming in will override and make redundant the
  previous pick, we allow the render commands to do just that. If a new
  command comes in, we remove any previous commands with the same tag
  and put the command in the first match (this prevents a tagged invoke
  always being pushed to the back of the queue).
This commit is contained in:
baldurk
2017-04-03 18:31:59 +01:00
parent b63a32fe3b
commit 666aee093b
4 changed files with 98 additions and 12 deletions
+90 -4
View File
@@ -45,12 +45,21 @@ namespace renderdocui.Code
{
private class InvokeHandle
{
public InvokeHandle(InvokeMethod m)
public InvokeHandle(string t, InvokeMethod m)
{
tag = t;
method = m;
processed = false;
}
public InvokeHandle(InvokeMethod m)
{
tag = "";
method = m;
processed = false;
}
public string tag;
public InvokeMethod method;
public bool paintInvoke = false;
volatile public bool processed;
@@ -423,6 +432,55 @@ namespace renderdocui.Code
CatchExceptions = catching;
}
// 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
public void BeginInvoke(string tag, InvokeMethod m)
{
InvokeHandle cmd = new InvokeHandle(tag, m);
if (tag != "")
{
lock (m_renderQueue)
{
bool added = false;
for (int i = 0; i < m_renderQueue.Count;)
{
if (m_renderQueue[i].tag == tag)
{
m_renderQueue[i].processed = true;
if (!added)
{
m_renderQueue[i] = cmd;
added = true;
}
else
{
m_renderQueue.RemoveAt(i);
}
}
else
{
i++;
}
}
if (!added)
m_renderQueue.Add(cmd);
}
m_WakeupEvent.Set();
}
else
{
PushInvoke(cmd);
}
}
public void BeginInvoke(InvokeMethod m)
{
InvokeHandle cmd = new InvokeHandle(m);
@@ -442,7 +500,7 @@ namespace renderdocui.Code
throw cmd.ex;
}
public void InvokeForPaint(InvokeMethod m)
public void InvokeForPaint(string tag, InvokeMethod m)
{
if (m_Thread == null || !Running)
return;
@@ -458,7 +516,7 @@ namespace renderdocui.Code
bool waitable = true;
InvokeHandle cmd = new InvokeHandle(m);
InvokeHandle cmd = new InvokeHandle(tag, m);
cmd.paintInvoke = true;
lock (m_renderQueue)
@@ -473,7 +531,35 @@ namespace renderdocui.Code
if (!m_renderQueue[i].paintInvoke)
waitable = false;
m_renderQueue.Add(cmd);
// remove any duplicated paints if we have a tag
bool added = false;
if (tag != "")
{
for (int i = 0; i < m_renderQueue.Count;)
{
if (m_renderQueue[i].tag == tag)
{
m_renderQueue[i].processed = true;
if (!added)
{
m_renderQueue[i] = cmd;
added = true;
}
else
{
m_renderQueue.RemoveAt(i);
}
}
else
{
i++;
}
}
}
if (!added)
m_renderQueue.Add(cmd);
}
m_WakeupEvent.Set();
+1 -1
View File
@@ -155,7 +155,7 @@ namespace renderdocui.Controls
}
if (m_Output != null)
m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { m_Output.Display(); });
m_Core.Renderer.InvokeForPaint("thumbpaint", (ReplayRenderer r) => { m_Output.Display(); });
}
public void SetSize(Size s)
+2 -2
View File
@@ -2391,7 +2391,7 @@ namespace renderdocui.Windows
if (!m_Core.LogLoaded)
return;
m_Core.Renderer.BeginInvoke((ReplayRenderer r) =>
m_Core.Renderer.BeginInvoke("PickVertex", (ReplayRenderer r) =>
{
UInt32 instanceSelected = 0;
UInt32 vertSelected = m_Output.PickVertex(m_Core.CurEvent, (UInt32)p.X, (UInt32)p.Y, out instanceSelected);
@@ -2598,7 +2598,7 @@ namespace renderdocui.Windows
return;
}
m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { RT_UpdateRenderOutput(r); if (m_Output != null) m_Output.Display(); });
m_Core.Renderer.InvokeForPaint("bufferpaint", (ReplayRenderer r) => { RT_UpdateRenderOutput(r); if (m_Output != null) m_Output.Display(); });
}
private void BufferViewer_Load(object sender, EventArgs e)
+5 -5
View File
@@ -2452,7 +2452,7 @@ namespace renderdocui.Windows
return;
}
m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { if (m_Output != null) m_Output.Display(); });
m_Core.Renderer.InvokeForPaint("contextpaint", (ReplayRenderer r) => { if (m_Output != null) m_Output.Display(); });
}
private void render_Paint(object sender, PaintEventArgs e)
@@ -2470,7 +2470,7 @@ namespace renderdocui.Windows
foreach (var prev in roPanel.Thumbnails)
if (prev.Unbound) prev.Clear();
m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { if (m_Output != null) m_Output.Display(); });
m_Core.Renderer.InvokeForPaint("texpaint", (ReplayRenderer r) => { if (m_Output != null) m_Output.Display(); });
}
#endregion
@@ -2910,7 +2910,7 @@ namespace renderdocui.Windows
m_PickedPoint.X = Helpers.Clamp(m_PickedPoint.X, 0, (int)tex.width - 1);
m_PickedPoint.Y = Helpers.Clamp(m_PickedPoint.Y, 0, (int)tex.height - 1);
m_Core.Renderer.BeginInvoke((ReplayRenderer r) =>
m_Core.Renderer.BeginInvoke("PickPixelClick", (ReplayRenderer r) =>
{
if (m_Output != null)
RT_PickPixelsAndUpdate(m_PickedPoint.X, m_PickedPoint.Y, true);
@@ -2926,7 +2926,7 @@ namespace renderdocui.Windows
if (tex != null)
{
m_Core.Renderer.BeginInvoke((ReplayRenderer r) =>
m_Core.Renderer.BeginInvoke("PickPixelHover", (ReplayRenderer r) =>
{
if (m_Output != null)
{
@@ -3289,7 +3289,7 @@ namespace renderdocui.Windows
rangePaintThread = Helpers.NewThread(new ThreadStart(() =>
{
m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { RT_UpdateAndDisplay(r); if (m_Output != null) m_Output.Display(); });
m_Core.Renderer.InvokeForPaint("", (ReplayRenderer r) => { RT_UpdateAndDisplay(r); if (m_Output != null) m_Output.Display(); });
Thread.Sleep(8);
}));
rangePaintThread.Start();