Send capture progress over an active target control connection

This commit is contained in:
baldurk
2017-12-29 14:31:18 +00:00
parent ed98925eef
commit 559656e0f6
11 changed files with 132 additions and 11 deletions
@@ -1113,6 +1113,12 @@ void LiveCapture::connectionThreadEntry()
});
}
if(msg.type == TargetControlMessageType::CaptureProgress)
{
float progress = msg.capProgress;
GUIInvoke::call([this, progress]() {});
}
if(msg.type == TargetControlMessageType::NewCapture)
{
uint32_t capID = msg.newCapture.captureId;
+6
View File
@@ -476,6 +476,12 @@ struct TargetControlMessage
BusyData busy;
DOCUMENT("The :class:`new child process data <NewChildData>`.");
NewChildData newChild;
DOCUMENT(R"(The progress of an on-going capture.
When valid, will be in the range of 0.0 to 1.0 (0 - 100%). If not valid when a capture isn't going
or has finished, it will be -1.0
)");
float capProgress = -1.0f;
};
DECLARE_REFLECTION_STRUCT(TargetControlMessage);
+5
View File
@@ -2929,6 +2929,10 @@ DOCUMENT(R"(The type of message received from or sent to an application target c
.. data:: NewChild
The target has created a child process.
.. data:: CaptureProgress
Progress update on an on-going frame capture.
)");
enum class TargetControlMessageType : uint32_t
{
@@ -2940,6 +2944,7 @@ enum class TargetControlMessageType : uint32_t
CaptureCopied,
RegisterAPI,
NewChild,
CaptureProgress,
};
DECLARE_REFLECTION_ENUM(TargetControlMessageType);
+42 -9
View File
@@ -247,8 +247,14 @@ enum class CaptureProgress
{
PrepareInitialStates,
First = PrepareInitialStates,
// frame capture goes here but we have no way to estimate its length, and the progress would be
// updated all over the place as every API call or every draw call would have to update it.
// In general we can't know how long the frame capture will take to have an explicit progress, but
// we can hack it by getting closer and closer to 100% without quite reaching it, with some
// heuristic for how far we expect to get. Some APIs will have no useful way to update progress
// during frame capture, but for explicit APIs like Vulkan we can update once per submission, and
// tune it so that it doesn't start crawling approaching 100% until well past the number of
// submissions we'd expect in a frame.
// Other APIs will simply skip this progress section entirely, which is fine.
FrameCapture,
AddReferencedResources,
SerialiseInitialStates,
SerialiseFrameContents,
@@ -259,18 +265,45 @@ enum class CaptureProgress
DECLARE_REFLECTION_ENUM(CaptureProgress);
ITERABLE_OPERATORS(CaptureProgress);
// different APIs spend their capture time in different places. So the weighting is roughly even for
// the potential hot-spots. So D3D11 might zoom past the PrepareInitialStates while Vulkan takes a
// couple of seconds, but then the situation is reversed for AddReferencedResources
inline constexpr float ProgressWeight(CaptureProgress section)
{
// values must sum to 1.0
return section == CaptureProgress::PrepareInitialStates
? 0.35f
? 0.25f
: section == CaptureProgress::AddReferencedResources
? 0.1f
: section == CaptureProgress::SerialiseInitialStates
? 0.5f
: section == CaptureProgress::SerialiseFrameContents
? 0.04f
: section == CaptureProgress::FileWriting ? 0.01f : 0.0f;
? 0.25f
: section == CaptureProgress::FrameCapture
? 0.15f
: section == CaptureProgress::SerialiseInitialStates
? 0.25f
: section == CaptureProgress::SerialiseFrameContents
? 0.08f
: section == CaptureProgress::FileWriting ? 0.02f : 0.0f;
}
// utility function to fake progress with x going from 0 to infinity, mapping to 0% to 100% in an
// inverse curve. For x from 0 to maxX the progress is reasonably spaced, past that it will be quite
// crushed.
//
// The equation is y = 1 - (1 / (x * param) + 1)
//
// => maxX will be when the curve reaches 80%
// 0.8 = 1 - (1 / (maxX * param) + 1)
//
// => gather constants on RHS
// 1 / (maxX * param) + 1 = 0.2
//
// => switch denominators
// maxX * param + 1 = 5
//
// => re-arrange for param
// param = 4 / maxX
inline constexpr float FakeProgress(uint32_t x, uint32_t maxX)
{
return 1.0f - (1.0f / (x * (4.0f / float(maxX)) + 1));
}
class IRemoteDriver;
+40 -2
View File
@@ -44,6 +44,7 @@ enum PacketType : uint32_t
ePacket_DeleteCapture,
ePacket_QueueCapture,
ePacket_NewChild,
ePacket_CaptureProgress,
};
DECLARE_REFLECTION_ENUM(PacketType);
@@ -104,13 +105,18 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli
return;
}
const int pingtime = 1000; // ping every 1000ms
const int ticktime = 10; // tick every 10ms
float captureProgress = -1.0f;
RenderDoc::Inst().SetProgressPointer<CaptureProgress>(&captureProgress);
const int pingtime = 1000; // ping every 1000ms
const int ticktime = 10; // tick every 10ms
const int progresstime = 100; // update capture progress every 100ms
int curtime = 0;
std::vector<CaptureData> captures;
std::vector<pair<uint32_t, uint32_t> > children;
std::map<RDCDriver, bool> drivers;
float prevCaptureProgress = captureProgress;
while(client)
{
@@ -200,6 +206,26 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli
SERIALISE_ELEMENT(children.back().second);
}
}
else if(prevCaptureProgress != captureProgress)
{
if(captureProgress == 1.0f || captureProgress == -1.0f)
captureProgress = -1.0f;
// send progress packets at reduced rate (not every tick), or if the progress is finished.
// we don't need to ping while we're sending capture progress, so we re-use curtime
if(captureProgress == -1.0f || curtime > progresstime)
{
curtime = 0;
prevCaptureProgress = captureProgress;
WRITE_DATA_SCOPE();
{
SCOPED_SERIALISE_CHUNK(ePacket_CaptureProgress);
SERIALISE_ELEMENT(captureProgress);
}
}
}
if(curtime > pingtime)
{
@@ -284,6 +310,8 @@ void RenderDoc::TargetControlClientThread(uint32_t version, Network::Socket *cli
}
}
RenderDoc::Inst().SetProgressPointer<CaptureProgress>(NULL);
// give up our connection
{
SCOPED_LOCK(RenderDoc::Inst().m_SingleClientLock);
@@ -610,6 +638,16 @@ public:
reader.EndChunk();
return msg;
}
else if(type == ePacket_CaptureProgress)
{
msg.type = TargetControlMessageType::CaptureProgress;
READ_DATA_SCOPE();
SERIALISE_ELEMENT(msg.capProgress).Named("Capture Progress");
reader.EndChunk();
return msg;
}
else if(type == ePacket_NewCapture)
{
msg.type = TargetControlMessageType::NewCapture;
@@ -333,6 +333,9 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists(
RenderDoc::Inst().AddActiveDriver(RDCDriver::Vulkan, false);
}
if(IsActiveCapturing(m_State))
m_pDevice->AddCaptureSubmission();
SERIALISE_TIME_CALL(m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped));
if(IsCaptureMode(m_State))
+14
View File
@@ -540,6 +540,18 @@ void WrappedID3D12Device::ApplyInitialContents()
initStateCurList = NULL;
}
void WrappedID3D12Device::AddCaptureSubmission()
{
if(IsActiveCapturing(m_State))
{
// 15 is quite a lot of submissions.
const int expectedMaxSubmissions = 15;
RenderDoc::Inst().SetProgress(CaptureProgress::FrameCapture, FakeProgress(m_SubmitCounter, 15));
m_SubmitCounter++;
}
}
void WrappedID3D12Device::CheckForDeath()
{
if(!m_Alive)
@@ -1227,6 +1239,8 @@ void WrappedID3D12Device::StartFrameCapture(void *dev, void *wnd)
m_AppControlledCapture = true;
m_SubmitCounter = 0;
m_FrameCounter = RDCMAX(1 + (uint32_t)m_CapturedFrames.size(), m_FrameCounter);
FrameDescription frame;
+4
View File
@@ -299,6 +299,8 @@ private:
Threading::CriticalSection m_CapTransitionLock;
CaptureState m_State;
uint32_t m_SubmitCounter = 0;
D3D12InitParams m_InitParams;
uint64_t m_SectionVersion;
ID3D12InfoQueue *m_pInfoQueue;
@@ -458,6 +460,8 @@ public:
ID3D12Resource *GetUploadBuffer(uint64_t chunkOffset, uint64_t byteSize);
void ApplyInitialContents();
void AddCaptureSubmission();
void ExecuteList(ID3D12GraphicsCommandList *list, ID3D12CommandQueue *queue = NULL);
void ExecuteLists(ID3D12CommandQueue *queue = NULL);
void FlushLists(bool forceSync = false, ID3D12CommandQueue *queue = NULL);
+2
View File
@@ -881,6 +881,8 @@ void WrappedVulkan::StartFrameCapture(void *dev, void *wnd)
m_AppControlledCapture = true;
m_SubmitCounter = 0;
m_FrameCounter = RDCMAX(1 + (uint32_t)m_CapturedFrames.size(), m_FrameCounter);
FrameDescription frame;
+1
View File
@@ -221,6 +221,7 @@ private:
bool m_AppControlledCapture;
bool m_MarkedActive = false;
uint32_t m_SubmitCounter = 0;
uint64_t threadSerialiserTLSSlot;
@@ -416,6 +416,15 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
RenderDoc::Inst().AddActiveDriver(RDCDriver::Vulkan, false);
}
if(IsActiveCapturing(m_State))
{
// 15 is quite a lot of submissions.
const int expectedMaxSubmissions = 15;
RenderDoc::Inst().SetProgress(CaptureProgress::FrameCapture, FakeProgress(m_SubmitCounter, 15));
m_SubmitCounter++;
}
size_t tempmemSize = sizeof(VkSubmitInfo) * submitCount;
// need to count how many semaphore and command buffer arrays to allocate for