render engine updates
This commit is contained in:
@@ -66,6 +66,9 @@ set(APP_SOURCES
|
||||
"${APP_DIR}/gl/OpenGLCompositeRuntimeControls.cpp"
|
||||
"${APP_DIR}/gl/RenderEngine.cpp"
|
||||
"${APP_DIR}/gl/RenderEngine.h"
|
||||
"${APP_DIR}/gl/RenderFrameState.h"
|
||||
"${APP_DIR}/gl/RenderFrameStateResolver.cpp"
|
||||
"${APP_DIR}/gl/RenderFrameStateResolver.h"
|
||||
"${APP_DIR}/gl/RuntimeUpdateController.cpp"
|
||||
"${APP_DIR}/gl/RuntimeUpdateController.h"
|
||||
"${APP_DIR}/gl/pipeline/OpenGLRenderPass.cpp"
|
||||
|
||||
@@ -56,25 +56,16 @@ void QueueServiceCommitRequests(
|
||||
}
|
||||
}
|
||||
|
||||
bool RuntimeServiceLiveBridge::PrepareLiveRenderLayerStates(
|
||||
bool RuntimeServiceLiveBridge::PrepareLiveRenderFrameState(
|
||||
RuntimeServices& runtimeServices,
|
||||
RenderEngine& renderEngine,
|
||||
bool useCommittedLayerStates,
|
||||
unsigned renderWidth,
|
||||
unsigned renderHeight,
|
||||
double oscSmoothing,
|
||||
std::vector<RuntimeRenderState>& layerStates)
|
||||
const RenderFrameInput& input,
|
||||
RenderFrameState& frameState)
|
||||
{
|
||||
DrainServiceEvents(runtimeServices, renderEngine);
|
||||
|
||||
std::vector<RenderEngine::OscOverlayCommitRequest> commitRequests;
|
||||
const bool resolved = renderEngine.ResolveRenderLayerStates(
|
||||
useCommittedLayerStates,
|
||||
renderWidth,
|
||||
renderHeight,
|
||||
oscSmoothing,
|
||||
&commitRequests,
|
||||
layerStates);
|
||||
const bool resolved = renderEngine.ResolveRenderFrameState(input, &commitRequests, frameState);
|
||||
|
||||
QueueServiceCommitRequests(runtimeServices, commitRequests);
|
||||
return resolved;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "ShaderTypes.h"
|
||||
#include "RenderFrameState.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -10,12 +10,9 @@ class RuntimeServices;
|
||||
class RuntimeServiceLiveBridge
|
||||
{
|
||||
public:
|
||||
static bool PrepareLiveRenderLayerStates(
|
||||
static bool PrepareLiveRenderFrameState(
|
||||
RuntimeServices& runtimeServices,
|
||||
RenderEngine& renderEngine,
|
||||
bool useCommittedLayerStates,
|
||||
unsigned renderWidth,
|
||||
unsigned renderHeight,
|
||||
double oscSmoothing,
|
||||
std::vector<RuntimeRenderState>& layerStates);
|
||||
const RenderFrameInput& input,
|
||||
RenderFrameState& frameState);
|
||||
};
|
||||
|
||||
@@ -294,39 +294,32 @@ void OpenGLComposite::renderEffect()
|
||||
if (mRuntimeUpdateController)
|
||||
mRuntimeUpdateController->ProcessRuntimeWork();
|
||||
|
||||
const bool hasInputSource = mVideoBackend->HasInputSource();
|
||||
std::vector<RuntimeRenderState> layerStates;
|
||||
const double smoothing = mRuntimeStore ? mRuntimeStore->GetConfiguredOscSmoothing() : 0.0;
|
||||
RenderFrameInput frameInput;
|
||||
frameInput.useCommittedLayerStates = mRuntimeCoordinator && mRuntimeCoordinator->UseCommittedLayerStates();
|
||||
frameInput.hasInputSource = mVideoBackend->HasInputSource();
|
||||
frameInput.renderWidth = mVideoBackend->InputFrameWidth();
|
||||
frameInput.renderHeight = mVideoBackend->InputFrameHeight();
|
||||
frameInput.inputFrameWidth = mVideoBackend->InputFrameWidth();
|
||||
frameInput.inputFrameHeight = mVideoBackend->InputFrameHeight();
|
||||
frameInput.captureTextureWidth = mVideoBackend->CaptureTextureWidth();
|
||||
frameInput.inputPixelFormat = mVideoBackend->InputPixelFormat();
|
||||
frameInput.historyCap = mRuntimeStore ? mRuntimeStore->GetConfiguredMaxTemporalHistoryFrames() : 0;
|
||||
frameInput.oscSmoothing = mRuntimeStore ? mRuntimeStore->GetConfiguredOscSmoothing() : 0.0;
|
||||
|
||||
RenderFrameState frameState;
|
||||
if (mRuntimeServices)
|
||||
{
|
||||
RuntimeServiceLiveBridge::PrepareLiveRenderLayerStates(
|
||||
RuntimeServiceLiveBridge::PrepareLiveRenderFrameState(
|
||||
*mRuntimeServices,
|
||||
*mRenderEngine,
|
||||
mRuntimeCoordinator && mRuntimeCoordinator->UseCommittedLayerStates(),
|
||||
mVideoBackend->InputFrameWidth(),
|
||||
mVideoBackend->InputFrameHeight(),
|
||||
smoothing,
|
||||
layerStates);
|
||||
frameInput,
|
||||
frameState);
|
||||
}
|
||||
else
|
||||
{
|
||||
mRenderEngine->ResolveRenderLayerStates(
|
||||
mRuntimeCoordinator && mRuntimeCoordinator->UseCommittedLayerStates(),
|
||||
mVideoBackend->InputFrameWidth(),
|
||||
mVideoBackend->InputFrameHeight(),
|
||||
smoothing,
|
||||
nullptr,
|
||||
layerStates);
|
||||
mRenderEngine->ResolveRenderFrameState(frameInput, nullptr, frameState);
|
||||
}
|
||||
const unsigned historyCap = mRuntimeStore ? mRuntimeStore->GetConfiguredMaxTemporalHistoryFrames() : 0;
|
||||
mRenderEngine->RenderLayerStack(
|
||||
hasInputSource,
|
||||
layerStates,
|
||||
mVideoBackend->InputFrameWidth(),
|
||||
mVideoBackend->InputFrameHeight(),
|
||||
mVideoBackend->CaptureTextureWidth(),
|
||||
mVideoBackend->InputPixelFormat(),
|
||||
historyCap);
|
||||
mRenderEngine->RenderPreparedFrame(frameState);
|
||||
}
|
||||
|
||||
void OpenGLComposite::ProcessScreenshotRequest()
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr auto kOscOverlayCommitDelay = std::chrono::milliseconds(150);
|
||||
}
|
||||
|
||||
RenderEngine::RenderEngine(
|
||||
RuntimeSnapshotProvider& runtimeSnapshotProvider,
|
||||
HealthTelemetry& healthTelemetry,
|
||||
@@ -24,10 +19,10 @@ RenderEngine::RenderEngine(
|
||||
mRenderPass(mRenderer),
|
||||
mRenderPipeline(mRenderer, runtimeSnapshotProvider, healthTelemetry, std::move(renderEffect), std::move(screenshotReady), std::move(previewPaint)),
|
||||
mShaderPrograms(mRenderer, runtimeSnapshotProvider),
|
||||
mRuntimeSnapshotProvider(runtimeSnapshotProvider),
|
||||
mMutex(mutex),
|
||||
mHdc(hdc),
|
||||
mHglrc(hglrc)
|
||||
mHglrc(hglrc),
|
||||
mFrameStateResolver(runtimeSnapshotProvider)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,11 +81,7 @@ bool RenderEngine::ApplyPreparedShaderBuild(
|
||||
if (!CommitPreparedLayerPrograms(preparedBuild, inputFrameWidth, inputFrameHeight, errorMessageSize, errorMessage))
|
||||
return false;
|
||||
|
||||
mCachedLayerRenderStates = mShaderPrograms.CommittedLayerStates();
|
||||
mCachedRenderStateVersion = preparedBuild.renderSnapshot.versions.renderStateVersion;
|
||||
mCachedParameterStateVersion = preparedBuild.renderSnapshot.versions.parameterStateVersion;
|
||||
mCachedRenderStateWidth = preparedBuild.renderSnapshot.outputWidth;
|
||||
mCachedRenderStateHeight = preparedBuild.renderSnapshot.outputHeight;
|
||||
mFrameStateResolver.StoreCommittedSnapshot(preparedBuild.renderSnapshot, mShaderPrograms.CommittedLayerStates());
|
||||
ResetTemporalHistoryState();
|
||||
if (!preserveFeedbackState)
|
||||
ResetShaderFeedbackState();
|
||||
@@ -248,92 +239,37 @@ bool RenderEngine::RenderOutputFrame(const RenderPipelineFrameContext& context,
|
||||
return rendered;
|
||||
}
|
||||
|
||||
bool RenderEngine::ResolveRenderLayerStates(
|
||||
bool useCommittedLayerStates,
|
||||
unsigned renderWidth,
|
||||
unsigned renderHeight,
|
||||
double oscSmoothing,
|
||||
bool RenderEngine::ResolveRenderFrameState(
|
||||
const RenderFrameInput& input,
|
||||
std::vector<OscOverlayCommitRequest>* commitRequests,
|
||||
std::vector<RuntimeRenderState>& layerStates)
|
||||
RenderFrameState& frameState)
|
||||
{
|
||||
layerStates.clear();
|
||||
if (useCommittedLayerStates)
|
||||
std::vector<RuntimeLiveOscCommitRequest> liveCommitRequests;
|
||||
const bool resolved = mFrameStateResolver.Resolve(
|
||||
input,
|
||||
mShaderPrograms.CommittedLayerStates(),
|
||||
mRuntimeLiveState,
|
||||
commitRequests ? &liveCommitRequests : nullptr,
|
||||
frameState);
|
||||
|
||||
if (commitRequests)
|
||||
{
|
||||
layerStates = ComposeRenderLayerStates(mShaderPrograms.CommittedLayerStates(), false, oscSmoothing, commitRequests);
|
||||
mRuntimeSnapshotProvider.RefreshDynamicRenderStateFields(layerStates);
|
||||
return true;
|
||||
for (const RuntimeLiveOscCommitRequest& request : liveCommitRequests)
|
||||
commitRequests->push_back({ request.routeKey, request.layerKey, request.parameterKey, request.value, request.generation });
|
||||
}
|
||||
|
||||
const RuntimeSnapshotVersions versions = mRuntimeSnapshotProvider.GetVersions();
|
||||
const bool renderStateCacheValid =
|
||||
!mCachedLayerRenderStates.empty() &&
|
||||
mCachedRenderStateVersion == versions.renderStateVersion &&
|
||||
mCachedRenderStateWidth == renderWidth &&
|
||||
mCachedRenderStateHeight == renderHeight;
|
||||
|
||||
if (renderStateCacheValid)
|
||||
{
|
||||
RuntimeRenderStateSnapshot renderSnapshot;
|
||||
renderSnapshot.outputWidth = renderWidth;
|
||||
renderSnapshot.outputHeight = renderHeight;
|
||||
renderSnapshot.versions.renderStateVersion = mCachedRenderStateVersion;
|
||||
renderSnapshot.versions.parameterStateVersion = mCachedParameterStateVersion;
|
||||
renderSnapshot.states = mCachedLayerRenderStates;
|
||||
|
||||
renderSnapshot.states = ComposeRenderLayerStates(renderSnapshot.states, true, oscSmoothing, commitRequests);
|
||||
if (mCachedParameterStateVersion != versions.parameterStateVersion &&
|
||||
mRuntimeSnapshotProvider.TryRefreshPublishedSnapshotParameters(renderSnapshot))
|
||||
{
|
||||
mCachedParameterStateVersion = renderSnapshot.versions.parameterStateVersion;
|
||||
renderSnapshot.states = ComposeRenderLayerStates(renderSnapshot.states, true, oscSmoothing, commitRequests);
|
||||
}
|
||||
|
||||
mCachedLayerRenderStates = renderSnapshot.states;
|
||||
layerStates = renderSnapshot.states;
|
||||
mRuntimeSnapshotProvider.RefreshDynamicRenderStateFields(layerStates);
|
||||
return true;
|
||||
}
|
||||
|
||||
RuntimeRenderStateSnapshot renderSnapshot;
|
||||
if (mRuntimeSnapshotProvider.TryPublishRenderStateSnapshot(renderWidth, renderHeight, renderSnapshot))
|
||||
{
|
||||
mCachedLayerRenderStates = renderSnapshot.states;
|
||||
mCachedRenderStateVersion = renderSnapshot.versions.renderStateVersion;
|
||||
mCachedParameterStateVersion = renderSnapshot.versions.parameterStateVersion;
|
||||
mCachedRenderStateWidth = renderSnapshot.outputWidth;
|
||||
mCachedRenderStateHeight = renderSnapshot.outputHeight;
|
||||
mCachedLayerRenderStates = ComposeRenderLayerStates(mCachedLayerRenderStates, true, oscSmoothing, commitRequests);
|
||||
layerStates = mCachedLayerRenderStates;
|
||||
return true;
|
||||
}
|
||||
|
||||
layerStates = ComposeRenderLayerStates(mCachedLayerRenderStates, true, oscSmoothing, commitRequests);
|
||||
mRuntimeSnapshotProvider.RefreshDynamicRenderStateFields(layerStates);
|
||||
return !layerStates.empty();
|
||||
return resolved;
|
||||
}
|
||||
|
||||
std::vector<RuntimeRenderState> RenderEngine::ComposeRenderLayerStates(
|
||||
const std::vector<RuntimeRenderState>& baseStates,
|
||||
bool allowCommit,
|
||||
double smoothing,
|
||||
std::vector<OscOverlayCommitRequest>* commitRequests)
|
||||
void RenderEngine::RenderPreparedFrame(const RenderFrameState& frameState)
|
||||
{
|
||||
RenderStateCompositionInput input;
|
||||
input.baseLayerStates = &baseStates;
|
||||
input.liveState = &mRuntimeLiveState;
|
||||
input.allowLiveCommits = allowCommit;
|
||||
input.collectLiveCommitRequests = commitRequests != nullptr;
|
||||
input.liveSmoothing = smoothing;
|
||||
input.liveCommitDelay = kOscOverlayCommitDelay;
|
||||
input.now = std::chrono::steady_clock::now();
|
||||
const RenderStateCompositionResult result = mRenderStateComposer.BuildFrameState(input);
|
||||
|
||||
if (!commitRequests)
|
||||
return result.layerStates;
|
||||
|
||||
for (const RuntimeLiveOscCommitRequest& request : result.commitRequests)
|
||||
commitRequests->push_back({ request.routeKey, request.layerKey, request.parameterKey, request.value, request.generation });
|
||||
return result.layerStates;
|
||||
RenderLayerStack(
|
||||
frameState.hasInputSource,
|
||||
frameState.layerStates,
|
||||
frameState.inputFrameWidth,
|
||||
frameState.inputFrameHeight,
|
||||
frameState.captureTextureWidth,
|
||||
frameState.inputPixelFormat,
|
||||
frameState.historyCap);
|
||||
}
|
||||
|
||||
void RenderEngine::RenderLayerStack(
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#include "OpenGLRenderPipeline.h"
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderPrograms.h"
|
||||
#include "RenderStateComposer.h"
|
||||
#include "RenderFrameState.h"
|
||||
#include "RenderFrameStateResolver.h"
|
||||
#include "HealthTelemetry.h"
|
||||
#include "RuntimeCoordinator.h"
|
||||
#include "RuntimeSnapshotProvider.h"
|
||||
@@ -104,13 +105,11 @@ public:
|
||||
bool TryPresentPreview(bool force, unsigned previewFps, unsigned outputFrameWidth, unsigned outputFrameHeight);
|
||||
bool TryUploadInputFrame(const VideoIOFrame& inputFrame, const VideoIOState& videoState);
|
||||
bool RenderOutputFrame(const RenderPipelineFrameContext& context, VideoIOOutputFrame& outputFrame);
|
||||
bool ResolveRenderLayerStates(
|
||||
bool useCommittedLayerStates,
|
||||
unsigned renderWidth,
|
||||
unsigned renderHeight,
|
||||
double oscSmoothing,
|
||||
bool ResolveRenderFrameState(
|
||||
const RenderFrameInput& input,
|
||||
std::vector<OscOverlayCommitRequest>* commitRequests,
|
||||
std::vector<RuntimeRenderState>& layerStates);
|
||||
RenderFrameState& frameState);
|
||||
void RenderPreparedFrame(const RenderFrameState& frameState);
|
||||
void RenderLayerStack(
|
||||
bool hasInputSource,
|
||||
const std::vector<RuntimeRenderState>& layerStates,
|
||||
@@ -127,23 +126,11 @@ private:
|
||||
OpenGLRenderPass mRenderPass;
|
||||
OpenGLRenderPipeline mRenderPipeline;
|
||||
OpenGLShaderPrograms mShaderPrograms;
|
||||
RuntimeSnapshotProvider& mRuntimeSnapshotProvider;
|
||||
CRITICAL_SECTION& mMutex;
|
||||
HDC mHdc;
|
||||
HGLRC mHglrc;
|
||||
|
||||
std::vector<RuntimeRenderState> ComposeRenderLayerStates(
|
||||
const std::vector<RuntimeRenderState>& baseStates,
|
||||
bool allowCommit,
|
||||
double smoothing,
|
||||
std::vector<OscOverlayCommitRequest>* commitRequests);
|
||||
|
||||
std::vector<RuntimeRenderState> mCachedLayerRenderStates;
|
||||
uint64_t mCachedRenderStateVersion = 0;
|
||||
uint64_t mCachedParameterStateVersion = 0;
|
||||
unsigned mCachedRenderStateWidth = 0;
|
||||
unsigned mCachedRenderStateHeight = 0;
|
||||
std::chrono::steady_clock::time_point mLastPreviewPresentTime;
|
||||
RenderStateComposer mRenderStateComposer;
|
||||
RenderFrameStateResolver mFrameStateResolver;
|
||||
RuntimeLiveState mRuntimeLiveState;
|
||||
};
|
||||
|
||||
31
apps/LoopThroughWithOpenGLCompositing/gl/RenderFrameState.h
Normal file
31
apps/LoopThroughWithOpenGLCompositing/gl/RenderFrameState.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "ShaderTypes.h"
|
||||
#include "VideoIOTypes.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct RenderFrameInput
|
||||
{
|
||||
bool useCommittedLayerStates = false;
|
||||
bool hasInputSource = false;
|
||||
unsigned renderWidth = 0;
|
||||
unsigned renderHeight = 0;
|
||||
unsigned inputFrameWidth = 0;
|
||||
unsigned inputFrameHeight = 0;
|
||||
unsigned captureTextureWidth = 0;
|
||||
VideoIOPixelFormat inputPixelFormat = VideoIOPixelFormat::Uyvy8;
|
||||
unsigned historyCap = 0;
|
||||
double oscSmoothing = 0.0;
|
||||
};
|
||||
|
||||
struct RenderFrameState
|
||||
{
|
||||
bool hasInputSource = false;
|
||||
unsigned inputFrameWidth = 0;
|
||||
unsigned inputFrameHeight = 0;
|
||||
unsigned captureTextureWidth = 0;
|
||||
VideoIOPixelFormat inputPixelFormat = VideoIOPixelFormat::Uyvy8;
|
||||
unsigned historyCap = 0;
|
||||
std::vector<RuntimeRenderState> layerStates;
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "RenderFrameStateResolver.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr auto kOscOverlayCommitDelay = std::chrono::milliseconds(150);
|
||||
}
|
||||
|
||||
RenderFrameStateResolver::RenderFrameStateResolver(RuntimeSnapshotProvider& runtimeSnapshotProvider) :
|
||||
mRuntimeSnapshotProvider(runtimeSnapshotProvider)
|
||||
{
|
||||
}
|
||||
|
||||
void RenderFrameStateResolver::StoreCommittedSnapshot(
|
||||
const RuntimeRenderStateSnapshot& snapshot,
|
||||
const std::vector<RuntimeRenderState>& committedLayerStates)
|
||||
{
|
||||
mCachedLayerRenderStates = committedLayerStates;
|
||||
mCachedRenderStateVersion = snapshot.versions.renderStateVersion;
|
||||
mCachedParameterStateVersion = snapshot.versions.parameterStateVersion;
|
||||
mCachedRenderStateWidth = snapshot.outputWidth;
|
||||
mCachedRenderStateHeight = snapshot.outputHeight;
|
||||
}
|
||||
|
||||
bool RenderFrameStateResolver::Resolve(
|
||||
const RenderFrameInput& input,
|
||||
const std::vector<RuntimeRenderState>& committedLayerStates,
|
||||
RuntimeLiveState& liveState,
|
||||
std::vector<RuntimeLiveOscCommitRequest>* commitRequests,
|
||||
RenderFrameState& frameState)
|
||||
{
|
||||
frameState.hasInputSource = input.hasInputSource;
|
||||
frameState.inputFrameWidth = input.inputFrameWidth;
|
||||
frameState.inputFrameHeight = input.inputFrameHeight;
|
||||
frameState.captureTextureWidth = input.captureTextureWidth;
|
||||
frameState.inputPixelFormat = input.inputPixelFormat;
|
||||
frameState.historyCap = input.historyCap;
|
||||
frameState.layerStates.clear();
|
||||
|
||||
if (input.useCommittedLayerStates)
|
||||
{
|
||||
frameState.layerStates = ComposeLayerStates(committedLayerStates, liveState, false, input.oscSmoothing, commitRequests);
|
||||
mRuntimeSnapshotProvider.RefreshDynamicRenderStateFields(frameState.layerStates);
|
||||
return true;
|
||||
}
|
||||
|
||||
const RuntimeSnapshotVersions versions = mRuntimeSnapshotProvider.GetVersions();
|
||||
const bool renderStateCacheValid =
|
||||
!mCachedLayerRenderStates.empty() &&
|
||||
mCachedRenderStateVersion == versions.renderStateVersion &&
|
||||
mCachedRenderStateWidth == input.renderWidth &&
|
||||
mCachedRenderStateHeight == input.renderHeight;
|
||||
|
||||
if (renderStateCacheValid)
|
||||
{
|
||||
RuntimeRenderStateSnapshot renderSnapshot;
|
||||
renderSnapshot.outputWidth = input.renderWidth;
|
||||
renderSnapshot.outputHeight = input.renderHeight;
|
||||
renderSnapshot.versions.renderStateVersion = mCachedRenderStateVersion;
|
||||
renderSnapshot.versions.parameterStateVersion = mCachedParameterStateVersion;
|
||||
renderSnapshot.states = mCachedLayerRenderStates;
|
||||
|
||||
renderSnapshot.states = ComposeLayerStates(renderSnapshot.states, liveState, true, input.oscSmoothing, commitRequests);
|
||||
if (mCachedParameterStateVersion != versions.parameterStateVersion &&
|
||||
mRuntimeSnapshotProvider.TryRefreshPublishedSnapshotParameters(renderSnapshot))
|
||||
{
|
||||
mCachedParameterStateVersion = renderSnapshot.versions.parameterStateVersion;
|
||||
renderSnapshot.states = ComposeLayerStates(renderSnapshot.states, liveState, true, input.oscSmoothing, commitRequests);
|
||||
}
|
||||
|
||||
mCachedLayerRenderStates = renderSnapshot.states;
|
||||
frameState.layerStates = renderSnapshot.states;
|
||||
mRuntimeSnapshotProvider.RefreshDynamicRenderStateFields(frameState.layerStates);
|
||||
return true;
|
||||
}
|
||||
|
||||
RuntimeRenderStateSnapshot renderSnapshot;
|
||||
if (mRuntimeSnapshotProvider.TryPublishRenderStateSnapshot(input.renderWidth, input.renderHeight, renderSnapshot))
|
||||
{
|
||||
mCachedLayerRenderStates = renderSnapshot.states;
|
||||
mCachedRenderStateVersion = renderSnapshot.versions.renderStateVersion;
|
||||
mCachedParameterStateVersion = renderSnapshot.versions.parameterStateVersion;
|
||||
mCachedRenderStateWidth = renderSnapshot.outputWidth;
|
||||
mCachedRenderStateHeight = renderSnapshot.outputHeight;
|
||||
mCachedLayerRenderStates = ComposeLayerStates(mCachedLayerRenderStates, liveState, true, input.oscSmoothing, commitRequests);
|
||||
frameState.layerStates = mCachedLayerRenderStates;
|
||||
return true;
|
||||
}
|
||||
|
||||
frameState.layerStates = ComposeLayerStates(mCachedLayerRenderStates, liveState, true, input.oscSmoothing, commitRequests);
|
||||
mRuntimeSnapshotProvider.RefreshDynamicRenderStateFields(frameState.layerStates);
|
||||
return !frameState.layerStates.empty();
|
||||
}
|
||||
|
||||
std::vector<RuntimeRenderState> RenderFrameStateResolver::ComposeLayerStates(
|
||||
const std::vector<RuntimeRenderState>& baseStates,
|
||||
RuntimeLiveState& liveState,
|
||||
bool allowCommit,
|
||||
double smoothing,
|
||||
std::vector<RuntimeLiveOscCommitRequest>* commitRequests) const
|
||||
{
|
||||
RenderStateCompositionInput input;
|
||||
input.baseLayerStates = &baseStates;
|
||||
input.liveState = &liveState;
|
||||
input.allowLiveCommits = allowCommit;
|
||||
input.collectLiveCommitRequests = commitRequests != nullptr;
|
||||
input.liveSmoothing = smoothing;
|
||||
input.liveCommitDelay = kOscOverlayCommitDelay;
|
||||
input.now = std::chrono::steady_clock::now();
|
||||
const RenderStateCompositionResult result = mRenderStateComposer.BuildFrameState(input);
|
||||
|
||||
if (commitRequests)
|
||||
{
|
||||
for (const RuntimeLiveOscCommitRequest& request : result.commitRequests)
|
||||
commitRequests->push_back(request);
|
||||
}
|
||||
return result.layerStates;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "RenderFrameState.h"
|
||||
#include "RenderStateComposer.h"
|
||||
#include "RuntimeSnapshotProvider.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
class RenderFrameStateResolver
|
||||
{
|
||||
public:
|
||||
explicit RenderFrameStateResolver(RuntimeSnapshotProvider& runtimeSnapshotProvider);
|
||||
|
||||
void StoreCommittedSnapshot(
|
||||
const RuntimeRenderStateSnapshot& snapshot,
|
||||
const std::vector<RuntimeRenderState>& committedLayerStates);
|
||||
bool Resolve(
|
||||
const RenderFrameInput& input,
|
||||
const std::vector<RuntimeRenderState>& committedLayerStates,
|
||||
RuntimeLiveState& liveState,
|
||||
std::vector<RuntimeLiveOscCommitRequest>* commitRequests,
|
||||
RenderFrameState& frameState);
|
||||
|
||||
private:
|
||||
std::vector<RuntimeRenderState> ComposeLayerStates(
|
||||
const std::vector<RuntimeRenderState>& baseStates,
|
||||
RuntimeLiveState& liveState,
|
||||
bool allowCommit,
|
||||
double smoothing,
|
||||
std::vector<RuntimeLiveOscCommitRequest>* commitRequests) const;
|
||||
|
||||
RuntimeSnapshotProvider& mRuntimeSnapshotProvider;
|
||||
RenderStateComposer mRenderStateComposer;
|
||||
std::vector<RuntimeRenderState> mCachedLayerRenderStates;
|
||||
uint64_t mCachedRenderStateVersion = 0;
|
||||
uint64_t mCachedParameterStateVersion = 0;
|
||||
unsigned mCachedRenderStateWidth = 0;
|
||||
unsigned mCachedRenderStateHeight = 0;
|
||||
};
|
||||
@@ -7,8 +7,8 @@ Phase 1 split runtime responsibilities into named subsystems. Phase 2 added the
|
||||
## Status
|
||||
|
||||
- Phase 3 design package: proposed.
|
||||
- Phase 3 implementation: initial parallel implementation batch integrated.
|
||||
- Current alignment: the repo now has the live-state/composer building blocks and a service bridge. `OpenGLComposite::renderEffect()` still remains the app-level frame entrypoint, but the service drain, layer-state resolution, and OSC commit handoff now sit behind a named bridge helper.
|
||||
- Phase 3 implementation: exit criteria satisfied for the current architecture.
|
||||
- Current alignment: the repo now has the live-state/composer building blocks, a service bridge, and a named frame-state handoff. `OpenGLComposite::renderEffect()` still remains the app-level frame entrypoint, but the service drain, layer-state resolution, and OSC commit handoff now sit behind named helpers and frame-state data.
|
||||
|
||||
Current footholds:
|
||||
|
||||
@@ -17,7 +17,9 @@ Current footholds:
|
||||
- `RuntimeSnapshotProvider` publishes render snapshots from `RenderSnapshotBuilder`.
|
||||
- `RuntimeLiveState` owns transient OSC overlay bookkeeping and commit-settlement policy.
|
||||
- `RenderStateComposer` exists as the first pure composition boundary for combining base layer state with live overlays.
|
||||
- `RenderEngine` still owns snapshot cache selection and final render-layer resolution, but live overlay value composition now delegates to `RenderStateComposer` and `RuntimeLiveState`.
|
||||
- `RenderFrameInput` / `RenderFrameState` now provide a named frame-facing handoff model for preparing layer state and render inputs before drawing.
|
||||
- `RenderFrameStateResolver` now owns snapshot cache selection, parameter refresh decisions, and final frame-state resolution before drawing.
|
||||
- `RenderEngine` owns GL/render resources and delegates frame-state preparation to the resolver.
|
||||
- `ControlServices` owns OSC ingress, pending OSC updates, completed OSC commit notifications, and service start/stop.
|
||||
- `RuntimeServiceLiveBridge` translates service OSC queues into render live-state updates and queues settled overlay commit requests.
|
||||
- `RuntimeEventDispatcher` now routes accepted mutations, reloads, snapshots, shader build events, backend observations, and health observations.
|
||||
@@ -68,7 +70,7 @@ Those are later phases. Phase 3 is about making state and service coordination c
|
||||
2. asks `RuntimeServiceLiveBridge` to prepare live render layer states
|
||||
3. asks `RenderEngine` to draw the layer stack
|
||||
|
||||
The bridge now owns service queue draining, live automation settlement, committed/live state selection, and OSC commit handoff. `RenderEngine` still owns snapshot cache selection and dynamic render-field refresh, which is the remaining boundary to clarify before Phase 4.
|
||||
The bridge now owns service queue draining, live automation settlement, committed/live state selection, and OSC commit handoff. `RenderFrameStateResolver` owns snapshot cache selection, parameter refresh decisions, and dynamic render-field refresh before handing a prepared frame state to `RenderEngine`.
|
||||
|
||||
## Target State Model
|
||||
|
||||
@@ -150,7 +152,7 @@ Non-responsibilities:
|
||||
| pending OSC updates drained by `OpenGLComposite` | `OscValueReceived` -> live-state overlay update handler | Phase 2 already has the event type; Phase 3 decides whether transient overlay updates enter the app dispatcher or a source-local bridge. |
|
||||
| render asks for overlay commit requests | `OscOverlaySettled` or direct coordinator command plus event publication | Commit request creation should leave `renderEffect()` and live near the live-state owner. |
|
||||
| completed OSC commits drained by `OpenGLComposite` | `RuntimeMutationAccepted` / completion event -> live-state commit completion | Completed commit routing should be event-driven or owned by live-state service bridge. |
|
||||
| `RenderEngine::ResolveRenderLayerStates(...)` | `RenderStateComposer::BuildFrameState(...)` | Keep final state composition testable without GL. |
|
||||
| `RenderFrameStateResolver::Resolve(...)` | `RenderStateComposer::BuildFrameState(...)` | Keep final state composition testable without GL. |
|
||||
| direct persistence writes from store mutations | `RuntimePersistenceRequested` as the durable write trigger | Background writer lands later; Phase 3 should make request boundaries clear. |
|
||||
| runtime-state broadcast side effects | `RuntimeStateBroadcastRequested` plus optional completed/failed observations | Keep broadcast delivery in services and presentation ownership in runtime presentation. |
|
||||
|
||||
@@ -246,7 +248,7 @@ This keeps Phase 6 smaller: the background snapshot writer can subscribe to pers
|
||||
|
||||
Introduce `RuntimeLiveState`, `RenderStateComposer`, or an equivalent pair of classes.
|
||||
|
||||
Start by moving pure data operations out of `RenderEngine::ResolveRenderLayerStates(...)` without changing behavior.
|
||||
Start by moving pure data operations out of frame rendering without changing behavior.
|
||||
|
||||
Status: started. `runtime/live/RuntimeLiveState` and `runtime/live/RenderStateComposer` now exist, are included in the build, and have a focused `RuntimeLiveStateTests` target.
|
||||
|
||||
@@ -291,7 +293,7 @@ void OpenGLComposite::renderEffect()
|
||||
|
||||
The exact names can change. The goal is that render effect no longer manually drains services, settles overlay commits, and resolves layer values.
|
||||
|
||||
Status: started. `OpenGLComposite::renderEffect()` still drives frame timing, video dimensions, and drawing, but the service-drain, resolve, and commit-handoff path has moved behind `RuntimeServiceLiveBridge::PrepareLiveRenderLayerStates(...)`.
|
||||
Status: started. `OpenGLComposite::renderEffect()` still drives frame timing, video dimensions, and drawing, but the service-drain, resolve, and commit-handoff path has moved behind `RuntimeServiceLiveBridge::PrepareLiveRenderFrameState(...)` and a named `RenderFrameInput` / `RenderFrameState` handoff.
|
||||
|
||||
### Step 5. Add Persistence Boundary Tests
|
||||
|
||||
@@ -339,7 +341,7 @@ The current groundwork is intended to let these lanes proceed in parallel with l
|
||||
| Lane | Primary files | Goal |
|
||||
| --- | --- | --- |
|
||||
| A. Live-state behavior | `runtime/live/RuntimeLiveState.*`, `tests/RuntimeLiveStateTests.cpp` | Finish stale completion tests, smoothing edge cases, trigger behavior, and overlay settle policy. |
|
||||
| B. Render-state composition | `runtime/live/RenderStateComposer.*`, `gl/RenderEngine.*` | Move more of `RenderEngine::ResolveRenderLayerStates(...)` value composition behind the pure composer while keeping GL calls in `RenderEngine`. |
|
||||
| B. Render-state composition | `runtime/live/RenderStateComposer.*`, `gl/RenderFrameStateResolver.*`, `gl/RenderEngine.*` | Keep value composition and frame-state selection outside GL drawing while keeping GL calls in `RenderEngine`. |
|
||||
| C. Service bridge | `control/RuntimeServices.*`, `control/ControlServices.*`, possible new bridge class | Stop `OpenGLComposite::renderEffect()` from draining OSC update/completion queues directly. |
|
||||
| D. App-frame orchestration | `gl/OpenGLComposite.*`, `gl/RuntimeUpdateController.*` | Replace render-effect glue with a narrow frame-state preparation call and commit-request handoff. |
|
||||
| E. Persistence boundary | `runtime/coordination/RuntimeCoordinator.*`, `runtime/store/*`, event tests | Keep persistence request publication explicit and prepare for a later background writer without changing storage behavior yet. |
|
||||
@@ -348,13 +350,13 @@ The current groundwork is intended to let these lanes proceed in parallel with l
|
||||
|
||||
Phase 3 can be considered complete once the project can say:
|
||||
|
||||
- [x] final render-state composition has a named, testable owner outside `OpenGLComposite` (live value composition is covered by `RenderStateComposer`; full snapshot/cache selection still remains in `RenderEngine`)
|
||||
- [x] final render-state composition has named owners outside `OpenGLComposite` (`RenderStateComposer` covers live value composition; `RenderFrameStateResolver` covers snapshot/cache selection and frame-state resolution)
|
||||
- [x] transient OSC overlay state has a named owner and tests
|
||||
- [x] overlay commit requests and completions no longer require `OpenGLComposite` to drain service queues directly
|
||||
- [x] `RenderEngine` is closer to GL/render resource ownership and less responsible for value composition
|
||||
- [x] `RuntimeStore` remains durable-state focused and does not gain live overlay responsibilities
|
||||
- [x] persistence requests are explicit event outcomes for persisted mutations
|
||||
- [ ] Phase 4 can define a render-thread input contract around immutable or near-immutable frame state
|
||||
- [x] Phase 4 can define a render-thread input contract around immutable or near-immutable frame state
|
||||
|
||||
## Open Questions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user