V2 working
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m54s
CI / Windows Release Package (push) Successful in 3m14s

This commit is contained in:
Aiden
2026-05-12 01:59:02 +10:00
parent 2531d871e8
commit e0ca548ef5
32 changed files with 3492 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
#pragma once
#include "../video/DeckLinkOutput.h"
#include "../video/DeckLinkOutputThread.h"
#include <chrono>
#include <cstddef>
#include <cstdint>
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;
bool deckLinkBufferedAvailable = false;
uint64_t deckLinkBuffered = 0;
double deckLinkScheduleCallMilliseconds = 0.0;
};
class CadenceTelemetry
{
public:
template <typename SystemFrameExchange, typename OutputThread>
CadenceTelemetrySnapshot Sample(
const SystemFrameExchange& exchange,
const DeckLinkOutput& 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 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<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;
}
private:
using Clock = std::chrono::steady_clock;
Clock::time_point mLastSampleTime = Clock::now();
uint64_t mLastRenderedFrames = 0;
uint64_t mLastScheduledFrames = 0;
bool mHasLastSample = false;
};
}

View File

@@ -0,0 +1,86 @@
#pragma once
#include "CadenceTelemetry.h"
#include <atomic>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <thread>
namespace RenderCadenceCompositor
{
struct TelemetryPrinterConfig
{
std::chrono::milliseconds interval = std::chrono::seconds(1);
};
class TelemetryPrinter
{
public:
explicit TelemetryPrinter(TelemetryPrinterConfig config = TelemetryPrinterConfig()) :
mConfig(config)
{
}
TelemetryPrinter(const TelemetryPrinter&) = delete;
TelemetryPrinter& operator=(const TelemetryPrinter&) = delete;
~TelemetryPrinter()
{
Stop();
}
template <typename SystemFrameExchange, typename OutputThread>
void Start(const SystemFrameExchange& exchange, const DeckLinkOutput& output, const OutputThread& outputThread)
{
if (mRunning)
return;
mStopping = false;
mThread = std::thread([this, &exchange, &output, &outputThread]() {
CadenceTelemetry telemetry;
while (!mStopping)
{
std::this_thread::sleep_for(mConfig.interval);
Print(telemetry.Sample(exchange, output, outputThread));
}
});
mRunning = true;
}
void Stop()
{
mStopping = true;
if (mThread.joinable())
mThread.join();
mRunning = false;
}
private:
static void Print(const CadenceTelemetrySnapshot& snapshot)
{
std::cout << std::fixed << std::setprecision(1)
<< "renderFps=" << snapshot.renderFps
<< " scheduleFps=" << snapshot.scheduleFps
<< " free=" << snapshot.freeFrames
<< " completed=" << snapshot.completedFrames
<< " scheduled=" << snapshot.scheduledFrames
<< " completedPollMisses=" << snapshot.completedPollMisses
<< " scheduleFailures=" << snapshot.scheduleFailures
<< " completions=" << snapshot.completions
<< " late=" << snapshot.displayedLate
<< " dropped=" << snapshot.dropped
<< " decklinkBuffered=";
if (snapshot.deckLinkBufferedAvailable)
std::cout << snapshot.deckLinkBuffered;
else
std::cout << "n/a";
std::cout << " scheduleCallMs=" << snapshot.deckLinkScheduleCallMilliseconds << "\n";
}
TelemetryPrinterConfig mConfig;
std::thread mThread;
std::atomic<bool> mStopping{ false };
std::atomic<bool> mRunning{ false };
};
}