pass 1
This commit is contained in:
@@ -9,10 +9,7 @@
|
|||||||
ControlServices::ControlServices() :
|
ControlServices::ControlServices() :
|
||||||
mControlServer(std::make_unique<ControlServer>()),
|
mControlServer(std::make_unique<ControlServer>()),
|
||||||
mOscServer(std::make_unique<OscServer>()),
|
mOscServer(std::make_unique<OscServer>()),
|
||||||
mPollRunning(false),
|
mPollRunning(false)
|
||||||
mRegistryChanged(false),
|
|
||||||
mReloadRequested(false),
|
|
||||||
mPollFailed(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,9 +31,9 @@ bool ControlServices::Start(OpenGLComposite& composite, RuntimeStore& runtimeSto
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlServices::BeginPolling(RuntimeStore& runtimeStore)
|
void ControlServices::BeginPolling(RuntimeCoordinator& runtimeCoordinator)
|
||||||
{
|
{
|
||||||
StartPolling(runtimeStore);
|
StartPolling(runtimeCoordinator);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlServices::Stop()
|
void ControlServices::Stop()
|
||||||
@@ -158,28 +155,23 @@ void ControlServices::ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>
|
|||||||
completedCommits.swap(mCompletedOscCommits);
|
completedCommits.swap(mCompletedOscCommits);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimePollEvents ControlServices::ConsumePollEvents()
|
void ControlServices::ConsumeRuntimeCoordinatorResults(std::vector<RuntimeCoordinatorServiceResult>& results)
|
||||||
{
|
{
|
||||||
RuntimePollEvents events;
|
results.clear();
|
||||||
events.registryChanged = mRegistryChanged.exchange(false);
|
|
||||||
events.reloadRequested = mReloadRequested.exchange(false);
|
|
||||||
events.failed = mPollFailed.exchange(false);
|
|
||||||
|
|
||||||
if (events.failed)
|
std::lock_guard<std::mutex> lock(mRuntimeCoordinatorResultMutex);
|
||||||
{
|
if (mRuntimeCoordinatorResults.empty())
|
||||||
std::lock_guard<std::mutex> lock(mPollErrorMutex);
|
return;
|
||||||
events.error = mPollError;
|
|
||||||
}
|
|
||||||
|
|
||||||
return events;
|
results.swap(mRuntimeCoordinatorResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlServices::StartPolling(RuntimeStore& runtimeStore)
|
void ControlServices::StartPolling(RuntimeCoordinator& runtimeCoordinator)
|
||||||
{
|
{
|
||||||
if (mPollRunning.exchange(true))
|
if (mPollRunning.exchange(true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mPollThread = std::thread([this, &runtimeStore]() { PollLoop(runtimeStore); });
|
mPollThread = std::thread([this, &runtimeCoordinator]() { PollLoop(runtimeCoordinator); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlServices::StopPolling()
|
void ControlServices::StopPolling()
|
||||||
@@ -191,7 +183,7 @@ void ControlServices::StopPolling()
|
|||||||
mPollThread.join();
|
mPollThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlServices::PollLoop(RuntimeStore& runtimeStore)
|
void ControlServices::PollLoop(RuntimeCoordinator& runtimeCoordinator)
|
||||||
{
|
{
|
||||||
while (mPollRunning)
|
while (mPollRunning)
|
||||||
{
|
{
|
||||||
@@ -202,46 +194,41 @@ void ControlServices::PollLoop(RuntimeStore& runtimeStore)
|
|||||||
}
|
}
|
||||||
for (const auto& entry : pendingCommits)
|
for (const auto& entry : pendingCommits)
|
||||||
{
|
{
|
||||||
std::string commitError;
|
const RuntimeCoordinatorResult result = runtimeCoordinator.CommitOscParameterByControlKey(
|
||||||
if (runtimeStore.SetStoredParameterValueByControlKey(
|
|
||||||
entry.second.layerKey,
|
entry.second.layerKey,
|
||||||
entry.second.parameterKey,
|
entry.second.parameterKey,
|
||||||
entry.second.value,
|
entry.second.value);
|
||||||
false,
|
if (result.accepted)
|
||||||
commitError))
|
|
||||||
{
|
{
|
||||||
CompletedOscCommit completedCommit;
|
CompletedOscCommit completedCommit;
|
||||||
completedCommit.routeKey = entry.second.routeKey;
|
completedCommit.routeKey = entry.second.routeKey;
|
||||||
completedCommit.generation = entry.second.generation;
|
completedCommit.generation = entry.second.generation;
|
||||||
std::lock_guard<std::mutex> lock(mCompletedOscCommitMutex);
|
std::lock_guard<std::mutex> lock(mCompletedOscCommitMutex);
|
||||||
mCompletedOscCommits.push_back(std::move(completedCommit));
|
mCompletedOscCommits.push_back(std::move(completedCommit));
|
||||||
|
QueueRuntimeCoordinatorResult(result);
|
||||||
}
|
}
|
||||||
else if (!commitError.empty())
|
else if (!result.errorMessage.empty())
|
||||||
{
|
{
|
||||||
OutputDebugStringA(("OSC commit failed: " + commitError + "\n").c_str());
|
OutputDebugStringA(("OSC commit failed: " + result.errorMessage + "\n").c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool registryChanged = false;
|
bool registryChanged = false;
|
||||||
bool reloadRequested = false;
|
const RuntimeCoordinatorResult pollResult = runtimeCoordinator.PollRuntimeStoreChanges(registryChanged);
|
||||||
std::string runtimeError;
|
if (pollResult.runtimeStateBroadcastRequired || pollResult.shaderBuildRequested || pollResult.compileStatusChanged)
|
||||||
if (!runtimeStore.PollStoredFileChanges(registryChanged, reloadRequested, runtimeError))
|
QueueRuntimeCoordinatorResult(pollResult, pollResult.compileStatusChanged && !pollResult.compileStatusSucceeded && !pollResult.compileStatusMessage.empty());
|
||||||
{
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mPollErrorMutex);
|
|
||||||
mPollError = runtimeError;
|
|
||||||
}
|
|
||||||
mPollFailed = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (registryChanged)
|
|
||||||
mRegistryChanged = true;
|
|
||||||
if (reloadRequested)
|
|
||||||
mReloadRequested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 25 && mPollRunning; ++i)
|
for (int i = 0; i < 25 && mPollRunning; ++i)
|
||||||
Sleep(10);
|
Sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ControlServices::QueueRuntimeCoordinatorResult(const RuntimeCoordinatorResult& result, bool failed)
|
||||||
|
{
|
||||||
|
RuntimeCoordinatorServiceResult serviceResult;
|
||||||
|
serviceResult.result = result;
|
||||||
|
serviceResult.failed = failed;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeCoordinatorResultMutex);
|
||||||
|
mRuntimeCoordinatorResults.push_back(std::move(serviceResult));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "RuntimeJson.h"
|
#include "RuntimeJson.h"
|
||||||
|
#include "RuntimeCoordinator.h"
|
||||||
#include "ShaderTypes.h"
|
#include "ShaderTypes.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -16,12 +17,10 @@ class OpenGLComposite;
|
|||||||
class OscServer;
|
class OscServer;
|
||||||
class RuntimeStore;
|
class RuntimeStore;
|
||||||
|
|
||||||
struct RuntimePollEvents
|
struct RuntimeCoordinatorServiceResult
|
||||||
{
|
{
|
||||||
bool registryChanged = false;
|
RuntimeCoordinatorResult result;
|
||||||
bool reloadRequested = false;
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
std::string error;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ControlServices
|
class ControlServices
|
||||||
@@ -45,7 +44,7 @@ public:
|
|||||||
~ControlServices();
|
~ControlServices();
|
||||||
|
|
||||||
bool Start(OpenGLComposite& composite, RuntimeStore& runtimeStore, std::string& error);
|
bool Start(OpenGLComposite& composite, RuntimeStore& runtimeStore, std::string& error);
|
||||||
void BeginPolling(RuntimeStore& runtimeStore);
|
void BeginPolling(RuntimeCoordinator& runtimeCoordinator);
|
||||||
void Stop();
|
void Stop();
|
||||||
void BroadcastState();
|
void BroadcastState();
|
||||||
void RequestBroadcastState();
|
void RequestBroadcastState();
|
||||||
@@ -54,7 +53,7 @@ public:
|
|||||||
bool QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, 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 ClearOscState();
|
||||||
void ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>& completedCommits);
|
void ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>& completedCommits);
|
||||||
RuntimePollEvents ConsumePollEvents();
|
void ConsumeRuntimeCoordinatorResults(std::vector<RuntimeCoordinatorServiceResult>& results);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct PendingOscUpdate
|
struct PendingOscUpdate
|
||||||
@@ -73,19 +72,17 @@ private:
|
|||||||
uint64_t generation = 0;
|
uint64_t generation = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void StartPolling(RuntimeStore& runtimeStore);
|
void StartPolling(RuntimeCoordinator& runtimeCoordinator);
|
||||||
void StopPolling();
|
void StopPolling();
|
||||||
void PollLoop(RuntimeStore& runtimeStore);
|
void PollLoop(RuntimeCoordinator& runtimeCoordinator);
|
||||||
|
void QueueRuntimeCoordinatorResult(const RuntimeCoordinatorResult& result, bool failed = false);
|
||||||
|
|
||||||
std::unique_ptr<ControlServer> mControlServer;
|
std::unique_ptr<ControlServer> mControlServer;
|
||||||
std::unique_ptr<OscServer> mOscServer;
|
std::unique_ptr<OscServer> mOscServer;
|
||||||
std::thread mPollThread;
|
std::thread mPollThread;
|
||||||
std::atomic<bool> mPollRunning;
|
std::atomic<bool> mPollRunning;
|
||||||
std::atomic<bool> mRegistryChanged;
|
std::mutex mRuntimeCoordinatorResultMutex;
|
||||||
std::atomic<bool> mReloadRequested;
|
std::vector<RuntimeCoordinatorServiceResult> mRuntimeCoordinatorResults;
|
||||||
std::atomic<bool> mPollFailed;
|
|
||||||
std::mutex mPollErrorMutex;
|
|
||||||
std::string mPollError;
|
|
||||||
std::mutex mPendingOscMutex;
|
std::mutex mPendingOscMutex;
|
||||||
std::map<std::string, PendingOscUpdate> mPendingOscUpdates;
|
std::map<std::string, PendingOscUpdate> mPendingOscUpdates;
|
||||||
std::mutex mPendingOscCommitMutex;
|
std::mutex mPendingOscCommitMutex;
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ bool RuntimeServices::Start(OpenGLComposite& composite, RuntimeStore& runtimeSto
|
|||||||
return mControlServices && mControlServices->Start(composite, runtimeStore, error);
|
return mControlServices && mControlServices->Start(composite, runtimeStore, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeServices::BeginPolling(RuntimeStore& runtimeStore)
|
void RuntimeServices::BeginPolling(RuntimeCoordinator& runtimeCoordinator)
|
||||||
{
|
{
|
||||||
if (mControlServices)
|
if (mControlServices)
|
||||||
mControlServices->BeginPolling(runtimeStore);
|
mControlServices->BeginPolling(runtimeCoordinator);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeServices::Stop()
|
void RuntimeServices::Stop()
|
||||||
@@ -79,7 +79,13 @@ void RuntimeServices::ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>
|
|||||||
mControlServices->ConsumeCompletedOscCommits(completedCommits);
|
mControlServices->ConsumeCompletedOscCommits(completedCommits);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimePollEvents RuntimeServices::ConsumePollEvents()
|
void RuntimeServices::ConsumeRuntimeCoordinatorResults(std::vector<RuntimeCoordinatorServiceResult>& results)
|
||||||
{
|
{
|
||||||
return mControlServices ? mControlServices->ConsumePollEvents() : RuntimePollEvents{};
|
if (!mControlServices)
|
||||||
|
{
|
||||||
|
results.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mControlServices->ConsumeRuntimeCoordinatorResults(results);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
class OpenGLComposite;
|
class OpenGLComposite;
|
||||||
|
class RuntimeCoordinator;
|
||||||
class RuntimeStore;
|
class RuntimeStore;
|
||||||
|
|
||||||
class RuntimeServices
|
class RuntimeServices
|
||||||
@@ -17,7 +18,7 @@ public:
|
|||||||
~RuntimeServices();
|
~RuntimeServices();
|
||||||
|
|
||||||
bool Start(OpenGLComposite& composite, RuntimeStore& runtimeStore, std::string& error);
|
bool Start(OpenGLComposite& composite, RuntimeStore& runtimeStore, std::string& error);
|
||||||
void BeginPolling(RuntimeStore& runtimeStore);
|
void BeginPolling(RuntimeCoordinator& runtimeCoordinator);
|
||||||
void Stop();
|
void Stop();
|
||||||
void BroadcastState();
|
void BroadcastState();
|
||||||
void RequestBroadcastState();
|
void RequestBroadcastState();
|
||||||
@@ -26,7 +27,7 @@ public:
|
|||||||
bool QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, 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 ClearOscState();
|
||||||
void ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>& completedCommits);
|
void ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>& completedCommits);
|
||||||
RuntimePollEvents ConsumePollEvents();
|
void ConsumeRuntimeCoordinatorResults(std::vector<RuntimeCoordinatorServiceResult>& results);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<ControlServices> mControlServices;
|
std::unique_ptr<ControlServices> mControlServices;
|
||||||
|
|||||||
@@ -31,20 +31,19 @@ OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
|||||||
mScreenshotRequested(false)
|
mScreenshotRequested(false)
|
||||||
{
|
{
|
||||||
InitializeCriticalSection(&pMutex);
|
InitializeCriticalSection(&pMutex);
|
||||||
mRuntimeHost = std::make_unique<RuntimeHost>();
|
mRuntimeStore = std::make_unique<RuntimeStore>();
|
||||||
mRuntimeStore = std::make_unique<RuntimeStore>(*mRuntimeHost);
|
mRuntimeSnapshotProvider = std::make_unique<RuntimeSnapshotProvider>(*mRuntimeStore);
|
||||||
mRuntimeSnapshotProvider = std::make_unique<RuntimeSnapshotProvider>(*mRuntimeHost);
|
|
||||||
mRuntimeCoordinator = std::make_unique<RuntimeCoordinator>(*mRuntimeStore);
|
mRuntimeCoordinator = std::make_unique<RuntimeCoordinator>(*mRuntimeStore);
|
||||||
mRenderEngine = std::make_unique<RenderEngine>(
|
mRenderEngine = std::make_unique<RenderEngine>(
|
||||||
*mRuntimeSnapshotProvider,
|
*mRuntimeSnapshotProvider,
|
||||||
mRuntimeHost->GetHealthTelemetry(),
|
mRuntimeStore->GetHealthTelemetry(),
|
||||||
pMutex,
|
pMutex,
|
||||||
hGLDC,
|
hGLDC,
|
||||||
hGLRC,
|
hGLRC,
|
||||||
[this]() { renderEffect(); },
|
[this]() { renderEffect(); },
|
||||||
[this]() { ProcessScreenshotRequest(); },
|
[this]() { ProcessScreenshotRequest(); },
|
||||||
[this]() { paintGL(false); });
|
[this]() { paintGL(false); });
|
||||||
mVideoBackend = std::make_unique<VideoBackend>(*mRenderEngine, mRuntimeHost->GetHealthTelemetry());
|
mVideoBackend = std::make_unique<VideoBackend>(*mRenderEngine, mRuntimeStore->GetHealthTelemetry());
|
||||||
mShaderBuildQueue = std::make_unique<ShaderBuildQueue>(*mRuntimeSnapshotProvider);
|
mShaderBuildQueue = std::make_unique<ShaderBuildQueue>(*mRuntimeSnapshotProvider);
|
||||||
mRuntimeServices = std::make_unique<RuntimeServices>();
|
mRuntimeServices = std::make_unique<RuntimeServices>();
|
||||||
}
|
}
|
||||||
@@ -247,7 +246,7 @@ bool OpenGLComposite::InitOpenGLState()
|
|||||||
mRenderEngine->ResetShaderFeedbackState();
|
mRenderEngine->ResetShaderFeedbackState();
|
||||||
|
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
mRuntimeServices->BeginPolling(*mRuntimeStore);
|
mRuntimeServices->BeginPolling(*mRuntimeCoordinator);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,17 +405,18 @@ bool OpenGLComposite::ProcessRuntimePollResults()
|
|||||||
if (!mRuntimeServices)
|
if (!mRuntimeServices)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const RuntimePollEvents events = mRuntimeServices->ConsumePollEvents();
|
bool shaderBuildRequested = false;
|
||||||
if (events.failed)
|
std::vector<RuntimeCoordinatorServiceResult> serviceResults;
|
||||||
|
mRuntimeServices->ConsumeRuntimeCoordinatorResults(serviceResults);
|
||||||
|
for (const RuntimeCoordinatorServiceResult& serviceResult : serviceResults)
|
||||||
{
|
{
|
||||||
ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->HandleRuntimePollFailure(events.error));
|
shaderBuildRequested = shaderBuildRequested || serviceResult.result.shaderBuildRequested;
|
||||||
return false;
|
ApplyRuntimeCoordinatorResult(serviceResult.result);
|
||||||
|
if (serviceResult.failed)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events.registryChanged)
|
if (!shaderBuildRequested)
|
||||||
broadcastRuntimeState();
|
|
||||||
|
|
||||||
if (!events.reloadRequested)
|
|
||||||
{
|
{
|
||||||
if (!mShaderBuildQueue || !mRenderEngine)
|
if (!mShaderBuildQueue || !mRenderEngine)
|
||||||
return true;
|
return true;
|
||||||
@@ -439,7 +439,6 @@ bool OpenGLComposite::ProcessRuntimePollResults()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyRuntimeCoordinatorResult(mRuntimeCoordinator->HandleRuntimeReloadRequest());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
#include "RuntimeCoordinator.h"
|
#include "RuntimeCoordinator.h"
|
||||||
#include "RuntimeHost.h"
|
|
||||||
#include "RuntimeSnapshotProvider.h"
|
#include "RuntimeSnapshotProvider.h"
|
||||||
#include "RuntimeStore.h"
|
#include "RuntimeStore.h"
|
||||||
|
|
||||||
@@ -73,7 +72,6 @@ private:
|
|||||||
HGLRC hGLRC;
|
HGLRC hGLRC;
|
||||||
CRITICAL_SECTION pMutex;
|
CRITICAL_SECTION pMutex;
|
||||||
|
|
||||||
std::unique_ptr<RuntimeHost> mRuntimeHost;
|
|
||||||
std::unique_ptr<RuntimeStore> mRuntimeStore;
|
std::unique_ptr<RuntimeStore> mRuntimeStore;
|
||||||
std::unique_ptr<RuntimeCoordinator> mRuntimeCoordinator;
|
std::unique_ptr<RuntimeCoordinator> mRuntimeCoordinator;
|
||||||
std::unique_ptr<RuntimeSnapshotProvider> mRuntimeSnapshotProvider;
|
std::unique_ptr<RuntimeSnapshotProvider> mRuntimeSnapshotProvider;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include "RuntimeStore.h"
|
#include "RuntimeStore.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
RuntimeCoordinator::RuntimeCoordinator(RuntimeStore& runtimeStore) :
|
RuntimeCoordinator::RuntimeCoordinator(RuntimeStore& runtimeStore) :
|
||||||
mRuntimeStore(runtimeStore)
|
mRuntimeStore(runtimeStore)
|
||||||
{
|
{
|
||||||
@@ -9,55 +12,110 @@ RuntimeCoordinator::RuntimeCoordinator(RuntimeStore& runtimeStore) :
|
|||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::AddLayer(const std::string& shaderId)
|
RuntimeCoordinatorResult RuntimeCoordinator::AddLayer(const std::string& shaderId)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
if (!ValidateShaderExists(shaderId, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
return ApplyStoreMutation(mRuntimeStore.CreateStoredLayer(shaderId, error), error, true, true);
|
return ApplyStoreMutation(mRuntimeStore.CreateStoredLayer(shaderId, error), error, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::RemoveLayer(const std::string& layerId)
|
RuntimeCoordinatorResult RuntimeCoordinator::RemoveLayer(const std::string& layerId)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
if (!ValidateLayerExists(layerId, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
return ApplyStoreMutation(mRuntimeStore.DeleteStoredLayer(layerId, error), error, true, true);
|
return ApplyStoreMutation(mRuntimeStore.DeleteStoredLayer(layerId, error), error, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::MoveLayer(const std::string& layerId, int direction)
|
RuntimeCoordinatorResult RuntimeCoordinator::MoveLayer(const std::string& layerId, int direction)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
bool shouldMove = false;
|
||||||
|
if (!ResolveLayerMove(layerId, direction, shouldMove, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
if (!shouldMove)
|
||||||
|
return BuildAcceptedNoReloadResult();
|
||||||
|
|
||||||
return ApplyStoreMutation(mRuntimeStore.MoveStoredLayer(layerId, direction, error), error, true, true);
|
return ApplyStoreMutation(mRuntimeStore.MoveStoredLayer(layerId, direction, error), error, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex)
|
RuntimeCoordinatorResult RuntimeCoordinator::MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
bool shouldMove = false;
|
||||||
|
if (!ResolveLayerMoveToIndex(layerId, targetIndex, shouldMove, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
if (!shouldMove)
|
||||||
|
return BuildAcceptedNoReloadResult();
|
||||||
|
|
||||||
return ApplyStoreMutation(mRuntimeStore.MoveStoredLayerToIndex(layerId, targetIndex, error), error, true, true);
|
return ApplyStoreMutation(mRuntimeStore.MoveStoredLayerToIndex(layerId, targetIndex, error), error, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::SetLayerBypass(const std::string& layerId, bool bypassed)
|
RuntimeCoordinatorResult RuntimeCoordinator::SetLayerBypass(const std::string& layerId, bool bypassed)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
if (!ValidateLayerExists(layerId, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
return ApplyStoreMutation(mRuntimeStore.SetStoredLayerBypassState(layerId, bypassed, error), error, true, false);
|
return ApplyStoreMutation(mRuntimeStore.SetStoredLayerBypassState(layerId, bypassed, error), error, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::SetLayerShader(const std::string& layerId, const std::string& shaderId)
|
RuntimeCoordinatorResult RuntimeCoordinator::SetLayerShader(const std::string& layerId, const std::string& shaderId)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
if (!ValidateLayerExists(layerId, error) || !ValidateShaderExists(shaderId, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
return ApplyStoreMutation(mRuntimeStore.SetStoredLayerShaderSelection(layerId, shaderId, error), error, true, false);
|
return ApplyStoreMutation(mRuntimeStore.SetStoredLayerShaderSelection(layerId, shaderId, error), error, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::UpdateLayerParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue)
|
RuntimeCoordinatorResult RuntimeCoordinator::UpdateLayerParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
return ApplyStoreMutation(mRuntimeStore.SetStoredParameterValue(layerId, parameterId, newValue, error), error, false, false);
|
ResolvedParameterMutation mutation;
|
||||||
|
if (!BuildParameterMutationById(layerId, parameterId, newValue, true, mutation, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
|
return ApplyStoreMutation(mRuntimeStore.SetStoredParameterValue(mutation.layerId, mutation.parameterId, mutation.value, mutation.persistState, error), error, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue)
|
RuntimeCoordinatorResult RuntimeCoordinator::UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
return ApplyStoreMutation(mRuntimeStore.SetStoredParameterValueByControlKey(layerKey, parameterKey, newValue, error), error, false, false);
|
ResolvedParameterMutation mutation;
|
||||||
|
if (!BuildParameterMutationByControlKey(layerKey, parameterKey, newValue, true, mutation, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
|
return ApplyStoreMutation(mRuntimeStore.SetStoredParameterValue(mutation.layerId, mutation.parameterId, mutation.value, mutation.persistState, error), error, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeCoordinatorResult RuntimeCoordinator::CommitOscParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
std::string error;
|
||||||
|
ResolvedParameterMutation mutation;
|
||||||
|
if (!BuildParameterMutationByControlKey(layerKey, parameterKey, newValue, false, mutation, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
|
return ApplyStoreMutation(mRuntimeStore.SetStoredParameterValue(mutation.layerId, mutation.parameterId, mutation.value, mutation.persistState, error), error, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::ResetLayerParameters(const std::string& layerId)
|
RuntimeCoordinatorResult RuntimeCoordinator::ResetLayerParameters(const std::string& layerId)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
if (!ValidateLayerExists(layerId, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
RuntimeCoordinatorResult result = ApplyStoreMutation(mRuntimeStore.ResetStoredLayerParameterValues(layerId, error), error, false, false);
|
RuntimeCoordinatorResult result = ApplyStoreMutation(mRuntimeStore.ResetStoredLayerParameterValues(layerId, error), error, false, false);
|
||||||
if (!result.accepted)
|
if (!result.accepted)
|
||||||
return result;
|
return result;
|
||||||
@@ -69,21 +127,51 @@ RuntimeCoordinatorResult RuntimeCoordinator::ResetLayerParameters(const std::str
|
|||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::SaveStackPreset(const std::string& presetName)
|
RuntimeCoordinatorResult RuntimeCoordinator::SaveStackPreset(const std::string& presetName)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
if (!ValidatePresetName(presetName, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
return ApplyStoreMutation(mRuntimeStore.SaveStackPresetSnapshot(presetName, error), error, false, false);
|
return ApplyStoreMutation(mRuntimeStore.SaveStackPresetSnapshot(presetName, error), error, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::LoadStackPreset(const std::string& presetName)
|
RuntimeCoordinatorResult RuntimeCoordinator::LoadStackPreset(const std::string& presetName)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
std::string error;
|
std::string error;
|
||||||
|
if (!ValidatePresetName(presetName, error))
|
||||||
|
return ApplyStoreMutation(false, error, false, false);
|
||||||
|
|
||||||
return ApplyStoreMutation(mRuntimeStore.LoadStackPresetSnapshot(presetName, error), error, true, false);
|
return ApplyStoreMutation(mRuntimeStore.LoadStackPresetSnapshot(presetName, error), error, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::RequestShaderReload(bool preserveFeedbackState)
|
RuntimeCoordinatorResult RuntimeCoordinator::RequestShaderReload(bool preserveFeedbackState)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
return BuildQueuedReloadResult(preserveFeedbackState);
|
return BuildQueuedReloadResult(preserveFeedbackState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RuntimeCoordinatorResult RuntimeCoordinator::PollRuntimeStoreChanges(bool& registryChanged)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
|
registryChanged = false;
|
||||||
|
bool reloadRequested = false;
|
||||||
|
std::string error;
|
||||||
|
if (!mRuntimeStore.PollStoredFileChanges(registryChanged, reloadRequested, error))
|
||||||
|
return HandleRuntimePollFailure(error);
|
||||||
|
|
||||||
|
if (reloadRequested)
|
||||||
|
return BuildQueuedReloadResult(false);
|
||||||
|
|
||||||
|
if (registryChanged)
|
||||||
|
return BuildAcceptedNoReloadResult();
|
||||||
|
|
||||||
|
RuntimeCoordinatorResult result;
|
||||||
|
result.accepted = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::HandleRuntimePollFailure(const std::string& error)
|
RuntimeCoordinatorResult RuntimeCoordinator::HandleRuntimePollFailure(const std::string& error)
|
||||||
{
|
{
|
||||||
RuntimeCoordinatorResult result;
|
RuntimeCoordinatorResult result;
|
||||||
@@ -97,6 +185,7 @@ RuntimeCoordinatorResult RuntimeCoordinator::HandleRuntimePollFailure(const std:
|
|||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::HandlePreparedShaderBuildFailure(const std::string& error)
|
RuntimeCoordinatorResult RuntimeCoordinator::HandlePreparedShaderBuildFailure(const std::string& error)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
mPreserveFeedbackOnNextShaderBuild = false;
|
mPreserveFeedbackOnNextShaderBuild = false;
|
||||||
mUseCommittedLayerStates = true;
|
mUseCommittedLayerStates = true;
|
||||||
|
|
||||||
@@ -112,6 +201,7 @@ RuntimeCoordinatorResult RuntimeCoordinator::HandlePreparedShaderBuildFailure(co
|
|||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::HandlePreparedShaderBuildSuccess()
|
RuntimeCoordinatorResult RuntimeCoordinator::HandlePreparedShaderBuildSuccess()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
mUseCommittedLayerStates = false;
|
mUseCommittedLayerStates = false;
|
||||||
|
|
||||||
RuntimeCoordinatorResult result;
|
RuntimeCoordinatorResult result;
|
||||||
@@ -127,11 +217,13 @@ RuntimeCoordinatorResult RuntimeCoordinator::HandlePreparedShaderBuildSuccess()
|
|||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::HandleRuntimeReloadRequest()
|
RuntimeCoordinatorResult RuntimeCoordinator::HandleRuntimeReloadRequest()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
return BuildQueuedReloadResult(false);
|
return BuildQueuedReloadResult(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeCoordinator::ApplyCommittedStateMode(RuntimeCoordinatorCommittedStateMode mode)
|
void RuntimeCoordinator::ApplyCommittedStateMode(RuntimeCoordinatorCommittedStateMode mode)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case RuntimeCoordinatorCommittedStateMode::UseCommittedStates:
|
case RuntimeCoordinatorCommittedStateMode::UseCommittedStates:
|
||||||
@@ -153,9 +245,158 @@ bool RuntimeCoordinator::UseCommittedLayerStates() const
|
|||||||
|
|
||||||
bool RuntimeCoordinator::PreserveFeedbackOnNextShaderBuild() const
|
bool RuntimeCoordinator::PreserveFeedbackOnNextShaderBuild() const
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
return mPreserveFeedbackOnNextShaderBuild;
|
return mPreserveFeedbackOnNextShaderBuild;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::BuildParameterMutationById(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue,
|
||||||
|
bool persistState, ResolvedParameterMutation& mutation, std::string& error) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeStore.mRuntimeHost.mMutex);
|
||||||
|
|
||||||
|
RuntimeHost::LayerPersistentState* layer = mRuntimeStore.mRuntimeHost.FindLayerById(layerId);
|
||||||
|
if (!layer)
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shaderIt = mRuntimeStore.mRuntimeHost.mPackagesById.find(layer->shaderId);
|
||||||
|
if (shaderIt == mRuntimeStore.mRuntimeHost.mPackagesById.end())
|
||||||
|
{
|
||||||
|
error = "Unknown shader id: " + layer->shaderId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parameterIt = std::find_if(shaderIt->second.parameters.begin(), shaderIt->second.parameters.end(),
|
||||||
|
[¶meterId](const ShaderParameterDefinition& definition) { return definition.id == parameterId; });
|
||||||
|
if (parameterIt == shaderIt->second.parameters.end())
|
||||||
|
{
|
||||||
|
error = "Unknown parameter id: " + parameterId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BuildParameterMutationLocked(*layer, *parameterIt, newValue, persistState, mutation, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::BuildParameterMutationByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue,
|
||||||
|
bool persistState, ResolvedParameterMutation& mutation, std::string& error) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeStore.mRuntimeHost.mMutex);
|
||||||
|
|
||||||
|
RuntimeHost::LayerPersistentState* matchedLayer = nullptr;
|
||||||
|
const ShaderPackage* matchedPackage = nullptr;
|
||||||
|
std::vector<ShaderParameterDefinition>::const_iterator parameterIt;
|
||||||
|
if (!mRuntimeStore.TryResolveStoredLayerAndParameterByControlKeyLocked(layerKey, parameterKey, matchedLayer, matchedPackage, parameterIt, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return BuildParameterMutationLocked(*matchedLayer, *parameterIt, newValue, persistState, mutation, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::BuildParameterMutationLocked(RuntimeHost::LayerPersistentState& layer, const ShaderParameterDefinition& definition, const JsonValue& newValue,
|
||||||
|
bool persistState, ResolvedParameterMutation& mutation, std::string& error) const
|
||||||
|
{
|
||||||
|
mutation.layerId = layer.id;
|
||||||
|
mutation.parameterId = definition.id;
|
||||||
|
mutation.persistState = persistState;
|
||||||
|
|
||||||
|
if (definition.type == ShaderParameterType::Trigger)
|
||||||
|
{
|
||||||
|
const auto existingValue = layer.parameterValues.find(definition.id);
|
||||||
|
const double previousCount = existingValue == layer.parameterValues.end() || existingValue->second.numberValues.empty()
|
||||||
|
? 0.0
|
||||||
|
: existingValue->second.numberValues[0];
|
||||||
|
const double triggerTime = std::chrono::duration_cast<std::chrono::duration<double>>(
|
||||||
|
std::chrono::steady_clock::now() - mRuntimeStore.mRuntimeHost.mStartTime).count();
|
||||||
|
mutation.value.numberValues = { previousCount + 1.0, triggerTime };
|
||||||
|
mutation.persistState = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mRuntimeStore.mRuntimeHost.NormalizeAndValidateValue(definition, newValue, mutation.value, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::HasLayerLocked(const std::string& layerId) const
|
||||||
|
{
|
||||||
|
return mRuntimeStore.mRuntimeHost.FindLayerById(layerId) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::HasShaderLocked(const std::string& shaderId) const
|
||||||
|
{
|
||||||
|
return mRuntimeStore.mRuntimeHost.mPackagesById.find(shaderId) != mRuntimeStore.mRuntimeHost.mPackagesById.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::ValidateLayerExists(const std::string& layerId, std::string& error) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeStore.mRuntimeHost.mMutex);
|
||||||
|
if (HasLayerLocked(layerId))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::ValidateShaderExists(const std::string& shaderId, std::string& error) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeStore.mRuntimeHost.mMutex);
|
||||||
|
if (HasShaderLocked(shaderId))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error = "Unknown shader id: " + shaderId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::ResolveLayerMove(const std::string& layerId, int direction, bool& shouldMove, std::string& error) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeStore.mRuntimeHost.mMutex);
|
||||||
|
const auto& layers = mRuntimeStore.mRuntimeHost.mPersistentState.layers;
|
||||||
|
auto it = std::find_if(layers.begin(), layers.end(),
|
||||||
|
[&layerId](const RuntimeHost::LayerPersistentState& layer) { return layer.id == layerId; });
|
||||||
|
if (it == layers.end())
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::ptrdiff_t index = std::distance(layers.begin(), it);
|
||||||
|
const std::ptrdiff_t newIndex = index + direction;
|
||||||
|
shouldMove = newIndex >= 0 && newIndex < static_cast<std::ptrdiff_t>(layers.size()) && newIndex != index;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::ResolveLayerMoveToIndex(const std::string& layerId, std::size_t targetIndex, bool& shouldMove, std::string& error) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeStore.mRuntimeHost.mMutex);
|
||||||
|
const auto& layers = mRuntimeStore.mRuntimeHost.mPersistentState.layers;
|
||||||
|
auto it = std::find_if(layers.begin(), layers.end(),
|
||||||
|
[&layerId](const RuntimeHost::LayerPersistentState& layer) { return layer.id == layerId; });
|
||||||
|
if (it == layers.end())
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layers.empty())
|
||||||
|
{
|
||||||
|
shouldMove = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t clampedTargetIndex = (std::min)(targetIndex, layers.size() - 1);
|
||||||
|
const std::size_t sourceIndex = static_cast<std::size_t>(std::distance(layers.begin(), it));
|
||||||
|
shouldMove = sourceIndex != clampedTargetIndex;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeCoordinator::ValidatePresetName(const std::string& presetName, std::string& error) const
|
||||||
|
{
|
||||||
|
if (!mRuntimeStore.MakeSafePresetFileStem(presetName).empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error = "Preset name must include at least one letter or number.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
RuntimeCoordinatorResult RuntimeCoordinator::ApplyStoreMutation(bool succeeded, const std::string& errorMessage, bool reloadRequired, bool preserveFeedbackState)
|
RuntimeCoordinatorResult RuntimeCoordinator::ApplyStoreMutation(bool succeeded, const std::string& errorMessage, bool reloadRequired, bool preserveFeedbackState)
|
||||||
{
|
{
|
||||||
if (!succeeded)
|
if (!succeeded)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "RuntimeHost.h"
|
||||||
#include "RuntimeJson.h"
|
#include "RuntimeJson.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class RuntimeStore;
|
class RuntimeStore;
|
||||||
@@ -50,11 +52,13 @@ public:
|
|||||||
RuntimeCoordinatorResult SetLayerShader(const std::string& layerId, const std::string& shaderId);
|
RuntimeCoordinatorResult SetLayerShader(const std::string& layerId, const std::string& shaderId);
|
||||||
RuntimeCoordinatorResult UpdateLayerParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue);
|
RuntimeCoordinatorResult UpdateLayerParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue);
|
||||||
RuntimeCoordinatorResult UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue);
|
RuntimeCoordinatorResult UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue);
|
||||||
|
RuntimeCoordinatorResult CommitOscParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue);
|
||||||
RuntimeCoordinatorResult ResetLayerParameters(const std::string& layerId);
|
RuntimeCoordinatorResult ResetLayerParameters(const std::string& layerId);
|
||||||
RuntimeCoordinatorResult SaveStackPreset(const std::string& presetName);
|
RuntimeCoordinatorResult SaveStackPreset(const std::string& presetName);
|
||||||
RuntimeCoordinatorResult LoadStackPreset(const std::string& presetName);
|
RuntimeCoordinatorResult LoadStackPreset(const std::string& presetName);
|
||||||
|
|
||||||
RuntimeCoordinatorResult RequestShaderReload(bool preserveFeedbackState = false);
|
RuntimeCoordinatorResult RequestShaderReload(bool preserveFeedbackState = false);
|
||||||
|
RuntimeCoordinatorResult PollRuntimeStoreChanges(bool& registryChanged);
|
||||||
RuntimeCoordinatorResult HandleRuntimePollFailure(const std::string& error);
|
RuntimeCoordinatorResult HandleRuntimePollFailure(const std::string& error);
|
||||||
RuntimeCoordinatorResult HandlePreparedShaderBuildFailure(const std::string& error);
|
RuntimeCoordinatorResult HandlePreparedShaderBuildFailure(const std::string& error);
|
||||||
RuntimeCoordinatorResult HandlePreparedShaderBuildSuccess();
|
RuntimeCoordinatorResult HandlePreparedShaderBuildSuccess();
|
||||||
@@ -64,11 +68,33 @@ public:
|
|||||||
bool PreserveFeedbackOnNextShaderBuild() const;
|
bool PreserveFeedbackOnNextShaderBuild() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ResolvedParameterMutation
|
||||||
|
{
|
||||||
|
std::string layerId;
|
||||||
|
std::string parameterId;
|
||||||
|
ShaderParameterValue value;
|
||||||
|
bool persistState = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool BuildParameterMutationById(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue,
|
||||||
|
bool persistState, ResolvedParameterMutation& mutation, std::string& error) const;
|
||||||
|
bool BuildParameterMutationByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue,
|
||||||
|
bool persistState, ResolvedParameterMutation& mutation, std::string& error) const;
|
||||||
|
bool BuildParameterMutationLocked(RuntimeHost::LayerPersistentState& layer, const ShaderParameterDefinition& definition, const JsonValue& newValue,
|
||||||
|
bool persistState, ResolvedParameterMutation& mutation, std::string& error) const;
|
||||||
|
bool HasLayerLocked(const std::string& layerId) const;
|
||||||
|
bool HasShaderLocked(const std::string& shaderId) const;
|
||||||
|
bool ValidateLayerExists(const std::string& layerId, std::string& error) const;
|
||||||
|
bool ValidateShaderExists(const std::string& shaderId, std::string& error) const;
|
||||||
|
bool ResolveLayerMove(const std::string& layerId, int direction, bool& shouldMove, std::string& error) const;
|
||||||
|
bool ResolveLayerMoveToIndex(const std::string& layerId, std::size_t targetIndex, bool& shouldMove, std::string& error) const;
|
||||||
|
bool ValidatePresetName(const std::string& presetName, std::string& error) const;
|
||||||
RuntimeCoordinatorResult ApplyStoreMutation(bool succeeded, const std::string& errorMessage, bool reloadRequired, bool preserveFeedbackState);
|
RuntimeCoordinatorResult ApplyStoreMutation(bool succeeded, const std::string& errorMessage, bool reloadRequired, bool preserveFeedbackState);
|
||||||
RuntimeCoordinatorResult BuildQueuedReloadResult(bool preserveFeedbackState);
|
RuntimeCoordinatorResult BuildQueuedReloadResult(bool preserveFeedbackState);
|
||||||
RuntimeCoordinatorResult BuildAcceptedNoReloadResult() const;
|
RuntimeCoordinatorResult BuildAcceptedNoReloadResult() const;
|
||||||
|
|
||||||
RuntimeStore& mRuntimeStore;
|
RuntimeStore& mRuntimeStore;
|
||||||
|
mutable std::mutex mMutex;
|
||||||
bool mPreserveFeedbackOnNextShaderBuild = false;
|
bool mPreserveFeedbackOnNextShaderBuild = false;
|
||||||
std::atomic<bool> mUseCommittedLayerStates{ false };
|
std::atomic<bool> mUseCommittedLayerStates{ false };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class RuntimeStore;
|
class RuntimeStore;
|
||||||
class RuntimeSnapshotProvider;
|
|
||||||
|
|
||||||
class RuntimeHost
|
class RuntimeHost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -71,7 +69,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RuntimeStore;
|
friend class RuntimeStore;
|
||||||
friend class RuntimeSnapshotProvider;
|
friend class RuntimeCoordinator;
|
||||||
HealthTelemetry mHealthTelemetry;
|
HealthTelemetry mHealthTelemetry;
|
||||||
mutable std::mutex mMutex;
|
mutable std::mutex mMutex;
|
||||||
AppConfig mConfig;
|
AppConfig mConfig;
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
#include "RuntimeSnapshotProvider.h"
|
#include "RuntimeSnapshotProvider.h"
|
||||||
|
|
||||||
#include "RuntimeClock.h"
|
|
||||||
#include "ShaderCompiler.h"
|
#include "ShaderCompiler.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <filesystem>
|
||||||
#include <mutex>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
RuntimeSnapshotProvider::RuntimeSnapshotProvider(RuntimeHost& runtimeHost) :
|
RuntimeSnapshotProvider::RuntimeSnapshotProvider(RuntimeStore& runtimeStore) :
|
||||||
mRuntimeHost(runtimeHost)
|
mRuntimeStore(runtimeStore)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,30 +15,22 @@ bool RuntimeSnapshotProvider::BuildLayerPassFragmentShaderSources(const std::str
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ShaderPackage shaderPackage;
|
ShaderPackage shaderPackage;
|
||||||
{
|
if (!mRuntimeStore.CopyShaderPackageForStoredLayer(layerId, shaderPackage, error))
|
||||||
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
return false;
|
||||||
const RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
|
|
||||||
if (!layer)
|
|
||||||
{
|
|
||||||
error = "Unknown layer id: " + layerId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = mRuntimeHost.mPackagesById.find(layer->shaderId);
|
std::filesystem::path repoRoot;
|
||||||
if (it == mRuntimeHost.mPackagesById.end())
|
std::filesystem::path wrapperPath;
|
||||||
{
|
std::filesystem::path generatedGlslPath;
|
||||||
error = "Unknown shader id: " + layer->shaderId;
|
std::filesystem::path patchedGlslPath;
|
||||||
return false;
|
unsigned maxTemporalHistoryFrames = 0;
|
||||||
}
|
mRuntimeStore.GetShaderCompilerInputs(repoRoot, wrapperPath, generatedGlslPath, patchedGlslPath, maxTemporalHistoryFrames);
|
||||||
shaderPackage = it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderCompiler compiler(
|
ShaderCompiler compiler(
|
||||||
mRuntimeHost.mRepoRoot,
|
repoRoot,
|
||||||
mRuntimeHost.mWrapperPath,
|
wrapperPath,
|
||||||
mRuntimeHost.mGeneratedGlslPath,
|
generatedGlslPath,
|
||||||
mRuntimeHost.mPatchedGlslPath,
|
patchedGlslPath,
|
||||||
mRuntimeHost.mConfig.maxTemporalHistoryFrames);
|
maxTemporalHistoryFrames);
|
||||||
passSources.clear();
|
passSources.clear();
|
||||||
passSources.reserve(shaderPackage.passes.size());
|
passSources.reserve(shaderPackage.passes.size());
|
||||||
for (const ShaderPassDefinition& pass : shaderPackage.passes)
|
for (const ShaderPassDefinition& pass : shaderPackage.passes)
|
||||||
@@ -69,20 +59,20 @@ bool RuntimeSnapshotProvider::BuildLayerPassFragmentShaderSources(const std::str
|
|||||||
|
|
||||||
unsigned RuntimeSnapshotProvider::GetMaxTemporalHistoryFrames() const
|
unsigned RuntimeSnapshotProvider::GetMaxTemporalHistoryFrames() const
|
||||||
{
|
{
|
||||||
return mRuntimeHost.mConfig.maxTemporalHistoryFrames;
|
return mRuntimeStore.GetConfiguredMaxTemporalHistoryFrames();
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeSnapshotVersions RuntimeSnapshotProvider::GetVersions() const
|
RuntimeSnapshotVersions RuntimeSnapshotProvider::GetVersions() const
|
||||||
{
|
{
|
||||||
RuntimeSnapshotVersions versions;
|
RuntimeSnapshotVersions versions;
|
||||||
versions.renderStateVersion = mRuntimeHost.mRenderStateVersion.load(std::memory_order_relaxed);
|
versions.renderStateVersion = mRuntimeStore.GetRenderStateVersion();
|
||||||
versions.parameterStateVersion = mRuntimeHost.mParameterStateVersion.load(std::memory_order_relaxed);
|
versions.parameterStateVersion = mRuntimeStore.GetParameterStateVersion();
|
||||||
return versions;
|
return versions;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeSnapshotProvider::AdvanceFrame()
|
void RuntimeSnapshotProvider::AdvanceFrame()
|
||||||
{
|
{
|
||||||
++mRuntimeHost.mFrameCounter;
|
mRuntimeStore.AdvanceFrameCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeRenderStateSnapshot RuntimeSnapshotProvider::GetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight) const
|
RuntimeRenderStateSnapshot RuntimeSnapshotProvider::GetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight) const
|
||||||
@@ -94,10 +84,7 @@ RuntimeRenderStateSnapshot RuntimeSnapshotProvider::GetRenderStateSnapshot(unsig
|
|||||||
RuntimeRenderStateSnapshot snapshot;
|
RuntimeRenderStateSnapshot snapshot;
|
||||||
snapshot.outputWidth = outputWidth;
|
snapshot.outputWidth = outputWidth;
|
||||||
snapshot.outputHeight = outputHeight;
|
snapshot.outputHeight = outputHeight;
|
||||||
{
|
mRuntimeStore.BuildLayerRenderStates(outputWidth, outputHeight, snapshot.states);
|
||||||
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
|
||||||
BuildLayerRenderStatesLocked(outputWidth, outputHeight, snapshot.states);
|
|
||||||
}
|
|
||||||
|
|
||||||
const RuntimeSnapshotVersions versionsAfter = GetVersions();
|
const RuntimeSnapshotVersions versionsAfter = GetVersions();
|
||||||
if (versionsBefore.renderStateVersion == versionsAfter.renderStateVersion &&
|
if (versionsBefore.renderStateVersion == versionsAfter.renderStateVersion &&
|
||||||
@@ -114,13 +101,8 @@ bool RuntimeSnapshotProvider::TryGetRenderStateSnapshot(unsigned outputWidth, un
|
|||||||
const RuntimeSnapshotVersions versionsBefore = GetVersions();
|
const RuntimeSnapshotVersions versionsBefore = GetVersions();
|
||||||
|
|
||||||
std::vector<RuntimeRenderState> states;
|
std::vector<RuntimeRenderState> states;
|
||||||
{
|
if (!mRuntimeStore.TryBuildLayerRenderStates(outputWidth, outputHeight, states))
|
||||||
std::unique_lock<std::mutex> lock(mRuntimeHost.mMutex, std::try_to_lock);
|
return false;
|
||||||
if (!lock.owns_lock())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
BuildLayerRenderStatesLocked(outputWidth, outputHeight, states);
|
|
||||||
}
|
|
||||||
|
|
||||||
const RuntimeSnapshotVersions versionsAfter = GetVersions();
|
const RuntimeSnapshotVersions versionsAfter = GetVersions();
|
||||||
if (versionsBefore.renderStateVersion != versionsAfter.renderStateVersion ||
|
if (versionsBefore.renderStateVersion != versionsAfter.renderStateVersion ||
|
||||||
@@ -139,13 +121,8 @@ bool RuntimeSnapshotProvider::TryGetRenderStateSnapshot(unsigned outputWidth, un
|
|||||||
bool RuntimeSnapshotProvider::TryRefreshSnapshotParameters(RuntimeRenderStateSnapshot& snapshot) const
|
bool RuntimeSnapshotProvider::TryRefreshSnapshotParameters(RuntimeRenderStateSnapshot& snapshot) const
|
||||||
{
|
{
|
||||||
const uint64_t expectedRenderStateVersion = snapshot.versions.renderStateVersion;
|
const uint64_t expectedRenderStateVersion = snapshot.versions.renderStateVersion;
|
||||||
{
|
if (!mRuntimeStore.TryRefreshLayerParameters(snapshot.states))
|
||||||
std::unique_lock<std::mutex> lock(mRuntimeHost.mMutex, std::try_to_lock);
|
return false;
|
||||||
if (!lock.owns_lock())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RefreshCachedLayerStatesLocked(snapshot.states);
|
|
||||||
}
|
|
||||||
|
|
||||||
const RuntimeSnapshotVersions versions = GetVersions();
|
const RuntimeSnapshotVersions versions = GetVersions();
|
||||||
if (versions.renderStateVersion != expectedRenderStateVersion)
|
if (versions.renderStateVersion != expectedRenderStateVersion)
|
||||||
@@ -157,88 +134,5 @@ bool RuntimeSnapshotProvider::TryRefreshSnapshotParameters(RuntimeRenderStateSna
|
|||||||
|
|
||||||
void RuntimeSnapshotProvider::RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const
|
void RuntimeSnapshotProvider::RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
mRuntimeStore.RefreshDynamicRenderStateFields(states);
|
||||||
RefreshDynamicRenderStateFieldsLocked(states);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeSnapshotProvider::BuildLayerRenderStatesLocked(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const
|
|
||||||
{
|
|
||||||
const HealthTelemetry::SignalStatusSnapshot signalStatus = mRuntimeHost.mHealthTelemetry.GetSignalStatusSnapshot();
|
|
||||||
|
|
||||||
for (const RuntimeHost::LayerPersistentState& layer : mRuntimeHost.mPersistentState.layers)
|
|
||||||
{
|
|
||||||
auto shaderIt = mRuntimeHost.mPackagesById.find(layer.shaderId);
|
|
||||||
if (shaderIt == mRuntimeHost.mPackagesById.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
RuntimeRenderState state;
|
|
||||||
state.layerId = layer.id;
|
|
||||||
state.shaderId = layer.shaderId;
|
|
||||||
state.shaderName = shaderIt->second.displayName;
|
|
||||||
state.mixAmount = 1.0;
|
|
||||||
state.bypass = layer.bypass ? 1.0 : 0.0;
|
|
||||||
state.inputWidth = signalStatus.width;
|
|
||||||
state.inputHeight = signalStatus.height;
|
|
||||||
state.outputWidth = outputWidth;
|
|
||||||
state.outputHeight = outputHeight;
|
|
||||||
state.parameterDefinitions = shaderIt->second.parameters;
|
|
||||||
state.textureAssets = shaderIt->second.textureAssets;
|
|
||||||
state.fontAssets = shaderIt->second.fontAssets;
|
|
||||||
state.isTemporal = shaderIt->second.temporal.enabled;
|
|
||||||
state.temporalHistorySource = shaderIt->second.temporal.historySource;
|
|
||||||
state.requestedTemporalHistoryLength = shaderIt->second.temporal.requestedHistoryLength;
|
|
||||||
state.effectiveTemporalHistoryLength = shaderIt->second.temporal.effectiveHistoryLength;
|
|
||||||
state.feedback = shaderIt->second.feedback;
|
|
||||||
|
|
||||||
for (const ShaderParameterDefinition& definition : shaderIt->second.parameters)
|
|
||||||
{
|
|
||||||
ShaderParameterValue value = mRuntimeHost.DefaultValueForDefinition(definition);
|
|
||||||
auto valueIt = layer.parameterValues.find(definition.id);
|
|
||||||
if (valueIt != layer.parameterValues.end())
|
|
||||||
value = valueIt->second;
|
|
||||||
state.parameterValues[definition.id] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
states.push_back(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
RefreshDynamicRenderStateFieldsLocked(states);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeSnapshotProvider::RefreshCachedLayerStatesLocked(std::vector<RuntimeRenderState>& states) const
|
|
||||||
{
|
|
||||||
for (RuntimeRenderState& state : states)
|
|
||||||
{
|
|
||||||
const auto layerIt = std::find_if(mRuntimeHost.mPersistentState.layers.begin(), mRuntimeHost.mPersistentState.layers.end(),
|
|
||||||
[&state](const RuntimeHost::LayerPersistentState& layer) { return layer.id == state.layerId; });
|
|
||||||
if (layerIt == mRuntimeHost.mPersistentState.layers.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
state.bypass = layerIt->bypass ? 1.0 : 0.0;
|
|
||||||
state.parameterValues.clear();
|
|
||||||
for (const ShaderParameterDefinition& definition : state.parameterDefinitions)
|
|
||||||
{
|
|
||||||
ShaderParameterValue value = mRuntimeHost.DefaultValueForDefinition(definition);
|
|
||||||
auto valueIt = layerIt->parameterValues.find(definition.id);
|
|
||||||
if (valueIt != layerIt->parameterValues.end())
|
|
||||||
value = valueIt->second;
|
|
||||||
state.parameterValues[definition.id] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeSnapshotProvider::RefreshDynamicRenderStateFieldsLocked(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() - mRuntimeHost.mStartTime).count();
|
|
||||||
const double frameCount = static_cast<double>(mRuntimeHost.mFrameCounter.load(std::memory_order_relaxed));
|
|
||||||
|
|
||||||
for (RuntimeRenderState& state : states)
|
|
||||||
{
|
|
||||||
state.timeSeconds = timeSeconds;
|
|
||||||
state.utcTimeSeconds = clock.utcTimeSeconds;
|
|
||||||
state.utcOffsetSeconds = clock.utcOffsetSeconds;
|
|
||||||
state.startupRandom = mRuntimeHost.mStartupRandom;
|
|
||||||
state.frameCount = frameCount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "RuntimeHost.h"
|
#include "RuntimeStore.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -23,7 +23,7 @@ struct RuntimeRenderStateSnapshot
|
|||||||
class RuntimeSnapshotProvider
|
class RuntimeSnapshotProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit RuntimeSnapshotProvider(RuntimeHost& runtimeHost);
|
explicit RuntimeSnapshotProvider(RuntimeStore& runtimeStore);
|
||||||
|
|
||||||
bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<ShaderPassBuildSource>& passSources, std::string& error) const;
|
bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<ShaderPassBuildSource>& passSources, std::string& error) const;
|
||||||
unsigned GetMaxTemporalHistoryFrames() const;
|
unsigned GetMaxTemporalHistoryFrames() const;
|
||||||
@@ -35,9 +35,5 @@ public:
|
|||||||
void RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const;
|
void RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void BuildLayerRenderStatesLocked(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const;
|
RuntimeStore& mRuntimeStore;
|
||||||
void RefreshCachedLayerStatesLocked(std::vector<RuntimeRenderState>& states) const;
|
|
||||||
void RefreshDynamicRenderStateFieldsLocked(std::vector<RuntimeRenderState>& states) const;
|
|
||||||
|
|
||||||
RuntimeHost& mRuntimeHost;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#include "RuntimeStore.h"
|
#include "RuntimeStore.h"
|
||||||
|
|
||||||
|
#include "RuntimeClock.h"
|
||||||
#include "ShaderPackageRegistry.h"
|
#include "ShaderPackageRegistry.h"
|
||||||
#include "RuntimeParameterUtils.h"
|
#include "RuntimeParameterUtils.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <mutex>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -129,11 +131,20 @@ bool FontAssetsEqual(const std::vector<ShaderFontAsset>& left, const std::vector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeStore::RuntimeStore(RuntimeHost& runtimeHost) :
|
RuntimeStore::RuntimeStore()
|
||||||
mRuntimeHost(runtimeHost)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HealthTelemetry& RuntimeStore::GetHealthTelemetry()
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetHealthTelemetry();
|
||||||
|
}
|
||||||
|
|
||||||
|
const HealthTelemetry& RuntimeStore::GetHealthTelemetry() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetHealthTelemetry();
|
||||||
|
}
|
||||||
|
|
||||||
bool RuntimeStore::InitializeStore(std::string& error)
|
bool RuntimeStore::InitializeStore(std::string& error)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -422,7 +433,7 @@ bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, con
|
|||||||
return SavePersistentState(error);
|
return SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error)
|
bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const ShaderParameterValue& value, bool persistState, std::string& error)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
|
||||||
@@ -433,71 +444,7 @@ bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto shaderIt = mRuntimeHost.mPackagesById.find(layer->shaderId);
|
layer->parameterValues[parameterId] = value;
|
||||||
if (shaderIt == mRuntimeHost.mPackagesById.end())
|
|
||||||
{
|
|
||||||
error = "Unknown shader id: " + layer->shaderId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ShaderPackage& shaderPackage = shaderIt->second;
|
|
||||||
auto parameterIt = std::find_if(shaderPackage.parameters.begin(), shaderPackage.parameters.end(),
|
|
||||||
[¶meterId](const ShaderParameterDefinition& definition) { return definition.id == parameterId; });
|
|
||||||
if (parameterIt == shaderPackage.parameters.end())
|
|
||||||
{
|
|
||||||
error = "Unknown parameter id: " + parameterId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parameterIt->type == ShaderParameterType::Trigger)
|
|
||||||
{
|
|
||||||
ShaderParameterValue& value = layer->parameterValues[parameterId];
|
|
||||||
const double previousCount = value.numberValues.empty() ? 0.0 : value.numberValues[0];
|
|
||||||
const double triggerTime = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mRuntimeHost.mStartTime).count();
|
|
||||||
value.numberValues = { previousCount + 1.0, triggerTime };
|
|
||||||
mRuntimeHost.MarkParameterStateDirtyLocked();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderParameterValue normalized;
|
|
||||||
if (!mRuntimeHost.NormalizeAndValidateValue(*parameterIt, newValue, normalized, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
layer->parameterValues[parameterId] = normalized;
|
|
||||||
mRuntimeHost.MarkParameterStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error)
|
|
||||||
{
|
|
||||||
return SetStoredParameterValueByControlKey(layerKey, parameterKey, newValue, true, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
|
||||||
|
|
||||||
RuntimeHost::LayerPersistentState* matchedLayer = nullptr;
|
|
||||||
const ShaderPackage* matchedPackage = nullptr;
|
|
||||||
std::vector<ShaderParameterDefinition>::const_iterator parameterIt;
|
|
||||||
if (!TryResolveStoredLayerAndParameterByControlKeyLocked(layerKey, parameterKey, matchedLayer, matchedPackage, parameterIt, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (parameterIt->type == ShaderParameterType::Trigger)
|
|
||||||
{
|
|
||||||
ShaderParameterValue& value = matchedLayer->parameterValues[parameterIt->id];
|
|
||||||
const double previousCount = value.numberValues.empty() ? 0.0 : value.numberValues[0];
|
|
||||||
const double triggerTime = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mRuntimeHost.mStartTime).count();
|
|
||||||
value.numberValues = { previousCount + 1.0, triggerTime };
|
|
||||||
mRuntimeHost.MarkParameterStateDirtyLocked();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderParameterValue normalized;
|
|
||||||
if (!mRuntimeHost.NormalizeAndValidateValue(*parameterIt, newValue, normalized, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
matchedLayer->parameterValues[parameterIt->id] = normalized;
|
|
||||||
mRuntimeHost.MarkParameterStateDirtyLocked();
|
mRuntimeHost.MarkParameterStateDirtyLocked();
|
||||||
return !persistState || SavePersistentState(error);
|
return !persistState || SavePersistentState(error);
|
||||||
}
|
}
|
||||||
@@ -1194,3 +1141,165 @@ bool RuntimeStore::TryResolveStoredLayerAndParameterByControlKeyLocked(const std
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::CopyShaderPackageForStoredLayer(const std::string& layerId, ShaderPackage& shaderPackage, std::string& error) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
const RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
|
||||||
|
if (!layer)
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = mRuntimeHost.mPackagesById.find(layer->shaderId);
|
||||||
|
if (it == mRuntimeHost.mPackagesById.end())
|
||||||
|
{
|
||||||
|
error = "Unknown shader id: " + layer->shaderId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderPackage = it->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::GetShaderCompilerInputs(std::filesystem::path& repoRoot, std::filesystem::path& wrapperPath,
|
||||||
|
std::filesystem::path& generatedGlslPath, std::filesystem::path& patchedGlslPath, unsigned& maxTemporalHistoryFrames) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
repoRoot = mRuntimeHost.mRepoRoot;
|
||||||
|
wrapperPath = mRuntimeHost.mWrapperPath;
|
||||||
|
generatedGlslPath = mRuntimeHost.mGeneratedGlslPath;
|
||||||
|
patchedGlslPath = mRuntimeHost.mPatchedGlslPath;
|
||||||
|
maxTemporalHistoryFrames = mRuntimeHost.mConfig.maxTemporalHistoryFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t RuntimeStore::GetRenderStateVersion() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.mRenderStateVersion.load(std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t RuntimeStore::GetParameterStateVersion() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.mParameterStateVersion.load(std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::AdvanceFrameCounter()
|
||||||
|
{
|
||||||
|
++mRuntimeHost.mFrameCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::BuildLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
BuildLayerRenderStatesLocked(outputWidth, outputHeight, states);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::TryBuildLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mRuntimeHost.mMutex, std::try_to_lock);
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BuildLayerRenderStatesLocked(outputWidth, outputHeight, states);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::TryRefreshLayerParameters(std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mRuntimeHost.mMutex, std::try_to_lock);
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RefreshLayerParametersLocked(states);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
RefreshDynamicRenderStateFieldsLocked(states);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::BuildLayerRenderStatesLocked(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
states.clear();
|
||||||
|
const HealthTelemetry::SignalStatusSnapshot signalStatus = mRuntimeHost.mHealthTelemetry.GetSignalStatusSnapshot();
|
||||||
|
|
||||||
|
for (const RuntimeHost::LayerPersistentState& layer : mRuntimeHost.mPersistentState.layers)
|
||||||
|
{
|
||||||
|
auto shaderIt = mRuntimeHost.mPackagesById.find(layer.shaderId);
|
||||||
|
if (shaderIt == mRuntimeHost.mPackagesById.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
RuntimeRenderState state;
|
||||||
|
state.layerId = layer.id;
|
||||||
|
state.shaderId = layer.shaderId;
|
||||||
|
state.shaderName = shaderIt->second.displayName;
|
||||||
|
state.mixAmount = 1.0;
|
||||||
|
state.bypass = layer.bypass ? 1.0 : 0.0;
|
||||||
|
state.inputWidth = signalStatus.width;
|
||||||
|
state.inputHeight = signalStatus.height;
|
||||||
|
state.outputWidth = outputWidth;
|
||||||
|
state.outputHeight = outputHeight;
|
||||||
|
state.parameterDefinitions = shaderIt->second.parameters;
|
||||||
|
state.textureAssets = shaderIt->second.textureAssets;
|
||||||
|
state.fontAssets = shaderIt->second.fontAssets;
|
||||||
|
state.isTemporal = shaderIt->second.temporal.enabled;
|
||||||
|
state.temporalHistorySource = shaderIt->second.temporal.historySource;
|
||||||
|
state.requestedTemporalHistoryLength = shaderIt->second.temporal.requestedHistoryLength;
|
||||||
|
state.effectiveTemporalHistoryLength = shaderIt->second.temporal.effectiveHistoryLength;
|
||||||
|
state.feedback = shaderIt->second.feedback;
|
||||||
|
|
||||||
|
for (const ShaderParameterDefinition& definition : shaderIt->second.parameters)
|
||||||
|
{
|
||||||
|
ShaderParameterValue value = mRuntimeHost.DefaultValueForDefinition(definition);
|
||||||
|
auto valueIt = layer.parameterValues.find(definition.id);
|
||||||
|
if (valueIt != layer.parameterValues.end())
|
||||||
|
value = valueIt->second;
|
||||||
|
state.parameterValues[definition.id] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
states.push_back(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshDynamicRenderStateFieldsLocked(states);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::RefreshLayerParametersLocked(std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
for (RuntimeRenderState& state : states)
|
||||||
|
{
|
||||||
|
const auto layerIt = std::find_if(mRuntimeHost.mPersistentState.layers.begin(), mRuntimeHost.mPersistentState.layers.end(),
|
||||||
|
[&state](const RuntimeHost::LayerPersistentState& layer) { return layer.id == state.layerId; });
|
||||||
|
if (layerIt == mRuntimeHost.mPersistentState.layers.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
state.bypass = layerIt->bypass ? 1.0 : 0.0;
|
||||||
|
state.parameterValues.clear();
|
||||||
|
for (const ShaderParameterDefinition& definition : state.parameterDefinitions)
|
||||||
|
{
|
||||||
|
ShaderParameterValue value = mRuntimeHost.DefaultValueForDefinition(definition);
|
||||||
|
auto valueIt = layerIt->parameterValues.find(definition.id);
|
||||||
|
if (valueIt != layerIt->parameterValues.end())
|
||||||
|
value = valueIt->second;
|
||||||
|
state.parameterValues[definition.id] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::RefreshDynamicRenderStateFieldsLocked(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() - mRuntimeHost.mStartTime).count();
|
||||||
|
const double frameCount = static_cast<double>(mRuntimeHost.mFrameCounter.load(std::memory_order_relaxed));
|
||||||
|
|
||||||
|
for (RuntimeRenderState& state : states)
|
||||||
|
{
|
||||||
|
state.timeSeconds = timeSeconds;
|
||||||
|
state.utcTimeSeconds = clock.utcTimeSeconds;
|
||||||
|
state.utcOffsetSeconds = clock.utcOffsetSeconds;
|
||||||
|
state.startupRandom = mRuntimeHost.mStartupRandom;
|
||||||
|
state.frameCount = frameCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,13 +2,18 @@
|
|||||||
|
|
||||||
#include "RuntimeHost.h"
|
#include "RuntimeHost.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
class RuntimeSnapshotProvider;
|
||||||
|
|
||||||
class RuntimeStore
|
class RuntimeStore
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit RuntimeStore(RuntimeHost& runtimeHost);
|
RuntimeStore();
|
||||||
|
HealthTelemetry& GetHealthTelemetry();
|
||||||
|
const HealthTelemetry& GetHealthTelemetry() const;
|
||||||
|
|
||||||
bool InitializeStore(std::string& error);
|
bool InitializeStore(std::string& error);
|
||||||
std::string BuildPersistentStateJson() const;
|
std::string BuildPersistentStateJson() const;
|
||||||
@@ -20,9 +25,7 @@ public:
|
|||||||
bool MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, 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 SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error);
|
||||||
bool SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, 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 SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const ShaderParameterValue& value, bool persistState, 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 ResetStoredLayerParameterValues(const std::string& layerId, std::string& error);
|
||||||
bool SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const;
|
bool SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const;
|
||||||
bool LoadStackPresetSnapshot(const std::string& presetName, std::string& error);
|
bool LoadStackPresetSnapshot(const std::string& presetName, std::string& error);
|
||||||
@@ -48,6 +51,8 @@ public:
|
|||||||
void ClearReloadRequest();
|
void ClearReloadRequest();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class RuntimeCoordinator;
|
||||||
|
friend class RuntimeSnapshotProvider;
|
||||||
bool LoadConfig(std::string& error);
|
bool LoadConfig(std::string& error);
|
||||||
bool LoadPersistentState(std::string& error);
|
bool LoadPersistentState(std::string& error);
|
||||||
bool SavePersistentState(std::string& error) const;
|
bool SavePersistentState(std::string& error) const;
|
||||||
@@ -60,8 +65,21 @@ private:
|
|||||||
bool TryResolveStoredLayerAndParameterByControlKeyLocked(const std::string& layerKey, const std::string& parameterKey,
|
bool TryResolveStoredLayerAndParameterByControlKeyLocked(const std::string& layerKey, const std::string& parameterKey,
|
||||||
RuntimeHost::LayerPersistentState*& matchedLayer, const ShaderPackage*& matchedPackage,
|
RuntimeHost::LayerPersistentState*& matchedLayer, const ShaderPackage*& matchedPackage,
|
||||||
std::vector<ShaderParameterDefinition>::const_iterator& parameterIt, std::string& error) const;
|
std::vector<ShaderParameterDefinition>::const_iterator& parameterIt, std::string& error) 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;
|
||||||
|
uint64_t GetRenderStateVersion() const;
|
||||||
|
uint64_t GetParameterStateVersion() const;
|
||||||
|
void AdvanceFrameCounter();
|
||||||
|
void BuildLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const;
|
||||||
|
bool TryBuildLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const;
|
||||||
|
bool TryRefreshLayerParameters(std::vector<RuntimeRenderState>& states) const;
|
||||||
|
void RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const;
|
||||||
|
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;
|
||||||
JsonValue BuildRuntimeStateValue() const;
|
JsonValue BuildRuntimeStateValue() const;
|
||||||
JsonValue SerializeLayerStack() const;
|
JsonValue SerializeLayerStack() const;
|
||||||
|
|
||||||
RuntimeHost& mRuntimeHost;
|
mutable RuntimeHost mRuntimeHost;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ This note summarizes the main architectural improvements that would make the app
|
|||||||
|
|
||||||
Phase checklist:
|
Phase checklist:
|
||||||
|
|
||||||
- [ ] Define subsystem boundaries and target architecture
|
- [x] Define subsystem boundaries and target architecture
|
||||||
- [ ] Introduce an internal event model
|
- [ ] Introduce an internal event model
|
||||||
- [ ] Split `RuntimeHost`
|
- [ ] Split `RuntimeHost`
|
||||||
- [ ] Make the render thread the sole GL owner
|
- [ ] Make the render thread the sole GL owner
|
||||||
@@ -13,6 +13,11 @@ Phase checklist:
|
|||||||
- [ ] Make DeckLink/backend lifecycle explicit with a state machine
|
- [ ] Make DeckLink/backend lifecycle explicit with a state machine
|
||||||
- [ ] Add structured health, telemetry, and operational reporting
|
- [ ] Add structured health, telemetry, and operational reporting
|
||||||
|
|
||||||
|
Checklist note:
|
||||||
|
|
||||||
|
- The checked Phase 1 item means the subsystem vocabulary, dependency direction, state categories, and design package are in place.
|
||||||
|
- It does not mean the target boundaries are fully extracted in code. The current implementation has Phase 1 compatibility seams, while the full ownership split continues through later phases.
|
||||||
|
|
||||||
## Timing Review
|
## Timing Review
|
||||||
|
|
||||||
The recent OSC work removed several control-path stalls, but the app still has a few deeper timing characteristics that matter for live resilience:
|
The recent OSC work removed several control-path stalls, but the app still has a few deeper timing characteristics that matter for live resilience:
|
||||||
@@ -356,6 +361,12 @@ This roadmap is ordered by architectural dependency rather than by “quick wins
|
|||||||
|
|
||||||
Before changing major internals, formalize the target responsibilities for each major part of the app.
|
Before changing major internals, formalize the target responsibilities for each major part of the app.
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
- Design deliverable: complete.
|
||||||
|
- Compatibility seams in code: partially complete and expanding.
|
||||||
|
- Target boundary extraction: not complete; remaining work is tracked by later phases, especially the event model, `RuntimeHost` split, render ownership, and persistence work.
|
||||||
|
|
||||||
Target split:
|
Target split:
|
||||||
|
|
||||||
- `RuntimeStore`
|
- `RuntimeStore`
|
||||||
@@ -402,6 +413,10 @@ Suggested deliverables:
|
|||||||
- a subsystem design bundle index:
|
- a subsystem design bundle index:
|
||||||
- [docs/subsystems/README.md](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/docs/subsystems/README.md)
|
- [docs/subsystems/README.md](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/docs/subsystems/README.md)
|
||||||
|
|
||||||
|
Current implementation note:
|
||||||
|
|
||||||
|
The repo now has concrete classes for the Phase 1 subsystem names and several call paths already route through them. These classes should be treated as migration boundaries, not proof that the target architecture is fully extracted.
|
||||||
|
|
||||||
### Phase 2. Introduce an internal event model
|
### Phase 2. Introduce an internal event model
|
||||||
|
|
||||||
Once subsystem boundaries are defined, introduce a typed event pipeline between them. This should happen before large state splits so the app has a stable coordination model.
|
Once subsystem boundaries are defined, introduce a typed event pipeline between them. This should happen before large state splits so the app has a stable coordination model.
|
||||||
|
|||||||
@@ -4,6 +4,15 @@ This document expands Phase 1 of [ARCHITECTURE_RESILIENCE_REVIEW.md](/c:/Users/A
|
|||||||
|
|
||||||
The main goal of Phase 1 is not to immediately rewrite the app. It is to establish clear ownership boundaries so later refactors all move toward the same architecture instead of solving local problems in conflicting ways.
|
The main goal of Phase 1 is not to immediately rewrite the app. It is to establish clear ownership boundaries so later refactors all move toward the same architecture instead of solving local problems in conflicting ways.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Phase 1 has two different meanings in this repo, and they should not be collapsed:
|
||||||
|
|
||||||
|
- Phase 1 design package: complete.
|
||||||
|
- Phase 1 target extraction in code: in progress.
|
||||||
|
|
||||||
|
The completed design package includes the agreed subsystem names, responsibilities, dependency rules, state categories, and current-to-target migration map. The codebase also has concrete compatibility seams for those subsystems. That is different from saying every target boundary is fully extracted: several subsystems still delegate through compatibility helpers, and later roadmap phases are still responsible for the event model, remaining `RuntimeHost` split, sole-owner render thread, explicit live-state layering, background persistence, backend state machine, and fuller telemetry.
|
||||||
|
|
||||||
## Why Phase 1 Exists
|
## Why Phase 1 Exists
|
||||||
|
|
||||||
Today the app works, but too many responsibilities still converge in a few places:
|
Today the app works, but too many responsibilities still converge in a few places:
|
||||||
@@ -112,17 +121,20 @@ The codebase now has an initial Phase 1 compatibility split in place:
|
|||||||
- [VideoBackend.h](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/videoio/VideoBackend.h)
|
- [VideoBackend.h](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/videoio/VideoBackend.h)
|
||||||
- [VideoBackend.cpp](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/videoio/VideoBackend.cpp)
|
- [VideoBackend.cpp](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/videoio/VideoBackend.cpp)
|
||||||
|
|
||||||
These are still compatibility seams, not a completed subsystem extraction. Most of them continue to delegate heavily to `RuntimeHost`, `OpenGLComposite`, `DeckLinkSession`, and the existing bridge/pipeline classes. Their purpose is to give later Phase 1 work real code boundaries that can be expanded in parallel:
|
These are still compatibility seams, not a completed subsystem extraction. Some responsibilities have moved behind the new boundaries, while other paths still delegate through compatibility helpers, `OpenGLComposite`, `DeckLinkSession`, and the existing bridge/pipeline classes. Their purpose is to give later work real code boundaries that can be expanded without first inventing the names:
|
||||||
|
|
||||||
- store-facing UI/runtime control calls in `OpenGLCompositeRuntimeControls.cpp` now route through `RuntimeStore`
|
- UI/runtime control calls in `OpenGLCompositeRuntimeControls.cpp` now route through `RuntimeCoordinator`
|
||||||
- runtime startup for path resolution, config load, persistent state load, and shader package scan now initializes through `RuntimeStore`
|
- runtime startup for path resolution, config load, persistent state load, and shader package scan now initializes through `RuntimeStore`
|
||||||
- runtime/UI state JSON composition now lives in `RuntimeStore` instead of `RuntimeHost`
|
- runtime/UI state JSON composition now lives in `RuntimeStore` instead of `RuntimeHost`
|
||||||
- regular stored layer mutations and stack preset save/load now live in `RuntimeStore` instead of `RuntimeHost` public APIs
|
- regular stored layer mutations and stack preset save/load now live in `RuntimeStore` instead of `RuntimeHost` public APIs
|
||||||
- persisted OSC-by-control-key commits now apply through `RuntimeStore`, while `RuntimeHost` no longer exposes the old OSC smoothing/apply helper
|
- persisted OSC-by-control-key commits now route through `RuntimeCoordinator` before applying store changes
|
||||||
- mutation and reload policy now routes through `RuntimeCoordinator`
|
- mutation and reload policy now routes through `RuntimeCoordinator`
|
||||||
|
- parameter target resolution, value normalization, trigger classification, and move no-op classification now live under `RuntimeCoordinator`
|
||||||
- render-state and shader-build reads in `OpenGLComposite.cpp`, `OpenGLShaderPrograms.cpp`, and `ShaderBuildQueue.cpp` now route through `RuntimeSnapshotProvider`
|
- render-state and shader-build reads in `OpenGLComposite.cpp`, `OpenGLShaderPrograms.cpp`, and `ShaderBuildQueue.cpp` now route through `RuntimeSnapshotProvider`
|
||||||
- render-state assembly, cached parameter refresh, and frame-context application now live in `RuntimeSnapshotProvider` instead of `RuntimeHost` public APIs
|
- `RuntimeSnapshotProvider` now depends on `RuntimeStore` rather than sharing `RuntimeHost` directly
|
||||||
|
- render-state assembly, cached parameter refresh, and frame-context application now flow through `RuntimeSnapshotProvider` and store-owned snapshot helpers instead of `RuntimeHost` public APIs
|
||||||
- service ingress and polling coordination now route through `ControlServices`
|
- service ingress and polling coordination now route through `ControlServices`
|
||||||
|
- `ControlServices` now queues coordinator results for OSC commit and file-poll outcomes instead of directly deciding runtime/store policy
|
||||||
- timing and status writes now route through `HealthTelemetry`
|
- timing and status writes now route through `HealthTelemetry`
|
||||||
- `HealthTelemetry` now owns the live signal, video-I/O, and performance snapshots directly instead of `RuntimeHost` keeping those backing fields
|
- `HealthTelemetry` now owns the live signal, video-I/O, and performance snapshots directly instead of `RuntimeHost` keeping those backing fields
|
||||||
- render-side frame advancement and render-performance reporting now flow through `RuntimeSnapshotProvider` and `HealthTelemetry` instead of directly through `RuntimeHost`
|
- render-side frame advancement and render-performance reporting now flow through `RuntimeSnapshotProvider` and `HealthTelemetry` instead of directly through `RuntimeHost`
|
||||||
@@ -131,7 +143,15 @@ These are still compatibility seams, not a completed subsystem extraction. Most
|
|||||||
- `OpenGLComposite` now owns a `VideoBackend` seam for device/session ownership and callback wiring
|
- `OpenGLComposite` now owns a `VideoBackend` seam for device/session ownership and callback wiring
|
||||||
- `OpenGLVideoIOBridge` now acts as an explicit compatibility adapter between `VideoBackend` and `RenderEngine`, instead of `OpenGLComposite` directly owning both sides
|
- `OpenGLVideoIOBridge` now acts as an explicit compatibility adapter between `VideoBackend` and `RenderEngine`, instead of `OpenGLComposite` directly owning both sides
|
||||||
|
|
||||||
That means the next parallel Phase 1 work can focus on moving responsibility behind these seams instead of first inventing them.
|
That means the next extraction work can focus on moving responsibility behind these seams instead of first inventing them.
|
||||||
|
|
||||||
|
Remaining extraction work includes:
|
||||||
|
|
||||||
|
- replacing the compatibility `RuntimeHost` backing object still owned inside `RuntimeStore`
|
||||||
|
- removing coordinator friendship/access to store-internal host data
|
||||||
|
- publishing render snapshots as explicit immutable or near-immutable objects rather than building them from store internals on demand
|
||||||
|
- moving persistence to an asynchronous writer in a later phase
|
||||||
|
- replacing polling/shared-object coordination with the planned internal event model
|
||||||
|
|
||||||
## Subsystem Responsibilities
|
## Subsystem Responsibilities
|
||||||
|
|
||||||
@@ -646,6 +666,8 @@ Phase 1 can reasonably be considered complete once the project has:
|
|||||||
- a current-to-target responsibility map for `RuntimeHost`, `RuntimeServices`, `OpenGLComposite`, and backend/render bridge code
|
- a current-to-target responsibility map for `RuntimeHost`, `RuntimeServices`, `OpenGLComposite`, and backend/render bridge code
|
||||||
- a decision that later phases will build against this target rather than inventing new boundaries ad hoc
|
- a decision that later phases will build against this target rather than inventing new boundaries ad hoc
|
||||||
|
|
||||||
|
By that definition, the Phase 1 design deliverable is complete. The implementation should still be described as partially extracted until the compatibility backing objects and cross-subsystem shims are removed.
|
||||||
|
|
||||||
## Open Questions For Later Phases
|
## Open Questions For Later Phases
|
||||||
|
|
||||||
These do not block Phase 1, but they should remain visible.
|
These do not block Phase 1, but they should remain visible.
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ Parent documents:
|
|||||||
- The notes in this directory expand each subsystem boundary without changing the parent Phase 1 design.
|
- The notes in this directory expand each subsystem boundary without changing the parent Phase 1 design.
|
||||||
- The subsystem notes are meant to be read as design companions, not as independent alternate architectures.
|
- The subsystem notes are meant to be read as design companions, not as independent alternate architectures.
|
||||||
|
|
||||||
|
Status note:
|
||||||
|
|
||||||
|
- The Phase 1 design package is complete.
|
||||||
|
- The codebase has compatibility seams for the named subsystems.
|
||||||
|
- The target subsystem extraction is still in progress, so these notes describe the architecture the implementation is moving toward, not a claim that every boundary is already pure.
|
||||||
|
|
||||||
## Recommended Reading Order
|
## Recommended Reading Order
|
||||||
|
|
||||||
1. [PHASE_1_SUBSYSTEM_BOUNDARIES_DESIGN.md](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/docs/PHASE_1_SUBSYSTEM_BOUNDARIES_DESIGN.md)
|
1. [PHASE_1_SUBSYSTEM_BOUNDARIES_DESIGN.md](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/docs/PHASE_1_SUBSYSTEM_BOUNDARIES_DESIGN.md)
|
||||||
@@ -60,3 +66,5 @@ Phase 1 should leave the project with:
|
|||||||
- one agreed current-to-target migration story
|
- one agreed current-to-target migration story
|
||||||
|
|
||||||
Phase 1 does not need to settle every later implementation detail. The subsystem notes intentionally leave some questions open where later phases need room to choose concrete mechanics.
|
Phase 1 does not need to settle every later implementation detail. The subsystem notes intentionally leave some questions open where later phases need room to choose concrete mechanics.
|
||||||
|
|
||||||
|
As of the current codebase, those design questions are settled well enough for later work to build against them. Remaining implementation work should be tracked as extraction progress under later phases, especially eventing, the `RuntimeHost` split, render-thread ownership, persistence, backend lifecycle, and telemetry.
|
||||||
|
|||||||
Reference in New Issue
Block a user