diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index 464a35843..c6081a0b9 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -211,7 +211,8 @@ struct TargetControlMessage uint32_t ID; uint64_t timestamp; rdctype::array thumbnail; - rdctype::str localpath; + rdctype::str path; + bool32 local; } NewCapture; struct RegisterAPIData diff --git a/renderdoc/core/target_control.cpp b/renderdoc/core/target_control.cpp index 6811321c9..fcc92de6c 100644 --- a/renderdoc/core/target_control.cpp +++ b/renderdoc/core/target_control.cpp @@ -532,9 +532,9 @@ public: SAFE_DELETE(ser); - msg->NewCapture.localpath = m_CaptureCopies[msg->NewCapture.ID]; + msg->NewCapture.path = m_CaptureCopies[msg->NewCapture.ID]; - if(!RecvChunkedFile(m_Socket, ePacket_CopyCapture, msg->NewCapture.localpath.elems, ser, NULL)) + if(!RecvChunkedFile(m_Socket, ePacket_CopyCapture, msg->NewCapture.path.elems, ser, NULL)) { SAFE_DELETE(ser); SAFE_DELETE(m_Socket); @@ -571,10 +571,8 @@ public: string path; ser->Serialise("", path); - msg->NewCapture.localpath = path; - - if(!m_Local) - msg->NewCapture.localpath = ""; + msg->NewCapture.path = path; + msg->NewCapture.local = m_Local; uint32_t thumblen = 0; ser->Serialise("", thumblen); diff --git a/renderdocui/Code/Core.cs b/renderdocui/Code/Core.cs index 46a7f4e1d..565431bb0 100644 --- a/renderdocui/Code/Core.cs +++ b/renderdocui/Code/Core.cs @@ -451,7 +451,7 @@ namespace renderdocui.Code } } - public void LoadLogfile(string logFile, bool temporary) + public void LoadLogfile(string logFile, bool temporary, bool local) { m_LogFile = logFile; @@ -503,7 +503,7 @@ namespace renderdocui.Code thread.Start(); // this function call will block until the log is either loaded, or there's some failure - m_Renderer.Init(logFile); + m_Renderer.OpenCapture(logFile); // if the renderer isn't running, we hit a failure case so display an error message if (!m_Renderer.Running) @@ -598,12 +598,15 @@ namespace renderdocui.Code m_LogLoaded = true; progressThread = false; - m_LogWatcher = new FileSystemWatcher(Path.GetDirectoryName(m_LogFile), Path.GetFileName(m_LogFile)); - m_LogWatcher.EnableRaisingEvents = true; - m_LogWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite; - m_LogWatcher.Created += new FileSystemEventHandler(OnLogfileChanged); - m_LogWatcher.Changed += new FileSystemEventHandler(OnLogfileChanged); - m_LogWatcher.SynchronizingObject = m_MainWindow; // callbacks on UI thread please + if (local) + { + m_LogWatcher = new FileSystemWatcher(Path.GetDirectoryName(m_LogFile), Path.GetFileName(m_LogFile)); + m_LogWatcher.EnableRaisingEvents = true; + m_LogWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite; + m_LogWatcher.Created += new FileSystemEventHandler(OnLogfileChanged); + m_LogWatcher.Changed += new FileSystemEventHandler(OnLogfileChanged); + m_LogWatcher.SynchronizingObject = m_MainWindow; // callbacks on UI thread please + } List logviewers = new List(); logviewers.AddRange(m_LogViewers); diff --git a/renderdocui/Code/Helpers.cs b/renderdocui/Code/Helpers.cs index c2de04b3a..5214dccf8 100644 --- a/renderdocui/Code/Helpers.cs +++ b/renderdocui/Code/Helpers.cs @@ -117,6 +117,21 @@ namespace renderdocui.Code return (float)(0.2126 * Math.Pow(c.R * 255.0, 2.2) + 0.7152 * Math.Pow(c.G * 255.0, 2.2) + 0.0722 * Math.Pow(c.B * 255.0, 2.2)); } + public static int CharCount(string s, char c) + { + int ret = 0; + + int offs = s.IndexOf(c); + + while (offs >= 0) + { + ret++; + offs = s.IndexOf(c, offs + 1); + } + + return ret; + } + public static string SafeGetFileName(string filename) { try diff --git a/renderdocui/Code/RenderManager.cs b/renderdocui/Code/RenderManager.cs index f0ea1e457..f55b5f76b 100644 --- a/renderdocui/Code/RenderManager.cs +++ b/renderdocui/Code/RenderManager.cs @@ -77,7 +77,7 @@ namespace renderdocui.Code m_renderQueue = new List(); } - public void Init(string logfile) + public void OpenCapture(string logfile) { if(Running) return; @@ -95,6 +95,47 @@ namespace renderdocui.Code while (m_Thread.IsAlive && !Running) ; } + public UInt32 ExecuteAndInject(string app, string workingDir, string cmdLine, string logfile, CaptureOptions opts) + { + if (m_Remote == null) + { + return StaticExports.ExecuteAndInject(app, workingDir, cmdLine, logfile, opts); + } + else + { + return m_Remote.ExecuteAndInject(app, workingDir, cmdLine, opts); + } + } + + public bool IsRemoteConnected + { + get + { + return m_Remote != null; + } + } + + public void DeleteCapture(string logfile, bool local) + { + if (Running) + { + BeginInvoke((ReplayRenderer r) => { DeleteCapture(logfile, local); }); + return; + } + + if (local) + { + System.IO.File.Delete(logfile); + } + else + { + // this will be cleaned up automatically when the remote connection + // is closed. + if (m_Remote != null) + m_Remote.TakeOwnershipCapture(logfile); + } + } + public bool Running { get { return m_Running; } diff --git a/renderdocui/Interop/ReplayRenderer.cs b/renderdocui/Interop/ReplayRenderer.cs index c0470b05e..fde2b5730 100644 --- a/renderdocui/Interop/ReplayRenderer.cs +++ b/renderdocui/Interop/ReplayRenderer.cs @@ -42,7 +42,8 @@ namespace renderdoc [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] public byte[] thumbnail; [CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)] - public string localpath; + public string path; + public bool local; }; [CustomMarshalAs(CustomUnmanagedType.CustomClass)] public NewCaptureData NewCapture; @@ -1119,7 +1120,7 @@ namespace renderdoc else if (msg.Type == TargetControlMessageType.CaptureCopied) { CaptureFile.ID = msg.NewCapture.ID; - CaptureFile.localpath = msg.NewCapture.localpath; + CaptureFile.path = msg.NewCapture.path; CaptureCopied = true; } else if (msg.Type == TargetControlMessageType.RegisterAPI) diff --git a/renderdocui/Windows/Dialogs/CaptureDialog.cs b/renderdocui/Windows/Dialogs/CaptureDialog.cs index 5fb236c28..66b10790b 100644 --- a/renderdocui/Windows/Dialogs/CaptureDialog.cs +++ b/renderdocui/Windows/Dialogs/CaptureDialog.cs @@ -268,10 +268,15 @@ namespace renderdocui.Windows.Dialogs private void OnCapture() { string exe = exePath.Text; - if (!File.Exists(exe)) + + // for non-remote captures, check the executable locally + if (!m_Core.Renderer.IsRemoteConnected) { - MessageBox.Show("Invalid application executable: " + exe, "Invalid executable", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; + if (!File.Exists(exe)) + { + MessageBox.Show("Invalid application executable: " + exe, "Invalid executable", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } } string workingDir = ""; @@ -304,9 +309,6 @@ namespace renderdocui.Windows.Dialogs private void TriggerCapture() { - //(new LiveCapture()).Show(DockPanel); - //return; - if(InjectMode && m_InjectCallback != null) OnInject(); @@ -538,6 +540,12 @@ namespace renderdocui.Windows.Dialogs { // invalid path or similar } + + // if it's a unix style path, maintain the slash type + if (Helpers.CharCount(exePath.Text, '/') > Helpers.CharCount(exePath.Text, '\\')) + { + workDirPath.Text.Replace('\\', '/'); + } } public void UpdateGlobalHook() diff --git a/renderdocui/Windows/Dialogs/LiveCapture.cs b/renderdocui/Windows/Dialogs/LiveCapture.cs index 2333923d3..486008cd3 100644 --- a/renderdocui/Windows/Dialogs/LiveCapture.cs +++ b/renderdocui/Windows/Dialogs/LiveCapture.cs @@ -72,11 +72,11 @@ namespace renderdocui.Windows public string api; public DateTime timestamp; - public bool copying; public bool saved; public bool opened; - public string localpath; + public string path; + public bool local; }; class ChildProcess @@ -214,33 +214,20 @@ namespace renderdocui.Windows DateTime timestamp = new DateTime(1970, 1, 1, 0, 0, 0); timestamp = timestamp.AddSeconds(m_Connection.CaptureFile.timestamp).ToLocalTime(); byte[] thumb = m_Connection.CaptureFile.thumbnail; - string path = m_Connection.CaptureFile.localpath; + string path = m_Connection.CaptureFile.path; + bool local = m_Connection.CaptureFile.local; - if (path.Length == 0 || File.Exists(path)) + this.BeginInvoke((MethodInvoker)delegate { - this.BeginInvoke((MethodInvoker)delegate - { - CaptureAdded(capID, m_Connection.Target, m_Connection.API, thumb, timestamp); - if (path.Length > 0) - CaptureRetrieved(capID, path); - }); - m_Connection.CaptureExists = false; - - if (path.Length == 0) - m_Connection.CopyCapture(capID, m_Core.TempLogFilename("remotecopy_" + m_Connection.Target)); - } + CaptureAdded(capID, m_Connection.Target, m_Connection.API, thumb, timestamp, path, local); + }); + m_Connection.CaptureExists = false; } if (m_Connection.CaptureCopied) { uint capID = m_Connection.CaptureFile.ID; - string path = m_Connection.CaptureFile.localpath; - - this.BeginInvoke((MethodInvoker)delegate - { - CaptureRetrieved(capID, path); - }); - m_Connection.CaptureCopied = false; + string path = m_Connection.CaptureFile.path; } if (m_Connection.ChildAdded) @@ -347,21 +334,8 @@ namespace renderdocui.Windows openMenu.Enabled = openThisCaptureToolStripMenuItem.Enabled = (captures.SelectedItems.Count == 1); - if (captures.SelectedItems.Count > 0) - { - foreach(ListViewItem i in captures.SelectedItems) - { - var log = i.Tag as CaptureLog; - - if (log.copying) - { - deleteMenu.Enabled = - saveMenu.Enabled = saveThisCaptureToolStripMenuItem.Enabled = - openMenu.Enabled = openThisCaptureToolStripMenuItem.Enabled = false; - return; - } - } - } + if(captures.SelectedItems.Count == 1) + newInstanceToolStripMenuItem.Enabled = (captures.SelectedItems[0].Tag as CaptureLog).local; } private void captures_MouseDoubleClick(object sender, MouseEventArgs e) @@ -378,27 +352,30 @@ namespace renderdocui.Windows private void OpenCapture(CaptureLog log) { - if (!log.copying) - { - m_Main.LoadLogfile(log.localpath, !log.saved); - log.opened = true; - } + m_Main.LoadLogfile(log.path, !log.saved, log.local); + log.opened = true; } private bool SaveCapture(CaptureLog log) { - if (log.copying) return false; - string path = m_Main.GetSavePath(); // we copy the temp log to the desired path, but the log item remains referring to the temp path. // This ensures that if the user deletes the saved path we can still open or re-save it. if (path.Length > 0) { + string localpath = log.path; + + if (!log.local) + { + // copy locally first + } + try { - File.Copy(log.localpath, path, true); + File.Copy(localpath, path, true); log.saved = true; + log.path = localpath; m_Core.Config.AddRecentFile(m_Core.Config.RecentLogFiles, path, 10); m_Main.PopulateRecentFiles(); } @@ -463,10 +440,14 @@ namespace renderdocui.Windows { try { - if (log.localpath == m_Core.LogFileName) + if (log.path == m_Core.LogFileName) + { m_Main.OwnTemporaryLog = true; + } else - File.Delete(log.localpath); + { + m_Core.Renderer.DeleteCapture(log.path, log.local); + } } catch (System.Exception) { @@ -542,15 +523,15 @@ namespace renderdocui.Windows if (!log.saved) { - if (log.localpath == m_Core.LogFileName) + if (log.path == m_Core.LogFileName) { - m_Main.OwnTemporaryLog = false; + m_Main.OwnTemporaryLog = true; m_Main.CloseLogfile(); } try { - File.Delete(log.localpath); + m_Core.Renderer.DeleteCapture(log.path, log.local); } catch (System.Exception) { @@ -575,9 +556,16 @@ namespace renderdocui.Windows var temppath = m_Core.TempLogFilename(log.exe); + if (!log.local) + { + MessageBox.Show("Can't open log in new instance with remote server in use", "Cannot open new instance", + MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + try { - File.Copy(log.localpath, temppath); + File.Copy(log.path, temppath); } catch (System.Exception ex) { @@ -616,7 +604,7 @@ namespace renderdocui.Windows } } - private void CaptureAdded(uint ID, string executable, string api, byte[] thumbnail, DateTime timestamp) + private void CaptureAdded(uint ID, string executable, string api, byte[] thumbnail, DateTime timestamp, string path, bool local) { if (thumbnail == null || thumbnail.Length == 0) { @@ -639,32 +627,22 @@ namespace renderdocui.Windows log.exe = executable; log.api = api; log.timestamp = timestamp; - log.copying = true; log.saved = false; + log.path = path; + log.local = local; - var item = new ListViewItem(new string[] { log.exe + " (Copying)", log.api, log.timestamp.ToString() }, thumbs.Images.Count - 1); + string title = log.exe; + if (!local) + title += " (Remote)"; + + var item = new ListViewItem(new string[] { title, log.api, log.timestamp.ToString() }, thumbs.Images.Count - 1); item.Tag = log; - item.SubItems[0].Font = new Font(item.SubItems[0].Font, FontStyle.Italic); + if(!local) + item.SubItems[0].Font = new Font(item.SubItems[0].Font, FontStyle.Italic); captures.Items.Add(item); } - private void CaptureRetrieved(uint ID, string localpath) - { - foreach (ListViewItem i in captures.Items) - { - var log = i.Tag as CaptureLog; - - if (log.remoteID == ID && log.copying) - { - log.copying = false; - log.localpath = localpath; - i.SubItems[0].Text = log.exe; - i.SubItems[0].Font = new Font(i.SubItems[0].Font, FontStyle.Regular); - } - } - } - private void ConnectionClosed() { if (m_IgnoreThreadClosed) return; diff --git a/renderdocui/Windows/MainWindow.cs b/renderdocui/Windows/MainWindow.cs index be92ef3f2..e7530cc86 100644 --- a/renderdocui/Windows/MainWindow.cs +++ b/renderdocui/Windows/MainWindow.cs @@ -613,36 +613,43 @@ namespace renderdocui.Windows #region Capture & Log Loading - private void LoadLogAsync(string filename, bool temporary) + public void LoadLogfile(string filename, bool temporary, bool local) { - if (m_Core.LogLoading) return; - - string driver = ""; - bool support = StaticExports.SupportLocalReplay(filename, out driver); - - Thread thread = null; - - // if driver is empty something went wrong loading the log, let it be handled as usual - // below. Otherwise indicate that support is missing. - if (driver.Length > 0 && !support) + if (PromptCloseLog()) { - string remoteMessage = String.Format("This log was captured with {0} and cannot be replayed locally.\n\n", driver); + if (m_Core.LogLoading) return; - remoteMessage += "Try selecting a remote context in the status bar."; + string driver = ""; + bool support = false; - MessageBox.Show(remoteMessage, "Unsupported logfile type", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); - return; + if (local) + support = StaticExports.SupportLocalReplay(filename, out driver); + + Thread thread = null; + + // if driver is empty something went wrong loading the log, let it be handled as usual + // below. Otherwise indicate that support is missing. + if (driver.Length > 0 && !support && local) + { + string remoteMessage = String.Format("This log was captured with {0} and cannot be replayed locally.\n\n", driver); + + remoteMessage += "Try selecting a remote context in the status bar."; + + MessageBox.Show(remoteMessage, "Unsupported logfile type", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + else + { + thread = Helpers.NewThread(new ThreadStart(() => m_Core.LoadLogfile(filename, temporary, local))); + } + + thread.Start(); + + if(local) + m_Core.Config.LastLogPath = Path.GetDirectoryName(filename); + + statusText.Text = "Loading " + filename + "..."; } - else - { - thread = Helpers.NewThread(new ThreadStart(() => m_Core.LoadLogfile(filename, temporary))); - } - - thread.Start(); - - m_Core.Config.LastLogPath = Path.GetDirectoryName(filename); - - statusText.Text = "Loading " + filename + "..."; } public void PopulateRecentFiles() @@ -713,12 +720,6 @@ namespace renderdocui.Windows m_LiveCaptures.Remove(live); } - public void LoadLogfile(string fn, bool temporary) - { - if (PromptCloseLog()) - LoadLogAsync(fn, temporary); - } - private void OpenCaptureConfigFile(String filename, bool exe) { if (m_Core.CaptureDialog == null) @@ -744,7 +745,7 @@ namespace renderdocui.Windows { if (Path.GetExtension(filename) == ".rdc") { - LoadLogfile(filename, false); + LoadLogfile(filename, false, true); } else if (Path.GetExtension(filename) == ".cap") { @@ -757,7 +758,7 @@ namespace renderdocui.Windows else { // not a recognised filetype, see if we can load it anyway - LoadLogfile(filename, false); + LoadLogfile(filename, false, true); } } @@ -785,7 +786,7 @@ namespace renderdocui.Windows string logfile = m_Core.TempLogFilename(Path.GetFileNameWithoutExtension(exe)); - UInt32 ret = StaticExports.ExecuteAndInject(exe, workingDir, cmdLine, logfile, opts); + UInt32 ret = m_Core.Renderer.ExecuteAndInject(exe, workingDir, cmdLine, logfile, opts); if (ret == 0) { @@ -794,7 +795,7 @@ namespace renderdocui.Windows return null; } - var live = new LiveCapture(m_Core, "", ret, this); + var live = new LiveCapture(m_Core, m_RemoteHost == null ? "" : m_RemoteHost.Hostname, ret, this); ShowLiveCapture(live); return live; } @@ -920,6 +921,8 @@ namespace renderdocui.Windows m_Core.Renderer.DisconnectFromRemoteServer(); + injectIntoProcessToolStripMenuItem.Enabled = true; + m_RemoteHost = null; statusText.Text = ""; @@ -937,6 +940,8 @@ namespace renderdocui.Windows // disable until checking is done contextChooser.Enabled = false; + injectIntoProcessToolStripMenuItem.Enabled = false; + m_RemoteHost = host; SetTitle(); @@ -1425,7 +1430,7 @@ namespace renderdocui.Windows if(File.Exists(filename)) { - LoadLogfile(filename, false); + LoadLogfile(filename, false, true); } else {