phase 1 runtime complete
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m46s
CI / Windows Release Package (push) Successful in 2m59s

This commit is contained in:
Aiden
2026-05-11 02:23:01 +10:00
parent cbf1b541dc
commit 9cbb5d8004
20 changed files with 265 additions and 1288 deletions

View File

@@ -1,103 +0,0 @@
#pragma once
#include "HealthTelemetry.h"
#include "RuntimeJson.h"
#include "ShaderTypes.h"
#include <atomic>
#include <chrono>
#include <filesystem>
#include <map>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
class RuntimeStore;
class RuntimeHost
{
public:
RuntimeHost();
HealthTelemetry& GetHealthTelemetry() { return mHealthTelemetry; }
const HealthTelemetry& GetHealthTelemetry() const { return mHealthTelemetry; }
bool AutoReloadEnabled() const { return mAutoReloadEnabled; }
private:
struct AppConfig
{
std::string shaderLibrary = "shaders";
unsigned short serverPort = 8080;
unsigned short oscPort = 9000;
std::string oscBindAddress = "127.0.0.1";
double oscSmoothing = 0.18;
bool autoReload = true;
unsigned maxTemporalHistoryFrames = 4;
unsigned previewFps = 30;
bool enableExternalKeying = false;
std::string inputVideoFormat = "1080p";
std::string inputFrameRate = "59.94";
std::string outputVideoFormat = "1080p";
std::string outputFrameRate = "59.94";
};
struct LayerPersistentState
{
std::string id;
std::string shaderId;
bool bypass = false;
std::map<std::string, ShaderParameterValue> parameterValues;
};
struct PersistentState
{
std::vector<LayerPersistentState> layers;
};
bool NormalizeAndValidateValue(const ShaderParameterDefinition& definition, const JsonValue& value, ShaderParameterValue& normalizedValue, std::string& error) const;
ShaderParameterValue DefaultValueForDefinition(const ShaderParameterDefinition& definition) const;
void EnsureLayerDefaultsLocked(LayerPersistentState& layerState, const ShaderPackage& shaderPackage) const;
JsonValue SerializeLayerStackLocked() const;
bool DeserializeLayerStackLocked(const JsonValue& layersValue, std::vector<LayerPersistentState>& layers, std::string& error);
void NormalizePersistentLayerIdsLocked();
JsonValue SerializeParameterValue(const ShaderParameterDefinition& definition, const ShaderParameterValue& value) const;
std::string TemporalHistorySourceToString(TemporalHistorySource source) const;
LayerPersistentState* FindLayerById(const std::string& layerId);
const LayerPersistentState* FindLayerById(const std::string& layerId) const;
std::string GenerateLayerId();
void MarkRenderStateDirtyLocked();
void MarkParameterStateDirtyLocked();
private:
friend class RuntimeStore;
friend class RuntimeCoordinator;
HealthTelemetry mHealthTelemetry;
mutable std::mutex mMutex;
AppConfig mConfig;
PersistentState mPersistentState;
std::filesystem::path mRepoRoot;
std::filesystem::path mUiRoot;
std::filesystem::path mDocsRoot;
std::filesystem::path mShaderRoot;
std::filesystem::path mRuntimeRoot;
std::filesystem::path mPresetRoot;
std::filesystem::path mRuntimeStatePath;
std::filesystem::path mConfigPath;
std::filesystem::path mWrapperPath;
std::filesystem::path mGeneratedGlslPath;
std::filesystem::path mPatchedGlslPath;
std::map<std::string, ShaderPackage> mPackagesById;
std::vector<std::string> mPackageOrder;
std::vector<ShaderPackageStatus> mPackageStatuses;
bool mReloadRequested;
bool mCompileSucceeded;
std::string mCompileMessage;
double mStartupRandom;
unsigned short mServerPort;
bool mAutoReloadEnabled;
std::chrono::steady_clock::time_point mStartTime;
std::chrono::steady_clock::time_point mLastScanTime;
std::atomic<uint64_t> mFrameCounter{ 0 };
std::atomic<uint64_t> mRenderStateVersion{ 0 };
std::atomic<uint64_t> mParameterStateVersion{ 0 };
uint64_t mNextLayerId;
};

View File

