Files
video-shader-toys/apps/LoopThroughWithOpenGLCompositing/runtime/presentation/RuntimeStatePresenter.cpp
Aiden f8adbbe0fe
Some checks failed
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m45s
CI / Windows Release Package (push) Has been cancelled
Phase 7.5 timing logs
2026-05-11 21:32:40 +10:00

184 lines
12 KiB
C++

#include "RuntimeStatePresenter.h"
#include "RuntimeStateJson.h"
#include "RuntimeStore.h"
std::string RuntimeStatePresenter::BuildRuntimeStateJson(const RuntimeStore& runtimeStore)
{
return SerializeJson(BuildRuntimeStateValue(runtimeStore), true);
}
JsonValue RuntimeStatePresenter::BuildRuntimeStateValue(const RuntimeStore& runtimeStore)
{
const RuntimeStatePresentationReadModel model = runtimeStore.BuildRuntimeStatePresentationReadModel();
const HealthTelemetry::Snapshot& telemetrySnapshot = model.telemetry;
JsonValue root = JsonValue::MakeObject();
JsonValue app = JsonValue::MakeObject();
app.set("serverPort", JsonValue(static_cast<double>(model.serverPort)));
app.set("oscPort", JsonValue(static_cast<double>(model.config.oscPort)));
app.set("oscBindAddress", JsonValue(model.config.oscBindAddress));
app.set("oscSmoothing", JsonValue(model.config.oscSmoothing));
app.set("autoReload", JsonValue(model.autoReloadEnabled));
app.set("maxTemporalHistoryFrames", JsonValue(static_cast<double>(model.config.maxTemporalHistoryFrames)));
app.set("previewFps", JsonValue(static_cast<double>(model.config.previewFps)));
app.set("enableExternalKeying", JsonValue(model.config.enableExternalKeying));
app.set("inputVideoFormat", JsonValue(model.config.inputVideoFormat));
app.set("inputFrameRate", JsonValue(model.config.inputFrameRate));
app.set("outputVideoFormat", JsonValue(model.config.outputVideoFormat));
app.set("outputFrameRate", JsonValue(model.config.outputFrameRate));
root.set("app", app);
JsonValue runtime = JsonValue::MakeObject();
runtime.set("layerCount", JsonValue(static_cast<double>(model.layerStack.LayerCount())));
runtime.set("compileSucceeded", JsonValue(model.compileSucceeded));
runtime.set("compileMessage", JsonValue(model.compileMessage));
root.set("runtime", runtime);
JsonValue video = JsonValue::MakeObject();
video.set("hasSignal", JsonValue(telemetrySnapshot.signal.hasSignal));
video.set("width", JsonValue(static_cast<double>(telemetrySnapshot.signal.width)));
video.set("height", JsonValue(static_cast<double>(telemetrySnapshot.signal.height)));
video.set("modeName", JsonValue(telemetrySnapshot.signal.modeName));
root.set("video", video);
JsonValue deckLink = JsonValue::MakeObject();
deckLink.set("modelName", JsonValue(telemetrySnapshot.videoIO.modelName));
deckLink.set("supportsInternalKeying", JsonValue(telemetrySnapshot.videoIO.supportsInternalKeying));
deckLink.set("supportsExternalKeying", JsonValue(telemetrySnapshot.videoIO.supportsExternalKeying));
deckLink.set("keyerInterfaceAvailable", JsonValue(telemetrySnapshot.videoIO.keyerInterfaceAvailable));
deckLink.set("externalKeyingRequested", JsonValue(telemetrySnapshot.videoIO.externalKeyingRequested));
deckLink.set("externalKeyingActive", JsonValue(telemetrySnapshot.videoIO.externalKeyingActive));
deckLink.set("statusMessage", JsonValue(telemetrySnapshot.videoIO.statusMessage));
root.set("decklink", deckLink);
JsonValue videoIO = JsonValue::MakeObject();
videoIO.set("backend", JsonValue(telemetrySnapshot.videoIO.backendName));
videoIO.set("modelName", JsonValue(telemetrySnapshot.videoIO.modelName));
videoIO.set("supportsInternalKeying", JsonValue(telemetrySnapshot.videoIO.supportsInternalKeying));
videoIO.set("supportsExternalKeying", JsonValue(telemetrySnapshot.videoIO.supportsExternalKeying));
videoIO.set("keyerInterfaceAvailable", JsonValue(telemetrySnapshot.videoIO.keyerInterfaceAvailable));
videoIO.set("externalKeyingRequested", JsonValue(telemetrySnapshot.videoIO.externalKeyingRequested));
videoIO.set("externalKeyingActive", JsonValue(telemetrySnapshot.videoIO.externalKeyingActive));
videoIO.set("statusMessage", JsonValue(telemetrySnapshot.videoIO.statusMessage));
root.set("videoIO", videoIO);
JsonValue performance = JsonValue::MakeObject();
performance.set("frameBudgetMs", JsonValue(telemetrySnapshot.performance.frameBudgetMilliseconds));
performance.set("renderMs", JsonValue(telemetrySnapshot.performance.renderMilliseconds));
performance.set("smoothedRenderMs", JsonValue(telemetrySnapshot.performance.smoothedRenderMilliseconds));
performance.set("budgetUsedPercent", JsonValue(
telemetrySnapshot.performance.frameBudgetMilliseconds > 0.0
? (telemetrySnapshot.performance.smoothedRenderMilliseconds / telemetrySnapshot.performance.frameBudgetMilliseconds) * 100.0
: 0.0));
performance.set("completionIntervalMs", JsonValue(telemetrySnapshot.performance.completionIntervalMilliseconds));
performance.set("smoothedCompletionIntervalMs", JsonValue(telemetrySnapshot.performance.smoothedCompletionIntervalMilliseconds));
performance.set("maxCompletionIntervalMs", JsonValue(telemetrySnapshot.performance.maxCompletionIntervalMilliseconds));
performance.set("lateFrameCount", JsonValue(static_cast<double>(telemetrySnapshot.performance.lateFrameCount)));
performance.set("droppedFrameCount", JsonValue(static_cast<double>(telemetrySnapshot.performance.droppedFrameCount)));
performance.set("flushedFrameCount", JsonValue(static_cast<double>(telemetrySnapshot.performance.flushedFrameCount)));
root.set("performance", performance);
JsonValue readyQueue = JsonValue::MakeObject();
readyQueue.set("depth", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.readyQueueDepth)));
readyQueue.set("capacity", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.readyQueueCapacity)));
readyQueue.set("minDepth", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.minReadyQueueDepth)));
readyQueue.set("maxDepth", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.maxReadyQueueDepth)));
readyQueue.set("zeroDepthCount", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.readyQueueZeroDepthCount)));
readyQueue.set("pushedCount", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.readyQueuePushedCount)));
readyQueue.set("poppedCount", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.readyQueuePoppedCount)));
readyQueue.set("droppedCount", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.readyQueueDroppedCount)));
readyQueue.set("underrunCount", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.readyQueueUnderrunCount)));
JsonValue outputRender = JsonValue::MakeObject();
outputRender.set("renderMs", JsonValue(telemetrySnapshot.backendPlayout.outputRenderMilliseconds));
outputRender.set("smoothedRenderMs", JsonValue(telemetrySnapshot.backendPlayout.smoothedOutputRenderMilliseconds));
outputRender.set("maxRenderMs", JsonValue(telemetrySnapshot.backendPlayout.maxOutputRenderMilliseconds));
JsonValue recovery = JsonValue::MakeObject();
recovery.set("completionResult", JsonValue(telemetrySnapshot.backendPlayout.completionResult));
recovery.set("completedFrameIndex", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.completedFrameIndex)));
recovery.set("scheduledFrameIndex", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.scheduledFrameIndex)));
recovery.set("scheduledLeadFrames", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.scheduledLeadFrames)));
recovery.set("measuredLagFrames", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.measuredLagFrames)));
recovery.set("catchUpFrames", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.catchUpFrames)));
recovery.set("lateStreak", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.lateStreak)));
recovery.set("dropStreak", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.dropStreak)));
JsonValue backendPlayout = JsonValue::MakeObject();
backendPlayout.set("lifecycleState", JsonValue(telemetrySnapshot.backendPlayout.lifecycleState));
backendPlayout.set("degraded", JsonValue(telemetrySnapshot.backendPlayout.degraded));
backendPlayout.set("statusMessage", JsonValue(telemetrySnapshot.backendPlayout.statusMessage));
backendPlayout.set("lateFrameCount", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.lateFrameCount)));
backendPlayout.set("droppedFrameCount", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.droppedFrameCount)));
backendPlayout.set("flushedFrameCount", JsonValue(static_cast<double>(telemetrySnapshot.backendPlayout.flushedFrameCount)));
backendPlayout.set("readyQueue", readyQueue);
backendPlayout.set("outputRender", outputRender);
backendPlayout.set("recovery", recovery);
root.set("backendPlayout", backendPlayout);
JsonValue eventQueue = JsonValue::MakeObject();
eventQueue.set("name", JsonValue(telemetrySnapshot.runtimeEvents.queue.queueName));
eventQueue.set("depth", JsonValue(static_cast<double>(telemetrySnapshot.runtimeEvents.queue.depth)));
eventQueue.set("capacity", JsonValue(static_cast<double>(telemetrySnapshot.runtimeEvents.queue.capacity)));
eventQueue.set("droppedCount", JsonValue(static_cast<double>(telemetrySnapshot.runtimeEvents.queue.droppedCount)));
eventQueue.set("oldestEventAgeMs", JsonValue(telemetrySnapshot.runtimeEvents.queue.oldestEventAgeMilliseconds));
JsonValue eventDispatch = JsonValue::MakeObject();
eventDispatch.set("dispatchCallCount", JsonValue(static_cast<double>(telemetrySnapshot.runtimeEvents.dispatch.dispatchCallCount)));
eventDispatch.set("dispatchedEventCount", JsonValue(static_cast<double>(telemetrySnapshot.runtimeEvents.dispatch.dispatchedEventCount)));
eventDispatch.set("handlerInvocationCount", JsonValue(static_cast<double>(telemetrySnapshot.runtimeEvents.dispatch.handlerInvocationCount)));
eventDispatch.set("handlerFailureCount", JsonValue(static_cast<double>(telemetrySnapshot.runtimeEvents.dispatch.handlerFailureCount)));
eventDispatch.set("lastDispatchDurationMs", JsonValue(telemetrySnapshot.runtimeEvents.dispatch.lastDispatchDurationMilliseconds));
eventDispatch.set("maxDispatchDurationMs", JsonValue(telemetrySnapshot.runtimeEvents.dispatch.maxDispatchDurationMilliseconds));
JsonValue runtimeEvents = JsonValue::MakeObject();
runtimeEvents.set("queue", eventQueue);
runtimeEvents.set("dispatch", eventDispatch);
root.set("runtimeEvents", runtimeEvents);
JsonValue shaderLibrary = JsonValue::MakeArray();
for (const ShaderPackageStatus& status : model.packageStatuses)
{
JsonValue shader = JsonValue::MakeObject();
shader.set("id", JsonValue(status.id));
shader.set("name", JsonValue(status.displayName));
shader.set("description", JsonValue(status.description));
shader.set("category", JsonValue(status.category));
shader.set("available", JsonValue(status.available));
if (!status.available)
shader.set("error", JsonValue(status.error));
auto shaderIt = model.shaderCatalog.packagesById.find(status.id);
if (status.available && shaderIt != model.shaderCatalog.packagesById.end() && shaderIt->second.temporal.enabled)
{
const ShaderPackage& shaderPackage = shaderIt->second;
JsonValue temporal = JsonValue::MakeObject();
temporal.set("enabled", JsonValue(true));
temporal.set("historySource", JsonValue(RuntimeStateJson::TemporalHistorySourceToString(shaderPackage.temporal.historySource)));
temporal.set("requestedHistoryLength", JsonValue(static_cast<double>(shaderPackage.temporal.requestedHistoryLength)));
temporal.set("effectiveHistoryLength", JsonValue(static_cast<double>(shaderPackage.temporal.effectiveHistoryLength)));
shader.set("temporal", temporal);
}
if (status.available && shaderIt != model.shaderCatalog.packagesById.end() && shaderIt->second.feedback.enabled)
{
const ShaderPackage& shaderPackage = shaderIt->second;
JsonValue feedback = JsonValue::MakeObject();
feedback.set("enabled", JsonValue(true));
feedback.set("writePass", JsonValue(shaderPackage.feedback.writePassId));
shader.set("feedback", feedback);
}
shaderLibrary.pushBack(shader);
}
root.set("shaders", shaderLibrary);
JsonValue stackPresets = JsonValue::MakeArray();
for (const std::string& presetName : model.stackPresetNames)
stackPresets.pushBack(JsonValue(presetName));
root.set("stackPresets", stackPresets);
root.set("layers", RuntimeStateJson::SerializeLayerStack(model.layerStack.Layers(), model.shaderCatalog.packagesById));
return root;
}