#pragma once #include "../video/DeckLinkOutput.h" #include "../video/DeckLinkOutputThread.h" #include #include #include 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; bool deckLinkBufferedAvailable = false; uint64_t deckLinkBuffered = 0; double deckLinkScheduleCallMilliseconds = 0.0; }; class CadenceTelemetry { public: template CadenceTelemetrySnapshot Sample( const SystemFrameExchange& exchange, const DeckLinkOutput& output, const OutputThread& outputThread) { const auto now = Clock::now(); const double seconds = mHasLastSample ? std::chrono::duration_cast>(now - mLastSampleTime).count() : 0.0; const auto exchangeMetrics = exchange.Metrics(); const DeckLinkOutputMetrics 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(snapshot.renderedTotal - mLastRenderedFrames) / seconds; snapshot.scheduleFps = static_cast(snapshot.scheduledTotal - mLastScheduledFrames) / seconds; } mLastSampleTime = now; mLastRenderedFrames = snapshot.renderedTotal; mLastScheduledFrames = snapshot.scheduledTotal; mHasLastSample = true; return snapshot; } template CadenceTelemetrySnapshot Sample( const SystemFrameExchange& exchange, const DeckLinkOutput& 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; return snapshot; } private: using Clock = std::chrono::steady_clock; Clock::time_point mLastSampleTime = Clock::now(); uint64_t mLastRenderedFrames = 0; uint64_t mLastScheduledFrames = 0; bool mHasLastSample = false; }; }