|
32 | 32 | #include "Code/pyrenderdoc/PythonContext.h" |
33 | 33 | #include "ui_PythonShell.h" |
34 | 34 |
|
| 35 | +// a forwarder that invokes onto the UI thread wherever necessary. |
| 36 | +// Note this does NOT make CaptureContext thread safe. We just invoke for any potentially UI |
| 37 | +// operations. All invokes are blocking, so there can't be any times when the UI thread waits |
| 38 | +// on the python thread. |
| 39 | +struct CaptureContextInvoker : ICaptureContext |
| 40 | +{ |
| 41 | + ICaptureContext &m_Ctx; |
| 42 | + CaptureContextInvoker(ICaptureContext &ctx) : m_Ctx(ctx) {} |
| 43 | + // |
| 44 | + /////////////////////////////////////////////////////////////////////// |
| 45 | + // pass-through functions that don't need the UI thread |
| 46 | + /////////////////////////////////////////////////////////////////////// |
| 47 | + // |
| 48 | + virtual QString ConfigFilePath(const QString &filename) override |
| 49 | + { |
| 50 | + return m_Ctx.ConfigFilePath(filename); |
| 51 | + } |
| 52 | + virtual QString TempLogFilename(QString appname) override |
| 53 | + { |
| 54 | + return m_Ctx.TempLogFilename(appname); |
| 55 | + } |
| 56 | + virtual IReplayManager &Replay() override { return m_Ctx.Replay(); } |
| 57 | + virtual bool LogLoaded() override { return m_Ctx.LogLoaded(); } |
| 58 | + virtual bool IsLogLocal() override { return m_Ctx.IsLogLocal(); } |
| 59 | + virtual bool LogLoading() override { return m_Ctx.LogLoading(); } |
| 60 | + virtual QString LogFilename() override { return m_Ctx.LogFilename(); } |
| 61 | + virtual const FrameDescription &FrameInfo() override { return m_Ctx.FrameInfo(); } |
| 62 | + virtual const APIProperties &APIProps() override { return m_Ctx.APIProps(); } |
| 63 | + virtual uint32_t CurSelectedEvent() override { return m_Ctx.CurSelectedEvent(); } |
| 64 | + virtual uint32_t CurEvent() override { return m_Ctx.CurEvent(); } |
| 65 | + virtual const DrawcallDescription *CurSelectedDrawcall() override |
| 66 | + { |
| 67 | + return m_Ctx.CurSelectedDrawcall(); |
| 68 | + } |
| 69 | + virtual const DrawcallDescription *CurDrawcall() override { return m_Ctx.CurDrawcall(); } |
| 70 | + virtual const rdctype::array<DrawcallDescription> &CurDrawcalls() override |
| 71 | + { |
| 72 | + return m_Ctx.CurDrawcalls(); |
| 73 | + } |
| 74 | + virtual TextureDescription *GetTexture(ResourceId id) override { return m_Ctx.GetTexture(id); } |
| 75 | + virtual const rdctype::array<TextureDescription> &GetTextures() override |
| 76 | + { |
| 77 | + return m_Ctx.GetTextures(); |
| 78 | + } |
| 79 | + virtual BufferDescription *GetBuffer(ResourceId id) override { return m_Ctx.GetBuffer(id); } |
| 80 | + virtual const rdctype::array<BufferDescription> &GetBuffers() override |
| 81 | + { |
| 82 | + return m_Ctx.GetBuffers(); |
| 83 | + } |
| 84 | + virtual const DrawcallDescription *GetDrawcall(uint32_t eventID) override |
| 85 | + { |
| 86 | + return m_Ctx.GetDrawcall(eventID); |
| 87 | + } |
| 88 | + virtual WindowingSystem CurWindowingSystem() override { return m_Ctx.CurWindowingSystem(); } |
| 89 | + virtual void *FillWindowingData(uintptr_t winId) override |
| 90 | + { |
| 91 | + return m_Ctx.FillWindowingData(winId); |
| 92 | + } |
| 93 | + virtual const QVector<DebugMessage> &DebugMessages() override { return m_Ctx.DebugMessages(); } |
| 94 | + virtual int UnreadMessageCount() override { return m_Ctx.UnreadMessageCount(); } |
| 95 | + virtual void MarkMessagesRead() override { return m_Ctx.MarkMessagesRead(); } |
| 96 | + virtual D3D11Pipe::State &CurD3D11PipelineState() override |
| 97 | + { |
| 98 | + return m_Ctx.CurD3D11PipelineState(); |
| 99 | + } |
| 100 | + virtual D3D12Pipe::State &CurD3D12PipelineState() override |
| 101 | + { |
| 102 | + return m_Ctx.CurD3D12PipelineState(); |
| 103 | + } |
| 104 | + virtual GLPipe::State &CurGLPipelineState() override { return m_Ctx.CurGLPipelineState(); } |
| 105 | + virtual VKPipe::State &CurVulkanPipelineState() override |
| 106 | + { |
| 107 | + return m_Ctx.CurVulkanPipelineState(); |
| 108 | + } |
| 109 | + virtual CommonPipelineState &CurPipelineState() override { return m_Ctx.CurPipelineState(); } |
| 110 | + virtual PersistantConfig &Config() override { return m_Ctx.Config(); } |
| 111 | + // |
| 112 | + /////////////////////////////////////////////////////////////////////// |
| 113 | + // functions that invoke onto the UI thread |
| 114 | + /////////////////////////////////////////////////////////////////////// |
| 115 | + // |
| 116 | + template <typename F, typename... paramTypes> |
| 117 | + void InvokeVoidFunction(F ptr, paramTypes... params) |
| 118 | + { |
| 119 | + if(!GUIInvoke::onUIThread()) |
| 120 | + { |
| 121 | + GUIInvoke::blockcall([this, ptr, params...]() { (m_Ctx.*ptr)(params...); }); |
| 122 | + |
| 123 | + return; |
| 124 | + } |
| 125 | + |
| 126 | + (m_Ctx.*ptr)(params...); |
| 127 | + } |
| 128 | + |
| 129 | + template <typename R, typename F, typename... paramTypes> |
| 130 | + R InvokeRetFunction(F ptr, paramTypes... params) |
| 131 | + { |
| 132 | + if(!GUIInvoke::onUIThread()) |
| 133 | + { |
| 134 | + R ret; |
| 135 | + GUIInvoke::blockcall([this, &ret, ptr, params...]() { ret = (m_Ctx.*ptr)(params...); }); |
| 136 | + |
| 137 | + return ret; |
| 138 | + } |
| 139 | + |
| 140 | + return (m_Ctx.*ptr)(params...); |
| 141 | + } |
| 142 | + |
| 143 | + virtual void LoadLogfile(const QString &logFile, const QString &origFilename, bool temporary, |
| 144 | + bool local) override |
| 145 | + { |
| 146 | + InvokeVoidFunction(&ICaptureContext::LoadLogfile, logFile, origFilename, temporary, local); |
| 147 | + } |
| 148 | + virtual void CloseLogfile() override { InvokeVoidFunction(&ICaptureContext::CloseLogfile); } |
| 149 | + virtual void SetEventID(const QVector<ILogViewer *> &exclude, uint32_t selectedEventID, |
| 150 | + uint32_t eventID, bool force = false) |
| 151 | + { |
| 152 | + InvokeVoidFunction(&ICaptureContext::SetEventID, exclude, selectedEventID, eventID, force); |
| 153 | + } |
| 154 | + virtual void RefreshStatus() override { InvokeVoidFunction(&ICaptureContext::RefreshStatus); } |
| 155 | + virtual void AddLogViewer(ILogViewer *viewer) override |
| 156 | + { |
| 157 | + InvokeVoidFunction(&ICaptureContext::AddLogViewer, viewer); |
| 158 | + } |
| 159 | + virtual void RemoveLogViewer(ILogViewer *viewer) override |
| 160 | + { |
| 161 | + InvokeVoidFunction(&ICaptureContext::RemoveLogViewer, viewer); |
| 162 | + } |
| 163 | + virtual void AddMessages(const rdctype::array<DebugMessage> &msgs) override |
| 164 | + { |
| 165 | + InvokeVoidFunction(&ICaptureContext::AddMessages, msgs); |
| 166 | + } |
| 167 | + virtual IMainWindow *GetMainWindow() override |
| 168 | + { |
| 169 | + return InvokeRetFunction<IMainWindow *>(&ICaptureContext::GetMainWindow); |
| 170 | + } |
| 171 | + virtual IEventBrowser *GetEventBrowser() override |
| 172 | + { |
| 173 | + return InvokeRetFunction<IEventBrowser *>(&ICaptureContext::GetEventBrowser); |
| 174 | + } |
| 175 | + virtual IAPIInspector *GetAPIInspector() override |
| 176 | + { |
| 177 | + return InvokeRetFunction<IAPIInspector *>(&ICaptureContext::GetAPIInspector); |
| 178 | + } |
| 179 | + virtual ITextureViewer *GetTextureViewer() override |
| 180 | + { |
| 181 | + return InvokeRetFunction<ITextureViewer *>(&ICaptureContext::GetTextureViewer); |
| 182 | + } |
| 183 | + virtual IBufferViewer *GetMeshPreview() override |
| 184 | + { |
| 185 | + return InvokeRetFunction<IBufferViewer *>(&ICaptureContext::GetMeshPreview); |
| 186 | + } |
| 187 | + virtual IPipelineStateViewer *GetPipelineViewer() override |
| 188 | + { |
| 189 | + return InvokeRetFunction<IPipelineStateViewer *>(&ICaptureContext::GetPipelineViewer); |
| 190 | + } |
| 191 | + virtual ICaptureDialog *GetCaptureDialog() override |
| 192 | + { |
| 193 | + return InvokeRetFunction<ICaptureDialog *>(&ICaptureContext::GetCaptureDialog); |
| 194 | + } |
| 195 | + virtual IDebugMessageView *GetDebugMessageView() override |
| 196 | + { |
| 197 | + return InvokeRetFunction<IDebugMessageView *>(&ICaptureContext::GetDebugMessageView); |
| 198 | + } |
| 199 | + virtual IStatisticsViewer *GetStatisticsViewer() override |
| 200 | + { |
| 201 | + return InvokeRetFunction<IStatisticsViewer *>(&ICaptureContext::GetStatisticsViewer); |
| 202 | + } |
| 203 | + virtual IPythonShell *GetPythonShell() override |
| 204 | + { |
| 205 | + return InvokeRetFunction<IPythonShell *>(&ICaptureContext::GetPythonShell); |
| 206 | + } |
| 207 | + virtual bool HasEventBrowser() override |
| 208 | + { |
| 209 | + return InvokeRetFunction<bool>(&ICaptureContext::HasEventBrowser); |
| 210 | + } |
| 211 | + virtual bool HasAPIInspector() override |
| 212 | + { |
| 213 | + return InvokeRetFunction<bool>(&ICaptureContext::HasAPIInspector); |
| 214 | + } |
| 215 | + virtual bool HasTextureViewer() override |
| 216 | + { |
| 217 | + return InvokeRetFunction<bool>(&ICaptureContext::HasTextureViewer); |
| 218 | + } |
| 219 | + virtual bool HasPipelineViewer() override |
| 220 | + { |
| 221 | + return InvokeRetFunction<bool>(&ICaptureContext::HasPipelineViewer); |
| 222 | + } |
| 223 | + virtual bool HasMeshPreview() override |
| 224 | + { |
| 225 | + return InvokeRetFunction<bool>(&ICaptureContext::HasMeshPreview); |
| 226 | + } |
| 227 | + virtual bool HasCaptureDialog() override |
| 228 | + { |
| 229 | + return InvokeRetFunction<bool>(&ICaptureContext::HasCaptureDialog); |
| 230 | + } |
| 231 | + virtual bool HasDebugMessageView() override |
| 232 | + { |
| 233 | + return InvokeRetFunction<bool>(&ICaptureContext::HasDebugMessageView); |
| 234 | + } |
| 235 | + virtual bool HasStatisticsViewer() override |
| 236 | + { |
| 237 | + return InvokeRetFunction<bool>(&ICaptureContext::HasStatisticsViewer); |
| 238 | + } |
| 239 | + virtual bool HasPythonShell() override |
| 240 | + { |
| 241 | + return InvokeRetFunction<bool>(&ICaptureContext::HasPythonShell); |
| 242 | + } |
| 243 | + |
| 244 | + virtual void ShowEventBrowser() override |
| 245 | + { |
| 246 | + InvokeVoidFunction(&ICaptureContext::ShowEventBrowser); |
| 247 | + } |
| 248 | + virtual void ShowAPIInspector() override |
| 249 | + { |
| 250 | + InvokeVoidFunction(&ICaptureContext::ShowAPIInspector); |
| 251 | + } |
| 252 | + virtual void ShowTextureViewer() override |
| 253 | + { |
| 254 | + InvokeVoidFunction(&ICaptureContext::ShowTextureViewer); |
| 255 | + } |
| 256 | + virtual void ShowMeshPreview() override { InvokeVoidFunction(&ICaptureContext::ShowMeshPreview); } |
| 257 | + virtual void ShowPipelineViewer() override |
| 258 | + { |
| 259 | + InvokeVoidFunction(&ICaptureContext::ShowPipelineViewer); |
| 260 | + } |
| 261 | + virtual void ShowCaptureDialog() override |
| 262 | + { |
| 263 | + InvokeVoidFunction(&ICaptureContext::ShowCaptureDialog); |
| 264 | + } |
| 265 | + virtual void ShowDebugMessageView() override |
| 266 | + { |
| 267 | + InvokeVoidFunction(&ICaptureContext::ShowDebugMessageView); |
| 268 | + } |
| 269 | + virtual void ShowStatisticsViewer() override |
| 270 | + { |
| 271 | + InvokeVoidFunction(&ICaptureContext::ShowStatisticsViewer); |
| 272 | + } |
| 273 | + virtual void ShowPythonShell() override { InvokeVoidFunction(&ICaptureContext::ShowPythonShell); } |
| 274 | + virtual IShaderViewer *EditShader(bool customShader, const QString &entryPoint, |
| 275 | + const QStringMap &files, IShaderViewer::SaveCallback saveCallback, |
| 276 | + IShaderViewer::CloseCallback closeCallback) override |
| 277 | + { |
| 278 | + return InvokeRetFunction<IShaderViewer *>(&ICaptureContext::EditShader, customShader, |
| 279 | + entryPoint, files, saveCallback, closeCallback); |
| 280 | + } |
| 281 | + |
| 282 | + virtual IShaderViewer *DebugShader(const ShaderBindpointMapping *bind, |
| 283 | + const ShaderReflection *shader, ShaderStage stage, |
| 284 | + ShaderDebugTrace *trace, const QString &debugContext) override |
| 285 | + { |
| 286 | + return InvokeRetFunction<IShaderViewer *>(&ICaptureContext::DebugShader, bind, shader, stage, |
| 287 | + trace, debugContext); |
| 288 | + } |
| 289 | + |
| 290 | + virtual IShaderViewer *ViewShader(const ShaderBindpointMapping *bind, |
| 291 | + const ShaderReflection *shader, ShaderStage stage) override |
| 292 | + { |
| 293 | + return InvokeRetFunction<IShaderViewer *>(&ICaptureContext::ViewShader, bind, shader, stage); |
| 294 | + } |
| 295 | + |
| 296 | + virtual IBufferViewer *ViewBuffer(uint64_t byteOffset, uint64_t byteSize, ResourceId id, |
| 297 | + const QString &format = QString()) override |
| 298 | + { |
| 299 | + return InvokeRetFunction<IBufferViewer *>(&ICaptureContext::ViewBuffer, byteOffset, byteSize, |
| 300 | + id, format); |
| 301 | + } |
| 302 | + |
| 303 | + virtual IBufferViewer *ViewTextureAsBuffer(uint32_t arrayIdx, uint32_t mip, ResourceId id, |
| 304 | + const QString &format = QString()) override |
| 305 | + { |
| 306 | + return InvokeRetFunction<IBufferViewer *>(&ICaptureContext::ViewTextureAsBuffer, arrayIdx, mip, |
| 307 | + id, format); |
| 308 | + } |
| 309 | + |
| 310 | + virtual IConstantBufferPreviewer *ViewConstantBuffer(ShaderStage stage, uint32_t slot, |
| 311 | + uint32_t idx) override |
| 312 | + { |
| 313 | + return InvokeRetFunction<IConstantBufferPreviewer *>(&ICaptureContext::ViewConstantBuffer, |
| 314 | + stage, slot, idx); |
| 315 | + } |
| 316 | + |
| 317 | + virtual IPixelHistoryView *ViewPixelHistory(ResourceId texID, int x, int y, |
| 318 | + const TextureDisplay &display) override |
| 319 | + { |
| 320 | + return InvokeRetFunction<IPixelHistoryView *>(&ICaptureContext::ViewPixelHistory, texID, x, y, |
| 321 | + display); |
| 322 | + } |
| 323 | + |
| 324 | + virtual QWidget *CreateBuiltinWindow(const QString &objectName) override |
| 325 | + { |
| 326 | + return InvokeRetFunction<QWidget *>(&ICaptureContext::CreateBuiltinWindow, objectName); |
| 327 | + } |
| 328 | + |
| 329 | + virtual void BuiltinWindowClosed(QWidget *window) override |
| 330 | + { |
| 331 | + InvokeVoidFunction(&ICaptureContext::BuiltinWindowClosed, window); |
| 332 | + } |
| 333 | + |
| 334 | + virtual void RaiseDockWindow(QWidget *dockWindow) override |
| 335 | + { |
| 336 | + InvokeVoidFunction(&ICaptureContext::RaiseDockWindow, dockWindow); |
| 337 | + } |
| 338 | + |
| 339 | + virtual void AddDockWindow(QWidget *newWindow, DockReference ref, QWidget *refWindow, |
| 340 | + float percentage = 0.5f) override |
| 341 | + { |
| 342 | + InvokeVoidFunction(&ICaptureContext::AddDockWindow, newWindow, ref, refWindow, percentage); |
| 343 | + } |
| 344 | +}; |
| 345 | + |
35 | 346 | PythonShell::PythonShell(ICaptureContext &ctx, QWidget *parent) |
36 | 347 | : QFrame(parent), ui(new Ui::PythonShell), m_Ctx(ctx) |
37 | 348 | { |
38 | 349 | ui->setupUi(this); |
39 | 350 |
|
| 351 | + m_ThreadCtx = new CaptureContextInvoker(m_Ctx); |
| 352 | + |
40 | 353 | QObject::connect(ui->lineInput, &RDLineEdit::keyPress, this, &PythonShell::interactive_keypress); |
41 | 354 |
|
42 | 355 | ui->lineInput->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); |
@@ -98,6 +411,8 @@ PythonShell::~PythonShell() |
98 | 411 |
|
99 | 412 | interactiveContext->Finish(); |
100 | 413 |
|
| 414 | + delete m_ThreadCtx; |
| 415 | + |
101 | 416 | delete ui; |
102 | 417 | } |
103 | 418 |
|
@@ -211,9 +526,10 @@ void PythonShell::on_runScript_clicked() |
211 | 526 | context->executeString(lit("script.py"), script); |
212 | 527 | scriptContext = NULL; |
213 | 528 |
|
214 | | - context->Finish(); |
215 | | - |
216 | | - GUIInvoke::call([this]() { enableButtons(true); }); |
| 529 | + GUIInvoke::call([this, context]() { |
| 530 | + context->Finish(); |
| 531 | + enableButtons(true); |
| 532 | + }); |
217 | 533 | }); |
218 | 534 |
|
219 | 535 | thread->selfDelete(true); |
@@ -341,7 +657,7 @@ PythonContext *PythonShell::newContext() |
341 | 657 | QObject::connect(ret, &PythonContext::exception, this, &PythonShell::exception); |
342 | 658 | QObject::connect(ret, &PythonContext::textOutput, this, &PythonShell::textOutput); |
343 | 659 |
|
344 | | - ret->setGlobal("pyrenderdoc", &m_Ctx); |
| 660 | + ret->setGlobal("pyrenderdoc", (ICaptureContext *)m_ThreadCtx); |
345 | 661 |
|
346 | 662 | return ret; |
347 | 663 | } |
0 commit comments