Runtime snapshot provider changes
Some checks failed
CI / React UI Build (push) Successful in 10s
CI / Native Windows Build And Tests (push) Successful in 2m38s
CI / Windows Release Package (push) Has been cancelled

This commit is contained in:
Aiden
2026-05-11 00:18:01 +10:00
parent 34c145e80b
commit 861593123d
9 changed files with 286 additions and 393 deletions

View File

@@ -7,12 +7,59 @@ RuntimeStore::RuntimeStore(RuntimeHost& runtimeHost) :
bool RuntimeStore::InitializeStore(std::string& error)
{
return mRuntimeHost.Initialize(error);
try
{
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
if (!mRuntimeHost.ResolvePaths(error))
return false;
if (!mRuntimeHost.LoadConfig(error))
return false;
mRuntimeHost.mShaderRoot = mRuntimeHost.mRepoRoot / mRuntimeHost.mConfig.shaderLibrary;
if (!mRuntimeHost.LoadPersistentState(error))
return false;
if (!mRuntimeHost.ScanShaderPackages(error))
return false;
mRuntimeHost.NormalizePersistentLayerIdsLocked();
for (RuntimeHost::LayerPersistentState& layer : mRuntimeHost.mPersistentState.layers)
{
auto shaderIt = mRuntimeHost.mPackagesById.find(layer.shaderId);
if (shaderIt != mRuntimeHost.mPackagesById.end())
mRuntimeHost.EnsureLayerDefaultsLocked(layer, shaderIt->second);
}
if (mRuntimeHost.mPersistentState.layers.empty() && !mRuntimeHost.mPackageOrder.empty())
{
RuntimeHost::LayerPersistentState layer;
layer.id = mRuntimeHost.GenerateLayerId();
layer.shaderId = mRuntimeHost.mPackageOrder.front();
layer.bypass = false;
mRuntimeHost.EnsureLayerDefaultsLocked(layer, mRuntimeHost.mPackagesById[layer.shaderId]);
mRuntimeHost.mPersistentState.layers.push_back(layer);
}
mRuntimeHost.mServerPort = mRuntimeHost.mConfig.serverPort;
mRuntimeHost.mAutoReloadEnabled = mRuntimeHost.mConfig.autoReload;
mRuntimeHost.mReloadRequested = true;
mRuntimeHost.mCompileMessage = "Waiting for shader compile.";
return true;
}
catch (const std::exception& exception)
{
error = std::string("RuntimeStore::InitializeStore exception: ") + exception.what();
return false;
}
catch (...)
{
error = "RuntimeStore::InitializeStore threw a non-standard exception.";
return false;
}
}
std::string RuntimeStore::BuildPersistentStateJson() const
{
return mRuntimeHost.BuildStateJson();
return SerializeJson(BuildRuntimeStateValue(), true);
}
bool RuntimeStore::CreateStoredLayer(const std::string& shaderId, std::string& error)
@@ -159,3 +206,122 @@ void RuntimeStore::ClearReloadRequest()
{
mRuntimeHost.ClearReloadRequest();
}
JsonValue RuntimeStore::BuildRuntimeStateValue() const
{
const HealthTelemetry::Snapshot telemetrySnapshot = mRuntimeHost.mHealthTelemetry.GetSnapshot();
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
JsonValue root = JsonValue::MakeObject();
JsonValue app = JsonValue::MakeObject();
app.set("serverPort", JsonValue(static_cast<double>(mRuntimeHost.mServerPort)));
app.set("oscPort", JsonValue(static_cast<double>(mRuntimeHost.mConfig.oscPort)));
app.set("oscBindAddress", JsonValue(mRuntimeHost.mConfig.oscBindAddress));
app.set("oscSmoothing", JsonValue(mRuntimeHost.mConfig.oscSmoothing));
app.set("autoReload", JsonValue(mRuntimeHost.mAutoReloadEnabled));
app.set("maxTemporalHistoryFrames", JsonValue(static_cast<double>(mRuntimeHost.mConfig.maxTemporalHistoryFrames)));
app.set("previewFps", JsonValue(static_cast<double>(mRuntimeHost.mConfig.previewFps)));
app.set("enableExternalKeying", JsonValue(mRuntimeHost.mConfig.enableExternalKeying));
app.set("inputVideoFormat", JsonValue(mRuntimeHost.mConfig.inputVideoFormat));
app.set("inputFrameRate", JsonValue(mRuntimeHost.mConfig.inputFrameRate));
app.set("outputVideoFormat", JsonValue(mRuntimeHost.mConfig.outputVideoFormat));
app.set("outputFrameRate", JsonValue(mRuntimeHost.mConfig.outputFrameRate));
root.set("app", app);
JsonValue runtime = JsonValue::MakeObject();
runtime.set("layerCount", JsonValue(static_cast<double>(mRuntimeHost.mPersistentState.layers.size())));
runtime.set("compileSucceeded", JsonValue(mRuntimeHost.mCompileSucceeded));
runtime.set("compileMessage", JsonValue(mRuntimeHost.mCompileMessage));
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 shaderLibrary = JsonValue::MakeArray();
for (const ShaderPackageStatus& status : mRuntimeHost.mPackageStatuses)
{
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 = mRuntimeHost.mPackagesById.find(status.id);
if (status.available && shaderIt != mRuntimeHost.mPackagesById.end() && shaderIt->second.temporal.enabled)
{
JsonValue temporal = JsonValue::MakeObject();
temporal.set("enabled", JsonValue(true));
temporal.set("historySource", JsonValue(mRuntimeHost.TemporalHistorySourceToString(shaderIt->second.temporal.historySource)));
temporal.set("requestedHistoryLength", JsonValue(static_cast<double>(shaderIt->second.temporal.requestedHistoryLength)));
temporal.set("effectiveHistoryLength", JsonValue(static_cast<double>(shaderIt->second.temporal.effectiveHistoryLength)));
shader.set("temporal", temporal);
}
if (status.available && shaderIt != mRuntimeHost.mPackagesById.end() && shaderIt->second.feedback.enabled)
{
JsonValue feedback = JsonValue::MakeObject();
feedback.set("enabled", JsonValue(true));
feedback.set("writePass", JsonValue(shaderIt->second.feedback.writePassId));
shader.set("feedback", feedback);
}
shaderLibrary.pushBack(shader);
}
root.set("shaders", shaderLibrary);
JsonValue stackPresets = JsonValue::MakeArray();
for (const std::string& presetName : mRuntimeHost.GetStackPresetNamesLocked())
stackPresets.pushBack(JsonValue(presetName));
root.set("stackPresets", stackPresets);
root.set("layers", SerializeLayerStack());
return root;
}
JsonValue RuntimeStore::SerializeLayerStack() const
{
return mRuntimeHost.SerializeLayerStackLocked();
}