From a35c88e57703b5c357d8c00f9f66ad7ee40600d4 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 30 Aug 2016 11:55:36 +0200 Subject: [PATCH] Close some minor UX holes when live-connected but without replay context * If there's no replay context we can still use the live connection to copy and delete captures remotely. Try to use that whenever possible and warn the user when it's not possible (i.e if the program has been closed and there's no replay context, we have no way to access the files anymore). * If the user tries to open a remote log without a replay context, prompt them either to swithc to a replay context on that host or to save the log locally. --- renderdoc/api/replay/renderdoc_replay.h | 3 + renderdoc/core/target_control.cpp | 28 ++++++ renderdocui/Interop/ReplayRenderer.cs | 7 ++ renderdocui/Windows/Dialogs/LiveCapture.cs | 112 +++++++++++++++++++-- 4 files changed, 143 insertions(+), 7 deletions(-) diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index 8d6d66eda..aa3529ae4 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -435,6 +435,7 @@ struct ITargetControl virtual void TriggerCapture(uint32_t numFrames) = 0; virtual void QueueCapture(uint32_t frameNumber) = 0; virtual void CopyCapture(uint32_t remoteID, const char *localpath) = 0; + virtual void DeleteCapture(uint32_t remoteID) = 0; virtual void ReceiveMessage(TargetControlMessage *msg) = 0; }; @@ -467,6 +468,8 @@ extern "C" RENDERDOC_API void RENDERDOC_CC TargetControl_QueueCapture(TargetCont extern "C" RENDERDOC_API void RENDERDOC_CC TargetControl_CopyCapture(TargetControl *control, uint32_t remoteID, const char *localpath); +extern "C" RENDERDOC_API void RENDERDOC_CC TargetControl_DeleteCapture(TargetControl *control, + uint32_t remoteID); extern "C" RENDERDOC_API void RENDERDOC_CC TargetControl_ReceiveMessage(TargetControl *control, TargetControlMessage *msg); diff --git a/renderdoc/core/target_control.cpp b/renderdoc/core/target_control.cpp index c71845ddd..0eb7c9467 100644 --- a/renderdoc/core/target_control.cpp +++ b/renderdoc/core/target_control.cpp @@ -39,6 +39,7 @@ enum PacketType ePacket_RegisterAPI, ePacket_TriggerCapture, ePacket_CopyCapture, + ePacket_DeleteCapture, ePacket_QueueCapture, ePacket_NewChild, }; @@ -177,6 +178,14 @@ void RenderDoc::TargetControlClientThread(void *s) RenderDoc::Inst().QueueCapture(frameNum); } + else if(type == ePacket_DeleteCapture) + { + uint32_t id = 0; + recvser->Serialise("", id); + + // this means it will be deleted on shutdown + RenderDoc::Inst().MarkCaptureRetrieved(id); + } else if(type == ePacket_CopyCapture) { caps = RenderDoc::Inst().GetCaptures(); @@ -465,6 +474,19 @@ public: m_CaptureCopies[remoteID] = localpath; } + void DeleteCapture(uint32_t remoteID) + { + Serialiser ser("", Serialiser::WRITING, false); + + ser.Serialise("", remoteID); + + if(!SendPacket(m_Socket, ePacket_DeleteCapture, ser)) + { + SAFE_DELETE(m_Socket); + return; + } + } + void ReceiveMessage(TargetControlMessage *msg) { if(m_Socket == NULL) @@ -664,6 +686,12 @@ extern "C" RENDERDOC_API void RENDERDOC_CC TargetControl_CopyCapture(TargetContr control->CopyCapture(remoteID, localpath); } +extern "C" RENDERDOC_API void RENDERDOC_CC TargetControl_DeleteCapture(TargetControl *control, + uint32_t remoteID) +{ + control->DeleteCapture(remoteID); +} + extern "C" RENDERDOC_API void RENDERDOC_CC TargetControl_ReceiveMessage(TargetControl *control, TargetControlMessage *msg) { diff --git a/renderdocui/Interop/ReplayRenderer.cs b/renderdocui/Interop/ReplayRenderer.cs index 4ae68f1d0..0b0ea71b5 100644 --- a/renderdocui/Interop/ReplayRenderer.cs +++ b/renderdocui/Interop/ReplayRenderer.cs @@ -1135,6 +1135,8 @@ namespace renderdoc private static extern void TargetControl_QueueCapture(IntPtr real, UInt32 frameNumber); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void TargetControl_CopyCapture(IntPtr real, UInt32 remoteID, IntPtr localpath); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void TargetControl_DeleteCapture(IntPtr real, UInt32 remoteID); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern void TargetControl_ReceiveMessage(IntPtr real, IntPtr outmsg); @@ -1213,6 +1215,11 @@ namespace renderdoc CustomMarshal.Free(localpath_mem); } + public void DeleteCapture(UInt32 id) + { + TargetControl_DeleteCapture(m_Real, id); + } + public void ReceiveMessage() { if (m_Real != IntPtr.Zero) diff --git a/renderdocui/Windows/Dialogs/LiveCapture.cs b/renderdocui/Windows/Dialogs/LiveCapture.cs index f1c585b4d..4cc726d25 100644 --- a/renderdocui/Windows/Dialogs/LiveCapture.cs +++ b/renderdocui/Windows/Dialogs/LiveCapture.cs @@ -60,6 +60,10 @@ namespace renderdocui.Windows bool m_Disconnect = false; TargetControl m_Connection = null; + uint m_CopyLogID = uint.MaxValue; + string m_CopyLogLocalPath = ""; + List m_DeleteLogs = new List(); + bool m_IgnoreThreadClosed = false; string m_Host; @@ -197,6 +201,23 @@ namespace renderdocui.Windows m_CaptureFrameNum = 0; } + if (m_CopyLogLocalPath != "") + { + m_Connection.CopyCapture(m_CopyLogID, m_CopyLogLocalPath); + m_CopyLogLocalPath = ""; + m_CopyLogID = uint.MaxValue; + } + + List dels = new List(); + lock (m_DeleteLogs) + { + dels.AddRange(m_DeleteLogs); + m_DeleteLogs.Clear(); + } + + foreach(var del in dels) + m_Connection.DeleteCapture(del); + if (m_Disconnect) { m_Connection.Shutdown(); @@ -236,6 +257,13 @@ namespace renderdocui.Windows { uint capID = m_Connection.CaptureFile.ID; string path = m_Connection.CaptureFile.path; + + this.BeginInvoke((MethodInvoker)delegate + { + CaptureCopied(capID, path); + }); + + m_Connection.CaptureCopied = false; } if (m_Connection.ChildAdded) @@ -363,8 +391,22 @@ namespace renderdocui.Windows private void OpenCapture(CaptureLog log) { - m_Main.LoadLogfile(log.path, !log.saved, log.local); log.opened = true; + + if (!log.local && + (m_Core.Renderer.Remote == null || + m_Core.Renderer.Remote.Hostname != m_Host || + !m_Core.Renderer.Remote.Connected) + ) + { + MessageBox.Show( + String.Format("This capture is on remote host {0} and there is no active replay context on that host.\n" + + "You can either save the log locally, or switch to a replay context on {0}.\n\n", m_Host), + "No active replay context", MessageBoxButtons.OK); + return; + } + + m_Main.LoadLogfile(log.path, !log.saved, log.local); } private bool SaveCapture(CaptureLog log) @@ -381,8 +423,25 @@ namespace renderdocui.Windows { File.Copy(log.path, path, true); } + else if (m_Connection.Connected) + { + // if we have a current live connection, prefer using it + m_CopyLogLocalPath = path; + m_CopyLogID = log.remoteID; + } else { + if (m_Core.Renderer.Remote == null || + m_Core.Renderer.Remote.Hostname != m_Host || + !m_Core.Renderer.Remote.Connected) + { + MessageBox.Show( + String.Format("This capture is on remote host {0} and there is no active replay context on that host.\n" + + "Without an active replay context the capture cannot be saved, try switching to a replay context on {0}.\n\n", m_Host), + "No active replay context", MessageBoxButtons.OK); + return false; + } + m_Core.Renderer.CopyCaptureFromRemote(log.path, path, this); m_Core.Renderer.DeleteCapture(log.path, false); } @@ -435,15 +494,15 @@ namespace renderdocui.Windows } // we either have to save or delete the log. Make sure that if it's remote that we are able - // to by having an active replay context on that host. - if (suppressRemoteWarning == false && + // to by having an active connection or replay context on that host. + if (suppressRemoteWarning == false && !m_Connection.Connected && (m_Core.Renderer.Remote == null || m_Core.Renderer.Remote.Hostname != m_Host || !m_Core.Renderer.Remote.Connected) ) { DialogResult res2 = MessageBox.Show( - String.Format("This connection is to a remote host {0} and there is no active replay context on that host.\n", m_Host) + + String.Format("This capture is on remote host {0} and there is no active replay context on that host.\n", m_Host) + "Without an active replay context the capture cannot be " + (res == DialogResult.Yes ? "saved.\n\n" : "deleted.\n\n") + "Would you like to continue and discard this capture and any others, to be left in the temporary folder on the remote machine?", "No active replay context", MessageBoxButtons.YesNoCancel); @@ -492,7 +551,18 @@ namespace renderdocui.Windows } else { - m_Core.Renderer.DeleteCapture(log.path, log.local); + // if connected, prefer using the live connection + if (m_Connection.Connected && !log.local) + { + lock (m_DeleteLogs) + { + m_DeleteLogs.Add(log.remoteID); + } + } + else + { + m_Core.Renderer.DeleteCapture(log.path, log.local); + } } } catch (System.Exception) @@ -512,6 +582,7 @@ namespace renderdocui.Windows return; } + CleanItems(); KillThread(); } @@ -532,8 +603,8 @@ namespace renderdocui.Windows captures.LargeImageList.Images.Clear(); thumbs.Dispose(); - KillThread(); CleanItems(); + KillThread(); } private bool CheckAllowDelete() @@ -577,7 +648,18 @@ namespace renderdocui.Windows try { - m_Core.Renderer.DeleteCapture(log.path, log.local); + // if connected, prefer using the live connection + if (m_Connection.Connected && !log.local) + { + lock (m_DeleteLogs) + { + m_DeleteLogs.Add(log.remoteID); + } + } + else + { + m_Core.Renderer.DeleteCapture(log.path, log.local); + } } catch (System.Exception) { @@ -650,6 +732,22 @@ namespace renderdocui.Windows } } + private void CaptureCopied(uint ID, string localPath) + { + foreach (ListViewItem item in captures.Items) + { + var log = item.Tag as CaptureLog; + + if (log != null && log.remoteID == ID) + { + log.local = true; + log.path = localPath; + item.SubItems[0].Text = log.exe; + item.SubItems[0].Font = new Font(item.SubItems[0].Font, FontStyle.Regular); + } + } + } + private void CaptureAdded(uint ID, string executable, string api, byte[] thumbnail, DateTime timestamp, string path, bool local) { if (thumbnail == null || thumbnail.Length == 0)