@@ -22,37 +22,50 @@ std::string ShaderParameterTypeToString(ShaderParameterType type)
JsonValue RuntimeStateJson::SerializeLayerStack(const LayerStackStore& layerStack, const ShaderPackageCatalog& shaderCatalog)
{
JsonValue layers = JsonValue::MakeArray();
for (const LayerStackStore::LayerPersistentState& layer : layerStack.Layers())
std::map<std::string, ShaderPackage> packagesById;
for (const std::string& packageId : shaderCatalog.PackageOrder())
{
const ShaderPackage* shaderPackage = shaderCatalog.FindPackage(layer.shaderId);
if (!shaderPackage)
ShaderPackage shaderPackage;
if (shaderCatalog.CopyPackage(packageId, shaderPackage))
packagesById[packageId] = shaderPackage;
}
return SerializeLayerStack(layerStack.Layers(), packagesById);
}
JsonValue RuntimeStateJson::SerializeLayerStack(const std::vector<LayerStackStore::LayerPersistentState>& layerStates, const std::map<std::string, ShaderPackage>& packagesById)
{
JsonValue layersValue = JsonValue::MakeArray();
for (const LayerStackStore::LayerPersistentState& layer : layerStates)
{
auto shaderIt = packagesById.find(layer.shaderId);
if (shaderIt == packagesById.end())
continue;
const ShaderPackage& shaderPackage = shaderIt->second;
JsonValue layerValue = JsonValue::MakeObject();
layerValue.set("id", JsonValue(layer.id));
layerValue.set("shaderId", JsonValue(layer.shaderId));
layerValue.set("shaderName", JsonValue(shaderPackage->displayName));
layerValue.set("shaderName", JsonValue(shaderPackage.displayName));
layerValue.set("bypass", JsonValue(layer.bypass));
if (shaderPackage->temporal.enabled)
if (shaderPackage.temporal.enabled)
{
JsonValue temporal = JsonValue::MakeObject();
temporal.set("enabled", JsonValue(true));
temporal.set("historySource", JsonValue(TemporalHistorySourceToString(shaderPackage->temporal.historySource)));
temporal.set("requestedHistoryLength", JsonValue(static_cast<double>(shaderPackage->temporal.requestedHistoryLength)));
temporal.set("effectiveHistoryLength", JsonValue(static_cast<double>(shaderPackage->temporal.effectiveHistoryLength)));
temporal.set("historySource", JsonValue(TemporalHistorySourceToString(shaderPackage.temporal.historySource)));
temporal.set("requestedHistoryLength", JsonValue(static_cast<double>(shaderPackage.temporal.requestedHistoryLength)));
temporal.set("effectiveHistoryLength", JsonValue(static_cast<double>(shaderPackage.temporal.effectiveHistoryLength)));
layerValue.set("temporal", temporal);
}
if (shaderPackage->feedback.enabled)
if (shaderPackage.feedback.enabled)
{
JsonValue feedback = JsonValue::MakeObject();
feedback.set("enabled", JsonValue(true));
feedback.set("writePass", JsonValue(shaderPackage->feedback.writePassId));
feedback.set("writePass", JsonValue(shaderPackage.feedback.writePassId));
layerValue.set("feedback", feedback);
}
JsonValue parameters = JsonValue::MakeArray();
for (const ShaderParameterDefinition& definition : shaderPackage->parameters)
for (const ShaderParameterDefinition& definition : shaderPackage.parameters)
{
JsonValue parameter = JsonValue::MakeObject();
parameter.set("id", JsonValue(definition.id));
@@ -111,9 +124,9 @@ JsonValue RuntimeStateJson::SerializeLayerStack(const LayerStackStore& layerStac
}
layerValue.set("parameters", parameters);
layers.pushBack(layerValue);
layersValue.pushBack(layerValue);
}
return layers;
return layersValue;
}
JsonValue RuntimeStateJson::SerializeParameterValue(const ShaderParameterDefinition& definition, const ShaderParameterValue& value)

View File

@@ -5,12 +5,15 @@
#include "ShaderPackageCatalog.h"
#include "ShaderTypes.h"
#include <map>
#include <string>
#include <vector>
class RuntimeStateJson
{
public:
static JsonValue SerializeLayerStack(const LayerStackStore& layerStack, const ShaderPackageCatalog& shaderCatalog);
static JsonValue SerializeLayerStack(const std::vector<LayerStackStore::LayerPersistentState>& layers, const std::map<std::string, ShaderPackage>& packagesById);
static JsonValue SerializeParameterValue(const ShaderParameterDefinition& definition, const ShaderParameterValue& value);
static std::string TemporalHistorySourceToString(TemporalHistorySource source);
};

View File

@@ -3,8 +3,6 @@
#include "RuntimeStateJson.h"
#include "RuntimeStore.h"
#include <mutex>
std::string RuntimeStatePresenter::BuildRuntimeStateJson(const RuntimeStore& runtimeStore)
{
return SerializeJson(BuildRuntimeStateValue(runtimeStore), true);
@@ -12,30 +10,30 @@ std::string RuntimeStatePresenter::BuildRuntimeStateJson(const RuntimeStore& run
JsonValue RuntimeStatePresenter::BuildRuntimeStateValue(const RuntimeStore& runtimeStore)
{
const HealthTelemetry::Snapshot telemetrySnapshot = runtimeStore.mHealthTelemetry.GetSnapshot();
std::lock_guard<std::mutex> lock(runtimeStore.mMutex);
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>(runtimeStore.mServerPort)));
app.set("oscPort", JsonValue(static_cast<double>(runtimeStore.mConfigStore.GetConfig().oscPort)));
app.set("oscBindAddress", JsonValue(runtimeStore.mConfigStore.GetConfig().oscBindAddress));
app.set("oscSmoothing", JsonValue(runtimeStore.mConfigStore.GetConfig().oscSmoothing));
app.set("autoReload", JsonValue(runtimeStore.mAutoReloadEnabled));
app.set("maxTemporalHistoryFrames", JsonValue(static_cast<double>(runtimeStore.mConfigStore.GetConfig().maxTemporalHistoryFrames)));
app.set("previewFps", JsonValue(static_cast<double>(runtimeStore.mConfigStore.GetConfig().previewFps)));
app.set("enableExternalKeying", JsonValue(runtimeStore.mConfigStore.GetConfig().enableExternalKeying));
app.set("inputVideoFormat", JsonValue(runtimeStore.mConfigStore.GetConfig().inputVideoFormat));
app.set("inputFrameRate", JsonValue(runtimeStore.mConfigStore.GetConfig().inputFrameRate));
app.set("outputVideoFormat", JsonValue(runtimeStore.mConfigStore.GetConfig().outputVideoFormat));
app.set("outputFrameRate", JsonValue(runtimeStore.mConfigStore.GetConfig().outputFrameRate));
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>(runtimeStore.mLayerStack.LayerCount())));
runtime.set("compileSucceeded", JsonValue(runtimeStore.mCompileSucceeded));
runtime.set("compileMessage", JsonValue(runtimeStore.mCompileMessage));
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();
@@ -83,7 +81,7 @@ JsonValue RuntimeStatePresenter::BuildRuntimeStateValue(const RuntimeStore& runt
root.set("performance", performance);
JsonValue shaderLibrary = JsonValue::MakeArray();
for (const ShaderPackageStatus& status : runtimeStore.mShaderCatalog.PackageStatuses())
for (const ShaderPackageStatus& status : model.packageStatuses)
{
JsonValue shader = JsonValue::MakeObject();
shader.set("id", JsonValue(status.id));
@@ -94,21 +92,23 @@ JsonValue RuntimeStatePresenter::BuildRuntimeStateValue(const RuntimeStore& runt
if (!status.available)
shader.set("error", JsonValue(status.error));
const ShaderPackage* shaderPackage = runtimeStore.mShaderCatalog.FindPackage(status.id);
if (status.available && shaderPackage && shaderPackage->temporal.enabled)
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)));
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 && shaderPackage && shaderPackage->feedback.enabled)
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));
feedback.set("writePass", JsonValue(shaderPackage.feedback.writePassId));
shader.set("feedback", feedback);
}
shaderLibrary.pushBack(shader);
@@ -116,10 +116,10 @@ JsonValue RuntimeStatePresenter::BuildRuntimeStateValue(const RuntimeStore& runt
root.set("shaders", shaderLibrary);
JsonValue stackPresets = JsonValue::MakeArray();
for (const std::string& presetName : runtimeStore.GetStackPresetNamesLocked())
for (const std::string& presetName : model.stackPresetNames)
stackPresets.pushBack(JsonValue(presetName));
root.set("stackPresets", stackPresets);
root.set("layers", RuntimeStateJson::SerializeLayerStack(runtimeStore.mLayerStack, runtimeStore.mShaderCatalog));
root.set("layers", RuntimeStateJson::SerializeLayerStack(model.layerStack.Layers(), model.shaderCatalog.packagesById));
return root;
}

