514 lines
19 KiB
C++
514 lines
19 KiB
C++
#include "RenderStateComposer.h"
|
|
#include "RuntimeLiveState.h"
|
|
|
|
#include <chrono>
|
|
#include <cmath>
|
|
#include <iostream>
|
|
|
|
namespace
|
|
{
|
|
int gFailures = 0;
|
|
|
|
void Expect(bool condition, const char* message)
|
|
{
|
|
if (condition)
|
|
return;
|
|
|
|
std::cerr << "FAIL: " << message << "\n";
|
|
++gFailures;
|
|
}
|
|
|
|
ShaderParameterDefinition FloatDefinition(const std::string& id, const std::string& label)
|
|
{
|
|
ShaderParameterDefinition definition;
|
|
definition.id = id;
|
|
definition.label = label;
|
|
definition.type = ShaderParameterType::Float;
|
|
definition.defaultNumbers = { 0.0 };
|
|
definition.minNumbers = { 0.0 };
|
|
definition.maxNumbers = { 1.0 };
|
|
return definition;
|
|
}
|
|
|
|
ShaderParameterDefinition Vec2Definition(const std::string& id, const std::string& label)
|
|
{
|
|
ShaderParameterDefinition definition;
|
|
definition.id = id;
|
|
definition.label = label;
|
|
definition.type = ShaderParameterType::Vec2;
|
|
definition.defaultNumbers = { 0.0, 0.0 };
|
|
definition.minNumbers = { 0.0, 0.0 };
|
|
definition.maxNumbers = { 1.0, 1.0 };
|
|
return definition;
|
|
}
|
|
|
|
ShaderParameterDefinition TriggerDefinition(const std::string& id, const std::string& label)
|
|
{
|
|
ShaderParameterDefinition definition;
|
|
definition.id = id;
|
|
definition.label = label;
|
|
definition.type = ShaderParameterType::Trigger;
|
|
return definition;
|
|
}
|
|
|
|
JsonValue NumberArray(std::initializer_list<double> numbers)
|
|
{
|
|
JsonValue value = JsonValue::MakeArray();
|
|
for (double number : numbers)
|
|
value.pushBack(JsonValue(number));
|
|
return value;
|
|
}
|
|
|
|
RuntimeRenderState MakeLayerState()
|
|
{
|
|
RuntimeRenderState state;
|
|
state.layerId = "layer-one";
|
|
state.shaderId = "test-shader";
|
|
state.shaderName = "Test Shader";
|
|
state.parameterDefinitions.push_back(FloatDefinition("amount", "Amount"));
|
|
ShaderParameterValue amount;
|
|
amount.numberValues = { 0.25 };
|
|
state.parameterValues["amount"] = amount;
|
|
return state;
|
|
}
|
|
|
|
RuntimeRenderState MakeLayerStateWithDefinitions(const std::vector<ShaderParameterDefinition>& definitions)
|
|
{
|
|
RuntimeRenderState state;
|
|
state.layerId = "layer-one";
|
|
state.shaderId = "test-shader";
|
|
state.shaderName = "Test Shader";
|
|
state.parameterDefinitions = definitions;
|
|
return state;
|
|
}
|
|
|
|
void TestRuntimeLiveStateAppliesLatestOscOverlay()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate first;
|
|
first.routeKey = "layer-one\namount";
|
|
first.layerKey = "layer-one";
|
|
first.parameterKey = "amount";
|
|
first.targetValue = JsonValue(0.5);
|
|
|
|
RuntimeLiveOscUpdate second = first;
|
|
second.targetValue = JsonValue(0.75);
|
|
|
|
liveState.ApplyOscUpdates({ first, second });
|
|
Expect(liveState.OverlayCount() == 1, "live state keeps one overlay per route");
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerState() };
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.allowCommit = false;
|
|
options.smoothing = 0.0;
|
|
liveState.ApplyToLayerStates(states, options, nullptr);
|
|
|
|
const auto valueIt = states[0].parameterValues.find("amount");
|
|
Expect(valueIt != states[0].parameterValues.end(), "overlay writes the target parameter");
|
|
Expect(!valueIt->second.numberValues.empty() && std::fabs(valueIt->second.numberValues[0] - 0.75) < 0.0001,
|
|
"overlay applies the latest target value");
|
|
}
|
|
|
|
void TestRuntimeLiveStateIgnoresStaleCommitCompletions()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "amount";
|
|
update.targetValue = JsonValue(0.9);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerState() };
|
|
std::vector<RuntimeLiveOscCommitRequest> commitRequests;
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.allowCommit = true;
|
|
options.smoothing = 0.0;
|
|
options.commitDelay = std::chrono::milliseconds(0);
|
|
options.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
|
liveState.ApplyToLayerStates(states, options, &commitRequests);
|
|
Expect(commitRequests.size() == 1, "initial commit request is queued");
|
|
|
|
liveState.ApplyOscCommitCompletions({ { "other-route", commitRequests[0].generation } });
|
|
Expect(liveState.OverlayCount() == 1, "completion for another route does not remove overlay");
|
|
|
|
liveState.ApplyOscCommitCompletions({ { commitRequests[0].routeKey, commitRequests[0].generation + 1 } });
|
|
Expect(liveState.OverlayCount() == 1, "completion for another generation does not remove overlay");
|
|
|
|
RuntimeLiveOscUpdate newerUpdate = update;
|
|
newerUpdate.targetValue = JsonValue(0.2);
|
|
liveState.ApplyOscUpdates({ newerUpdate });
|
|
liveState.ApplyOscCommitCompletions({ { commitRequests[0].routeKey, commitRequests[0].generation } });
|
|
Expect(liveState.OverlayCount() == 1, "stale completion for previous generation is ignored after newer update");
|
|
}
|
|
|
|
void TestRuntimeLiveStateQueuesAndCompletesCommit()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "amount";
|
|
update.targetValue = JsonValue(0.9);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerState() };
|
|
std::vector<RuntimeLiveOscCommitRequest> commitRequests;
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.allowCommit = true;
|
|
options.smoothing = 0.0;
|
|
options.commitDelay = std::chrono::milliseconds(0);
|
|
options.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
|
liveState.ApplyToLayerStates(states, options, &commitRequests);
|
|
|
|
Expect(commitRequests.size() == 1, "live state queues a commit request once the overlay can settle");
|
|
Expect(commitRequests[0].routeKey == "layer-one\namount", "commit request preserves route");
|
|
Expect(commitRequests[0].generation == 1, "commit request carries overlay generation");
|
|
|
|
liveState.ApplyOscCommitCompletions({ { commitRequests[0].routeKey, commitRequests[0].generation } });
|
|
Expect(liveState.OverlayCount() == 0, "matching commit completion removes settled overlay");
|
|
}
|
|
|
|
void TestRuntimeLiveStateQueuesOneCommitPerGeneration()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "amount";
|
|
update.targetValue = JsonValue(0.8);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.allowCommit = true;
|
|
options.smoothing = 0.0;
|
|
options.commitDelay = std::chrono::milliseconds(0);
|
|
options.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerState() };
|
|
std::vector<RuntimeLiveOscCommitRequest> commitRequests;
|
|
liveState.ApplyToLayerStates(states, options, &commitRequests);
|
|
Expect(commitRequests.size() == 1, "first apply queues one commit for generation");
|
|
Expect(commitRequests[0].generation == 1, "first commit uses generation one");
|
|
|
|
commitRequests.clear();
|
|
options.now += std::chrono::milliseconds(1);
|
|
liveState.ApplyToLayerStates(states, options, &commitRequests);
|
|
Expect(commitRequests.empty(), "second apply does not duplicate commit for same generation");
|
|
|
|
RuntimeLiveOscUpdate newerUpdate = update;
|
|
newerUpdate.targetValue = JsonValue(0.4);
|
|
liveState.ApplyOscUpdates({ newerUpdate });
|
|
|
|
commitRequests.clear();
|
|
options.now += std::chrono::milliseconds(1);
|
|
liveState.ApplyToLayerStates(states, options, &commitRequests);
|
|
Expect(commitRequests.size() == 1, "newer update allows a new commit request");
|
|
Expect(commitRequests[0].generation == 2, "new commit uses newer generation");
|
|
}
|
|
|
|
void TestRuntimeLiveStateSmoothingZeroAppliesTargetImmediately()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "amount";
|
|
update.targetValue = JsonValue(1.0);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerState() };
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.smoothing = 0.0;
|
|
liveState.ApplyToLayerStates(states, options, nullptr);
|
|
|
|
const auto valueIt = states[0].parameterValues.find("amount");
|
|
Expect(valueIt != states[0].parameterValues.end(), "smoothing zero writes amount");
|
|
Expect(!valueIt->second.numberValues.empty() && std::fabs(valueIt->second.numberValues[0] - 1.0) < 0.0001,
|
|
"smoothing zero applies target immediately");
|
|
}
|
|
|
|
void TestRuntimeLiveStateSmoothingOneConvergesImmediately()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "amount";
|
|
update.targetValue = JsonValue(1.0);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerState() };
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.smoothing = 1.0;
|
|
options.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(16);
|
|
liveState.ApplyToLayerStates(states, options, nullptr);
|
|
|
|
const auto valueIt = states[0].parameterValues.find("amount");
|
|
Expect(valueIt != states[0].parameterValues.end(), "smoothing one writes amount");
|
|
Expect(!valueIt->second.numberValues.empty() && std::fabs(valueIt->second.numberValues[0] - 1.0) < 0.0001,
|
|
"smoothing one converges immediately");
|
|
}
|
|
|
|
void TestRuntimeLiveStateSmoothingPartiallyConverges()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "amount";
|
|
update.targetValue = JsonValue(1.0);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerState() };
|
|
ShaderParameterValue amount;
|
|
amount.numberValues = { 0.0 };
|
|
states[0].parameterValues["amount"] = amount;
|
|
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.smoothing = 0.5;
|
|
options.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(16);
|
|
liveState.ApplyToLayerStates(states, options, nullptr);
|
|
|
|
const auto valueIt = states[0].parameterValues.find("amount");
|
|
Expect(valueIt != states[0].parameterValues.end(), "partial smoothing writes amount");
|
|
Expect(!valueIt->second.numberValues.empty() &&
|
|
valueIt->second.numberValues[0] > 0.0 &&
|
|
valueIt->second.numberValues[0] < 1.0,
|
|
"partial smoothing advances toward target without snapping");
|
|
}
|
|
|
|
void TestRuntimeLiveStateSmoothingVectorSizeMismatchUsesTargetShape()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\noffset";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "offset";
|
|
update.targetValue = NumberArray({ 0.25, 0.75 });
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerStateWithDefinitions({ Vec2Definition("offset", "Offset") }) };
|
|
ShaderParameterValue malformedOffset;
|
|
malformedOffset.numberValues = { 0.1 };
|
|
states[0].parameterValues["offset"] = malformedOffset;
|
|
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.smoothing = 0.5;
|
|
options.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(16);
|
|
liveState.ApplyToLayerStates(states, options, nullptr);
|
|
|
|
const auto valueIt = states[0].parameterValues.find("offset");
|
|
Expect(valueIt != states[0].parameterValues.end(), "vector mismatch writes offset");
|
|
Expect(valueIt->second.numberValues.size() == 2, "vector mismatch restores target vector size");
|
|
Expect(valueIt->second.numberValues.size() == 2 &&
|
|
std::fabs(valueIt->second.numberValues[0] - 0.25) < 0.0001 &&
|
|
std::fabs(valueIt->second.numberValues[1] - 0.75) < 0.0001,
|
|
"vector mismatch snaps to validated target shape");
|
|
}
|
|
|
|
void TestRuntimeLiveStateTriggerOverlayIncrementsAndClears()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\npulse";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "pulse";
|
|
update.targetValue = JsonValue(true);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> states = { MakeLayerStateWithDefinitions({ TriggerDefinition("pulse", "Pulse") }) };
|
|
states[0].timeSeconds = 42.0;
|
|
ShaderParameterValue pulse;
|
|
pulse.numberValues = { 2.0, 10.0 };
|
|
states[0].parameterValues["pulse"] = pulse;
|
|
|
|
std::vector<RuntimeLiveOscCommitRequest> commitRequests;
|
|
RuntimeLiveStateApplyOptions options;
|
|
options.allowCommit = true;
|
|
options.smoothing = 0.0;
|
|
options.commitDelay = std::chrono::milliseconds(0);
|
|
liveState.ApplyToLayerStates(states, options, &commitRequests);
|
|
|
|
const auto valueIt = states[0].parameterValues.find("pulse");
|
|
Expect(valueIt != states[0].parameterValues.end(), "trigger overlay writes pulse");
|
|
Expect(valueIt->second.numberValues.size() == 2 &&
|
|
std::fabs(valueIt->second.numberValues[0] - 3.0) < 0.0001 &&
|
|
std::fabs(valueIt->second.numberValues[1] - 42.0) < 0.0001,
|
|
"trigger overlay increments count and stamps layer time");
|
|
Expect(commitRequests.empty(), "trigger overlay does not queue commit");
|
|
Expect(liveState.OverlayCount() == 0, "trigger overlay clears after apply");
|
|
}
|
|
|
|
void TestRenderStateComposerBuildsFrameState()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "Test Shader";
|
|
update.parameterKey = "Amount";
|
|
update.targetValue = JsonValue(0.6);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
LayeredRenderStateInput input;
|
|
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
|
input.committedLiveLayerStates = &baseLayerStates;
|
|
input.transientAutomationOverlay = &liveState;
|
|
input.allowTransientAutomationCommits = false;
|
|
input.transientAutomationSmoothing = 0.0;
|
|
|
|
RenderStateComposer composer;
|
|
RenderStateCompositionResult result = composer.BuildFrameState(input);
|
|
|
|
Expect(result.hasLayerStates, "composer reports that it composed base layer states");
|
|
Expect(result.layerStates.size() == 1, "composer returns composed layer state");
|
|
const auto valueIt = result.layerStates[0].parameterValues.find("amount");
|
|
Expect(valueIt != result.layerStates[0].parameterValues.end(), "composer applies live overlay through live state");
|
|
Expect(!valueIt->second.numberValues.empty() && std::fabs(valueIt->second.numberValues[0] - 0.6) < 0.0001,
|
|
"composer uses OSC key matching against shader names and labels");
|
|
const auto baseValueIt = baseLayerStates[0].parameterValues.find("amount");
|
|
Expect(baseValueIt != baseLayerStates[0].parameterValues.end() &&
|
|
!baseValueIt->second.numberValues.empty() &&
|
|
std::fabs(baseValueIt->second.numberValues[0] - 0.25) < 0.0001,
|
|
"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()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "amount";
|
|
update.targetValue = JsonValue(0.8);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
|
LayeredRenderStateInput input;
|
|
input.committedLiveLayerStates = &baseLayerStates;
|
|
input.transientAutomationOverlay = &liveState;
|
|
input.allowTransientAutomationCommits = true;
|
|
input.collectTransientAutomationCommitRequests = true;
|
|
input.transientAutomationSmoothing = 0.0;
|
|
input.transientAutomationCommitDelay = std::chrono::milliseconds(0);
|
|
input.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
|
|
|
RenderStateComposer composer;
|
|
RenderStateCompositionResult result = composer.BuildFrameState(input);
|
|
|
|
Expect(result.commitRequests.size() == 1, "composer returns live commit requests when collection is enabled");
|
|
Expect(result.commitRequests[0].routeKey == "layer-one\namount", "composer commit request preserves route");
|
|
Expect(result.commitRequests[0].generation == 1, "composer commit request preserves generation");
|
|
}
|
|
|
|
void TestRenderStateComposerSuppressesCommitCollection()
|
|
{
|
|
RuntimeLiveState liveState;
|
|
RuntimeLiveOscUpdate update;
|
|
update.routeKey = "layer-one\namount";
|
|
update.layerKey = "layer-one";
|
|
update.parameterKey = "amount";
|
|
update.targetValue = JsonValue(0.7);
|
|
liveState.ApplyOscUpdates({ update });
|
|
|
|
std::vector<RuntimeRenderState> baseLayerStates = { MakeLayerState() };
|
|
LayeredRenderStateInput input;
|
|
input.committedLiveLayerStates = &baseLayerStates;
|
|
input.transientAutomationOverlay = &liveState;
|
|
input.allowTransientAutomationCommits = true;
|
|
input.collectTransientAutomationCommitRequests = false;
|
|
input.transientAutomationSmoothing = 0.0;
|
|
input.transientAutomationCommitDelay = std::chrono::milliseconds(0);
|
|
input.now = std::chrono::steady_clock::now() + std::chrono::milliseconds(1);
|
|
|
|
RenderStateComposer composer;
|
|
RenderStateCompositionResult result = composer.BuildFrameState(input);
|
|
|
|
Expect(result.commitRequests.empty(), "composer can apply overlays without collecting commit requests");
|
|
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.7) < 0.0001,
|
|
"composer still applies overlays when commit collection is disabled");
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
TestRuntimeLiveStateAppliesLatestOscOverlay();
|
|
TestRuntimeLiveStateIgnoresStaleCommitCompletions();
|
|
TestRuntimeLiveStateQueuesAndCompletesCommit();
|
|
TestRuntimeLiveStateQueuesOneCommitPerGeneration();
|
|
TestRuntimeLiveStateSmoothingZeroAppliesTargetImmediately();
|
|
TestRuntimeLiveStateSmoothingOneConvergesImmediately();
|
|
TestRuntimeLiveStateSmoothingPartiallyConverges();
|
|
TestRuntimeLiveStateSmoothingVectorSizeMismatchUsesTargetShape();
|
|
TestRuntimeLiveStateTriggerOverlayIncrementsAndClears();
|
|
TestRenderStateComposerBuildsFrameState();
|
|
TestRenderStateComposerUsesCommittedLayerOverBaseLayer();
|
|
TestRenderStateComposerUsesBaseLayerWhenCommittedLayerMissing();
|
|
TestRenderStateComposerQueuesCommitRequestsWhenEnabled();
|
|
TestRenderStateComposerSuppressesCommitCollection();
|
|
|
|
if (gFailures != 0)
|
|
{
|
|
std::cerr << gFailures << " RuntimeLiveState test failure(s).\n";
|
|
return 1;
|
|
}
|
|
|
|
std::cout << "RuntimeLiveState tests passed.\n";
|
|
return 0;
|
|
}
|