184 lines
7.5 KiB
C++
184 lines
7.5 KiB
C++
#pragma once
|
|
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
namespace RenderCadenceCompositor
|
|
{
|
|
struct CadenceTelemetrySnapshot
|
|
{
|
|
double sampleSeconds = 0.0;
|
|
double renderFps = 0.0;
|
|
double scheduleFps = 0.0;
|
|
std::size_t freeFrames = 0;
|
|
std::size_t completedFrames = 0;
|
|
std::size_t scheduledFrames = 0;
|
|
uint64_t renderedTotal = 0;
|
|
uint64_t scheduledTotal = 0;
|
|
uint64_t completedPollMisses = 0;
|
|
uint64_t scheduleFailures = 0;
|
|
uint64_t completedDrops = 0;
|
|
uint64_t acquireMisses = 0;
|
|
uint64_t completions = 0;
|
|
uint64_t displayedLate = 0;
|
|
uint64_t dropped = 0;
|
|
uint64_t clockOverruns = 0;
|
|
uint64_t clockSkippedFrames = 0;
|
|
uint64_t shaderBuildsCommitted = 0;
|
|
uint64_t shaderBuildFailures = 0;
|
|
double renderFrameMilliseconds = 0.0;
|
|
double renderFrameBudgetUsedPercent = 0.0;
|
|
double renderFrameMaxMilliseconds = 0.0;
|
|
double readbackQueueMilliseconds = 0.0;
|
|
double completedReadbackCopyMilliseconds = 0.0;
|
|
uint64_t inputFramesReceived = 0;
|
|
uint64_t inputFramesDropped = 0;
|
|
uint64_t inputConsumeMisses = 0;
|
|
uint64_t inputUploadMisses = 0;
|
|
std::size_t inputReadyFrames = 0;
|
|
std::size_t inputReadingFrames = 0;
|
|
double inputLatestAgeMilliseconds = 0.0;
|
|
double inputUploadMilliseconds = 0.0;
|
|
bool inputFormatSupported = true;
|
|
bool inputSignalPresent = false;
|
|
double inputCaptureFps = 0.0;
|
|
double inputConvertMilliseconds = 0.0;
|
|
double inputSubmitMilliseconds = 0.0;
|
|
uint64_t inputNoSignalFrames = 0;
|
|
uint64_t inputUnsupportedFrames = 0;
|
|
uint64_t inputSubmitMisses = 0;
|
|
std::string inputCaptureFormat = "none";
|
|
bool deckLinkBufferedAvailable = false;
|
|
uint64_t deckLinkBuffered = 0;
|
|
double deckLinkScheduleCallMilliseconds = 0.0;
|
|
bool deckLinkScheduleLeadAvailable = false;
|
|
int64_t deckLinkPlaybackStreamTime = 0;
|
|
uint64_t deckLinkPlaybackFrameIndex = 0;
|
|
uint64_t deckLinkNextScheduleFrameIndex = 0;
|
|
int64_t deckLinkScheduleLeadFrames = 0;
|
|
uint64_t deckLinkScheduleRealignments = 0;
|
|
};
|
|
|
|
class CadenceTelemetry
|
|
{
|
|
public:
|
|
template <typename SystemFrameExchange, typename Output, typename OutputThread>
|
|
CadenceTelemetrySnapshot Sample(
|
|
const SystemFrameExchange& exchange,
|
|
const Output& output,
|
|
const OutputThread& outputThread)
|
|
{
|
|
const auto now = Clock::now();
|
|
const double seconds = mHasLastSample
|
|
? std::chrono::duration_cast<std::chrono::duration<double>>(now - mLastSampleTime).count()
|
|
: 0.0;
|
|
|
|
const auto exchangeMetrics = exchange.Metrics();
|
|
const auto outputMetrics = output.Metrics();
|
|
const auto threadMetrics = outputThread.Metrics();
|
|
|
|
CadenceTelemetrySnapshot snapshot;
|
|
snapshot.sampleSeconds = seconds;
|
|
snapshot.renderedTotal = exchangeMetrics.completedFrames;
|
|
snapshot.scheduledTotal = exchangeMetrics.scheduledFrames;
|
|
snapshot.freeFrames = exchangeMetrics.freeCount;
|
|
snapshot.completedFrames = exchangeMetrics.completedCount;
|
|
snapshot.scheduledFrames = exchangeMetrics.scheduledCount;
|
|
snapshot.completedPollMisses = threadMetrics.completedPollMisses;
|
|
snapshot.scheduleFailures = outputMetrics.scheduleFailures > threadMetrics.scheduleFailures
|
|
? outputMetrics.scheduleFailures
|
|
: threadMetrics.scheduleFailures;
|
|
snapshot.completedDrops = exchangeMetrics.completedDrops;
|
|
snapshot.acquireMisses = exchangeMetrics.acquireMisses;
|
|
snapshot.completions = outputMetrics.completions;
|
|
snapshot.displayedLate = outputMetrics.displayedLate;
|
|
snapshot.dropped = outputMetrics.dropped;
|
|
snapshot.deckLinkBufferedAvailable = outputMetrics.actualBufferedFramesAvailable;
|
|
snapshot.deckLinkBuffered = outputMetrics.actualBufferedFrames;
|
|
snapshot.deckLinkScheduleCallMilliseconds = outputMetrics.scheduleCallMilliseconds;
|
|
snapshot.deckLinkScheduleLeadAvailable = outputMetrics.scheduleLeadAvailable;
|
|
snapshot.deckLinkPlaybackStreamTime = outputMetrics.playbackStreamTime;
|
|
snapshot.deckLinkPlaybackFrameIndex = outputMetrics.playbackFrameIndex;
|
|
snapshot.deckLinkNextScheduleFrameIndex = outputMetrics.nextScheduleFrameIndex;
|
|
snapshot.deckLinkScheduleLeadFrames = outputMetrics.scheduleLeadFrames;
|
|
snapshot.deckLinkScheduleRealignments = outputMetrics.scheduleRealignmentCount;
|
|
|
|
if (mHasLastSample && seconds > 0.0)
|
|
{
|
|
snapshot.renderFps = static_cast<double>(snapshot.renderedTotal - mLastRenderedFrames) / seconds;
|
|
snapshot.scheduleFps = static_cast<double>(snapshot.scheduledTotal - mLastScheduledFrames) / seconds;
|
|
}
|
|
|
|
mLastSampleTime = now;
|
|
mLastRenderedFrames = snapshot.renderedTotal;
|
|
mLastScheduledFrames = snapshot.scheduledTotal;
|
|
mHasLastSample = true;
|
|
return snapshot;
|
|
}
|
|
|
|
template <typename SystemFrameExchange, typename Output, typename OutputThread, typename RenderThread>
|
|
CadenceTelemetrySnapshot Sample(
|
|
const SystemFrameExchange& exchange,
|
|
const Output& output,
|
|
const OutputThread& outputThread,
|
|
const RenderThread& renderThread)
|
|
{
|
|
CadenceTelemetrySnapshot snapshot = Sample(exchange, output, outputThread);
|
|
const auto renderMetrics = renderThread.GetMetrics();
|
|
snapshot.clockOverruns = renderMetrics.clockOverruns;
|
|
snapshot.clockSkippedFrames = renderMetrics.skippedFrames;
|
|
snapshot.shaderBuildsCommitted = renderMetrics.shaderBuildsCommitted;
|
|
snapshot.shaderBuildFailures = renderMetrics.shaderBuildFailures;
|
|
snapshot.renderFrameMilliseconds = renderMetrics.renderFrameMilliseconds;
|
|
snapshot.renderFrameBudgetUsedPercent = renderMetrics.renderFrameBudgetUsedPercent;
|
|
snapshot.renderFrameMaxMilliseconds = renderMetrics.renderFrameMaxMilliseconds;
|
|
snapshot.readbackQueueMilliseconds = renderMetrics.readbackQueueMilliseconds;
|
|
snapshot.completedReadbackCopyMilliseconds = renderMetrics.completedReadbackCopyMilliseconds;
|
|
snapshot.inputFramesReceived = renderMetrics.inputFramesReceived;
|
|
snapshot.inputFramesDropped = renderMetrics.inputFramesDropped;
|
|
snapshot.inputConsumeMisses = renderMetrics.inputConsumeMisses;
|
|
snapshot.inputUploadMisses = renderMetrics.inputUploadMisses;
|
|
snapshot.inputReadyFrames = renderMetrics.inputReadyFrames;
|
|
snapshot.inputReadingFrames = renderMetrics.inputReadingFrames;
|
|
snapshot.inputLatestAgeMilliseconds = renderMetrics.inputLatestAgeMilliseconds;
|
|
snapshot.inputUploadMilliseconds = renderMetrics.inputUploadMilliseconds;
|
|
snapshot.inputFormatSupported = renderMetrics.inputFormatSupported;
|
|
snapshot.inputSignalPresent = renderMetrics.inputSignalPresent;
|
|
return snapshot;
|
|
}
|
|
|
|
template <typename SystemFrameExchange, typename Output, typename OutputThread, typename RenderThread, typename InputEdge>
|
|
CadenceTelemetrySnapshot Sample(
|
|
const SystemFrameExchange& exchange,
|
|
const Output& output,
|
|
const OutputThread& outputThread,
|
|
const RenderThread& renderThread,
|
|
const InputEdge& inputEdge)
|
|
{
|
|
CadenceTelemetrySnapshot snapshot = Sample(exchange, output, outputThread, renderThread);
|
|
const auto inputMetrics = inputEdge.Metrics();
|
|
snapshot.inputConvertMilliseconds = inputMetrics.convertMilliseconds;
|
|
snapshot.inputSubmitMilliseconds = inputMetrics.submitMilliseconds;
|
|
snapshot.inputNoSignalFrames = inputMetrics.noInputSourceFrames;
|
|
snapshot.inputUnsupportedFrames = inputMetrics.unsupportedFrames;
|
|
snapshot.inputSubmitMisses = inputMetrics.submitMisses;
|
|
snapshot.inputCaptureFormat = inputMetrics.captureFormat ? inputMetrics.captureFormat : "none";
|
|
if (snapshot.sampleSeconds > 0.0)
|
|
snapshot.inputCaptureFps = static_cast<double>(inputMetrics.capturedFrames - mLastInputCapturedFrames) / snapshot.sampleSeconds;
|
|
mLastInputCapturedFrames = inputMetrics.capturedFrames;
|
|
return snapshot;
|
|
}
|
|
|
|
private:
|
|
using Clock = std::chrono::steady_clock;
|
|
|
|
Clock::time_point mLastSampleTime = Clock::now();
|
|
uint64_t mLastRenderedFrames = 0;
|
|
uint64_t mLastScheduledFrames = 0;
|
|
uint64_t mLastInputCapturedFrames = 0;
|
|
bool mHasLastSample = false;
|
|
};
|
|
}
|