View File

@@ -24,19 +24,14 @@ bool RenderSnapshotBuilder::BuildLayerPassFragmentShaderSources(const std::strin
if (!mRuntimeStore.CopyShaderPackageForStoredLayer(layerId, shaderPackage, error))
return false;
std::filesystem::path repoRoot;
std::filesystem::path wrapperPath;
std::filesystem::path generatedGlslPath;
std::filesystem::path patchedGlslPath;
unsigned maxTemporalHistoryFrames = 0;
mRuntimeStore.GetShaderCompilerInputs(repoRoot, wrapperPath, generatedGlslPath, patchedGlslPath, maxTemporalHistoryFrames);
const ShaderCompilerInputs inputs = mRuntimeStore.GetShaderCompilerInputs();
ShaderCompiler compiler(
repoRoot,
wrapperPath,
generatedGlslPath,
patchedGlslPath,
maxTemporalHistoryFrames);
inputs.repoRoot,
inputs.wrapperPath,
inputs.generatedGlslPath,
inputs.patchedGlslPath,
inputs.maxTemporalHistoryFrames);
passSources.clear();
passSources.reserve(shaderPackage.passes.size());
for (const ShaderPassDefinition& pass : shaderPackage.passes)
@@ -83,34 +78,24 @@ void RenderSnapshotBuilder::AdvanceFrame()
void RenderSnapshotBuilder::BuildLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const
{
std::lock_guard<std::mutex> lock(mRuntimeStore.mMutex);
BuildLayerRenderStatesLocked(outputWidth, outputHeight, states);
BuildLayerRenderStates(outputWidth, outputHeight, mRuntimeStore.BuildRenderSnapshotReadModel(), states);
}
bool RenderSnapshotBuilder::TryBuildLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const
{
std::unique_lock<std::mutex> lock(mRuntimeStore.mMutex, std::try_to_lock);
if (!lock.owns_lock())
return false;
BuildLayerRenderStatesLocked(outputWidth, outputHeight, states);
BuildLayerRenderStates(outputWidth, outputHeight, mRuntimeStore.BuildRenderSnapshotReadModel(), states);
return true;
}
bool RenderSnapshotBuilder::TryRefreshLayerParameters(std::vector<RuntimeRenderState>& states) const
{
std::unique_lock<std::mutex> lock(mRuntimeStore.mMutex, std::try_to_lock);
if (!lock.owns_lock())
return false;
RefreshLayerParametersLocked(states);
RefreshLayerParameters(mRuntimeStore.CopyLayerStates(), states);
return true;
}
void RenderSnapshotBuilder::RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const
{
std::lock_guard<std::mutex> lock(mRuntimeStore.mMutex);
RefreshDynamicRenderStateFieldsLocked(states);
RefreshDynamicRenderStateFields(mRuntimeStore.GetRenderTimingSnapshot(), states);
}
void RenderSnapshotBuilder::MarkRenderStateDirty()
@@ -124,37 +109,37 @@ void RenderSnapshotBuilder::MarkParameterStateDirty()
mParameterStateVersion.fetch_add(1, std::memory_order_relaxed);
}
void RenderSnapshotBuilder::BuildLayerRenderStatesLocked(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const
void RenderSnapshotBuilder::BuildLayerRenderStates(unsigned outputWidth, unsigned outputHeight, const RenderSnapshotReadModel& readModel, std::vector<RuntimeRenderState>& states) const
{
states.clear();
const HealthTelemetry::SignalStatusSnapshot signalStatus = mRuntimeStore.mHealthTelemetry.GetSignalStatusSnapshot();
for (const RuntimeStore::LayerPersistentState& layer : mRuntimeStore.mLayerStack.Layers())
for (const LayerStackStore::LayerPersistentState& layer : readModel.layers)
{
const ShaderPackage* shaderPackage = mRuntimeStore.mShaderCatalog.FindPackage(layer.shaderId);
if (!shaderPackage)
auto shaderIt = readModel.packagesById.find(layer.shaderId);
if (shaderIt == readModel.packagesById.end())
continue;
const ShaderPackage& shaderPackage = shaderIt->second;
RuntimeRenderState state;
state.layerId = layer.id;
state.shaderId = layer.shaderId;
state.shaderName = shaderPackage->displayName;
state.shaderName = shaderPackage.displayName;
state.mixAmount = 1.0;
state.bypass = layer.bypass ? 1.0 : 0.0;
state.inputWidth = signalStatus.width;
state.inputHeight = signalStatus.height;
state.inputWidth = readModel.signalStatus.width;
state.inputHeight = readModel.signalStatus.height;
state.outputWidth = outputWidth;
state.outputHeight = outputHeight;
state.parameterDefinitions = shaderPackage->parameters;
state.textureAssets = shaderPackage->textureAssets;
state.fontAssets = shaderPackage->fontAssets;
state.isTemporal = shaderPackage->temporal.enabled;
state.temporalHistorySource = shaderPackage->temporal.historySource;
state.requestedTemporalHistoryLength = shaderPackage->temporal.requestedHistoryLength;
state.effectiveTemporalHistoryLength = shaderPackage->temporal.effectiveHistoryLength;
state.feedback = shaderPackage->feedback;
state.parameterDefinitions = shaderPackage.parameters;
state.textureAssets = shaderPackage.textureAssets;
state.fontAssets = shaderPackage.fontAssets;
state.isTemporal = shaderPackage.temporal.enabled;
state.temporalHistorySource = shaderPackage.temporal.historySource;
state.requestedTemporalHistoryLength = shaderPackage.temporal.requestedHistoryLength;
state.effectiveTemporalHistoryLength = shaderPackage.temporal.effectiveHistoryLength;
state.feedback = shaderPackage.feedback;
for (const ShaderParameterDefinition& definition : shaderPackage->parameters)
for (const ShaderParameterDefinition& definition : shaderPackage.parameters)
{
ShaderParameterValue value = DefaultValueForDefinition(definition);
auto valueIt = layer.parameterValues.find(definition.id);
@@ -166,16 +151,16 @@ void RenderSnapshotBuilder::BuildLayerRenderStatesLocked(unsigned outputWidth, u
states.push_back(state);
}
RefreshDynamicRenderStateFieldsLocked(states);
RefreshDynamicRenderStateFields(readModel.timing, states);
}
void RenderSnapshotBuilder::RefreshLayerParametersLocked(std::vector<RuntimeRenderState>& states) const
void RenderSnapshotBuilder::RefreshLayerParameters(const std::vector<LayerStackStore::LayerPersistentState>& layers, std::vector<RuntimeRenderState>& states) const
{
for (RuntimeRenderState& state : states)
{
const auto layerIt = std::find_if(mRuntimeStore.mLayerStack.Layers().begin(), mRuntimeStore.mLayerStack.Layers().end(),
[&state](const RuntimeStore::LayerPersistentState& layer) { return layer.id == state.layerId; });
if (layerIt == mRuntimeStore.mLayerStack.Layers().end())
const auto layerIt = std::find_if(layers.begin(), layers.end(),
[&state](const LayerStackStore::LayerPersistentState& layer) { return layer.id == state.layerId; });
if (layerIt == layers.end())
continue;
state.bypass = layerIt->bypass ? 1.0 : 0.0;
@@ -191,10 +176,10 @@ void RenderSnapshotBuilder::RefreshLayerParametersLocked(std::vector<RuntimeRend
}
}
void RenderSnapshotBuilder::RefreshDynamicRenderStateFieldsLocked(std::vector<RuntimeRenderState>& states) const
void RenderSnapshotBuilder::RefreshDynamicRenderStateFields(const RenderTimingSnapshot& timing, std::vector<RuntimeRenderState>& states) const
{
const RuntimeClockSnapshot clock = GetRuntimeClockSnapshot();
const double timeSeconds = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mRuntimeStore.mStartTime).count();
const double timeSeconds = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - timing.startTime).count();
const double frameCount = static_cast<double>(mFrameCounter.load(std::memory_order_relaxed));
for (RuntimeRenderState& state : states)
@@ -202,7 +187,7 @@ void RenderSnapshotBuilder::RefreshDynamicRenderStateFieldsLocked(std::vector<Ru
state.timeSeconds = timeSeconds;
state.utcTimeSeconds = clock.utcTimeSeconds;
state.utcOffsetSeconds = clock.utcOffsetSeconds;
state.startupRandom = mRuntimeStore.mStartupRandom;
state.startupRandom = timing.startupRandom;
state.frameCount = frameCount;
}
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include "RuntimeStoreReadModels.h"
#include "ShaderTypes.h"
#include <atomic>
@@ -32,9 +33,9 @@ public:
void MarkParameterStateDirty();
private:
void BuildLayerRenderStatesLocked(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const;
void RefreshLayerParametersLocked(std::vector<RuntimeRenderState>& states) const;
void RefreshDynamicRenderStateFieldsLocked(std::vector<RuntimeRenderState>& states) const;
void BuildLayerRenderStates(unsigned outputWidth, unsigned outputHeight, const RenderSnapshotReadModel& readModel, std::vector<RuntimeRenderState>& states) const;
void RefreshLayerParameters(const std::vector<LayerStackStore::LayerPersistentState>& layers, std::vector<RuntimeRenderState>& states) const;
void RefreshDynamicRenderStateFields(const RenderTimingSnapshot& timing, std::vector<RuntimeRenderState>& states) const;
RuntimeStore& mRuntimeStore;
std::atomic<uint64_t> mFrameCounter{ 0 };

View File

@@ -564,15 +564,60 @@ bool RuntimeStore::CopyShaderPackageForStoredLayer(const std::string& layerId, S
return true;
}
void RuntimeStore::GetShaderCompilerInputs(std::filesystem::path& repoRoot, std::filesystem::path& wrapperPath,
std::filesystem::path& generatedGlslPath, std::filesystem::path& patchedGlslPath, unsigned& maxTemporalHistoryFrames) const
ShaderCompilerInputs RuntimeStore::GetShaderCompilerInputs() const
{
std::lock_guard<std::mutex> lock(mMutex);
repoRoot = mConfigStore.GetRepoRoot();
wrapperPath = mConfigStore.GetWrapperPath();
generatedGlslPath = mConfigStore.GetGeneratedGlslPath();
patchedGlslPath = mConfigStore.GetPatchedGlslPath();
maxTemporalHistoryFrames = mConfigStore.GetConfig().maxTemporalHistoryFrames;
ShaderCompilerInputs inputs;
inputs.repoRoot = mConfigStore.GetRepoRoot();
inputs.wrapperPath = mConfigStore.GetWrapperPath();
inputs.generatedGlslPath = mConfigStore.GetGeneratedGlslPath();
inputs.patchedGlslPath = mConfigStore.GetPatchedGlslPath();
inputs.maxTemporalHistoryFrames = mConfigStore.GetConfig().maxTemporalHistoryFrames;
return inputs;
}
RenderSnapshotReadModel RuntimeStore::BuildRenderSnapshotReadModel() const
{
RenderSnapshotReadModel model;
model.signalStatus = mHealthTelemetry.GetSignalStatusSnapshot();
std::lock_guard<std::mutex> lock(mMutex);
model.layers = mLayerStack.Layers();
model.packagesById = mShaderCatalog.CaptureSnapshot().packagesById;
model.timing.startTime = mStartTime;
model.timing.startupRandom = mStartupRandom;
return model;
}
std::vector<RuntimeStore::LayerPersistentState> RuntimeStore::CopyLayerStates() const
{
std::lock_guard<std::mutex> lock(mMutex);
return mLayerStack.Layers();
}
RenderTimingSnapshot RuntimeStore::GetRenderTimingSnapshot() const
{
std::lock_guard<std::mutex> lock(mMutex);
RenderTimingSnapshot snapshot;
snapshot.startTime = mStartTime;
snapshot.startupRandom = mStartupRandom;
return snapshot;
}
RuntimeStatePresentationReadModel RuntimeStore::BuildRuntimeStatePresentationReadModel() const
{
RuntimeStatePresentationReadModel model;
model.telemetry = mHealthTelemetry.GetSnapshot();
std::lock_guard<std::mutex> lock(mMutex);
model.config = mConfigStore.GetConfig();
model.layerStack = mLayerStack;
model.shaderCatalog = mShaderCatalog.CaptureSnapshot();
model.packageStatuses = mShaderCatalog.PackageStatuses();
model.stackPresetNames = GetStackPresetNamesLocked();
model.serverPort = mServerPort;
model.autoReloadEnabled = mAutoReloadEnabled;
model.compileSucceeded = mCompileSucceeded;
model.compileMessage = mCompileMessage;
return model;
}
void RuntimeStore::MarkRenderStateDirtyLocked()

View File

@@ -5,6 +5,7 @@
#include "RenderSnapshotBuilder.h"
#include "RuntimeConfigStore.h"
#include "RuntimeJson.h"
#include "RuntimeStoreReadModels.h"
#include "ShaderPackageCatalog.h"
#include "ShaderTypes.h"
@@ -14,8 +15,6 @@
#include <string>
#include <vector>
class RuntimeStatePresenter;
class RuntimeStore
{
public:
@@ -70,19 +69,20 @@ public:
void SetCompileStatus(bool succeeded, const std::string& message);
void ClearReloadRequest();
bool CopyShaderPackageForStoredLayer(const std::string& layerId, ShaderPackage& shaderPackage, std::string& error) const;
::ShaderCompilerInputs GetShaderCompilerInputs() const;
::RenderSnapshotReadModel BuildRenderSnapshotReadModel() const;
std::vector<LayerPersistentState> CopyLayerStates() const;
::RenderTimingSnapshot GetRenderTimingSnapshot() const;
::RuntimeStatePresentationReadModel BuildRuntimeStatePresentationReadModel() const;
private:
friend class RenderSnapshotBuilder;
friend class RuntimeStatePresenter;
bool LoadPersistentState(std::string& error);
bool SavePersistentState(std::string& error) const;
bool ScanShaderPackages(std::string& error);
std::string ReadTextFile(const std::filesystem::path& path, std::string& error) const;
bool WriteTextFile(const std::filesystem::path& path, const std::string& contents, std::string& error) const;
std::vector<std::string> GetStackPresetNamesLocked() const;
bool CopyShaderPackageForStoredLayer(const std::string& layerId, ShaderPackage& shaderPackage, std::string& error) const;
void GetShaderCompilerInputs(std::filesystem::path& repoRoot, std::filesystem::path& wrapperPath,
std::filesystem::path& generatedGlslPath, std::filesystem::path& patchedGlslPath, unsigned& maxTemporalHistoryFrames) const;
void MarkRenderStateDirtyLocked();
void MarkParameterStateDirtyLocked();

View File

@@ -0,0 +1,50 @@
#pragma once
#include "HealthTelemetry.h"
#include "LayerStackStore.h"
#include "RuntimeConfigStore.h"
#include "ShaderPackageCatalog.h"
#include "ShaderTypes.h"
#include <chrono>
#include <filesystem>
#include <map>
#include <string>
#include <vector>
struct ShaderCompilerInputs
{
std::filesystem::path repoRoot;
std::filesystem::path wrapperPath;
std::filesystem::path generatedGlslPath;
std::filesystem::path patchedGlslPath;
unsigned maxTemporalHistoryFrames = 0;
};
struct RenderTimingSnapshot
{
std::chrono::steady_clock::time_point startTime;
double startupRandom = 0.0;
};
struct RenderSnapshotReadModel
{
std::vector<LayerStackStore::LayerPersistentState> layers;
std::map<std::string, ShaderPackage> packagesById;
HealthTelemetry::SignalStatusSnapshot signalStatus;
RenderTimingSnapshot timing;
};
struct RuntimeStatePresentationReadModel
{
RuntimeConfigStore::AppConfig config;
HealthTelemetry::Snapshot telemetry;
LayerStackStore layerStack;
ShaderPackageCatalog::Snapshot shaderCatalog;
std::vector<ShaderPackageStatus> packageStatuses;
std::vector<std::string> stackPresetNames;
unsigned short serverPort = 0;
bool autoReloadEnabled = false;
bool compileSucceeded = false;
std::string compileMessage;
};

View File

@@ -5,8 +5,8 @@
#include <string>
// Phase 1 compatibility seam for status and timing reporting. HealthTelemetry
// now owns the current operational status snapshot directly, so callers can
// target it without flowing through RuntimeHost-owned backing fields.
// owns the current operational status snapshot directly, so callers can report
// health without sharing runtime-store state.
class HealthTelemetry
{
public: