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
This commit is contained in:
baldurk
2022-08-05 13:03:32 +01:00
parent 69378f5c73
commit 33ea305efd
10 changed files with 107 additions and 29 deletions
+8 -6
View File
@@ -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("<br>"));
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);
+2 -1
View File
@@ -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);
+1 -1
View File
@@ -109,7 +109,7 @@
<string>API:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignTop</set>
</property>
</widget>
</item>
+6
View File
@@ -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);
+23 -6
View File
@@ -1669,7 +1669,16 @@ void RenderDoc::AddActiveDriver(RDCDriver driver, bool present)
}
}
std::map<RDCDriver, bool> RenderDoc::GetActiveDrivers()
void RenderDoc::SetDriverUnsupportedMessage(RDCDriver driver, rdcstr message)
{
if(driver == RDCDriver::Unknown)
return;
SCOPED_LOCK(m_DriverLock);
m_APISupportMessages[driver] = message;
}
std::map<RDCDriver, RDCDriverStatus> RenderDoc::GetActiveDrivers()
{
std::map<RDCDriver, uint64_t> drivers;
@@ -1678,20 +1687,28 @@ std::map<RDCDriver, bool> RenderDoc::GetActiveDrivers()
drivers = m_ActiveDrivers;
}
std::map<RDCDriver, bool> ret;
std::map<RDCDriver, RDCDriverStatus> 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;
+17 -1
View File
@@ -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<RDCDriver, bool> GetActiveDrivers();
void SetDriverUnsupportedMessage(RDCDriver driver, rdcstr message);
std::map<RDCDriver, RDCDriverStatus> 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<RDCDriver, uint64_t> m_ActiveDrivers;
std::map<RDCDriver, rdcstr> m_APISupportMessages;
Threading::ThreadHandle m_AvailableGPUThread = 0;
rdcarray<GPUDevice> m_AvailableGPUs;
+24 -13
View File
@@ -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<CaptureData> captures;
rdcarray<rdcpair<uint32_t, uint32_t> > children;
std::map<RDCDriver, bool> drivers;
std::map<RDCDriver, RDCDriverStatus> 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<RDCDriver, bool> curdrivers = RenderDoc::Inst().GetActiveDrivers();
std::map<RDCDriver, RDCDriverStatus> curdrivers = RenderDoc::Inst().GetActiveDrivers();
rdcarray<CaptureData> caps = RenderDoc::Inst().GetCaptures();
rdcarray<rdcpair<uint32_t, uint32_t> > 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;
+1
View File
@@ -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);
}
+1
View File
@@ -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);
}
+24 -1
View File
@@ -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)
{