From 33ea305efd68adf4d4c29374c6ae29738a238e43 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 5 Aug 2022 13:03:32 +0100 Subject: [PATCH] Show message in connection window for unsupported API capture * This is helpful when the normal overlay is not available or visible such as in VR headsets --- qrenderdoc/Windows/Dialogs/LiveCapture.cpp | 14 ++++---- qrenderdoc/Windows/Dialogs/LiveCapture.h | 3 +- qrenderdoc/Windows/Dialogs/LiveCapture.ui | 2 +- renderdoc/api/replay/control_types.h | 6 ++++ renderdoc/core/core.cpp | 29 +++++++++++++---- renderdoc/core/core.h | 18 ++++++++++- renderdoc/core/target_control.cpp | 37 ++++++++++++++-------- renderdoc/driver/d3d8/d3d8_device.cpp | 1 + renderdoc/driver/d3d9/d3d9_device.cpp | 1 + renderdoc/driver/gl/gl_driver.cpp | 25 ++++++++++++++- 10 files changed, 107 insertions(+), 29 deletions(-) diff --git a/qrenderdoc/Windows/Dialogs/LiveCapture.cpp b/qrenderdoc/Windows/Dialogs/LiveCapture.cpp index f29314ce4..f42df5f18 100644 --- a/qrenderdoc/Windows/Dialogs/LiveCapture.cpp +++ b/qrenderdoc/Windows/Dialogs/LiveCapture.cpp @@ -654,6 +654,8 @@ void LiveCapture::updateAPIStatus() if(!m_APIs[api].supported) { apiStatus += tr(", %1 (Unsupported)").arg(api); + if(!m_APIs[api].supportMessage.isEmpty()) + apiStatus += lit("\n") + m_APIs[api].supportMessage; } else if(!m_APIs[api].presenting) { @@ -665,6 +667,8 @@ void LiveCapture::updateAPIStatus() // remove the redundant starting ", " apiStatus.remove(0, 2); + apiStatus.replace(QLatin1Char('\n'), lit("
")); + ui->apiStatus->setText(apiStatus); ui->apiIcon->setVisible(nonpresenting); @@ -1344,13 +1348,11 @@ void LiveCapture::connectionThreadEntry() if(msg.type == TargetControlMessageType::RegisterAPI) { - QString api = msg.apiUse.name; - bool presenting = msg.apiUse.presenting; - bool supported = msg.apiUse.supported; - GUIInvoke::call(this, [this, api, presenting, supported]() { - m_APIs[api] = APIStatus(presenting, supported); + GUIInvoke::call(this, [this, msg]() { + m_APIs[msg.apiUse.name] = + APIStatus(msg.apiUse.presenting, msg.apiUse.supported, msg.apiUse.supportMessage); - if(presenting && supported) + if(msg.apiUse.presenting && msg.apiUse.supported) { ui->triggerImmediateCapture->setEnabled(true); ui->triggerDelayedCapture->setEnabled(true); diff --git a/qrenderdoc/Windows/Dialogs/LiveCapture.h b/qrenderdoc/Windows/Dialogs/LiveCapture.h index fa10c8030..89e6a53b5 100644 --- a/qrenderdoc/Windows/Dialogs/LiveCapture.h +++ b/qrenderdoc/Windows/Dialogs/LiveCapture.h @@ -127,9 +127,10 @@ private: struct APIStatus { APIStatus() = default; - APIStatus(bool p, bool s) : presenting(p), supported(s) {} + APIStatus(bool p, bool s, rdcstr m) : presenting(p), supported(s), supportMessage(m) {} bool presenting = false; bool supported = false; + rdcstr supportMessage; }; Capture *GetCapture(QListWidgetItem *item); diff --git a/qrenderdoc/Windows/Dialogs/LiveCapture.ui b/qrenderdoc/Windows/Dialogs/LiveCapture.ui index cc3396a77..785b04e67 100644 --- a/qrenderdoc/Windows/Dialogs/LiveCapture.ui +++ b/qrenderdoc/Windows/Dialogs/LiveCapture.ui @@ -109,7 +109,7 @@ API: - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignTop diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index 9ed872464..541924f92 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -562,6 +562,12 @@ struct APIUseData DOCUMENT("``True`` if the API can be captured."); bool supported = false; + + DOCUMENT(R"(A string message if the API is unsupported explaining why. + +:type: str +)"); + rdcstr supportMessage; }; DECLARE_REFLECTION_STRUCT(APIUseData); diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index 167caaf9b..4ad37e40c 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -1669,7 +1669,16 @@ void RenderDoc::AddActiveDriver(RDCDriver driver, bool present) } } -std::map RenderDoc::GetActiveDrivers() +void RenderDoc::SetDriverUnsupportedMessage(RDCDriver driver, rdcstr message) +{ + if(driver == RDCDriver::Unknown) + return; + + SCOPED_LOCK(m_DriverLock); + m_APISupportMessages[driver] = message; +} + +std::map RenderDoc::GetActiveDrivers() { std::map drivers; @@ -1678,20 +1687,28 @@ std::map RenderDoc::GetActiveDrivers() drivers = m_ActiveDrivers; } - std::map ret; + std::map ret; for(auto it = drivers.begin(); it != drivers.end(); ++it) { + RDCDriverStatus &status = ret[it->first]; // driver is presenting if the timestamp is greater than 0 and less than 10 seconds ago (gives a // little leeway for loading screens or something where the presentation stops temporarily). // we also assume that during a capture if it was presenting, then it's still capturing. // Otherwise a long capture would temporarily set it as not presenting. - bool presenting = it->second > 0; + status.presenting = it->second > 0; - if(presenting && !IsFrameCapturing() && it->second < Timing::GetUnixTimestamp() - 10) - presenting = false; + if(status.presenting && !IsFrameCapturing() && it->second < Timing::GetUnixTimestamp() - 10) + status.presenting = false; - ret[it->first] = presenting; + status.supported = (HasRemoteDriver(it->first) || HasReplayDriver(it->first)) && + HasActiveFrameCapturer(it->first); + + if(!status.supported) + { + SCOPED_LOCK(m_DriverLock); + status.supportMessage = m_APISupportMessages[it->first]; + } } return ret; diff --git a/renderdoc/core/core.h b/renderdoc/core/core.h index 850783b00..ecd9f8001 100644 --- a/renderdoc/core/core.h +++ b/renderdoc/core/core.h @@ -236,6 +236,20 @@ enum class RDCDriver : uint32_t DECLARE_REFLECTION_ENUM(RDCDriver); +struct RDCDriverStatus +{ + bool presenting = false; + bool supported = false; + rdcstr supportMessage; + + bool operator==(const RDCDriverStatus &o) const + { + return presenting == o.presenting && supported == o.supported && + supportMessage == o.supportMessage; + } + bool operator!=(const RDCDriverStatus &o) const { return !(*this == o); } +}; + enum ReplayLogType { eReplay_Full, @@ -547,7 +561,8 @@ public: bool HasRemoteDriver(RDCDriver driver) const; void AddActiveDriver(RDCDriver driver, bool present); - std::map GetActiveDrivers(); + void SetDriverUnsupportedMessage(RDCDriver driver, rdcstr message); + std::map GetActiveDrivers(); uint32_t GetTargetControlIdent() const { return m_RemoteIdent; } bool IsTargetControlConnected(); @@ -644,6 +659,7 @@ private: int32_t m_MarkerIndentLevel; Threading::CriticalSection m_DriverLock; std::map m_ActiveDrivers; + std::map m_APISupportMessages; Threading::ThreadHandle m_AvailableGPUThread = 0; rdcarray m_AvailableGPUs; diff --git a/renderdoc/core/target_control.cpp b/renderdoc/core/target_control.cpp index 327abbf44..bd16c1816 100644 --- a/renderdoc/core/target_control.cpp +++ b/renderdoc/core/target_control.cpp @@ -32,7 +32,7 @@ #include "replay/replay_driver.h" #include "serialise/serialiser.h" -static const uint32_t TargetControlProtocolVersion = 7; +static const uint32_t TargetControlProtocolVersion = 8; static bool IsProtocolVersionSupported(const uint32_t protocolVersion) { @@ -56,6 +56,10 @@ static bool IsProtocolVersionSupported(const uint32_t protocolVersion) if(protocolVersion == 6) return true; + // 7 -> 8 add custom message for unsupported APIs + if(protocolVersion == 7) + return true; + if(protocolVersion == TargetControlProtocolVersion) return true; @@ -156,7 +160,7 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli rdcarray captures; rdcarray > children; - std::map drivers; + std::map drivers; float prevCaptureProgress = captureProgress; uint32_t prevWindows = 0; @@ -171,7 +175,7 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli Threading::Sleep(ticktime); curtime += ticktime; - std::map curdrivers = RenderDoc::Inst().GetActiveDrivers(); + std::map curdrivers = RenderDoc::Inst().GetActiveDrivers(); rdcarray caps = RenderDoc::Inst().GetCaptures(); rdcarray > childprocs = RenderDoc::Inst().GetChildProcesses(); @@ -182,7 +186,7 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli { // find the first difference, either a new key or a key with a different value, and send it. RDCDriver driver = RDCDriver::Unknown; - bool presenting = false; + RDCDriverStatus status; // search for new drivers for(auto it = curdrivers.begin(); it != curdrivers.end(); it++) @@ -190,7 +194,7 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli if(drivers.find(it->first) == drivers.end() || drivers[it->first] != it->second) { driver = it->first; - presenting = it->second; + status = it->second; break; } } @@ -198,19 +202,18 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli RDCASSERTNOTEQUAL(driver, RDCDriver::Unknown); if(driver != RDCDriver::Unknown) - drivers[driver] = presenting; - - bool supported = - RenderDoc::Inst().HasRemoteDriver(driver) || RenderDoc::Inst().HasReplayDriver(driver); - - supported &= RenderDoc::Inst().HasActiveFrameCapturer(driver); + drivers[driver] = status; WRITE_DATA_SCOPE(); { SCOPED_SERIALISE_CHUNK(ePacket_APIUse); SERIALISE_ELEMENT(driver); - SERIALISE_ELEMENT(presenting); - SERIALISE_ELEMENT(supported); + SERIALISE_ELEMENT(status.presenting); + SERIALISE_ELEMENT(status.supported); + if(version >= 8) + { + SERIALISE_ELEMENT(status.supportMessage); + } } } else if(caps.size() != captures.size()) @@ -843,15 +846,21 @@ public: RDCDriver driver = RDCDriver::Unknown; bool presenting = false; bool supported = false; + rdcstr supportMessage; READ_DATA_SCOPE(); SERIALISE_ELEMENT(driver); SERIALISE_ELEMENT(presenting); SERIALISE_ELEMENT(supported); + if(m_Version >= 8) + { + SERIALISE_ELEMENT(supportMessage); + } msg.apiUse.name = ToStr(driver); msg.apiUse.presenting = presenting; msg.apiUse.supported = supported; + msg.apiUse.supportMessage = supportMessage; if(presenting) m_API = ToStr(driver); @@ -859,6 +868,8 @@ public: RDCLOG("Used API: %s (%s & %s)", msg.apiUse.name.c_str(), presenting ? "Presenting" : "Not presenting", supported ? "supported" : "not supported"); + if(!supportMessage.empty()) + RDCLOG("Support: %s", supportMessage.c_str()); reader.EndChunk(); return msg; diff --git a/renderdoc/driver/d3d8/d3d8_device.cpp b/renderdoc/driver/d3d8/d3d8_device.cpp index 7effac3c9..ccb9b23d8 100644 --- a/renderdoc/driver/d3d8/d3d8_device.cpp +++ b/renderdoc/driver/d3d8/d3d8_device.cpp @@ -283,6 +283,7 @@ HRESULT __stdcall WrappedD3DDevice8::Present(CONST RECT *pSourceRect, CONST RECT } RenderDoc::Inst().AddActiveDriver(RDCDriver::D3D8, true); + RenderDoc::Inst().SetDriverUnsupportedMessage(RDCDriver::D3D8, "D3D8 is not a supported API"); return m_device->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); } diff --git a/renderdoc/driver/d3d9/d3d9_device.cpp b/renderdoc/driver/d3d9/d3d9_device.cpp index ac54065e1..2b392fb2e 100644 --- a/renderdoc/driver/d3d9/d3d9_device.cpp +++ b/renderdoc/driver/d3d9/d3d9_device.cpp @@ -257,6 +257,7 @@ HRESULT __stdcall WrappedD3DDevice9::Present(CONST RECT *pSourceRect, CONST RECT } RenderDoc::Inst().AddActiveDriver(RDCDriver::D3D9, true); + RenderDoc::Inst().SetDriverUnsupportedMessage(RDCDriver::D3D9, "D3D9 is not a supported API"); return m_device->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); } diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 95d76b15d..950239bc7 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -1027,7 +1027,28 @@ void WrappedOpenGL::UseUnusedSupportedFunction(const char *name) } } + size_t sz = m_UnsupportedFunctions.size(); m_UnsupportedFunctions.insert(name); + + if(sz != m_UnsupportedFunctions.size()) + { + RDCERR("Unsupported function %s used", name); + + rdcstr unsupportedStatus = StringFormat::Fmt( + "Unsupported %s used:\n", m_UnsupportedFunctions.size() == 1 ? "function" : "functions"); + size_t i = 0; + for(const char *func : m_UnsupportedFunctions) + { + i++; + if(i > 4) + break; + unsupportedStatus += StringFormat::Fmt(" - %s\n", func); + } + if(m_UnsupportedFunctions.size() > i) + unsupportedStatus += " - ...\n"; + + RenderDoc::Inst().SetDriverUnsupportedMessage(RDCDriver::OpenGL, unsupportedStatus); + } } void WrappedOpenGL::CheckImplicitThread() @@ -2073,7 +2094,9 @@ void WrappedOpenGL::SwapBuffers(WindowingSystem winSystem, void *windowHandle) // print the unsupported functions (up to a handful) to show if(!m_UnsupportedFunctions.empty()) { - overlayText += "Captures disabled.\nUnsupported function used:\n"; + overlayText += + StringFormat::Fmt("Captures disabled.\nUnsupported %s used:\n", + m_UnsupportedFunctions.size() == 1 ? "function" : "functions"); size_t i = 0; for(const char *func : m_UnsupportedFunctions) {