Files
video-shader-toys/apps/RenderCadenceCompositor/telemetry/CadenceTelemetry.h
Aiden 5c66cfdc64
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m56s
CI / Windows Release Package (push) Has been skipped
Input telemetry
2026-05-12 21:13:22 +10:00

154 lines
5.9 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 completions = 0;
uint64_t displayedLate = 0;
uint64_t dropped = 0;
uint64_t shaderBuildsCommitted = 0;
uint64_t shaderBuildFailures = 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;
};
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.completions = outputMetrics.completions;
snapshot.displayedLate = outputMetrics.displayedLate;
snapshot.dropped = outputMetrics.dropped;
snapshot.deckLinkBufferedAvailable = outputMetrics.actualBufferedFramesAvailable;
snapshot.deckLinkBuffered = outputMetrics.actualBufferedFrames;
snapshot.deckLinkScheduleCallMilliseconds = outputMetrics.scheduleCallMilliseconds;
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.shaderBuildsCommitted = renderMetrics.shaderBuildsCommitted;
snapshot.shaderBuildFailures = renderMetrics.shaderBuildFailures;
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;
};
}