From 00159dafacf5e7f5eb88b4e9c1d1066a3b4aae2c Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 9 Jun 2026 13:15:34 +0100 Subject: [PATCH] Fix overload documentation for AsyncInvoke in replay manager * Python can't properly document fully independent overloads, only default- parameter type overloads. Moving the tag to last as an optional parameter means we can eliminate the different variants. * For cleanliness in C++ code we make an internal variant that swaps the parameters, since it is much cleaner to have a lambda callback as the last parameter. --- qrenderdoc/Code/Interface/QRDInterface.h | 30 ++++++++++++++---------- qrenderdoc/Code/ReplayManager.cpp | 10 +------- qrenderdoc/Code/ReplayManager.h | 4 ++-- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 962600fb6..f536ac27a 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -2007,28 +2007,34 @@ This can be used to identify if a command is long-running to display a progress )"); virtual float GetCurrentProcessingTime() = 0; - DOCUMENT(R"(Make a tagged non-blocking invoke call onto the replay thread. + DOCUMENT(R"(Make a non-blocking invoke call onto the replay thread. -This tagged function is for cases when we might send a request - e.g. to pick a vertex or pixel - +The callback can optionally have a tag provided. + +Tags are for cases when we might send a request - e.g. to pick a vertex or pixel - and want to pre-empt it with a new request before the first has returned. Either because some other work is taking a while or because we're sending requests faster than they can be processed. -The manager processes only the request on the top of the queue, so when a new tagged invoke -comes in, we remove any other requests in the queue before it that have the same tag. +If a tag is present the manager processes only the request on the top of the queue, so when a +new tagged invoke comes in, we remove any other requests in the queue before it that have the same tag. -:param str tag: The tag to identify this callback. -:param Callable[[renderdoc.ReplayController], None] method: The function to callback on the replay thread. - Callback function signature must match :func:`ReplayInvokeCallback`. -)"); - virtual void AsyncInvoke(const rdcstr &tag, ReplayInvokeCallback method) = 0; - - DOCUMENT(R"(Make a non-blocking invoke call onto the replay thread. +If no tag is present, the callback will be processed as normal. :param Callable[[renderdoc.ReplayController], None] method: The function to callback on the replay thread. Callback function signature must match :func:`ReplayInvokeCallback`. +:param str tag="": **Optional parameter**. The tag to identify this callback. )"); - virtual void AsyncInvoke(ReplayInvokeCallback method) = 0; + virtual void AsyncInvoke(ReplayInvokeCallback method, rdcstr tag = "") = 0; + +#if !defined(SWIG) && !defined(SWIG_GENERATED) + // it is convenient for us to have the tag first so a lambda is the last parameter, but this + // doesn't fit the python overloads so it's not exposed to swig + void AsyncInvoke(const rdcstr &tag, ReplayInvokeCallback method) + { + return AsyncInvoke(method, tag); + } +#endif // This is an ugly hack, but we leave BlockInvoke as the last method, so that when the class is // extended and the wrapper around BlockInvoke to release the python GIL happens, it picks up the diff --git a/qrenderdoc/Code/ReplayManager.cpp b/qrenderdoc/Code/ReplayManager.cpp index 5ad03eb81..83cc1bcca 100644 --- a/qrenderdoc/Code/ReplayManager.cpp +++ b/qrenderdoc/Code/ReplayManager.cpp @@ -252,7 +252,7 @@ QString ReplayManager::GetCurrentProcessingTag() return m_CommandTag; } -void ReplayManager::AsyncInvoke(const rdcstr &tag, ReplayManager::ReplayInvokeCallback m) +void ReplayManager::AsyncInvoke(ReplayManager::ReplayInvokeCallback m, rdcstr tag) { QString qtag; @@ -282,14 +282,6 @@ void ReplayManager::AsyncInvoke(const rdcstr &tag, ReplayManager::ReplayInvokeCa PushInvoke(cmd); } -void ReplayManager::AsyncInvoke(ReplayManager::ReplayInvokeCallback m) -{ - InvokeHandle *cmd = new InvokeHandle(m); - cmd->selfdelete = true; - - PushInvoke(cmd); -} - void ReplayManager::BlockInvoke(ReplayManager::ReplayInvokeCallback m) { if(IsRunning() && m_Thread->isCurrentThread()) diff --git a/qrenderdoc/Code/ReplayManager.h b/qrenderdoc/Code/ReplayManager.h index 316932e9e..d0d780d21 100644 --- a/qrenderdoc/Code/ReplayManager.h +++ b/qrenderdoc/Code/ReplayManager.h @@ -64,8 +64,8 @@ public: // processed. // the manager processes only the request on the top of the queue, so when a new tagged invoke // comes in, we remove any other requests in the queue before it that have the same tag - void AsyncInvoke(const rdcstr &tag, ReplayInvokeCallback m); - void AsyncInvoke(ReplayInvokeCallback m); + void AsyncInvoke(ReplayInvokeCallback m, rdcstr tag = ""); + using IReplayManager::AsyncInvoke; void BlockInvoke(ReplayInvokeCallback m); void CancelReplayLoop();