Add a menu item to do nothing but replay the capture in a tight loop.

This commit is contained in:
baldurk
2017-07-27 15:18:54 +01:00
parent 2e8f559f51
commit 806876c540
13 changed files with 306 additions and 28 deletions
+3
View File
@@ -606,6 +606,9 @@ struct IReplayManager
DOCUMENT("Ping the remote server to ensure the connection is still alive.");
virtual void PingRemote() = 0;
DOCUMENT("Cancels the active replay loop. See :meth:`~renderdoc.ReplayController.ReplayLoop`.");
virtual void CancelReplayLoop() = 0;
DOCUMENT(R"(Retrieves the host that the manager is currently connected to.
:return: The host connected to, or ``None`` if no connection is active.
+12 -7
View File
@@ -274,6 +274,11 @@ void ReplayManager::BlockInvoke(ReplayManager::InvokeCallback m)
delete cmd;
}
void ReplayManager::CancelReplayLoop()
{
m_Renderer->CancelReplayLoop();
}
void ReplayManager::CloseThread()
{
m_Running = false;
@@ -393,11 +398,11 @@ void ReplayManager::PushInvoke(ReplayManager::InvokeHandle *cmd)
void ReplayManager::run()
{
IReplayController *renderer = NULL;
m_Renderer = NULL;
if(m_Remote)
{
std::tie(m_CreateStatus, renderer) =
std::tie(m_CreateStatus, m_Renderer) =
m_Remote->OpenCapture(~0U, m_Logfile.toUtf8().data(), m_Progress);
}
else
@@ -407,12 +412,12 @@ void ReplayManager::run()
m_CreateStatus = file->OpenStatus();
if(m_CreateStatus == ReplayStatus::Succeeded)
std::tie(m_CreateStatus, renderer) = file->OpenCapture(m_Progress);
std::tie(m_CreateStatus, m_Renderer) = file->OpenCapture(m_Progress);
file->Shutdown();
}
if(renderer == NULL)
if(m_Renderer == NULL)
return;
qInfo() << "QRenderDoc - renderer created for" << m_Logfile;
@@ -439,7 +444,7 @@ void ReplayManager::run()
continue;
if(cmd->method != NULL)
cmd->method(renderer);
cmd->method(m_Renderer);
// if it's a throwaway command, delete it
if(cmd->selfdelete)
@@ -471,7 +476,7 @@ void ReplayManager::run()
// close the core renderer
if(m_Remote)
m_Remote->CloseCapture(renderer);
m_Remote->CloseCapture(m_Renderer);
else
renderer->Shutdown();
m_Renderer->Shutdown();
}
+4
View File
@@ -67,6 +67,8 @@ public:
void AsyncInvoke(InvokeCallback m);
void BlockInvoke(InvokeCallback m);
void CancelReplayLoop();
void CloseThread();
ReplayStatus ConnectToRemoteServer(RemoteHost *host);
@@ -107,6 +109,8 @@ private:
QQueue<InvokeHandle *> m_RenderQueue;
QWaitCondition m_RenderCondition;
IReplayController *m_Renderer = NULL;
void PushInvoke(InvokeHandle *cmd);
int m_ProxyRenderer;
+65
View File
@@ -165,6 +165,7 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
return m_Ctx.CreateBuiltinWindow(objectName);
});
ui->action_Start_Replay_Loop->setEnabled(false);
ui->action_Resolve_Symbols->setEnabled(false);
ui->action_Resolve_Symbols->setText(tr("Resolve Symbols"));
@@ -1246,6 +1247,8 @@ void MainWindow::OnLogfileLoaded()
statusProgress->setVisible(false);
ui->action_Start_Replay_Loop->setEnabled(true);
setLogHasErrors(!m_Ctx.DebugMessages().empty());
m_Ctx.Replay().AsyncInvoke([this](IReplayController *r) {
@@ -1272,6 +1275,8 @@ void MainWindow::OnLogfileClosed()
ui->action_Save_Log->setEnabled(false);
ui->action_Close_Log->setEnabled(false);
ui->action_Start_Replay_Loop->setEnabled(false);
contextChooser->setEnabled(true);
statusText->setText(QString());
@@ -1523,6 +1528,66 @@ void MainWindow::on_action_Resolve_Symbols_triggered()
m_Ctx.GetAPIInspector()->Refresh();
}
void MainWindow::on_action_Start_Replay_Loop_triggered()
{
if(!m_Ctx.LogLoaded())
return;
QDialog popup;
popup.setWindowFlags(popup.windowFlags() & ~Qt::WindowContextHelpButtonHint);
popup.setWindowIcon(windowIcon());
const TextureDescription *displayTex = NULL;
const DrawcallDescription *lastDraw = m_Ctx.GetLastDrawcall();
displayTex = m_Ctx.GetTexture(lastDraw->copyDestination);
if(!displayTex)
displayTex = m_Ctx.GetTexture(lastDraw->outputs[0]);
if(!displayTex)
{
// if no texture was bound, then use the first colour swapbuffer
for(const TextureDescription &tex : m_Ctx.GetTextures())
{
if((tex.creationFlags & TextureCategory::SwapBuffer) &&
tex.format.compType != CompType::Depth && tex.format.specialFormat != SpecialFormat::D16S8 &&
tex.format.specialFormat != SpecialFormat::D24S8 &&
tex.format.specialFormat != SpecialFormat::D32S8)
{
displayTex = &tex;
break;
}
}
}
ResourceId id;
if(displayTex)
{
id = displayTex->ID;
popup.resize((int)displayTex->width, (int)displayTex->height);
popup.setWindowTitle(
tr("Looping replay of %1 Displaying %2").arg(m_Ctx.LogFilename()).arg(ToQStr(displayTex->name)));
}
else
{
popup.resize(100, 100);
popup.setWindowTitle(
tr("Looping replay of %1 Displaying %2").arg(m_Ctx.LogFilename()).arg(tr("nothing")));
}
WindowingSystem winSys = m_Ctx.CurWindowingSystem();
void *winData = m_Ctx.FillWindowingData(popup.winId());
m_Ctx.Replay().AsyncInvoke(
[winSys, winData, id](IReplayController *r) { r->ReplayLoop(winSys, winData, id); });
RDDialog::show(&popup);
m_Ctx.Replay().CancelReplayLoop();
}
void MainWindow::on_action_Attach_to_Running_Instance_triggered()
{
on_action_Manage_Remote_Servers_triggered();
+1
View File
@@ -113,6 +113,7 @@ private slots:
void on_action_Python_Shell_triggered();
void on_action_Inject_into_Process_triggered();
void on_action_Resolve_Symbols_triggered();
void on_action_Start_Replay_Loop_triggered();
void on_action_Attach_to_Running_Instance_triggered();
void on_action_Manage_Remote_Servers_triggered();
void on_action_Settings_triggered();
+8 -1
View File
@@ -42,7 +42,7 @@
<x>0</x>
<y>0</y>
<width>1200</width>
<height>26</height>
<height>18</height>
</rect>
</property>
<widget class="QMenu" name="menu_Tools">
@@ -50,9 +50,11 @@
<string>&amp;Tools</string>
</property>
<addaction name="action_Resolve_Symbols"/>
<addaction name="action_Start_Replay_Loop"/>
<addaction name="separator"/>
<addaction name="action_Settings"/>
<addaction name="action_Manage_Remote_Servers"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menu_File">
<property name="title">
@@ -398,6 +400,11 @@
<string>&amp;Launch Application</string>
</property>
</action>
<action name="action_Start_Replay_Loop">
<property name="text">
<string>Start Replay &amp;Loop</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
+16
View File
@@ -444,6 +444,22 @@ struct IReplayController
)");
virtual void ShutdownOutput(IReplayOutput *output) = 0;
DOCUMENT(R"(Goes into a blocking loop, repeatedly replaying the open capture as fast as possible,
displaying the selected texture in a default unscaled manner to the given output window.
The function won't return until :meth:`CancelLoop` is called. Since this function is blocking, that
function must be called from another thread.
:param WindowingSystem system: The type of native window handle data being provided
:param data: The native window data, in a format defined by the system
:type data: opaque void * pointer
:param ResourceId texid: The id of the texture to display.
)");
virtual void ReplayLoop(WindowingSystem system, void *data, ResourceId texid) = 0;
DOCUMENT("Cancels a replay loop begun in :meth:`ReplayLoop`. Does nothing if no loop is active.");
virtual void CancelReplayLoop() = 0;
DOCUMENT("Notify the interface that the file it has open has been changed on disk.");
virtual void FileChanged() = 0;
+64
View File
@@ -1398,6 +1398,58 @@ rdctype::array<WindowingSystem> ReplayController::GetSupportedWindowSystems()
return m_pDevice->GetSupportedWindowSystems();
}
void ReplayController::ReplayLoop(WindowingSystem system, void *data, ResourceId texid)
{
ReplayOutput *output = CreateOutput(system, data, ReplayOutputType::Texture);
TextureDisplay d;
d.texid = texid;
d.mip = 0;
d.sampleIdx = ~0U;
d.overlay = DebugOverlay::NoOverlay;
d.typeHint = CompType::Typeless;
d.HDRMul = -1.0f;
d.linearDisplayAsGamma = true;
d.FlipY = false;
d.rangemin = 0.0f;
d.rangemax = 1.0f;
d.scale = 1.0f;
d.offx = 0.0f;
d.offy = 0.0f;
d.sliceFace = 0;
d.rawoutput = false;
d.Red = d.Green = d.Blue = true;
d.Alpha = false;
output->SetTextureDisplay(d);
m_ReplayLoopCancel = 0;
m_ReplayLoopFinished = 0;
while(Atomic::CmpExch32(&m_ReplayLoopCancel, 0, 0) == 0)
{
m_pDevice->ReplayLog(10000000, eReplay_Full);
output->Display();
}
// restore back to where we were
m_pDevice->ReplayLog(m_EventID, eReplay_Full);
ShutdownOutput(output);
// mark that the loop is finished
Atomic::Inc32(&m_ReplayLoopFinished);
}
void ReplayController::CancelReplayLoop()
{
Atomic::Inc32(&m_ReplayLoopCancel);
// wait for it to actually finish before returning
while(Atomic::CmpExch32(&m_ReplayLoopFinished, 0, 0) == 0)
Threading::Sleep(1);
}
ReplayOutput *ReplayController::CreateOutput(WindowingSystem system, void *data, ReplayOutputType type)
{
ReplayOutput *out = new ReplayOutput(this, system, data, type);
@@ -1672,6 +1724,18 @@ extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ShutdownOutput(IReplay
rend->ShutdownOutput(output);
}
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_ReplayLoop(IReplayController *rend,
WindowingSystem system,
void *data, ResourceId texid)
{
rend->ReplayLoop(system, data, texid);
}
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_CancelReplayLoop(IReplayController *rend)
{
rend->CancelReplayLoop();
}
extern "C" RENDERDOC_API void RENDERDOC_CC ReplayRenderer_FileChanged(IReplayController *rend)
{
rend->FileChanged();
+6
View File
@@ -191,6 +191,9 @@ public:
rdctype::array<WindowingSystem> GetSupportedWindowSystems();
void ReplayLoop(WindowingSystem system, void *data, ResourceId texid);
void CancelReplayLoop();
ReplayOutput *CreateOutput(WindowingSystem, void *data, ReplayOutputType type);
void ShutdownOutput(IReplayOutput *output);
@@ -205,6 +208,9 @@ private:
FrameRecord m_FrameRecord;
vector<DrawcallDescription *> m_Drawcalls;
volatile int32_t m_ReplayLoopCancel = 0;
volatile int32_t m_ReplayLoopFinished = 0;
uint32_t m_EventID;
D3D11Pipe::State m_D3D11PipelineState;
+15 -5
View File
@@ -410,6 +410,14 @@ namespace renderdocui.Code
}
}
public void CancelReplayLoop()
{
if (m_Thread == null || !Running)
return;
m_Renderer.CancelReplayLoop();
}
public ReplayCreateException InitException = null;
public void CloseThreadSync()
@@ -608,12 +616,14 @@ namespace renderdocui.Code
renderer.Shutdown();
}
private ReplayRenderer m_Renderer;
private void RunThread()
{
try
{
ReplayRenderer renderer = CreateReplayRenderer();
if(renderer != null)
m_Renderer = CreateReplayRenderer();
if(m_Renderer != null)
{
System.Diagnostics.Debug.WriteLine("Renderer created");
@@ -644,7 +654,7 @@ namespace renderdocui.Code
{
try
{
m_current.method(renderer);
m_current.method(m_Renderer);
}
catch (Exception ex)
{
@@ -653,7 +663,7 @@ namespace renderdocui.Code
}
else
{
m_current.method(renderer);
m_current.method(m_Renderer);
}
}
@@ -669,7 +679,7 @@ namespace renderdocui.Code
m_renderQueue.Clear();
}
DestroyReplayRenderer(renderer);
DestroyReplayRenderer(m_Renderer);
}
}
catch (ReplayCreateException ex)
+19
View File
@@ -285,6 +285,11 @@ namespace renderdoc
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern void ReplayRenderer_ShutdownOutput(IntPtr real, IntPtr replayOutput);
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ReplayRenderer_ReplayLoop(IntPtr real, UInt32 windowSystem, IntPtr WindowHandle, ResourceId texid);
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ReplayRenderer_CancelReplayLoop(IntPtr real);
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern void ReplayRenderer_FileChanged(IntPtr real);
@@ -396,6 +401,20 @@ namespace renderdoc
return ret;
}
public void ReplayLoop(IntPtr WindowHandle, ResourceId texid)
{
if (WindowHandle == IntPtr.Zero)
return;
// 1 == eWindowingSystem_Win32
ReplayRenderer_ReplayLoop(m_Real, 1u, WindowHandle, texid);
}
public void CancelReplayLoop()
{
ReplayRenderer_CancelReplayLoop(m_Real);
}
public ReplayOutput CreateOutput(IntPtr WindowHandle, OutputType type)
{
// 0 == eWindowingSystem_Unknown
+25 -15
View File
@@ -95,6 +95,7 @@
this.toolStripSeparator11 = new System.Windows.Forms.ToolStripSeparator();
this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.manageRemote = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator();
this.startAndroidRemoteServerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewDocsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -119,7 +120,7 @@
this.statusProgress = new System.Windows.Forms.ToolStripProgressBar();
this.dockPanel = new WeifenLuo.WinFormsUI.Docking.DockPanel();
this.saveDialog = new System.Windows.Forms.SaveFileDialog();
this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator();
this.startReplayLoopToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
this.toolStripContainer1.BottomToolStripPanel.SuspendLayout();
this.toolStripContainer1.ContentPanel.SuspendLayout();
@@ -516,6 +517,7 @@
//
this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.resolveSymbolsToolStripMenuItem,
this.startReplayLoopToolStripMenuItem,
this.toolStripSeparator11,
this.optionsToolStripMenuItem,
this.manageRemote,
@@ -528,29 +530,41 @@
// resolveSymbolsToolStripMenuItem
//
this.resolveSymbolsToolStripMenuItem.Name = "resolveSymbolsToolStripMenuItem";
this.resolveSymbolsToolStripMenuItem.Size = new System.Drawing.Size(192, 22);
this.resolveSymbolsToolStripMenuItem.Size = new System.Drawing.Size(213, 22);
this.resolveSymbolsToolStripMenuItem.Text = "&Resolve Symbols";
this.resolveSymbolsToolStripMenuItem.Click += new System.EventHandler(this.resolveSymbolsToolStripMenuItem_Click);
//
// toolStripSeparator11
//
this.toolStripSeparator11.Name = "toolStripSeparator11";
this.toolStripSeparator11.Size = new System.Drawing.Size(189, 6);
this.toolStripSeparator11.Size = new System.Drawing.Size(210, 6);
//
// optionsToolStripMenuItem
//
this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem";
this.optionsToolStripMenuItem.Size = new System.Drawing.Size(192, 22);
this.optionsToolStripMenuItem.Size = new System.Drawing.Size(213, 22);
this.optionsToolStripMenuItem.Text = "&Options";
this.optionsToolStripMenuItem.Click += new System.EventHandler(this.optionsToolStripMenuItem_Click);
//
// manageRemote
//
this.manageRemote.Name = "manageRemote";
this.manageRemote.Size = new System.Drawing.Size(192, 22);
this.manageRemote.Size = new System.Drawing.Size(213, 22);
this.manageRemote.Text = "&Manage Remote Servers";
this.manageRemote.Click += new System.EventHandler(this.manageRemote_Click);
//
// toolStripSeparator13
//
this.toolStripSeparator13.Name = "toolStripSeparator13";
this.toolStripSeparator13.Size = new System.Drawing.Size(210, 6);
//
// startAndroidRemoteServerToolStripMenuItem
//
this.startAndroidRemoteServerToolStripMenuItem.Name = "startAndroidRemoteServerToolStripMenuItem";
this.startAndroidRemoteServerToolStripMenuItem.Size = new System.Drawing.Size(213, 22);
this.startAndroidRemoteServerToolStripMenuItem.Text = "Start Android Remote Server";
this.startAndroidRemoteServerToolStripMenuItem.Click += new System.EventHandler(this.startAndroidRemoteServerToolStripMenuItem_Click);
//
// helpToolStripMenuItem
//
this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -808,17 +822,12 @@
this.saveDialog.Filter = "Log Files (*.rdc)|*.rdc";
this.saveDialog.Title = "Save Log As";
//
// toolStripSeparator13
// startReplayLoopToolStripMenuItem
//
this.toolStripSeparator13.Name = "toolStripSeparator13";
this.toolStripSeparator13.Size = new System.Drawing.Size(271, 6);
//
// startAndroidRemoteServerToolStripMenuItem
//
this.startAndroidRemoteServerToolStripMenuItem.Name = "startAndroidRemoteServerToolStripMenuItem";
this.startAndroidRemoteServerToolStripMenuItem.Size = new System.Drawing.Size(274, 26);
this.startAndroidRemoteServerToolStripMenuItem.Text = "Start Android Remote Server";
this.startAndroidRemoteServerToolStripMenuItem.Click += new System.EventHandler(this.startAndroidRemoteServerToolStripMenuItem_Click);
this.startReplayLoopToolStripMenuItem.Name = "startReplayLoopToolStripMenuItem";
this.startReplayLoopToolStripMenuItem.Size = new System.Drawing.Size(213, 22);
this.startReplayLoopToolStripMenuItem.Text = "Start Replay Loop";
this.startReplayLoopToolStripMenuItem.Click += new System.EventHandler(this.startReplayLoopToolStripMenuItem_Click);
//
// MainWindow
//
@@ -931,5 +940,6 @@
private System.Windows.Forms.ToolStripDropDownButton contextChooser;
private System.Windows.Forms.ToolStripMenuItem localContext;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator13;
private System.Windows.Forms.ToolStripMenuItem startReplayLoopToolStripMenuItem;
}
}
+68
View File
@@ -148,6 +148,7 @@ namespace renderdocui.Windows
m_InitRemoteIdent = remoteIdent;
OwnTemporaryLog = temp;
startReplayLoopToolStripMenuItem.Enabled = false;
resolveSymbolsToolStripMenuItem.Enabled = false;
resolveSymbolsToolStripMenuItem.Text = "Resolve Symbols";
@@ -277,6 +278,7 @@ namespace renderdocui.Windows
statusIcon.Image = null;
statusProgress.Visible = false;
startReplayLoopToolStripMenuItem.Enabled = false;
resolveSymbolsToolStripMenuItem.Enabled = false;
resolveSymbolsToolStripMenuItem.Text = "Resolve Symbols";
@@ -439,6 +441,8 @@ namespace renderdocui.Windows
statusProgress.Visible = false;
startReplayLoopToolStripMenuItem.Enabled = true;
m_Core.Renderer.BeginInvoke((ReplayRenderer r) => {
bool hasResolver = r.HasCallstacks();
@@ -2033,5 +2037,69 @@ namespace renderdocui.Windows
device = m_SelectedHost.Hostname;
StaticExports.StartAndroidRemoteServer(device);
}
private void startReplayLoopToolStripMenuItem_Click(object sender, EventArgs e)
{
if (!m_Core.LogLoaded)
return;
Form popup = new Form();
popup.Icon = this.Icon;
popup.StartPosition = FormStartPosition.CenterScreen;
popup.FormBorderStyle = FormBorderStyle.SizableToolWindow;
popup.SizeGripStyle = SizeGripStyle.Hide;
FetchTexture displayTex = null;
// display the texture bound at the last drawcall - typically the present
var lastDraw = m_Core.CurDrawcalls[m_Core.CurDrawcalls.Length - 1];
while (lastDraw.children != null && lastDraw.children.Length > 0)
lastDraw = lastDraw.children[lastDraw.children.Length - 1];
displayTex = m_Core.GetTexture(lastDraw.copyDestination);
if (displayTex == null)
displayTex = m_Core.GetTexture(lastDraw.outputs[0]);
if (displayTex == null)
{
// if no texture was bound, then use the first colour swapbuffer
foreach (FetchTexture tex in m_Core.CurTextures)
{
if (tex.creationFlags.HasFlag(TextureCreationFlags.SwapBuffer) &&
tex.format.compType != FormatComponentType.Depth &&
tex.format.specialFormat != SpecialFormat.D16S8 &&
tex.format.specialFormat != SpecialFormat.D24S8 &&
tex.format.specialFormat != SpecialFormat.D32S8)
{
displayTex = tex;
break;
}
}
}
ResourceId id = ResourceId.Null;
if (displayTex != null)
{
id = displayTex.ID;
popup.ClientSize = new Size((int)displayTex.width, (int)displayTex.height);
popup.Text = "Looping replay of " + m_Core.LogFileName + " Displaying " + displayTex.name;
}
else
{
popup.ClientSize = new Size(100, 100);
popup.Text = "Looping replay of " + m_Core.LogFileName + " Displaying nothing";
}
popup.CreateControl();
IntPtr handle = popup.Handle;
m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { r.ReplayLoop(handle, id); });
popup.ShowDialog();
m_Core.Renderer.CancelReplayLoop();
}
}
}