diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index e679388e4..8d6d66eda 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -480,6 +480,8 @@ struct IRemoteServer virtual void ShutdownServerAndConnection() = 0; + virtual bool Ping() = 0; + virtual bool LocalProxies(rdctype::array *out) = 0; virtual bool RemoteSupportedReplays(rdctype::array *out) = 0; @@ -517,6 +519,8 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RemoteServer_ShutdownConnection(Remot extern "C" RENDERDOC_API void RENDERDOC_CC RemoteServer_ShutdownServerAndConnection(RemoteServer *remote); +extern "C" RENDERDOC_API bool32 RENDERDOC_CC RemoteServer_Ping(RemoteServer *remote); + extern "C" RENDERDOC_API bool32 RENDERDOC_CC RemoteServer_LocalProxies(RemoteServer *remote, rdctype::array *out); extern "C" RENDERDOC_API bool32 RENDERDOC_CC diff --git a/renderdoc/core/remote_server.cpp b/renderdoc/core/remote_server.cpp index f20d90518..e13113284 100644 --- a/renderdoc/core/remote_server.cpp +++ b/renderdoc/core/remote_server.cpp @@ -75,6 +75,7 @@ enum RemoteServerPacket eRemoteServer_VersionMismatch, eRemoteServer_Busy, + eRemoteServer_Ping, eRemoteServer_RemoteDriverList, eRemoteServer_TakeOwnershipCapture, eRemoteServer_CopyCaptureToRemote, @@ -245,6 +246,10 @@ static void ActiveRemoteClientThread(void *data) SAFE_DELETE(recvser); continue; } + else if(type == eRemoteServer_Ping) + { + sendType = eRemoteServer_Ping; + } else if(type == eRemoteServer_RemoteDriverList) { map drivers = RenderDoc::Inst().GetRemoteDrivers(); @@ -721,6 +726,23 @@ public: delete this; } bool Connected() { return m_Socket != NULL && m_Socket->Connected(); } + bool Ping() + { + if(!Connected()) + return false; + + Serialiser sendData("", Serialiser::WRITING, false); + Send(eRemoteServer_Ping, sendData); + + RemoteServerPacket type = eRemoteServer_Noop; + Serialiser *ser = NULL; + Get(type, &ser); + + SAFE_DELETE(ser); + + return type == eRemoteServer_Ping; + } + bool LocalProxies(rdctype::array *out) { if(out == NULL) @@ -1078,6 +1100,11 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RemoteServer_ShutdownServerAndConnect remote->ShutdownServerAndConnection(); } +extern "C" RENDERDOC_API bool32 RENDERDOC_CC RemoteServer_Ping(RemoteServer *remote) +{ + return remote->Ping(); +} + extern "C" RENDERDOC_API bool32 RENDERDOC_CC RemoteServer_LocalProxies(RemoteServer *remote, rdctype::array *out) { diff --git a/renderdocui/Code/RenderManager.cs b/renderdocui/Code/RenderManager.cs index 66fbeaf69..2980e6e6c 100644 --- a/renderdocui/Code/RenderManager.cs +++ b/renderdocui/Code/RenderManager.cs @@ -70,6 +70,8 @@ namespace renderdocui.Code private List m_renderQueue; private InvokeHandle m_current = null; + private bool m_CopyInProgress = false; + //////////////////////////////////////////// // Interface @@ -217,8 +219,13 @@ namespace renderdocui.Code { Helpers.NewThread(new ThreadStart(() => { + // prevent pings while copying off-thread + m_CopyInProgress = true; + remotepath = m_Remote.CopyCaptureToRemote(localpath, ref progress); + m_CopyInProgress = false; + copied = true; })).Start(); } @@ -271,8 +278,13 @@ namespace renderdocui.Code { Helpers.NewThread(new ThreadStart(() => { + // prevent pings while copying off-thread + m_CopyInProgress = true; + m_Remote.CopyCaptureFromRemote(remotepath, localpath, ref progress); + m_CopyInProgress = false; + copied = true; })).Start(); } @@ -328,6 +340,19 @@ namespace renderdocui.Code m_Remote = null; } + public void PingRemote() + { + if(m_CopyInProgress) + return; + + // must only happen on render thread if running + if ((!Running || m_Thread == Thread.CurrentThread) && m_Remote != null) + { + if (!m_Remote.Ping()) + m_RemoteHost.ServerRunning = false; + } + } + public ReplayCreateException InitException = null; public void CloseThreadSync() diff --git a/renderdocui/Interop/ReplayRenderer.cs b/renderdocui/Interop/ReplayRenderer.cs index bafc7714a..4ae68f1d0 100644 --- a/renderdocui/Interop/ReplayRenderer.cs +++ b/renderdocui/Interop/ReplayRenderer.cs @@ -892,6 +892,9 @@ namespace renderdoc [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void RemoteServer_ShutdownServerAndConnection(IntPtr real); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool RemoteServer_Ping(IntPtr real); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool RemoteServer_LocalProxies(IntPtr real, IntPtr outlist); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] @@ -986,6 +989,11 @@ namespace renderdoc return ret; } + public bool Ping() + { + return RemoteServer_Ping(m_Real); + } + public string[] LocalProxies() { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); diff --git a/renderdocui/Windows/MainWindow.cs b/renderdocui/Windows/MainWindow.cs index cd3130d6b..4f5b079a8 100644 --- a/renderdocui/Windows/MainWindow.cs +++ b/renderdocui/Windows/MainWindow.cs @@ -167,6 +167,9 @@ namespace renderdocui.Windows m_Core.AddLogViewer(this); m_Core.AddLogProgressListener(this); + + m_MessageTick = new System.Threading.Timer(MessageCheck, this as object, 500, 500); + m_RemoteProbe = new System.Threading.Timer(RemoteProbe, this as object, 2500, 2500); } private void MainWindow_Load(object sender, EventArgs e) @@ -268,13 +271,38 @@ namespace renderdocui.Windows statusIcon.Image = null; statusProgress.Visible = false; - m_MessageTick.Dispose(); - m_MessageTick = null; - resolveSymbolsToolStripMenuItem.Enabled = false; resolveSymbolsToolStripMenuItem.Text = "Resolve Symbols"; SetTitle(); + + // if the remote sever disconnected during log replay, resort back to a 'disconnected' state + if (m_Core.Renderer.Remote != null && !m_Core.Renderer.Remote.ServerRunning) + { + statusText.Text = "Remote server disconnected. To attempt to reconnect please select it again."; + contextChooser.Text = "Replay Context: Local"; + m_Core.Renderer.DisconnectFromRemoteServer(); + } + } + + private static void RemoteProbe(object m) + { + if (!(m is MainWindow)) return; + + var me = (MainWindow)m; + + // perform a probe of known remote hosts to see if they're running or not + if (!me.m_Core.LogLoading && !me.m_Core.LogLoaded) + { + foreach (var host in me.m_Core.Config.RemoteHosts) + { + // don't mess with a host we're connected to - this is handled anyway + if (host.Connected) + continue; + + host.CheckStatus(); + } + } } private static void MessageCheck(object m) @@ -289,8 +317,33 @@ namespace renderdocui.Windows { DebugMessage[] msgs = r.GetDebugMessages(); + bool disconnected = false; + + if(me.m_Core.Renderer.Remote != null) + { + bool prev = me.m_Core.Renderer.Remote.ServerRunning; + + me.m_Core.Renderer.PingRemote(); + + if(prev != me.m_Core.Renderer.Remote.ServerRunning) + disconnected = true; + } + me.BeginInvoke(new Action(() => { + // if we just got disconnected while replaying a log, alert the user. + if (disconnected) + { + MessageBox.Show("Remote server disconnected during replaying of this capture.\n" + + "The replay will now be non-functional. To restore you will have to close the capture, allow\n" + + "RenderDoc to reconnect and load the capture again", + "Remote server disconnected", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + if (me.m_Core.Renderer.Remote != null && !me.m_Core.Renderer.Remote.ServerRunning) + me.contextChooser.Image = global::renderdocui.Properties.Resources.cross; + if (msgs.Length > 0) { me.m_Core.AddMessages(msgs); @@ -310,12 +363,27 @@ namespace renderdocui.Windows })); }); } + else if(!me.m_Core.LogLoaded && !me.m_Core.LogLoading) + { + if (me.m_Core.Renderer.Remote != null) + me.m_Core.Renderer.PingRemote(); - if (me == null) return; - if (me.m_MessageTick != null) me.m_MessageTick.Change(500, System.Threading.Timeout.Infinite); + me.BeginInvoke(new Action(() => + { + if (me.m_Core.Renderer.Remote != null && !me.m_Core.Renderer.Remote.ServerRunning) + { + me.contextChooser.Image = global::renderdocui.Properties.Resources.cross; + me.contextChooser.Text = "Replay Context: Local"; + me.statusText.Text = "Remote server disconnected. To attempt to reconnect please select it again."; + + me.m_Core.Renderer.DisconnectFromRemoteServer(); + } + })); + } } private System.Threading.Timer m_MessageTick = null; + private System.Threading.Timer m_RemoteProbe = null; private bool m_MessageAlternate = false; private bool LogHasErrors @@ -354,8 +422,6 @@ namespace renderdocui.Windows LogHasErrors = (m_Core.DebugMessages.Count > 0); - m_MessageTick = new System.Threading.Timer(MessageCheck, this as object, 500, System.Threading.Timeout.Infinite); - statusProgress.Visible = false; m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { @@ -1011,12 +1077,19 @@ namespace renderdocui.Windows ToolStripItem item = new ToolStripMenuItem(); - item.Image = host.ServerRunning + item.Image = host.ServerRunning && !host.VersionMismatch ? global::renderdocui.Properties.Resources.tick : global::renderdocui.Properties.Resources.cross; - item.Text = host.ServerRunning - ? String.Format("{0} (Online)", host.Hostname) - : String.Format("{0} (Offline)", host.Hostname); + if (host.Connected) + item.Text = String.Format("{0} (Connected)", host.Hostname); + else if (host.ServerRunning && host.VersionMismatch) + item.Text = String.Format("{0} (Bad Version)", host.Hostname); + else if (host.ServerRunning && host.Busy) + item.Text = String.Format("{0} (Busy)", host.Hostname); + else if (host.ServerRunning) + item.Text = String.Format("{0} (Online)", host.Hostname); + else + item.Text = String.Format("{0} (Offline)", host.Hostname); item.Click += new EventHandler(switchContext); item.Tag = host;