diff --git a/renderdocui/Code/RenderManager.cs b/renderdocui/Code/RenderManager.cs index b84328840..7967285ab 100644 --- a/renderdocui/Code/RenderManager.cs +++ b/renderdocui/Code/RenderManager.cs @@ -52,6 +52,7 @@ namespace renderdocui.Code } public InvokeMethod method; + public bool paintInvoke = false; volatile public bool processed; public Exception ex = null; }; @@ -67,6 +68,7 @@ namespace renderdocui.Code private RemoteServer m_Remote = null; private List m_renderQueue; + private InvokeHandle m_current = null; //////////////////////////////////////////// // Interface @@ -228,6 +230,7 @@ namespace renderdocui.Code while (m_Thread != null && m_Thread.IsAlive) ; m_renderQueue = new List(); + m_current = null; } public float LoadProgress; @@ -259,6 +262,51 @@ namespace renderdocui.Code throw cmd.ex; } + public void InvokeForPaint(InvokeMethod m) + { + if (m_Thread == null || !Running) + return; + + // special logic for painting invokes. Normally we want these to + // go off immediately, but if we have a remote connection active + // there could be slow operations on the pipe or currently being + // processed. + // So we check to see if the paint is likely to finish soon + // (0, or only other paint invokes on the queue, nothing active) + // and if so do it synchronously. Otherwise we just append to the + // queue and return immediately. + + bool waitable = true; + + InvokeHandle cmd = new InvokeHandle(m); + cmd.paintInvoke = true; + + lock (m_renderQueue) + { + InvokeHandle current = m_current; + + if (current != null && !current.paintInvoke) + waitable = false; + + // any non-painting commands on the queue? can't wait + for (int i = 0; waitable && i < m_renderQueue.Count; i++) + if (!m_renderQueue[i].paintInvoke) + waitable = false; + + m_renderQueue.Add(cmd); + } + + m_WakeupEvent.Set(); + + if (!waitable) + return; + + while (!cmd.processed) ; + + if (cmd.ex != null) + throw cmd.ex; + } + private void PushInvoke(InvokeHandle cmd) { if (m_Thread == null || !Running) @@ -267,12 +315,12 @@ namespace renderdocui.Code return; } - m_WakeupEvent.Set(); - lock (m_renderQueue) { m_renderQueue.Add(cmd); } + + m_WakeupEvent.Set(); } //////////////////////////////////////////// @@ -305,42 +353,46 @@ namespace renderdocui.Code Running = true; + m_current = null; + while (Running) { - List queue = new List(); lock (m_renderQueue) { - foreach (var cmd in m_renderQueue) - queue.Add(cmd); - - m_renderQueue.Clear(); + if (m_renderQueue.Count > 0) + { + m_current = m_renderQueue[0]; + m_renderQueue.RemoveAt(0); + } } - foreach (var cmd in queue) + if(m_current == null) { - if (cmd.method != null) + m_WakeupEvent.WaitOne(10); + continue; + } + + if (m_current.method != null) + { + if (CatchExceptions) { - if (CatchExceptions) + try { - try - { - cmd.method(renderer); - } - catch (Exception ex) - { - cmd.ex = ex; - } + m_current.method(renderer); } - else + catch (Exception ex) { - cmd.method(renderer); + m_current.ex = ex; } } - - cmd.processed = true; + else + { + m_current.method(renderer); + } } - m_WakeupEvent.WaitOne(10); + m_current.processed = true; + m_current = null; } lock (m_renderQueue) diff --git a/renderdocui/Controls/ResourcePreview.cs b/renderdocui/Controls/ResourcePreview.cs index f600ea2bf..938d56cf5 100644 --- a/renderdocui/Controls/ResourcePreview.cs +++ b/renderdocui/Controls/ResourcePreview.cs @@ -155,7 +155,7 @@ namespace renderdocui.Controls } if (m_Output != null) - m_Core.Renderer.Invoke((ReplayRenderer r) => { m_Output.Display(); }); + m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { m_Output.Display(); }); } public void SetSize(Size s) diff --git a/renderdocui/Windows/BufferViewer.cs b/renderdocui/Windows/BufferViewer.cs index b8f48cfff..6a0cfaf64 100644 --- a/renderdocui/Windows/BufferViewer.cs +++ b/renderdocui/Windows/BufferViewer.cs @@ -2568,7 +2568,7 @@ namespace renderdocui.Windows return; } - m_Core.Renderer.Invoke((ReplayRenderer r) => { RT_UpdateRenderOutput(r); if (m_Output != null) m_Output.Display(); }); + m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { RT_UpdateRenderOutput(r); if (m_Output != null) m_Output.Display(); }); } private void BufferViewer_Load(object sender, EventArgs e) diff --git a/renderdocui/Windows/TextureViewer.cs b/renderdocui/Windows/TextureViewer.cs index 19306f156..412657cc3 100644 --- a/renderdocui/Windows/TextureViewer.cs +++ b/renderdocui/Windows/TextureViewer.cs @@ -2418,7 +2418,7 @@ namespace renderdocui.Windows return; } - m_Core.Renderer.Invoke((ReplayRenderer r) => { if (m_Output != null) m_Output.Display(); }); + m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { if (m_Output != null) m_Output.Display(); }); } private void render_Paint(object sender, PaintEventArgs e) @@ -2436,7 +2436,7 @@ namespace renderdocui.Windows foreach (var prev in roPanel.Thumbnails) if (prev.Unbound) prev.Clear(); - m_Core.Renderer.Invoke((ReplayRenderer r) => { if (m_Output != null) m_Output.Display(); }); + m_Core.Renderer.InvokeForPaint((ReplayRenderer r) => { if (m_Output != null) m_Output.Display(); }); } #endregion @@ -3225,7 +3225,7 @@ namespace renderdocui.Windows rangePaintThread = Helpers.NewThread(new ThreadStart(() => { - m_Core.Renderer.Invoke((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();