private void resolveSymbolsToolStripMenuItem_Click(object sender, EventArgs e) { m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { r.InitResolver(); }); ProgressPopup modal = new ProgressPopup(SymbolResolveCallback, false); modal.SetModalText("Please Wait - Resolving Symbols."); modal.ShowDialog(); m_Core.GetAPIInspector().FillCallstack(); }
public void LoadLogfile(string filename, bool temporary, bool local) { if (PromptCloseLog()) { if (m_Core.LogLoading) return; string driver = ""; string machineIdent = ""; ReplaySupport support = ReplaySupport.Unsupported; bool remoteReplay = !local || (m_Core.Renderer.Remote != null && m_Core.Renderer.Remote.Connected); if (local) { support = StaticExports.SupportLocalReplay(filename, out driver, out machineIdent); // if the return value suggests remote replay, and it's not already selected, AND the user hasn't // previously chosen to always replay locally without being prompted, ask if they'd prefer to // switch to a remote context for replaying. if (support == ReplaySupport.SuggestRemote && !remoteReplay && !m_Core.Config.AlwaysReplayLocally) { var dialog = new Dialogs.SuggestRemoteDialog(driver, machineIdent); FillRemotesToolStrip(dialog.RemoteItems, false); dialog.ShowDialog(); if (dialog.Result == Dialogs.SuggestRemoteDialog.SuggestRemoteResult.Cancel) { return; } else if (dialog.Result == Dialogs.SuggestRemoteDialog.SuggestRemoteResult.Remote) { // we only get back here from the dialog once the context switch has begun, // so contextChooser will have been disabled. // Check once to see if it's enabled before even popping up the dialog in case // it has finished already. Otherwise pop up a waiting dialog until it completes // one way or another, then process the result. if (!contextChooser.Enabled) { ProgressPopup modal = new ProgressPopup((ModalCloseCallback)delegate { return contextChooser.Enabled; }, false); modal.SetModalText("Please Wait - Checking remote connection..."); modal.ShowDialog(); } remoteReplay = (m_Core.Renderer.Remote != null && m_Core.Renderer.Remote.Connected); if (!remoteReplay) { string remoteMessage = "Failed to make a connection to the remote server.\n\n"; remoteMessage += "More information may be available in the status bar."; MessageBox.Show(remoteMessage, "Couldn't connect to remote server", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } } else { // nothing to do - we just continue replaying locally // however we need to check if the user selected 'always replay locally' and // set that bit as sticky in the config if (dialog.AlwaysReplayLocally) { m_Core.Config.AlwaysReplayLocally = true; m_Core.Config.Serialize(Core.ConfigFilename); } } } if (remoteReplay) { support = ReplaySupport.Unsupported; string[] remoteDrivers = m_Core.Renderer.GetRemoteSupport(); for (int i = 0; i < remoteDrivers.Length; i++) { if (driver == remoteDrivers[i]) support = ReplaySupport.Supported; } } } Thread thread = null; string origFilename = filename; // 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 == ReplaySupport.Unsupported) { if (remoteReplay) { string remoteMessage = String.Format("This log was captured with {0} and cannot be replayed on {1}.\n\n", driver, m_Core.Renderer.Remote.Hostname); remoteMessage += "Try selecting a different remote context in the status bar."; MessageBox.Show(remoteMessage, "Unsupported logfile type", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } else { 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 { if (remoteReplay && local) { try { filename = m_Core.Renderer.CopyCaptureToRemote(filename, this); // deliberately leave local as true so that we keep referring to the locally saved log // some error if (filename == "") throw new ApplicationException(); } catch (Exception) { MessageBox.Show("Couldn't copy " + origFilename + " to remote host for replaying", "Error copying to remote", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } thread = Helpers.NewThread(new ThreadStart(() => m_Core.LoadLogfile(filename, origFilename, temporary, local))); } thread.Start(); if(!remoteReplay) m_Core.Config.LastLogPath = Path.GetDirectoryName(filename); statusText.Text = "Loading " + origFilename + "..."; } }
// generally logFile == origFilename, but if the log was transferred remotely then origFilename // is the log locally before being copied we can present to the user in dialogs, etc. public void LoadLogfile(string logFile, string origFilename, bool temporary, bool local) { m_LogFile = origFilename; m_LogLocal = local; m_LogLoadingInProgress = true; if (File.Exists(Core.ConfigFilename)) m_Config.Serialize(Core.ConfigFilename); float postloadProgress = 0.0f; bool progressThread = true; // start a modal dialog to prevent the user interacting with the form while the log is loading. // We'll close it down when log loading finishes (whether it succeeds or fails) ProgressPopup modal = new ProgressPopup(LogLoadCallback, true); Thread modalThread = Helpers.NewThread(new ThreadStart(() => { modal.SetModalText(string.Format("Loading Log: {0}", origFilename)); AppWindow.BeginInvoke(new Action(() => { modal.ShowDialog(AppWindow); })); })); modalThread.Start(); // this thread continually ticks and notifies any threads of the progress, through a float // that is updated by the main loading code Thread thread = Helpers.NewThread(new ThreadStart(() => { modal.LogfileProgressBegin(); foreach (var p in m_ProgressListeners) p.LogfileProgressBegin(); while (progressThread) { Thread.Sleep(2); float progress = 0.8f * m_Renderer.LoadProgress + 0.19f * postloadProgress + 0.01f; modal.LogfileProgress(progress); foreach (var p in m_ProgressListeners) p.LogfileProgress(progress); } })); thread.Start(); // this function call will block until the log is either loaded, or there's some failure m_Renderer.OpenCapture(logFile); // if the renderer isn't running, we hit a failure case so display an error message if (!m_Renderer.Running) { string errmsg = m_Renderer.InitException.Status.Str(); MessageBox.Show(String.Format("{0}\nFailed to open file for replay: {1}.\n\n" + "Check diagnostic log in Help menu for more details.", origFilename, errmsg), "Error opening log", MessageBoxButtons.OK, MessageBoxIcon.Error); progressThread = false; thread.Join(); m_LogLoadingInProgress = false; modal.LogfileProgress(-1.0f); foreach (var p in m_ProgressListeners) p.LogfileProgress(-1.0f); return; } if (!temporary) { m_Config.AddRecentFile(m_Config.RecentLogFiles, origFilename, 10); if (File.Exists(Core.ConfigFilename)) m_Config.Serialize(Core.ConfigFilename); } m_EventID = 0; m_FrameInfo = null; m_APIProperties = null; // fetch initial data like drawcalls, textures and buffers m_Renderer.Invoke((ReplayRenderer r) => { m_FrameInfo = r.GetFrameInfo(); m_APIProperties = r.GetAPIProperties(); postloadProgress = 0.2f; m_DrawCalls = FakeProfileMarkers(r.GetDrawcalls()); bool valid = HasValidMarkerColors(m_DrawCalls); if (!valid) RemoveMarkerColors(m_DrawCalls); postloadProgress = 0.4f; m_Buffers = r.GetBuffers(); postloadProgress = 0.7f; var texs = new List<FetchTexture>(r.GetTextures()); m_Textures = texs.OrderBy(o => o.name).ToArray(); postloadProgress = 0.9f; m_D3D11PipelineState = r.GetD3D11PipelineState(); m_D3D12PipelineState = r.GetD3D12PipelineState(); m_GLPipelineState = r.GetGLPipelineState(); m_VulkanPipelineState = r.GetVulkanPipelineState(); m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_D3D12PipelineState, m_GLPipelineState, m_VulkanPipelineState); UnreadMessageCount = 0; AddMessages(m_FrameInfo.debugMessages); postloadProgress = 1.0f; }); Thread.Sleep(20); DateTime today = DateTime.Now; DateTime compare = today.AddDays(-21); if (compare.CompareTo(Config.DegradedLog_LastUpdate) >= 0 && m_APIProperties.degraded) { Config.DegradedLog_LastUpdate = today; MessageBox.Show(String.Format("{0}\nThis log opened with degraded support - " + "this could mean missing hardware support caused a fallback to software rendering.\n\n" + "This warning will not appear every time this happens, " + "check debug errors/warnings window for more details.", origFilename), "Degraded support of log", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } m_LogLoaded = true; progressThread = false; 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<ILogViewerForm> logviewers = new List<ILogViewerForm>(); logviewers.AddRange(m_LogViewers); // notify all the registers log viewers that a log has been loaded foreach (var logviewer in logviewers) { if (logviewer == null || !(logviewer is Control)) continue; Control c = (Control)logviewer; if (c.InvokeRequired) { if (!c.IsDisposed) { c.Invoke(new Action(() => { try { logviewer.OnLogfileLoaded(); } catch (Exception ex) { throw new AccessViolationException("Rethrown from Invoke:\n" + ex.ToString()); } })); } } else if (!c.IsDisposed) logviewer.OnLogfileLoaded(); } m_LogLoadingInProgress = false; modal.LogfileProgress(1.0f); foreach (var p in m_ProgressListeners) p.LogfileProgress(1.0f); }