Phase 5 step 2
This commit is contained in:
@@ -100,13 +100,13 @@ std::vector<RuntimeRenderState> RenderFrameStateResolver::ComposeLayerStates(
|
|||||||
double smoothing,
|
double smoothing,
|
||||||
std::vector<RuntimeLiveOscCommitRequest>* commitRequests) const
|
std::vector<RuntimeLiveOscCommitRequest>* commitRequests) const
|
||||||
{
|
{
|
||||||
RenderStateCompositionInput input;
|
LayeredRenderStateInput input;
|
||||||
input.baseLayerStates = &baseStates;
|
input.committedLiveLayerStates = &baseStates;
|
||||||
input.liveState = &liveState;
|
input.transientAutomationOverlay = &liveState;
|
||||||
input.allowLiveCommits = allowCommit;
|
input.allowTransientAutomationCommits = allowCommit;
|
||||||
input.collectLiveCommitRequests = commitRequests != nullptr;
|
input.collectTransientAutomationCommitRequests = commitRequests != nullptr;
|
||||||
input.liveSmoothing = smoothing;
|
input.transientAutomationSmoothing = smoothing;
|
||||||
input.liveCommitDelay = kOscOverlayCommitDelay;
|
input.transientAutomationCommitDelay = kOscOverlayCommitDelay;
|
||||||
input.now = std::chrono::steady_clock::now();
|
input.now = std::chrono::steady_clock::now();
|
||||||
const RenderStateCompositionResult result = mRenderStateComposer.BuildFrameState(input);
|
const RenderStateCompositionResult result = mRenderStateComposer.BuildFrameState(input);
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
#include "RenderStateComposer.h"
|
#include "RenderStateComposer.h"
|
||||||
|
|
||||||
RenderStateCompositionResult RenderStateComposer::BuildFrameState(const RenderStateCompositionInput& input) const
|
RenderStateCompositionResult RenderStateComposer::BuildFrameState(const LayeredRenderStateInput& input) const
|
||||||
{
|
{
|
||||||
RenderStateCompositionResult result;
|
RenderStateCompositionResult result;
|
||||||
if (!input.baseLayerStates)
|
const std::vector<RuntimeRenderState>* layerStates =
|
||||||
|
input.committedLiveLayerStates ? input.committedLiveLayerStates : input.basePersistedLayerStates;
|
||||||
|
if (!layerStates)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result.layerStates = *input.baseLayerStates;
|
result.layerStates = *layerStates;
|
||||||
result.hasLayerStates = !result.layerStates.empty();
|
result.hasLayerStates = !result.layerStates.empty();
|
||||||
if (input.liveState)
|
if (input.transientAutomationOverlay)
|
||||||
{
|
{
|
||||||
RuntimeLiveStateApplyOptions options;
|
RuntimeLiveStateApplyOptions options;
|
||||||
options.allowCommit = input.allowLiveCommits;
|
options.allowCommit = input.allowTransientAutomationCommits;
|
||||||
options.smoothing = input.liveSmoothing;
|
options.smoothing = input.transientAutomationSmoothing;
|
||||||
options.commitDelay = input.liveCommitDelay;
|
options.commitDelay = input.transientAutomationCommitDelay;
|
||||||
options.now = input.now;
|
options.now = input.now;
|
||||||
input.liveState->ApplyToLayerStates(
|
input.transientAutomationOverlay->ApplyToLayerStates(
|
||||||
result.layerStates,
|
result.layerStates,
|
||||||
options,
|
options,
|
||||||
input.collectLiveCommitRequests ? &result.commitRequests : nullptr);
|
input.collectTransientAutomationCommitRequests ? &result.commitRequests : nullptr);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,15 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct RenderStateCompositionInput
|
struct LayeredRenderStateInput
|
||||||
{
|
{
|
||||||
const std::vector<RuntimeRenderState>* baseLayerStates = nullptr;
|
const std::vector<RuntimeRenderState>* basePersistedLayerStates = nullptr;
|
||||||
RuntimeLiveState* liveState = nullptr;
|
const std::vector<RuntimeRenderState>* committedLiveLayerStates = nullptr;
|
||||||
bool allowLiveCommits = false;
|
RuntimeLiveState* transientAutomationOverlay = nullptr;
|
||||||
bool collectLiveCommitRequests = true;
|
bool allowTransientAutomationCommits = false;
|
||||||
double liveSmoothing = 0.0;
|
bool collectTransientAutomationCommitRequests = true;
|
||||||
std::chrono::milliseconds liveCommitDelay = std::chrono::milliseconds(150);
|
double transientAutomationSmoothing = 0.0;
|
||||||
|
std::chrono::milliseconds transientAutomationCommitDelay = std::chrono::milliseconds(150);
|
||||||
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
|
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -26,5 +27,5 @@ struct RenderStateCompositionResult
|
|||||||
class RenderStateComposer
|
class RenderStateComposer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RenderStateCompositionResult BuildFrameState(const RenderStateCompositionInput& input) const;
|
RenderStateCompositionResult BuildFrameState(const LayeredRenderStateInput& input) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ Phase 1 named the subsystems. Phase 2 added the typed event substrate. Phase 3 m
|
|||||||
## Status
|
## Status
|
||||||
|
|
||||||
- Phase 5 design package: proposed.
|
- Phase 5 design package: proposed.
|
||||||
- Phase 5 implementation: Step 1 started.
|
- Phase 5 implementation: Step 2 started.
|
||||||
- Current alignment: Phase 3 introduced the first pure composition boundary and transient OSC overlay owner, and Phase 5 now has a small `RuntimeStateLayerModel` inventory that names the current state categories. Committed runtime values are still physically stored through `RuntimeStore`/`LayerStackStore`, and transient OSC overlay state is still applied through render-facing helpers rather than through the final layered composition contract.
|
- Current alignment: Phase 3 introduced the first pure composition boundary and transient OSC overlay owner. Phase 5 now has a small `RuntimeStateLayerModel` inventory that names the current state categories, and `RenderStateComposer` consumes a `LayeredRenderStateInput` whose fields make base persisted, committed live, and transient automation inputs explicit. Committed runtime values are still physically stored through `RuntimeStore`/`LayerStackStore`, and transient OSC overlay state is still applied through `RuntimeLiveState`.
|
||||||
|
|
||||||
Current live-state footholds:
|
Current live-state footholds:
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ Current live-state footholds:
|
|||||||
- `RuntimeCoordinator` owns mutation validation, classification, accepted/rejected event publication, snapshot/reload follow-ups, and the policy switch between committed states and live snapshots.
|
- `RuntimeCoordinator` owns mutation validation, classification, accepted/rejected event publication, snapshot/reload follow-ups, and the policy switch between committed states and live snapshots.
|
||||||
- `RuntimeSnapshotProvider` publishes render-facing snapshots from committed runtime state.
|
- `RuntimeSnapshotProvider` publishes render-facing snapshots from committed runtime state.
|
||||||
- `RuntimeLiveState` owns transient OSC overlay bookkeeping, smoothing, generation tracking, and commit-settlement policy.
|
- `RuntimeLiveState` owns transient OSC overlay bookkeeping, smoothing, generation tracking, and commit-settlement policy.
|
||||||
- `RenderStateComposer` combines base render states with live overlay state and returns final per-frame layer states plus settled commit requests.
|
- `RenderStateComposer` consumes `LayeredRenderStateInput`, chooses committed-live layer states over base-persisted layer states when both are supplied, applies transient automation on top, and returns final per-frame layer states plus settled commit requests.
|
||||||
- `RuntimeServiceLiveBridge` drains OSC ingress/completion queues and applies them to render live state during frame preparation.
|
- `RuntimeServiceLiveBridge` drains OSC ingress/completion queues and applies them to render live state during frame preparation.
|
||||||
- `RuntimeStateLayerModel` names the Phase 5 state categories and classifies current fields as base persisted, committed live, transient automation, render-local, or health/config state.
|
- `RuntimeStateLayerModel` names the Phase 5 state categories and classifies current fields as base persisted, committed live, transient automation, render-local, or health/config state.
|
||||||
|
|
||||||
@@ -246,19 +246,18 @@ Initial target:
|
|||||||
|
|
||||||
### Step 2. Name The Layered Composition Input
|
### Step 2. Name The Layered Composition Input
|
||||||
|
|
||||||
Introduce a named composition input model around the current `RenderStateCompositionInput`.
|
Introduce a named composition input model around the previous `RenderStateCompositionInput`.
|
||||||
|
|
||||||
Initial target:
|
Initial target:
|
||||||
|
|
||||||
- make base/committed/transient inputs visible in type names or field names
|
- [x] make base/committed/transient inputs visible in type names or field names
|
||||||
- keep `RenderStateComposer` behavior unchanged at first
|
- [x] keep `RenderStateComposer` behavior unchanged at first
|
||||||
- add tests that assert precedence with no GL
|
- [x] add tests that assert precedence with no GL
|
||||||
|
|
||||||
Possible outcomes:
|
Possible outcomes:
|
||||||
|
|
||||||
- evolve `RenderStateCompositionInput`
|
- [x] add a new `LayeredRenderStateInput`
|
||||||
- add a new `LayeredRenderStateInput`
|
- [ ] add a thin adapter if a later migration needs compatibility with the previous input shape
|
||||||
- add a thin adapter that feeds existing `RenderStateComposer`
|
|
||||||
|
|
||||||
### Step 3. Make Reset And Reload Policy Explicit
|
### Step 3. Make Reset And Reload Policy Explicit
|
||||||
|
|
||||||
@@ -366,9 +365,9 @@ Render-local resources such as temporal history, feedback buffers, readback cach
|
|||||||
|
|
||||||
Phase 5 can be considered complete once the project can say:
|
Phase 5 can be considered complete once the project can say:
|
||||||
|
|
||||||
- [ ] persisted, committed-live, and transient automation layers are named in code or clear read models
|
- [x] persisted, committed-live, and transient automation layers are named in code or clear read models
|
||||||
- [ ] final render-value precedence is explicit and covered by tests
|
- [x] final render-value precedence is explicit and covered by tests
|
||||||
- [ ] `RenderStateComposer` or its replacement consumes a layered input contract
|
- [x] `RenderStateComposer` or its replacement consumes a layered input contract
|
||||||
- [ ] reset/reload/preset behavior for transient overlays is centralized or clearly delegated
|
- [ ] reset/reload/preset behavior for transient overlays is centralized or clearly delegated
|
||||||
- [ ] OSC overlay settle/commit behavior is explicit, including persistence policy
|
- [ ] OSC overlay settle/commit behavior is explicit, including persistence policy
|
||||||
- [ ] `RuntimeStore` remains durable-state focused and does not absorb transient automation policy
|
- [ ] `RuntimeStore` remains durable-state focused and does not absorb transient automation policy
|
||||||
|
|||||||
@@ -359,12 +359,12 @@ void TestRenderStateComposerBuildsFrameState()
|
|||||||
update.targetValue = JsonValue(0.6);
|
update.targetValue = JsonValue(0.6);
|
||||||
liveState.ApplyOscUpdates({ update });
|
liveState.ApplyOscUpdates({ update });
|
||||||
|
|
||||||
RenderStateCompositionInput input;
|
LayeredRenderStateInput input;
|
||||||
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
||||||
input.baseLayerStates = &baseLayerStates;
|
input.committedLiveLayerStates = &baseLayerStates;
|
||||||
input.liveState = &liveState;
|
input.transientAutomationOverlay = &liveState;
|
||||||
input.allowLiveCommits = false;
|
input.allowTransientAutomationCommits = false;
|
||||||
input.liveSmoothing = 0.0;
|
input.transientAutomationSmoothing = 0.0;
|
||||||
|
|
||||||
RenderStateComposer composer;
|
RenderStateComposer composer;
|
||||||
RenderStateCompositionResult result = composer.BuildFrameState(input);
|
RenderStateCompositionResult result = composer.BuildFrameState(input);
|
||||||
@@ -382,6 +382,49 @@ void TestRenderStateComposerBuildsFrameState()
|
|||||||
"composer leaves base layer states unchanged");
|
"composer leaves base layer states unchanged");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestRenderStateComposerUsesCommittedLayerOverBaseLayer()
|
||||||
|
{
|
||||||
|
std::vector<RuntimeRenderState> basePersistedLayerStates = { MakeLayerState() };
|
||||||
|
std::vector<RuntimeRenderState> committedLiveLayerStates = { MakeLayerState() };
|
||||||
|
committedLiveLayerStates[0].parameterValues["amount"].numberValues = { 0.4 };
|
||||||
|
|
||||||
|
LayeredRenderStateInput input;
|
||||||
|
input.basePersistedLayerStates = &basePersistedLayerStates;
|
||||||
|
input.committedLiveLayerStates = &committedLiveLayerStates;
|
||||||
|
|
||||||
|
RenderStateComposer composer;
|
||||||
|
RenderStateCompositionResult result = composer.BuildFrameState(input);
|
||||||
|
|
||||||
|
const auto valueIt = result.layerStates[0].parameterValues.find("amount");
|
||||||
|
Expect(valueIt != result.layerStates[0].parameterValues.end() &&
|
||||||
|
!valueIt->second.numberValues.empty() &&
|
||||||
|
std::fabs(valueIt->second.numberValues[0] - 0.4) < 0.0001,
|
||||||
|
"committed live layer overrides base persisted layer");
|
||||||
|
const auto baseValueIt = basePersistedLayerStates[0].parameterValues.find("amount");
|
||||||
|
Expect(baseValueIt != basePersistedLayerStates[0].parameterValues.end() &&
|
||||||
|
!baseValueIt->second.numberValues.empty() &&
|
||||||
|
std::fabs(baseValueIt->second.numberValues[0] - 0.25) < 0.0001,
|
||||||
|
"committed override leaves base persisted layer unchanged");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestRenderStateComposerUsesBaseLayerWhenCommittedLayerMissing()
|
||||||
|
{
|
||||||
|
std::vector<RuntimeRenderState> basePersistedLayerStates = { MakeLayerState() };
|
||||||
|
|
||||||
|
LayeredRenderStateInput input;
|
||||||
|
input.basePersistedLayerStates = &basePersistedLayerStates;
|
||||||
|
|
||||||
|
RenderStateComposer composer;
|
||||||
|
RenderStateCompositionResult result = composer.BuildFrameState(input);
|
||||||
|
|
||||||
|
Expect(result.hasLayerStates, "composer can use base persisted layer states without committed layer states");
|
||||||
|
const auto valueIt = result.layerStates[0].parameterValues.find("amount");
|
||||||
|
Expect(valueIt != result.layerStates[0].parameterValues.end() &&
|
||||||
|
!valueIt->second.numberValues.empty() &&
|
||||||
|
std::fabs(valueIt->second.numberValues[0] - 0.25) < 0.0001,
|
||||||
|
"base persisted value is used when no committed live value exists");
|
||||||
|
}
|
||||||
|
|
||||||
void TestRenderStateComposerQueuesCommitRequestsWhenEnabled()
|
void TestRenderStateComposerQueuesCommitRequestsWhenEnabled()
|
||||||
{
|
{
|
||||||
RuntimeLiveState liveState;
|
RuntimeLiveState liveState;
|
||||||
@@ -393,13 +436,13 @@ void TestRenderStateComposerQueuesCommitRequestsWhenEnabled()
|
|||||||
liveState.ApplyOscUpdates({ update });
|
liveState.ApplyOscUpdates({ update });
|
||||||
|
|
||||||
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
||||||
RenderStateCompositionInput input;
|
LayeredRenderStateInput input;
|
||||||
input.baseLayerStates = &baseLayerStates;
|
input.committedLiveLayerStates = &baseLayerStates;
|
||||||
input.liveState = &liveState;
|
input.transientAutomationOverlay = &liveState;
|
||||||
input.allowLiveCommits = true;
|
input.allowTransientAutomationCommits = true;
|
||||||
input.collectLiveCommitRequests = true;
|
input.collectTransientAutomationCommitRequests = true;
|
||||||
input.liveSmoothing = 0.0;
|
input.transientAutomationSmoothing = 0.0;
|
||||||
input.liveCommitDelay = std::chrono::milliseconds(0);
|
input.transientAutomationCommitDelay = std::chrono::milliseconds(0);
|
||||||
input.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
input.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
||||||
|
|
||||||
RenderStateComposer composer;
|
RenderStateComposer composer;
|
||||||
@@ -421,13 +464,13 @@ void TestRenderStateComposerSuppressesCommitCollection()
|
|||||||
liveState.ApplyOscUpdates({ update });
|
liveState.ApplyOscUpdates({ update });
|
||||||
|
|
||||||
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
||||||
RenderStateCompositionInput input;
|
LayeredRenderStateInput input;
|
||||||
input.baseLayerStates = &baseLayerStates;
|
input.committedLiveLayerStates = &baseLayerStates;
|
||||||
input.liveState = &liveState;
|
input.transientAutomationOverlay = &liveState;
|
||||||
input.allowLiveCommits = true;
|
input.allowTransientAutomationCommits = true;
|
||||||
input.collectLiveCommitRequests = false;
|
input.collectTransientAutomationCommitRequests = false;
|
||||||
input.liveSmoothing = 0.0;
|
input.transientAutomationSmoothing = 0.0;
|
||||||
input.liveCommitDelay = std::chrono::milliseconds(0);
|
input.transientAutomationCommitDelay = std::chrono::milliseconds(0);
|
||||||
input.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
input.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
||||||
|
|
||||||
RenderStateComposer composer;
|
RenderStateComposer composer;
|
||||||
@@ -454,6 +497,8 @@ int main()
|
|||||||
TestRuntimeLiveStateSmoothingVectorSizeMismatchUsesTargetShape();
|
TestRuntimeLiveStateSmoothingVectorSizeMismatchUsesTargetShape();
|
||||||
TestRuntimeLiveStateTriggerOverlayIncrementsAndClears();
|
TestRuntimeLiveStateTriggerOverlayIncrementsAndClears();
|
||||||
TestRenderStateComposerBuildsFrameState();
|
TestRenderStateComposerBuildsFrameState();
|
||||||
|
TestRenderStateComposerUsesCommittedLayerOverBaseLayer();
|
||||||
|
TestRenderStateComposerUsesBaseLayerWhenCommittedLayerMissing();
|
||||||
TestRenderStateComposerQueuesCommitRequestsWhenEnabled();
|
TestRenderStateComposerQueuesCommitRequestsWhenEnabled();
|
||||||
TestRenderStateComposerSuppressesCommitCollection();
|
TestRenderStateComposerSuppressesCommitCollection();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user