#pragma once #include "RuntimeJson.h" #include "ShaderTypes.h" #include #include #include #include #include #include #include #include class RuntimeHost { public: RuntimeHost(); bool Initialize(std::string& error); bool PollFileChanges(bool& registryChanged, bool& reloadRequested, std::string& error); bool ManualReloadRequested(); void ClearReloadRequest(); bool AddLayer(const std::string& shaderId, std::string& error); bool RemoveLayer(const std::string& layerId, std::string& error); bool MoveLayer(const std::string& layerId, int direction, std::string& error); bool MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error); bool SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error); bool SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error); bool UpdateLayerParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error); bool UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error); bool ResetLayerParameters(const std::string& layerId, std::string& error); bool SaveStackPreset(const std::string& presetName, std::string& error) const; bool LoadStackPreset(const std::string& presetName, std::string& error); void SetCompileStatus(bool succeeded, const std::string& message); void SetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName); bool TrySetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName); void SetDeckLinkOutputStatus(const std::string& modelName, bool supportsInternalKeying, bool supportsExternalKeying, bool keyerInterfaceAvailable, bool externalKeyingRequested, bool externalKeyingActive, const std::string& statusMessage); void SetVideoIOStatus(const std::string& backendName, const std::string& modelName, bool supportsInternalKeying, bool supportsExternalKeying, bool keyerInterfaceAvailable, bool externalKeyingRequested, bool externalKeyingActive, const std::string& statusMessage); void SetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds); bool TrySetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds); void SetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); bool TrySetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); void AdvanceFrame(); bool TryAdvanceFrame(); bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector& passSources, std::string& error); std::vector GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const; bool TryGetLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector& states) const; void RefreshDynamicRenderStateFields(std::vector& states) const; std::string BuildStateJson() const; const std::filesystem::path& GetRepoRoot() const { return mRepoRoot; } const std::filesystem::path& GetUiRoot() const { return mUiRoot; } const std::filesystem::path& GetDocsRoot() const { return mDocsRoot; } const std::filesystem::path& GetRuntimeRoot() const { return mRuntimeRoot; } unsigned short GetServerPort() const { return mServerPort; } unsigned short GetOscPort() const { return mConfig.oscPort; } unsigned GetMaxTemporalHistoryFrames() const { return mConfig.maxTemporalHistoryFrames; } bool ExternalKeyingEnabled() const { return mConfig.enableExternalKeying; } const std::string& GetInputVideoFormat() const { return mConfig.inputVideoFormat; } const std::string& GetInputFrameRate() const { return mConfig.inputFrameRate; } const std::string& GetOutputVideoFormat() const { return mConfig.outputVideoFormat; } const std::string& GetOutputFrameRate() const { return mConfig.outputFrameRate; } void SetServerPort(unsigned short port); bool AutoReloadEnabled() const { return mAutoReloadEnabled; } private: struct AppConfig { std::string shaderLibrary = "shaders"; unsigned short serverPort = 8080; unsigned short oscPort = 9000; bool autoReload = true; unsigned maxTemporalHistoryFrames = 4; bool enableExternalKeying = false; std::string inputVideoFormat = "1080p"; std::string inputFrameRate = "59.94"; std::string outputVideoFormat = "1080p"; std::string outputFrameRate = "59.94"; }; struct DeckLinkOutputStatus { std::string backendName = "decklink"; std::string modelName; bool supportsInternalKeying = false; bool supportsExternalKeying = false; bool keyerInterfaceAvailable = false; bool externalKeyingRequested = false; bool externalKeyingActive = false; std::string statusMessage; }; struct LayerPersistentState { std::string id; std::string shaderId; bool bypass = false; std::map parameterValues; }; struct PersistentState { std::vector layers; }; bool LoadConfig(std::string& error); bool LoadPersistentState(std::string& error); bool SavePersistentState(std::string& error) const; bool ScanShaderPackages(std::string& error); 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; 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; bool ResolvePaths(std::string& error); void BuildLayerRenderStatesLocked(unsigned outputWidth, unsigned outputHeight, std::vector& states) const; JsonValue BuildStateValue() const; JsonValue SerializeLayerStackLocked() const; bool DeserializeLayerStackLocked(const JsonValue& layersValue, std::vector& layers, std::string& error); void NormalizePersistentLayerIdsLocked(); std::vector GetStackPresetNamesLocked() const; std::string MakeSafePresetFileStem(const std::string& presetName) const; 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 SetSignalStatusLocked(bool hasSignal, unsigned width, unsigned height, const std::string& modeName); void SetPerformanceStatsLocked(double frameBudgetMilliseconds, double renderMilliseconds); void SetFramePacingStatsLocked(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); private: 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 mPackagesById; std::vector mPackageOrder; std::vector mPackageStatuses; bool mReloadRequested; bool mCompileSucceeded; std::string mCompileMessage; bool mHasSignal; unsigned mSignalWidth; unsigned mSignalHeight; std::string mSignalModeName; double mFrameBudgetMilliseconds; double mRenderMilliseconds; double mSmoothedRenderMilliseconds; double mCompletionIntervalMilliseconds; double mSmoothedCompletionIntervalMilliseconds; double mMaxCompletionIntervalMilliseconds; double mStartupRandom; uint64_t mLateFrameCount; uint64_t mDroppedFrameCount; uint64_t mFlushedFrameCount; DeckLinkOutputStatus mDeckLinkOutputStatus; unsigned short mServerPort; bool mAutoReloadEnabled; std::chrono::steady_clock::time_point mStartTime; std::chrono::steady_clock::time_point mLastScanTime; std::atomic mFrameCounter; uint64_t mNextLayerId; };