diff --git a/CMakeLists.txt b/CMakeLists.txt index d12938a..3eb89ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,8 @@ set(APP_SOURCES "${APP_DIR}/videoio/decklink/DeckLinkAPI_i.c" "${APP_DIR}/control/ControlServer.cpp" "${APP_DIR}/control/ControlServer.h" + "${APP_DIR}/control/ControlServices.cpp" + "${APP_DIR}/control/ControlServices.h" "${APP_DIR}/control/OscServer.cpp" "${APP_DIR}/control/OscServer.h" "${APP_DIR}/control/RuntimeControlBridge.cpp" @@ -98,6 +100,8 @@ set(APP_SOURCES "${APP_DIR}/resource.h" "${APP_DIR}/runtime/RuntimeHost.cpp" "${APP_DIR}/runtime/RuntimeHost.h" + "${APP_DIR}/runtime/HealthTelemetry.cpp" + "${APP_DIR}/runtime/HealthTelemetry.h" "${APP_DIR}/runtime/RuntimeSnapshotProvider.cpp" "${APP_DIR}/runtime/RuntimeSnapshotProvider.h" "${APP_DIR}/runtime/RuntimeClock.cpp" diff --git a/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj b/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj index 5257d31..e3e3669 100644 --- a/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj +++ b/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj @@ -89,7 +89,7 @@ Disabled - .;control;gl;gl\pipeline;gl\renderer;gl\shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories) + .;control;gl;gl\pipeline;gl\renderer;gl\shader;platform;runtime;shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL @@ -99,7 +99,7 @@ stdcpp17 - opengl32.lib;Glu32.lib;Windowscodecs.lib;Ole32.lib;%(AdditionalDependencies) + opengl32.lib;Glu32.lib;Ws2_32.lib;Crypt32.lib;Advapi32.lib;Gdiplus.lib;Ole32.lib;Windowscodecs.lib;%(AdditionalDependencies) true Windows MachineX86 @@ -111,7 +111,7 @@ Disabled - .;control;gl;gl\pipeline;gl\renderer;gl\shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories) + .;control;gl;gl\pipeline;gl\renderer;gl\shader;platform;runtime;shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL @@ -121,7 +121,7 @@ stdcpp17 - opengl32.lib;Glu32.lib;Windowscodecs.lib;Ole32.lib;%(AdditionalDependencies) + opengl32.lib;Glu32.lib;Ws2_32.lib;Crypt32.lib;Advapi32.lib;Gdiplus.lib;Ole32.lib;Windowscodecs.lib;%(AdditionalDependencies) true Windows MachineX64 @@ -131,7 +131,7 @@ MaxSpeed true - .;control;gl;gl\pipeline;gl\renderer;gl\shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories) + .;control;gl;gl\pipeline;gl\renderer;gl\shader;platform;runtime;shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreadedDLL true @@ -141,7 +141,7 @@ stdcpp17 - opengl32.lib;Glu32.lib;Windowscodecs.lib;Ole32.lib;%(AdditionalDependencies) + opengl32.lib;Glu32.lib;Ws2_32.lib;Crypt32.lib;Advapi32.lib;Gdiplus.lib;Ole32.lib;Windowscodecs.lib;%(AdditionalDependencies) true Windows true @@ -156,7 +156,7 @@ MaxSpeed true - .;control;gl;gl\pipeline;gl\renderer;gl\shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories) + .;control;gl;gl\pipeline;gl\renderer;gl\shader;platform;runtime;shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreadedDLL true @@ -166,7 +166,7 @@ stdcpp17 - opengl32.lib;Glu32.lib;Windowscodecs.lib;Ole32.lib;%(AdditionalDependencies) + opengl32.lib;Glu32.lib;Ws2_32.lib;Crypt32.lib;Advapi32.lib;Gdiplus.lib;Ole32.lib;Windowscodecs.lib;%(AdditionalDependencies) true Windows true @@ -175,18 +175,31 @@ + + + + + + + + + + + + + + - Create Create @@ -194,34 +207,71 @@ Create - + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + - + + + - diff --git a/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj.filters b/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj.filters index c19a028..cf8f9c8 100644 --- a/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj.filters +++ b/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj.filters @@ -18,21 +18,45 @@ + + Source Files + + + Source Files + + + Source Files + + + Source Files + Source Files + + Source Files + + + Source Files + Source Files Source Files + + Source Files + Source Files Source Files + + Source Files + Source Files @@ -45,9 +69,21 @@ Source Files + + Source Files + Source Files + + Source Files + + + Source Files + + + Source Files + Source Files @@ -63,15 +99,45 @@ Source Files + + Source Files + + + Source Files + Source Files Source Files + + Source Files + Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + Source Files @@ -80,9 +146,33 @@ + + Header Files + + + Header Files + + + Header Files + + + Header Files + Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + Header Files @@ -98,6 +188,9 @@ Header Files + + Header Files + Header Files @@ -110,18 +203,66 @@ Header Files + + Header Files + Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + Header Files Header Files + + Header Files + + + Header Files + Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + Header Files @@ -137,6 +278,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + Header Files diff --git a/apps/LoopThroughWithOpenGLCompositing/control/ControlServices.cpp b/apps/LoopThroughWithOpenGLCompositing/control/ControlServices.cpp new file mode 100644 index 0000000..34f3a1c --- /dev/null +++ b/apps/LoopThroughWithOpenGLCompositing/control/ControlServices.cpp @@ -0,0 +1,247 @@ +#include "ControlServices.h" + +#include "ControlServer.h" +#include "OscServer.h" +#include "RuntimeControlBridge.h" +#include "RuntimeHost.h" +#include + +ControlServices::ControlServices() : + mControlServer(std::make_unique()), + mOscServer(std::make_unique()), + mPollRunning(false), + mRegistryChanged(false), + mReloadRequested(false), + mPollFailed(false) +{ +} + +ControlServices::~ControlServices() +{ + Stop(); +} + +bool ControlServices::Start(OpenGLComposite& composite, RuntimeHost& runtimeHost, std::string& error) +{ + Stop(); + + if (!StartControlServicesBoundary(composite, runtimeHost, *this, *mControlServer, *mOscServer, error)) + { + Stop(); + return false; + } + + return true; +} + +void ControlServices::BeginPolling(RuntimeHost& runtimeHost) +{ + StartPolling(runtimeHost); +} + +void ControlServices::Stop() +{ + StopPolling(); + + if (mOscServer) + mOscServer->Stop(); + + if (mControlServer) + mControlServer->Stop(); +} + +void ControlServices::BroadcastState() +{ + if (mControlServer) + mControlServer->BroadcastState(); +} + +void ControlServices::RequestBroadcastState() +{ + if (mControlServer) + mControlServer->RequestBroadcastState(); +} + +bool ControlServices::QueueOscUpdate(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error) +{ + (void)error; + + PendingOscUpdate update; + update.layerKey = layerKey; + update.parameterKey = parameterKey; + update.valueJson = valueJson; + + const std::string routeKey = layerKey + "\n" + parameterKey; + { + std::lock_guard lock(mPendingOscMutex); + mPendingOscUpdates[routeKey] = std::move(update); + } + return true; +} + +bool ControlServices::ApplyPendingOscUpdates(std::vector& appliedUpdates, std::string& error) +{ + appliedUpdates.clear(); + + std::map pending; + { + std::lock_guard lock(mPendingOscMutex); + if (mPendingOscUpdates.empty()) + return true; + pending.swap(mPendingOscUpdates); + } + + for (const auto& entry : pending) + { + JsonValue targetValue; + std::string parseError; + if (!ParseJson(entry.second.valueJson, targetValue, parseError)) + { + OutputDebugStringA(("OSC queued value parse failed: " + parseError + "\n").c_str()); + continue; + } + + AppliedOscUpdate appliedUpdate; + appliedUpdate.routeKey = entry.first; + appliedUpdate.layerKey = entry.second.layerKey; + appliedUpdate.parameterKey = entry.second.parameterKey; + appliedUpdate.targetValue = targetValue; + appliedUpdates.push_back(std::move(appliedUpdate)); + } + + (void)error; + return true; +} + +bool ControlServices::QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, std::string& error) +{ + (void)error; + + PendingOscCommit commit; + commit.routeKey = routeKey; + commit.layerKey = layerKey; + commit.parameterKey = parameterKey; + commit.value = value; + commit.generation = generation; + + { + std::lock_guard lock(mPendingOscCommitMutex); + mPendingOscCommits[routeKey] = std::move(commit); + } + return true; +} + +void ControlServices::ClearOscState() +{ + { + std::lock_guard lock(mPendingOscMutex); + mPendingOscUpdates.clear(); + } + { + std::lock_guard lock(mPendingOscCommitMutex); + mPendingOscCommits.clear(); + } + { + std::lock_guard lock(mCompletedOscCommitMutex); + mCompletedOscCommits.clear(); + } +} + +void ControlServices::ConsumeCompletedOscCommits(std::vector& completedCommits) +{ + completedCommits.clear(); + + std::lock_guard lock(mCompletedOscCommitMutex); + if (mCompletedOscCommits.empty()) + return; + + completedCommits.swap(mCompletedOscCommits); +} + +RuntimePollEvents ControlServices::ConsumePollEvents() +{ + RuntimePollEvents events; + events.registryChanged = mRegistryChanged.exchange(false); + events.reloadRequested = mReloadRequested.exchange(false); + events.failed = mPollFailed.exchange(false); + + if (events.failed) + { + std::lock_guard lock(mPollErrorMutex); + events.error = mPollError; + } + + return events; +} + +void ControlServices::StartPolling(RuntimeHost& runtimeHost) +{ + if (mPollRunning.exchange(true)) + return; + + mPollThread = std::thread([this, &runtimeHost]() { PollLoop(runtimeHost); }); +} + +void ControlServices::StopPolling() +{ + if (!mPollRunning.exchange(false)) + return; + + if (mPollThread.joinable()) + mPollThread.join(); +} + +void ControlServices::PollLoop(RuntimeHost& runtimeHost) +{ + while (mPollRunning) + { + std::map pendingCommits; + { + std::lock_guard lock(mPendingOscCommitMutex); + pendingCommits.swap(mPendingOscCommits); + } + for (const auto& entry : pendingCommits) + { + std::string commitError; + if (runtimeHost.UpdateLayerParameterByControlKey( + entry.second.layerKey, + entry.second.parameterKey, + entry.second.value, + false, + commitError)) + { + CompletedOscCommit completedCommit; + completedCommit.routeKey = entry.second.routeKey; + completedCommit.generation = entry.second.generation; + std::lock_guard lock(mCompletedOscCommitMutex); + mCompletedOscCommits.push_back(std::move(completedCommit)); + } + else if (!commitError.empty()) + { + OutputDebugStringA(("OSC commit failed: " + commitError + "\n").c_str()); + } + } + + bool registryChanged = false; + bool reloadRequested = false; + std::string runtimeError; + if (!runtimeHost.PollFileChanges(registryChanged, reloadRequested, runtimeError)) + { + { + std::lock_guard lock(mPollErrorMutex); + mPollError = runtimeError; + } + mPollFailed = true; + } + else + { + if (registryChanged) + mRegistryChanged = true; + if (reloadRequested) + mReloadRequested = true; + } + + for (int i = 0; i < 25 && mPollRunning; ++i) + Sleep(10); + } +} diff --git a/apps/LoopThroughWithOpenGLCompositing/control/ControlServices.h b/apps/LoopThroughWithOpenGLCompositing/control/ControlServices.h new file mode 100644 index 0000000..35690aa --- /dev/null +++ b/apps/LoopThroughWithOpenGLCompositing/control/ControlServices.h @@ -0,0 +1,95 @@ +#pragma once + +#include "RuntimeJson.h" +#include "ShaderTypes.h" + +#include +#include +#include +#include +#include +#include +#include + +class ControlServer; +class OpenGLComposite; +class OscServer; +class RuntimeHost; + +struct RuntimePollEvents +{ + bool registryChanged = false; + bool reloadRequested = false; + bool failed = false; + std::string error; +}; + +class ControlServices +{ +public: + struct AppliedOscUpdate + { + std::string routeKey; + std::string layerKey; + std::string parameterKey; + JsonValue targetValue; + }; + + struct CompletedOscCommit + { + std::string routeKey; + uint64_t generation = 0; + }; + + ControlServices(); + ~ControlServices(); + + bool Start(OpenGLComposite& composite, RuntimeHost& runtimeHost, std::string& error); + void BeginPolling(RuntimeHost& runtimeHost); + void Stop(); + void BroadcastState(); + void RequestBroadcastState(); + bool QueueOscUpdate(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error); + bool ApplyPendingOscUpdates(std::vector& appliedUpdates, std::string& error); + bool QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, std::string& error); + void ClearOscState(); + void ConsumeCompletedOscCommits(std::vector& completedCommits); + RuntimePollEvents ConsumePollEvents(); + +private: + struct PendingOscUpdate + { + std::string layerKey; + std::string parameterKey; + std::string valueJson; + }; + + struct PendingOscCommit + { + std::string routeKey; + std::string layerKey; + std::string parameterKey; + JsonValue value; + uint64_t generation = 0; + }; + + void StartPolling(RuntimeHost& runtimeHost); + void StopPolling(); + void PollLoop(RuntimeHost& runtimeHost); + + std::unique_ptr mControlServer; + std::unique_ptr mOscServer; + std::thread mPollThread; + std::atomic mPollRunning; + std::atomic mRegistryChanged; + std::atomic mReloadRequested; + std::atomic mPollFailed; + std::mutex mPollErrorMutex; + std::string mPollError; + std::mutex mPendingOscMutex; + std::map mPendingOscUpdates; + std::mutex mPendingOscCommitMutex; + std::map mPendingOscCommits; + std::mutex mCompletedOscCommitMutex; + std::vector mCompletedOscCommits; +}; diff --git a/apps/LoopThroughWithOpenGLCompositing/control/RuntimeControlBridge.cpp b/apps/LoopThroughWithOpenGLCompositing/control/RuntimeControlBridge.cpp index 322475b..3b2a0a1 100644 --- a/apps/LoopThroughWithOpenGLCompositing/control/RuntimeControlBridge.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/control/RuntimeControlBridge.cpp @@ -1,15 +1,15 @@ #include "RuntimeControlBridge.h" +#include "ControlServices.h" #include "ControlServer.h" #include "OpenGLComposite.h" #include "OscServer.h" #include "RuntimeHost.h" -#include "RuntimeServices.h" -bool StartRuntimeControlServices( +bool StartControlServicesBoundary( OpenGLComposite& composite, RuntimeHost& runtimeHost, - RuntimeServices& runtimeServices, + ControlServices& controlServices, ControlServer& controlServer, OscServer& oscServer, std::string& error) @@ -43,8 +43,8 @@ bool StartRuntimeControlServices( runtimeHost.SetServerPort(controlServer.GetPort()); OscServer::Callbacks oscCallbacks; - oscCallbacks.updateParameter = [&runtimeServices](const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& actionError) { - return runtimeServices.QueueOscUpdate(layerKey, parameterKey, valueJson, actionError); + oscCallbacks.updateParameter = [&controlServices](const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& actionError) { + return controlServices.QueueOscUpdate(layerKey, parameterKey, valueJson, actionError); }; if (runtimeHost.GetOscPort() > 0 && !oscServer.Start(runtimeHost.GetOscBindAddress(), runtimeHost.GetOscPort(), oscCallbacks, error)) return false; diff --git a/apps/LoopThroughWithOpenGLCompositing/control/RuntimeControlBridge.h b/apps/LoopThroughWithOpenGLCompositing/control/RuntimeControlBridge.h index e2f4244..0001065 100644 --- a/apps/LoopThroughWithOpenGLCompositing/control/RuntimeControlBridge.h +++ b/apps/LoopThroughWithOpenGLCompositing/control/RuntimeControlBridge.h @@ -3,15 +3,15 @@ #include class ControlServer; +class ControlServices; class OpenGLComposite; class OscServer; class RuntimeHost; -class RuntimeServices; -bool StartRuntimeControlServices( +bool StartControlServicesBoundary( OpenGLComposite& composite, RuntimeHost& runtimeHost, - RuntimeServices& runtimeServices, + ControlServices& controlServices, ControlServer& controlServer, OscServer& oscServer, std::string& error); diff --git a/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.cpp b/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.cpp index 9b9839f..35a034e 100644 --- a/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.cpp @@ -1,18 +1,7 @@ #include "RuntimeServices.h" -#include "ControlServer.h" -#include "OscServer.h" -#include "RuntimeControlBridge.h" -#include "RuntimeHost.h" -#include - RuntimeServices::RuntimeServices() : - mControlServer(std::make_unique()), - mOscServer(std::make_unique()), - mPollRunning(false), - mRegistryChanged(false), - mReloadRequested(false), - mPollFailed(false) + mControlServices(std::make_unique()) { } @@ -23,225 +12,72 @@ RuntimeServices::~RuntimeServices() bool RuntimeServices::Start(OpenGLComposite& composite, RuntimeHost& runtimeHost, std::string& error) { - Stop(); - - if (!StartRuntimeControlServices(composite, runtimeHost, *this, *mControlServer, *mOscServer, error)) - { - Stop(); - return false; - } - - return true; + return mControlServices && mControlServices->Start(composite, runtimeHost, error); } void RuntimeServices::BeginPolling(RuntimeHost& runtimeHost) { - StartPolling(runtimeHost); + if (mControlServices) + mControlServices->BeginPolling(runtimeHost); } void RuntimeServices::Stop() { - StopPolling(); - - if (mOscServer) - mOscServer->Stop(); - - if (mControlServer) - mControlServer->Stop(); + if (mControlServices) + mControlServices->Stop(); } void RuntimeServices::BroadcastState() { - if (mControlServer) - mControlServer->BroadcastState(); + if (mControlServices) + mControlServices->BroadcastState(); } void RuntimeServices::RequestBroadcastState() { - if (mControlServer) - mControlServer->RequestBroadcastState(); + if (mControlServices) + mControlServices->RequestBroadcastState(); } bool RuntimeServices::QueueOscUpdate(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error) { - (void)error; - - PendingOscUpdate update; - update.layerKey = layerKey; - update.parameterKey = parameterKey; - update.valueJson = valueJson; - - const std::string routeKey = layerKey + "\n" + parameterKey; - { - std::lock_guard lock(mPendingOscMutex); - mPendingOscUpdates[routeKey] = std::move(update); - } - return true; + return mControlServices && mControlServices->QueueOscUpdate(layerKey, parameterKey, valueJson, error); } bool RuntimeServices::ApplyPendingOscUpdates(std::vector& appliedUpdates, std::string& error) { - appliedUpdates.clear(); - - std::map pending; + if (!mControlServices) { - std::lock_guard lock(mPendingOscMutex); - if (mPendingOscUpdates.empty()) - return true; - pending.swap(mPendingOscUpdates); + appliedUpdates.clear(); + return true; } - for (const auto& entry : pending) - { - JsonValue targetValue; - std::string parseError; - if (!ParseJson(entry.second.valueJson, targetValue, parseError)) - { - OutputDebugStringA(("OSC queued value parse failed: " + parseError + "\n").c_str()); - continue; - } - - AppliedOscUpdate appliedUpdate; - appliedUpdate.routeKey = entry.first; - appliedUpdate.layerKey = entry.second.layerKey; - appliedUpdate.parameterKey = entry.second.parameterKey; - appliedUpdate.targetValue = targetValue; - appliedUpdates.push_back(std::move(appliedUpdate)); - } - - (void)error; - return true; + return mControlServices->ApplyPendingOscUpdates(appliedUpdates, error); } bool RuntimeServices::QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, std::string& error) { - (void)error; - - PendingOscCommit commit; - commit.routeKey = routeKey; - commit.layerKey = layerKey; - commit.parameterKey = parameterKey; - commit.value = value; - commit.generation = generation; - - { - std::lock_guard lock(mPendingOscCommitMutex); - mPendingOscCommits[routeKey] = std::move(commit); - } - return true; + return mControlServices && mControlServices->QueueOscCommit(routeKey, layerKey, parameterKey, value, generation, error); } void RuntimeServices::ClearOscState() { - { - std::lock_guard lock(mPendingOscMutex); - mPendingOscUpdates.clear(); - } - { - std::lock_guard lock(mPendingOscCommitMutex); - mPendingOscCommits.clear(); - } - { - std::lock_guard lock(mCompletedOscCommitMutex); - mCompletedOscCommits.clear(); - } + if (mControlServices) + mControlServices->ClearOscState(); } void RuntimeServices::ConsumeCompletedOscCommits(std::vector& completedCommits) { - completedCommits.clear(); - - std::lock_guard lock(mCompletedOscCommitMutex); - if (mCompletedOscCommits.empty()) + if (!mControlServices) + { + completedCommits.clear(); return; + } - completedCommits.swap(mCompletedOscCommits); + mControlServices->ConsumeCompletedOscCommits(completedCommits); } RuntimePollEvents RuntimeServices::ConsumePollEvents() { - RuntimePollEvents events; - events.registryChanged = mRegistryChanged.exchange(false); - events.reloadRequested = mReloadRequested.exchange(false); - events.failed = mPollFailed.exchange(false); - - if (events.failed) - { - std::lock_guard lock(mPollErrorMutex); - events.error = mPollError; - } - - return events; -} - -void RuntimeServices::StartPolling(RuntimeHost& runtimeHost) -{ - if (mPollRunning.exchange(true)) - return; - - mPollThread = std::thread([this, &runtimeHost]() { PollLoop(runtimeHost); }); -} - -void RuntimeServices::StopPolling() -{ - if (!mPollRunning.exchange(false)) - return; - - if (mPollThread.joinable()) - mPollThread.join(); -} - -void RuntimeServices::PollLoop(RuntimeHost& runtimeHost) -{ - while (mPollRunning) - { - std::map pendingCommits; - { - std::lock_guard lock(mPendingOscCommitMutex); - pendingCommits.swap(mPendingOscCommits); - } - for (const auto& entry : pendingCommits) - { - std::string commitError; - if (runtimeHost.UpdateLayerParameterByControlKey( - entry.second.layerKey, - entry.second.parameterKey, - entry.second.value, - false, - commitError)) - { - CompletedOscCommit completedCommit; - completedCommit.routeKey = entry.second.routeKey; - completedCommit.generation = entry.second.generation; - std::lock_guard lock(mCompletedOscCommitMutex); - mCompletedOscCommits.push_back(std::move(completedCommit)); - } - else if (!commitError.empty()) - { - OutputDebugStringA(("OSC commit failed: " + commitError + "\n").c_str()); - } - } - - bool registryChanged = false; - bool reloadRequested = false; - std::string runtimeError; - if (!runtimeHost.PollFileChanges(registryChanged, reloadRequested, runtimeError)) - { - { - std::lock_guard lock(mPollErrorMutex); - mPollError = runtimeError; - } - mPollFailed = true; - } - else - { - if (registryChanged) - mRegistryChanged = true; - if (reloadRequested) - mReloadRequested = true; - } - - for (int i = 0; i < 25 && mPollRunning; ++i) - Sleep(10); - } + return mControlServices ? mControlServices->ConsumePollEvents() : RuntimePollEvents{}; } diff --git a/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.h b/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.h index 9289067..9174bbe 100644 --- a/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.h +++ b/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.h @@ -1,44 +1,17 @@ #pragma once -#include "RuntimeJson.h" -#include "ShaderTypes.h" +#include "ControlServices.h" -#include -#include #include -#include #include -#include - -class ControlServer; class OpenGLComposite; -class OscServer; class RuntimeHost; -struct RuntimePollEvents -{ - bool registryChanged = false; - bool reloadRequested = false; - bool failed = false; - std::string error; -}; - class RuntimeServices { public: - struct AppliedOscUpdate - { - std::string routeKey; - std::string layerKey; - std::string parameterKey; - JsonValue targetValue; - }; - - struct CompletedOscCommit - { - std::string routeKey; - uint64_t generation = 0; - }; + using AppliedOscUpdate = ControlServices::AppliedOscUpdate; + using CompletedOscCommit = ControlServices::CompletedOscCommit; RuntimeServices(); ~RuntimeServices(); @@ -56,39 +29,5 @@ public: RuntimePollEvents ConsumePollEvents(); private: - struct PendingOscUpdate - { - std::string layerKey; - std::string parameterKey; - std::string valueJson; - }; - - struct PendingOscCommit - { - std::string routeKey; - std::string layerKey; - std::string parameterKey; - JsonValue value; - uint64_t generation = 0; - }; - - void StartPolling(RuntimeHost& runtimeHost); - void StopPolling(); - void PollLoop(RuntimeHost& runtimeHost); - - std::unique_ptr mControlServer; - std::unique_ptr mOscServer; - std::thread mPollThread; - std::atomic mPollRunning; - std::atomic mRegistryChanged; - std::atomic mReloadRequested; - std::atomic mPollFailed; - std::mutex mPollErrorMutex; - std::string mPollError; - std::mutex mPendingOscMutex; - std::map mPendingOscUpdates; - std::mutex mPendingOscCommitMutex; - std::map mPendingOscCommits; - std::mutex mCompletedOscCommitMutex; - std::vector mCompletedOscCommits; + std::unique_ptr mControlServices; }; diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp index 1affdbc..4e207bd 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp @@ -148,10 +148,10 @@ bool OpenGLComposite::InitVideoIO() VideoFormatSelection videoModes; std::string initFailureReason; - if (mRuntimeStore && mRuntimeStore->GetRepoRoot().empty()) + if (mRuntimeStore && mRuntimeStore->GetRuntimeRepositoryRoot().empty()) { std::string runtimeError; - if (!mRuntimeStore->Initialize(runtimeError)) + if (!mRuntimeStore->InitializeStore(runtimeError)) { MessageBoxA(NULL, runtimeError.c_str(), "Runtime host failed to initialize", MB_OK); return false; @@ -161,10 +161,10 @@ bool OpenGLComposite::InitVideoIO() if (mRuntimeStore) { if (!ResolveConfiguredVideoFormats( - mRuntimeStore->GetInputVideoFormat(), - mRuntimeStore->GetInputFrameRate(), - mRuntimeStore->GetOutputVideoFormat(), - mRuntimeStore->GetOutputFrameRate(), + mRuntimeStore->GetConfiguredInputVideoFormat(), + mRuntimeStore->GetConfiguredInputFrameRate(), + mRuntimeStore->GetConfiguredOutputVideoFormat(), + mRuntimeStore->GetConfiguredOutputFrameRate(), videoModes, initFailureReason)) { @@ -181,7 +181,7 @@ bool OpenGLComposite::InitVideoIO() MessageBoxA(NULL, initFailureReason.c_str(), title, MB_OK | MB_ICONERROR); return false; } - const bool outputAlphaRequired = mRuntimeStore && mRuntimeStore->ExternalKeyingEnabled(); + const bool outputAlphaRequired = mRuntimeStore && mRuntimeStore->IsExternalKeyingConfigured(); if (!mVideoIO->SelectPreferredFormats(videoModes, outputAlphaRequired, initFailureReason)) goto error; @@ -216,7 +216,7 @@ bool OpenGLComposite::InitVideoIO() mRuntimeHost->SetSignalStatus(false, mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight(), mVideoIO->InputDisplayModeName()); } - if (!mVideoIO->ConfigureOutput([this](const VideoIOCompletion& completion) { mVideoIOBridge->PlayoutFrameCompleted(completion); }, videoModes.output, mRuntimeStore && mRuntimeStore->ExternalKeyingEnabled(), initFailureReason)) + if (!mVideoIO->ConfigureOutput([this](const VideoIOCompletion& completion) { mVideoIOBridge->PlayoutFrameCompleted(completion); }, videoModes.output, mRuntimeStore && mRuntimeStore->IsExternalKeyingConfigured(), initFailureReason)) { goto error; } @@ -239,7 +239,7 @@ void OpenGLComposite::paintGL(bool force) if (IsIconic(hGLWnd)) return; - const unsigned previewFps = mRuntimeStore ? mRuntimeStore->GetPreviewFps() : 30u; + const unsigned previewFps = mRuntimeStore ? mRuntimeStore->GetConfiguredPreviewFps() : 30u; if (previewFps == 0) return; @@ -294,7 +294,7 @@ void OpenGLComposite::PublishVideoIOStatus(const std::string& statusMessage) mVideoIO->SupportsInternalKeying(), mVideoIO->SupportsExternalKeying(), mVideoIO->KeyerInterfaceAvailable(), - mRuntimeStore ? mRuntimeStore->ExternalKeyingEnabled() : false, + mRuntimeStore ? mRuntimeStore->IsExternalKeyingConfigured() : false, mVideoIO->ExternalKeyingActive(), mVideoIO->StatusMessage()); } @@ -305,7 +305,7 @@ bool OpenGLComposite::InitOpenGLState() return false; std::string runtimeError; - if (mRuntimeStore->GetRepoRoot().empty() && !mRuntimeStore->Initialize(runtimeError)) + if (mRuntimeStore->GetRuntimeRepositoryRoot().empty() && !mRuntimeStore->InitializeStore(runtimeError)) { MessageBoxA(NULL, runtimeError.c_str(), "Runtime host failed to initialize", MB_OK); return false; @@ -458,7 +458,7 @@ void OpenGLComposite::renderEffect() if (states.empty() || mOscOverlayStates.empty() || !mRuntimeHost) return; - const double smoothing = ClampOscAlpha(mRuntimeStore ? mRuntimeStore->GetOscSmoothing() : 0.0); + const double smoothing = ClampOscAlpha(mRuntimeStore ? mRuntimeStore->GetConfiguredOscSmoothing() : 0.0); std::vector overlayKeysToRemove; for (auto& item : mOscOverlayStates) { @@ -600,35 +600,44 @@ void OpenGLComposite::renderEffect() { const unsigned renderWidth = mVideoIO->InputFrameWidth(); const unsigned renderHeight = mVideoIO->InputFrameHeight(); - const uint64_t renderStateVersion = mRuntimeSnapshotProvider->GetRenderStateVersion(); - const uint64_t parameterStateVersion = mRuntimeSnapshotProvider->GetParameterStateVersion(); + const RuntimeSnapshotVersions versions = mRuntimeSnapshotProvider->GetVersions(); const bool renderStateCacheValid = !mCachedLayerRenderStates.empty() && - mCachedRenderStateVersion == renderStateVersion && + mCachedRenderStateVersion == versions.renderStateVersion && mCachedRenderStateWidth == renderWidth && mCachedRenderStateHeight == renderHeight; if (renderStateCacheValid) { - applyOscOverlays(mCachedLayerRenderStates, true); - if (mCachedParameterStateVersion != parameterStateVersion && - mRuntimeSnapshotProvider->TryRefreshCachedLayerStates(mCachedLayerRenderStates)) + RuntimeRenderStateSnapshot renderSnapshot; + renderSnapshot.outputWidth = renderWidth; + renderSnapshot.outputHeight = renderHeight; + renderSnapshot.versions.renderStateVersion = mCachedRenderStateVersion; + renderSnapshot.versions.parameterStateVersion = mCachedParameterStateVersion; + renderSnapshot.states = mCachedLayerRenderStates; + + applyOscOverlays(renderSnapshot.states, true); + if (mCachedParameterStateVersion != versions.parameterStateVersion && + mRuntimeSnapshotProvider->TryRefreshSnapshotParameters(renderSnapshot)) { - mCachedParameterStateVersion = parameterStateVersion; - applyOscOverlays(mCachedLayerRenderStates, true); + mCachedParameterStateVersion = renderSnapshot.versions.parameterStateVersion; + applyOscOverlays(renderSnapshot.states, true); } - layerStates = mCachedLayerRenderStates; + + mCachedLayerRenderStates = renderSnapshot.states; + layerStates = renderSnapshot.states; mRuntimeSnapshotProvider->RefreshDynamicRenderStateFields(layerStates); } else { - if (mRuntimeSnapshotProvider->TryGetLayerRenderStates(renderWidth, renderHeight, layerStates)) + RuntimeRenderStateSnapshot renderSnapshot; + if (mRuntimeSnapshotProvider->TryGetRenderStateSnapshot(renderWidth, renderHeight, renderSnapshot)) { - mCachedLayerRenderStates = layerStates; - mCachedRenderStateVersion = renderStateVersion; - mCachedParameterStateVersion = parameterStateVersion; - mCachedRenderStateWidth = renderWidth; - mCachedRenderStateHeight = renderHeight; + mCachedLayerRenderStates = renderSnapshot.states; + mCachedRenderStateVersion = renderSnapshot.versions.renderStateVersion; + mCachedParameterStateVersion = renderSnapshot.versions.parameterStateVersion; + mCachedRenderStateWidth = renderSnapshot.outputWidth; + mCachedRenderStateHeight = renderSnapshot.outputHeight; applyOscOverlays(mCachedLayerRenderStates, true); layerStates = mCachedLayerRenderStates; } @@ -640,7 +649,7 @@ void OpenGLComposite::renderEffect() } } } - const unsigned historyCap = mRuntimeStore ? mRuntimeStore->GetMaxTemporalHistoryFrames() : 0; + const unsigned historyCap = mRuntimeStore ? mRuntimeStore->GetConfiguredMaxTemporalHistoryFrames() : 0; mRenderPass->Render( hasInputSource, layerStates, @@ -701,8 +710,8 @@ void OpenGLComposite::ProcessScreenshotRequest() std::filesystem::path OpenGLComposite::BuildScreenshotPath() const { - const std::filesystem::path root = mRuntimeStore && !mRuntimeStore->GetRuntimeRoot().empty() - ? mRuntimeStore->GetRuntimeRoot() + const std::filesystem::path root = mRuntimeStore && !mRuntimeStore->GetRuntimeDataRoot().empty() + ? mRuntimeStore->GetRuntimeDataRoot() : std::filesystem::current_path(); const auto now = std::chrono::system_clock::now(); diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLCompositeRuntimeControls.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLCompositeRuntimeControls.cpp index 49d1509..970c710 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLCompositeRuntimeControls.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLCompositeRuntimeControls.cpp @@ -3,22 +3,22 @@ std::string OpenGLComposite::GetRuntimeStateJson() const { - return mRuntimeStore ? mRuntimeStore->BuildStateJson() : "{}"; + return mRuntimeStore ? mRuntimeStore->BuildPersistentStateJson() : "{}"; } unsigned short OpenGLComposite::GetControlServerPort() const { - return mRuntimeStore ? mRuntimeStore->GetServerPort() : 0; + return mRuntimeStore ? mRuntimeStore->GetConfiguredControlServerPort() : 0; } unsigned short OpenGLComposite::GetOscPort() const { - return mRuntimeStore ? mRuntimeStore->GetOscPort() : 0; + return mRuntimeStore ? mRuntimeStore->GetConfiguredOscPort() : 0; } std::string OpenGLComposite::GetOscBindAddress() const { - return mRuntimeStore ? mRuntimeStore->GetOscBindAddress() : "127.0.0.1"; + return mRuntimeStore ? mRuntimeStore->GetConfiguredOscBindAddress() : "127.0.0.1"; } std::string OpenGLComposite::GetControlUrl() const @@ -38,7 +38,7 @@ std::string OpenGLComposite::GetOscAddress() const bool OpenGLComposite::AddLayer(const std::string& shaderId, std::string& error) { - if (!mRuntimeStore->AddLayer(shaderId, error)) + if (!mRuntimeStore->CreateStoredLayer(shaderId, error)) return false; ReloadShader(true); @@ -48,7 +48,7 @@ bool OpenGLComposite::AddLayer(const std::string& shaderId, std::string& error) bool OpenGLComposite::RemoveLayer(const std::string& layerId, std::string& error) { - if (!mRuntimeStore->RemoveLayer(layerId, error)) + if (!mRuntimeStore->DeleteStoredLayer(layerId, error)) return false; ReloadShader(true); @@ -58,7 +58,7 @@ bool OpenGLComposite::RemoveLayer(const std::string& layerId, std::string& error bool OpenGLComposite::MoveLayer(const std::string& layerId, int direction, std::string& error) { - if (!mRuntimeStore->MoveLayer(layerId, direction, error)) + if (!mRuntimeStore->MoveStoredLayer(layerId, direction, error)) return false; ReloadShader(true); @@ -68,7 +68,7 @@ bool OpenGLComposite::MoveLayer(const std::string& layerId, int direction, std:: bool OpenGLComposite::MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error) { - if (!mRuntimeStore->MoveLayerToIndex(layerId, targetIndex, error)) + if (!mRuntimeStore->MoveStoredLayerToIndex(layerId, targetIndex, error)) return false; ReloadShader(true); @@ -78,7 +78,7 @@ bool OpenGLComposite::MoveLayerToIndex(const std::string& layerId, std::size_t t bool OpenGLComposite::SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error) { - if (!mRuntimeStore->SetLayerBypass(layerId, bypassed, error)) + if (!mRuntimeStore->SetStoredLayerBypassState(layerId, bypassed, error)) return false; ReloadShader(); @@ -88,7 +88,7 @@ bool OpenGLComposite::SetLayerBypass(const std::string& layerId, bool bypassed, bool OpenGLComposite::SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error) { - if (!mRuntimeStore->SetLayerShader(layerId, shaderId, error)) + if (!mRuntimeStore->SetStoredLayerShaderSelection(layerId, shaderId, error)) return false; ReloadShader(); @@ -102,7 +102,7 @@ bool OpenGLComposite::UpdateLayerParameterJson(const std::string& layerId, const if (!ParseJson(valueJson, parsedValue, error)) return false; - if (!mRuntimeStore->UpdateLayerParameter(layerId, parameterId, parsedValue, error)) + if (!mRuntimeStore->SetStoredParameterValue(layerId, parameterId, parsedValue, error)) return false; broadcastRuntimeState(); @@ -115,7 +115,7 @@ bool OpenGLComposite::UpdateLayerParameterByControlKeyJson(const std::string& la if (!ParseJson(valueJson, parsedValue, error)) return false; - if (!mRuntimeStore->UpdateLayerParameterByControlKey(layerKey, parameterKey, parsedValue, error)) + if (!mRuntimeStore->SetStoredParameterValueByControlKey(layerKey, parameterKey, parsedValue, error)) return false; broadcastRuntimeState(); @@ -124,7 +124,7 @@ bool OpenGLComposite::UpdateLayerParameterByControlKeyJson(const std::string& la bool OpenGLComposite::ResetLayerParameters(const std::string& layerId, std::string& error) { - if (!mRuntimeStore->ResetLayerParameters(layerId, error)) + if (!mRuntimeStore->ResetStoredLayerParameterValues(layerId, error)) return false; mOscOverlayStates.clear(); @@ -138,7 +138,7 @@ bool OpenGLComposite::ResetLayerParameters(const std::string& layerId, std::stri bool OpenGLComposite::SaveStackPreset(const std::string& presetName, std::string& error) { - if (!mRuntimeStore->SaveStackPreset(presetName, error)) + if (!mRuntimeStore->SaveStackPresetSnapshot(presetName, error)) return false; broadcastRuntimeState(); @@ -147,7 +147,7 @@ bool OpenGLComposite::SaveStackPreset(const std::string& presetName, std::string bool OpenGLComposite::LoadStackPreset(const std::string& presetName, std::string& error) { - if (!mRuntimeStore->LoadStackPreset(presetName, error)) + if (!mRuntimeStore->LoadStackPresetSnapshot(presetName, error)) return false; ReloadShader(); diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPipeline.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPipeline.cpp index e02eaee..7328f9d 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPipeline.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPipeline.cpp @@ -47,7 +47,7 @@ bool OpenGLRenderPipeline::RenderFrame(const RenderPipelineFrameContext& context const auto renderEndTime = std::chrono::steady_clock::now(); const double renderMilliseconds = std::chrono::duration_cast>(renderEndTime - renderStartTime).count(); - mRuntimeHost.TrySetPerformanceStats(state.frameBudgetMilliseconds, renderMilliseconds); + mRuntimeHost.GetHealthTelemetry().TryRecordPerformanceStats(state.frameBudgetMilliseconds, renderMilliseconds); mRuntimeHost.TryAdvanceFrame(); ReadOutputFrame(state, outputFrame); diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLVideoIOBridge.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLVideoIOBridge.cpp index 0dff738..11501c8 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLVideoIOBridge.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLVideoIOBridge.cpp @@ -46,7 +46,7 @@ void OpenGLVideoIOBridge::RecordFramePacing(VideoIOCompletionResult completionRe else if (completionResult == VideoIOCompletionResult::Flushed) ++mFlushedFrameCount; - mRuntimeHost.TrySetFramePacingStats( + mRuntimeHost.GetHealthTelemetry().TryRecordFramePacingStats( mCompletionIntervalMilliseconds, mSmoothedCompletionIntervalMilliseconds, mMaxCompletionIntervalMilliseconds, @@ -58,7 +58,7 @@ void OpenGLVideoIOBridge::RecordFramePacing(VideoIOCompletionResult completionRe void OpenGLVideoIOBridge::VideoFrameArrived(const VideoIOFrame& inputFrame) { const VideoIOState& state = mVideoIO.State(); - mRuntimeHost.TrySetSignalStatus(!inputFrame.hasNoInputSource, state.inputFrameSize.width, state.inputFrameSize.height, state.inputDisplayModeName); + mRuntimeHost.GetHealthTelemetry().TryReportSignalStatus(!inputFrame.hasNoInputSource, state.inputFrameSize.width, state.inputFrameSize.height, state.inputDisplayModeName); if (inputFrame.hasNoInputSource || inputFrame.bytes == nullptr) return; // don't transfer texture when there's no input diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/shader/OpenGLShaderPrograms.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/shader/OpenGLShaderPrograms.cpp index 78f2388..894ecfe 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/shader/OpenGLShaderPrograms.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/shader/OpenGLShaderPrograms.cpp @@ -40,7 +40,9 @@ OpenGLShaderPrograms::OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost bool OpenGLShaderPrograms::CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage) { - const std::vector layerStates = mRuntimeSnapshotProvider.GetLayerRenderStates(inputFrameWidth, inputFrameHeight); + const RuntimeRenderStateSnapshot renderSnapshot = + mRuntimeSnapshotProvider.GetRenderStateSnapshot(inputFrameWidth, inputFrameHeight); + const std::vector& layerStates = renderSnapshot.states; std::string temporalError; const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames(); if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(layerStates, historyCap, temporalError)) @@ -88,7 +90,7 @@ bool OpenGLShaderPrograms::CompileLayerPrograms(unsigned inputFrameWidth, unsign DestroyLayerPrograms(); mRenderer.ReplaceLayerPrograms(newPrograms); - mCommittedLayerStates = layerStates; + mCommittedLayerStates = renderSnapshot.states; mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully."); mRuntimeHost.ClearReloadRequest(); @@ -106,18 +108,18 @@ bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild std::string temporalError; const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames(); - if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(preparedBuild.layerStates, historyCap, temporalError)) + if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(preparedBuild.renderSnapshot.states, historyCap, temporalError)) { CopyErrorMessage(temporalError, errorMessageSize, errorMessage); return false; } - if (!mRenderer.TemporalHistory().EnsureResources(preparedBuild.layerStates, historyCap, inputFrameWidth, inputFrameHeight, temporalError)) + if (!mRenderer.TemporalHistory().EnsureResources(preparedBuild.renderSnapshot.states, historyCap, inputFrameWidth, inputFrameHeight, temporalError)) { CopyErrorMessage(temporalError, errorMessageSize, errorMessage); return false; } if (mRenderer.ResourcesInitialized() && - !mRenderer.FeedbackBuffers().EnsureResources(preparedBuild.layerStates, inputFrameWidth, inputFrameHeight, temporalError)) + !mRenderer.FeedbackBuffers().EnsureResources(preparedBuild.renderSnapshot.states, inputFrameWidth, inputFrameHeight, temporalError)) { CopyErrorMessage(temporalError, errorMessageSize, errorMessage); return false; @@ -151,7 +153,7 @@ bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild DestroyLayerPrograms(); mRenderer.ReplaceLayerPrograms(newPrograms); - mCommittedLayerStates = preparedBuild.layerStates; + mCommittedLayerStates = preparedBuild.renderSnapshot.states; mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully."); mRuntimeHost.ClearReloadRequest(); diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderBuildQueue.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderBuildQueue.cpp index 35c1bd8..ee9fb45 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderBuildQueue.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderBuildQueue.cpp @@ -111,10 +111,10 @@ PreparedShaderBuild ShaderBuildQueue::Build(uint64_t generation, unsigned output { PreparedShaderBuild build; build.generation = generation; - build.layerStates = mRuntimeSnapshotProvider.GetLayerRenderStates(outputWidth, outputHeight); - build.layers.reserve(build.layerStates.size()); + build.renderSnapshot = mRuntimeSnapshotProvider.GetRenderStateSnapshot(outputWidth, outputHeight); + build.layers.reserve(build.renderSnapshot.states.size()); - for (const RuntimeRenderState& state : build.layerStates) + for (const RuntimeRenderState& state : build.renderSnapshot.states) { PreparedLayerShader layer; layer.state = state; diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderBuildQueue.h b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderBuildQueue.h index 1fcec45..ea36368 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderBuildQueue.h +++ b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderBuildQueue.h @@ -21,7 +21,7 @@ struct PreparedShaderBuild uint64_t generation = 0; bool succeeded = false; std::string message; - std::vector layerStates; + RuntimeRenderStateSnapshot renderSnapshot; std::vector layers; }; diff --git a/apps/LoopThroughWithOpenGLCompositing/runtime/HealthTelemetry.cpp b/apps/LoopThroughWithOpenGLCompositing/runtime/HealthTelemetry.cpp new file mode 100644 index 0000000..0d41d2b --- /dev/null +++ b/apps/LoopThroughWithOpenGLCompositing/runtime/HealthTelemetry.cpp @@ -0,0 +1,43 @@ +#include "stdafx.h" +#include "HealthTelemetry.h" + +#include "RuntimeHost.h" + +HealthTelemetry::HealthTelemetry(RuntimeHost& runtimeHost) : + mRuntimeHost(runtimeHost) +{ +} + +void HealthTelemetry::ReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName) +{ + mRuntimeHost.WriteSignalStatus(hasSignal, width, height, modeName); +} + +bool HealthTelemetry::TryReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName) +{ + return mRuntimeHost.TryWriteSignalStatus(hasSignal, width, height, modeName); +} + +void HealthTelemetry::RecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds) +{ + mRuntimeHost.WritePerformanceStats(frameBudgetMilliseconds, renderMilliseconds); +} + +bool HealthTelemetry::TryRecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds) +{ + return mRuntimeHost.TryWritePerformanceStats(frameBudgetMilliseconds, renderMilliseconds); +} + +void HealthTelemetry::RecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, + double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount) +{ + mRuntimeHost.WriteFramePacingStats(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds, + maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount); +} + +bool HealthTelemetry::TryRecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, + double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount) +{ + return mRuntimeHost.TryWriteFramePacingStats(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds, + maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount); +} diff --git a/apps/LoopThroughWithOpenGLCompositing/runtime/HealthTelemetry.h b/apps/LoopThroughWithOpenGLCompositing/runtime/HealthTelemetry.h new file mode 100644 index 0000000..1420697 --- /dev/null +++ b/apps/LoopThroughWithOpenGLCompositing/runtime/HealthTelemetry.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +class RuntimeHost; + +// Phase 1 compatibility seam for status and timing reporting. The current +// implementation still writes through RuntimeHost, but callers can now target +// HealthTelemetry as the home for operational visibility work. +class HealthTelemetry +{ +public: + explicit HealthTelemetry(RuntimeHost& runtimeHost); + + void ReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName); + bool TryReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName); + + void RecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds); + bool TryRecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds); + + void RecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, + double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); + bool TryRecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, + double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); + +private: + RuntimeHost& mRuntimeHost; +}; diff --git a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.cpp b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.cpp index e9aee36..50d0383 100644 --- a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.cpp @@ -699,7 +699,8 @@ bool ParseParameterDefinitions(const JsonValue& manifestJson, ShaderPackage& sha } RuntimeHost::RuntimeHost() - : mReloadRequested(false), + : mHealthTelemetry(*this), + mReloadRequested(false), mCompileSucceeded(false), mHasSignal(false), mSignalWidth(0), @@ -1351,12 +1352,22 @@ void RuntimeHost::SetCompileStatus(bool succeeded, const std::string& message) } void RuntimeHost::SetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName) +{ + mHealthTelemetry.ReportSignalStatus(hasSignal, width, height, modeName); +} + +bool RuntimeHost::TrySetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName) +{ + return mHealthTelemetry.TryReportSignalStatus(hasSignal, width, height, modeName); +} + +void RuntimeHost::WriteSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName) { std::lock_guard lock(mMutex); SetSignalStatusLocked(hasSignal, width, height, modeName); } -bool RuntimeHost::TrySetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName) +bool RuntimeHost::TryWriteSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName) { std::unique_lock lock(mMutex, std::try_to_lock); if (!lock.owns_lock()) @@ -1413,12 +1424,22 @@ void RuntimeHost::SetVideoIOStatus(const std::string& backendName, const std::st } void RuntimeHost::SetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds) +{ + mHealthTelemetry.RecordPerformanceStats(frameBudgetMilliseconds, renderMilliseconds); +} + +bool RuntimeHost::TrySetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds) +{ + return mHealthTelemetry.TryRecordPerformanceStats(frameBudgetMilliseconds, renderMilliseconds); +} + +void RuntimeHost::WritePerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds) { std::lock_guard lock(mMutex); SetPerformanceStatsLocked(frameBudgetMilliseconds, renderMilliseconds); } -bool RuntimeHost::TrySetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds) +bool RuntimeHost::TryWritePerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds) { std::unique_lock lock(mMutex, std::try_to_lock); if (!lock.owns_lock()) @@ -1440,13 +1461,27 @@ void RuntimeHost::SetPerformanceStatsLocked(double frameBudgetMilliseconds, doub void RuntimeHost::SetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount) +{ + mHealthTelemetry.RecordFramePacingStats(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds, + maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount); +} + +bool RuntimeHost::TrySetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, + double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount) +{ + return mHealthTelemetry.TryRecordFramePacingStats(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds, + maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount); +} + +void RuntimeHost::WriteFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, + double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount) { std::lock_guard lock(mMutex); SetFramePacingStatsLocked(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds, maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount); } -bool RuntimeHost::TrySetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, +bool RuntimeHost::TryWriteFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount) { std::unique_lock lock(mMutex, std::try_to_lock); diff --git a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.h b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.h index 0a33330..c1837b1 100644 --- a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.h +++ b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.h @@ -1,5 +1,6 @@ #pragma once +#include "HealthTelemetry.h" #include "RuntimeJson.h" #include "ShaderTypes.h" @@ -52,6 +53,8 @@ public: double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); void AdvanceFrame(); bool TryAdvanceFrame(); + HealthTelemetry& GetHealthTelemetry() { return mHealthTelemetry; } + const HealthTelemetry& GetHealthTelemetry() const { return mHealthTelemetry; } bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector& passSources, std::string& error); std::vector GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const; @@ -145,14 +148,24 @@ private: LayerPersistentState* FindLayerById(const std::string& layerId); const LayerPersistentState* FindLayerById(const std::string& layerId) const; std::string GenerateLayerId(); + void WriteSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName); + bool TryWriteSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName); void SetSignalStatusLocked(bool hasSignal, unsigned width, unsigned height, const std::string& modeName); void MarkRenderStateDirtyLocked(); void MarkParameterStateDirtyLocked(); + void WritePerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds); + bool TryWritePerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds); void SetPerformanceStatsLocked(double frameBudgetMilliseconds, double renderMilliseconds); + void WriteFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, + double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); + bool TryWriteFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, + double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); void SetFramePacingStatsLocked(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds, double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount); private: + friend class HealthTelemetry; + HealthTelemetry mHealthTelemetry; mutable std::mutex mMutex; AppConfig mConfig; PersistentState mPersistentState; diff --git a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeSnapshotProvider.cpp b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeSnapshotProvider.cpp index 5cd1802..e4d590d 100644 --- a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeSnapshotProvider.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeSnapshotProvider.cpp @@ -1,5 +1,7 @@ #include "RuntimeSnapshotProvider.h" +#include + RuntimeSnapshotProvider::RuntimeSnapshotProvider(RuntimeHost& runtimeHost) : mRuntimeHost(runtimeHost) { @@ -10,32 +12,142 @@ bool RuntimeSnapshotProvider::BuildLayerPassFragmentShaderSources(const std::str return mRuntimeHost.BuildLayerPassFragmentShaderSources(layerId, passSources, error); } +RuntimeSnapshotVersions RuntimeSnapshotProvider::GetVersions() const +{ + RuntimeSnapshotVersions versions; + versions.renderStateVersion = mRuntimeHost.GetRenderStateVersion(); + versions.parameterStateVersion = mRuntimeHost.GetParameterStateVersion(); + return versions; +} + +RuntimeRenderFrameContext RuntimeSnapshotProvider::GetFrameContext() const +{ + std::vector stateScratch(1); + mRuntimeHost.RefreshDynamicRenderStateFields(stateScratch); + + RuntimeRenderFrameContext frameContext; + const RuntimeRenderState& state = stateScratch.front(); + frameContext.timeSeconds = state.timeSeconds; + frameContext.utcTimeSeconds = state.utcTimeSeconds; + frameContext.utcOffsetSeconds = state.utcOffsetSeconds; + frameContext.startupRandom = state.startupRandom; + frameContext.frameCount = state.frameCount; + return frameContext; +} + +RuntimeRenderStateSnapshot RuntimeSnapshotProvider::GetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight) const +{ + for (;;) + { + const RuntimeSnapshotVersions versionsBefore = GetVersions(); + + RuntimeRenderStateSnapshot snapshot; + snapshot.outputWidth = outputWidth; + snapshot.outputHeight = outputHeight; + snapshot.states = mRuntimeHost.GetLayerRenderStates(outputWidth, outputHeight); + + const RuntimeSnapshotVersions versionsAfter = GetVersions(); + if (versionsBefore.renderStateVersion == versionsAfter.renderStateVersion && + versionsBefore.parameterStateVersion == versionsAfter.parameterStateVersion) + { + snapshot.versions = versionsAfter; + return snapshot; + } + } +} + +bool RuntimeSnapshotProvider::TryGetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight, RuntimeRenderStateSnapshot& snapshot) const +{ + const RuntimeSnapshotVersions versionsBefore = GetVersions(); + + std::vector states; + if (!mRuntimeHost.TryGetLayerRenderStates(outputWidth, outputHeight, states)) + return false; + + const RuntimeSnapshotVersions versionsAfter = GetVersions(); + if (versionsBefore.renderStateVersion != versionsAfter.renderStateVersion || + versionsBefore.parameterStateVersion != versionsAfter.parameterStateVersion) + { + return false; + } + + snapshot.outputWidth = outputWidth; + snapshot.outputHeight = outputHeight; + snapshot.versions = versionsAfter; + snapshot.states = std::move(states); + return true; +} + +bool RuntimeSnapshotProvider::TryRefreshSnapshotParameters(RuntimeRenderStateSnapshot& snapshot) const +{ + const uint64_t expectedRenderStateVersion = snapshot.versions.renderStateVersion; + if (!mRuntimeHost.TryRefreshCachedLayerStates(snapshot.states)) + return false; + + const RuntimeSnapshotVersions versions = GetVersions(); + if (versions.renderStateVersion != expectedRenderStateVersion) + return false; + + snapshot.versions = versions; + return true; +} + +void RuntimeSnapshotProvider::ApplyFrameContext(std::vector& states, const RuntimeRenderFrameContext& frameContext) const +{ + for (RuntimeRenderState& state : states) + { + state.timeSeconds = frameContext.timeSeconds; + state.utcTimeSeconds = frameContext.utcTimeSeconds; + state.utcOffsetSeconds = frameContext.utcOffsetSeconds; + state.startupRandom = frameContext.startupRandom; + state.frameCount = frameContext.frameCount; + } +} + +void RuntimeSnapshotProvider::ApplyFrameContext(RuntimeRenderStateSnapshot& snapshot, const RuntimeRenderFrameContext& frameContext) const +{ + ApplyFrameContext(snapshot.states, frameContext); +} + std::vector RuntimeSnapshotProvider::GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const { - return mRuntimeHost.GetLayerRenderStates(outputWidth, outputHeight); + return GetRenderStateSnapshot(outputWidth, outputHeight).states; } bool RuntimeSnapshotProvider::TryGetLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector& states) const { - return mRuntimeHost.TryGetLayerRenderStates(outputWidth, outputHeight, states); + RuntimeRenderStateSnapshot snapshot; + if (!TryGetRenderStateSnapshot(outputWidth, outputHeight, snapshot)) + return false; + + states = std::move(snapshot.states); + return true; } bool RuntimeSnapshotProvider::TryRefreshCachedLayerStates(std::vector& states) const { - return mRuntimeHost.TryRefreshCachedLayerStates(states); + RuntimeRenderStateSnapshot snapshot; + snapshot.versions.renderStateVersion = mRuntimeHost.GetRenderStateVersion(); + snapshot.versions.parameterStateVersion = mRuntimeHost.GetParameterStateVersion(); + snapshot.states = states; + if (!TryRefreshSnapshotParameters(snapshot)) + return false; + + states = std::move(snapshot.states); + return true; } void RuntimeSnapshotProvider::RefreshDynamicRenderStateFields(std::vector& states) const { - mRuntimeHost.RefreshDynamicRenderStateFields(states); + ApplyFrameContext(states, GetFrameContext()); } uint64_t RuntimeSnapshotProvider::GetRenderStateVersion() const { - return mRuntimeHost.GetRenderStateVersion(); + return GetVersions().renderStateVersion; } uint64_t RuntimeSnapshotProvider::GetParameterStateVersion() const { - return mRuntimeHost.GetParameterStateVersion(); + return GetVersions().parameterStateVersion; } diff --git a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeSnapshotProvider.h b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeSnapshotProvider.h index f7555a0..d791bfa 100644 --- a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeSnapshotProvider.h +++ b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeSnapshotProvider.h @@ -6,12 +6,43 @@ #include #include +struct RuntimeSnapshotVersions +{ + uint64_t renderStateVersion = 0; + uint64_t parameterStateVersion = 0; +}; + +struct RuntimeRenderFrameContext +{ + double timeSeconds = 0.0; + double utcTimeSeconds = 0.0; + double utcOffsetSeconds = 0.0; + double startupRandom = 0.0; + double frameCount = 0.0; +}; + +struct RuntimeRenderStateSnapshot +{ + RuntimeSnapshotVersions versions; + unsigned outputWidth = 0; + unsigned outputHeight = 0; + std::vector states; +}; + class RuntimeSnapshotProvider { public: explicit RuntimeSnapshotProvider(RuntimeHost& runtimeHost); bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector& passSources, std::string& error) const; + RuntimeSnapshotVersions GetVersions() const; + RuntimeRenderFrameContext GetFrameContext() const; + RuntimeRenderStateSnapshot GetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight) const; + bool TryGetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight, RuntimeRenderStateSnapshot& snapshot) const; + bool TryRefreshSnapshotParameters(RuntimeRenderStateSnapshot& snapshot) const; + void ApplyFrameContext(std::vector& states, const RuntimeRenderFrameContext& frameContext) const; + void ApplyFrameContext(RuntimeRenderStateSnapshot& snapshot, const RuntimeRenderFrameContext& frameContext) const; + std::vector GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const; bool TryGetLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector& states) const; bool TryRefreshCachedLayerStates(std::vector& states) const; diff --git a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.cpp b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.cpp index 465a5da..909129f 100644 --- a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.cpp @@ -5,147 +5,147 @@ RuntimeStore::RuntimeStore(RuntimeHost& runtimeHost) : { } -bool RuntimeStore::Initialize(std::string& error) +bool RuntimeStore::InitializeStore(std::string& error) { return mRuntimeHost.Initialize(error); } -bool RuntimeStore::AddLayer(const std::string& shaderId, std::string& error) -{ - return mRuntimeHost.AddLayer(shaderId, error); -} - -bool RuntimeStore::RemoveLayer(const std::string& layerId, std::string& error) -{ - return mRuntimeHost.RemoveLayer(layerId, error); -} - -bool RuntimeStore::MoveLayer(const std::string& layerId, int direction, std::string& error) -{ - return mRuntimeHost.MoveLayer(layerId, direction, error); -} - -bool RuntimeStore::MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error) -{ - return mRuntimeHost.MoveLayerToIndex(layerId, targetIndex, error); -} - -bool RuntimeStore::SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error) -{ - return mRuntimeHost.SetLayerBypass(layerId, bypassed, error); -} - -bool RuntimeStore::SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error) -{ - return mRuntimeHost.SetLayerShader(layerId, shaderId, error); -} - -bool RuntimeStore::UpdateLayerParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error) -{ - return mRuntimeHost.UpdateLayerParameter(layerId, parameterId, newValue, error); -} - -bool RuntimeStore::UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error) -{ - return mRuntimeHost.UpdateLayerParameterByControlKey(layerKey, parameterKey, newValue, error); -} - -bool RuntimeStore::UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, std::string& error) -{ - return mRuntimeHost.UpdateLayerParameterByControlKey(layerKey, parameterKey, newValue, persistState, error); -} - -bool RuntimeStore::ResetLayerParameters(const std::string& layerId, std::string& error) -{ - return mRuntimeHost.ResetLayerParameters(layerId, error); -} - -bool RuntimeStore::SaveStackPreset(const std::string& presetName, std::string& error) const -{ - return mRuntimeHost.SaveStackPreset(presetName, error); -} - -bool RuntimeStore::LoadStackPreset(const std::string& presetName, std::string& error) -{ - return mRuntimeHost.LoadStackPreset(presetName, error); -} - -std::string RuntimeStore::BuildStateJson() const +std::string RuntimeStore::BuildPersistentStateJson() const { return mRuntimeHost.BuildStateJson(); } -const std::filesystem::path& RuntimeStore::GetRepoRoot() const +bool RuntimeStore::CreateStoredLayer(const std::string& shaderId, std::string& error) +{ + return mRuntimeHost.AddLayer(shaderId, error); +} + +bool RuntimeStore::DeleteStoredLayer(const std::string& layerId, std::string& error) +{ + return mRuntimeHost.RemoveLayer(layerId, error); +} + +bool RuntimeStore::MoveStoredLayer(const std::string& layerId, int direction, std::string& error) +{ + return mRuntimeHost.MoveLayer(layerId, direction, error); +} + +bool RuntimeStore::MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error) +{ + return mRuntimeHost.MoveLayerToIndex(layerId, targetIndex, error); +} + +bool RuntimeStore::SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error) +{ + return mRuntimeHost.SetLayerBypass(layerId, bypassed, error); +} + +bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error) +{ + return mRuntimeHost.SetLayerShader(layerId, shaderId, error); +} + +bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error) +{ + return mRuntimeHost.UpdateLayerParameter(layerId, parameterId, newValue, error); +} + +bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error) +{ + return mRuntimeHost.UpdateLayerParameterByControlKey(layerKey, parameterKey, newValue, error); +} + +bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, std::string& error) +{ + return mRuntimeHost.UpdateLayerParameterByControlKey(layerKey, parameterKey, newValue, persistState, error); +} + +bool RuntimeStore::ResetStoredLayerParameterValues(const std::string& layerId, std::string& error) +{ + return mRuntimeHost.ResetLayerParameters(layerId, error); +} + +bool RuntimeStore::SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const +{ + return mRuntimeHost.SaveStackPreset(presetName, error); +} + +bool RuntimeStore::LoadStackPresetSnapshot(const std::string& presetName, std::string& error) +{ + return mRuntimeHost.LoadStackPreset(presetName, error); +} + +const std::filesystem::path& RuntimeStore::GetRuntimeRepositoryRoot() const { return mRuntimeHost.GetRepoRoot(); } -const std::filesystem::path& RuntimeStore::GetUiRoot() const +const std::filesystem::path& RuntimeStore::GetRuntimeUiRoot() const { return mRuntimeHost.GetUiRoot(); } -const std::filesystem::path& RuntimeStore::GetDocsRoot() const +const std::filesystem::path& RuntimeStore::GetRuntimeDocsRoot() const { return mRuntimeHost.GetDocsRoot(); } -const std::filesystem::path& RuntimeStore::GetRuntimeRoot() const +const std::filesystem::path& RuntimeStore::GetRuntimeDataRoot() const { return mRuntimeHost.GetRuntimeRoot(); } -unsigned short RuntimeStore::GetServerPort() const +unsigned short RuntimeStore::GetConfiguredControlServerPort() const { return mRuntimeHost.GetServerPort(); } -unsigned short RuntimeStore::GetOscPort() const +unsigned short RuntimeStore::GetConfiguredOscPort() const { return mRuntimeHost.GetOscPort(); } -const std::string& RuntimeStore::GetOscBindAddress() const +const std::string& RuntimeStore::GetConfiguredOscBindAddress() const { return mRuntimeHost.GetOscBindAddress(); } -double RuntimeStore::GetOscSmoothing() const +double RuntimeStore::GetConfiguredOscSmoothing() const { return mRuntimeHost.GetOscSmoothing(); } -unsigned RuntimeStore::GetMaxTemporalHistoryFrames() const +unsigned RuntimeStore::GetConfiguredMaxTemporalHistoryFrames() const { return mRuntimeHost.GetMaxTemporalHistoryFrames(); } -unsigned RuntimeStore::GetPreviewFps() const +unsigned RuntimeStore::GetConfiguredPreviewFps() const { return mRuntimeHost.GetPreviewFps(); } -bool RuntimeStore::ExternalKeyingEnabled() const +bool RuntimeStore::IsExternalKeyingConfigured() const { return mRuntimeHost.ExternalKeyingEnabled(); } -const std::string& RuntimeStore::GetInputVideoFormat() const +const std::string& RuntimeStore::GetConfiguredInputVideoFormat() const { return mRuntimeHost.GetInputVideoFormat(); } -const std::string& RuntimeStore::GetInputFrameRate() const +const std::string& RuntimeStore::GetConfiguredInputFrameRate() const { return mRuntimeHost.GetInputFrameRate(); } -const std::string& RuntimeStore::GetOutputVideoFormat() const +const std::string& RuntimeStore::GetConfiguredOutputVideoFormat() const { return mRuntimeHost.GetOutputVideoFormat(); } -const std::string& RuntimeStore::GetOutputFrameRate() const +const std::string& RuntimeStore::GetConfiguredOutputFrameRate() const { return mRuntimeHost.GetOutputFrameRate(); } diff --git a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.h b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.h index 9532282..8599f12 100644 --- a/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.h +++ b/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.h @@ -10,38 +10,37 @@ class RuntimeStore public: explicit RuntimeStore(RuntimeHost& runtimeHost); - bool Initialize(std::string& error); + bool InitializeStore(std::string& error); + std::string BuildPersistentStateJson() const; - 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 UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, 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); + bool CreateStoredLayer(const std::string& shaderId, std::string& error); + bool DeleteStoredLayer(const std::string& layerId, std::string& error); + bool MoveStoredLayer(const std::string& layerId, int direction, std::string& error); + bool MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error); + bool SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error); + bool SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error); + bool SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error); + bool SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error); + bool SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, std::string& error); + bool ResetStoredLayerParameterValues(const std::string& layerId, std::string& error); + bool SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const; + bool LoadStackPresetSnapshot(const std::string& presetName, std::string& error); - std::string BuildStateJson() const; - - const std::filesystem::path& GetRepoRoot() const; - const std::filesystem::path& GetUiRoot() const; - const std::filesystem::path& GetDocsRoot() const; - const std::filesystem::path& GetRuntimeRoot() const; - unsigned short GetServerPort() const; - unsigned short GetOscPort() const; - const std::string& GetOscBindAddress() const; - double GetOscSmoothing() const; - unsigned GetMaxTemporalHistoryFrames() const; - unsigned GetPreviewFps() const; - bool ExternalKeyingEnabled() const; - const std::string& GetInputVideoFormat() const; - const std::string& GetInputFrameRate() const; - const std::string& GetOutputVideoFormat() const; - const std::string& GetOutputFrameRate() const; + const std::filesystem::path& GetRuntimeRepositoryRoot() const; + const std::filesystem::path& GetRuntimeUiRoot() const; + const std::filesystem::path& GetRuntimeDocsRoot() const; + const std::filesystem::path& GetRuntimeDataRoot() const; + unsigned short GetConfiguredControlServerPort() const; + unsigned short GetConfiguredOscPort() const; + const std::string& GetConfiguredOscBindAddress() const; + double GetConfiguredOscSmoothing() const; + unsigned GetConfiguredMaxTemporalHistoryFrames() const; + unsigned GetConfiguredPreviewFps() const; + bool IsExternalKeyingConfigured() const; + const std::string& GetConfiguredInputVideoFormat() const; + const std::string& GetConfiguredInputFrameRate() const; + const std::string& GetConfiguredOutputVideoFormat() const; + const std::string& GetConfiguredOutputFrameRate() const; void SetCompileStatus(bool succeeded, const std::string& message); void ClearReloadRequest();