#include "RuntimeUpdateController.h" #include "RenderEngine.h" #include "RuntimeEventDispatcher.h" #include "RuntimeServices.h" #include "RuntimeStore.h" #include "ShaderBuildQueue.h" #include "VideoBackend.h" #include #include namespace { RuntimeCoordinatorRenderResetScope ToRuntimeCoordinatorRenderResetScope(RuntimeEventRenderResetScope scope) { switch (scope) { case RuntimeEventRenderResetScope::TemporalHistoryOnly: return RuntimeCoordinatorRenderResetScope::TemporalHistoryOnly; case RuntimeEventRenderResetScope::TemporalHistoryAndFeedback: return RuntimeCoordinatorRenderResetScope::TemporalHistoryAndFeedback; case RuntimeEventRenderResetScope::None: default: return RuntimeCoordinatorRenderResetScope::None; } } } RuntimeUpdateController::RuntimeUpdateController( RuntimeStore& runtimeStore, RuntimeCoordinator& runtimeCoordinator, RuntimeEventDispatcher& runtimeEventDispatcher, RuntimeServices& runtimeServices, RenderEngine& renderEngine, ShaderBuildQueue& shaderBuildQueue, VideoBackend& videoBackend) : mRuntimeStore(runtimeStore), mRuntimeCoordinator(runtimeCoordinator), mRuntimeEventDispatcher(runtimeEventDispatcher), mRuntimeServices(runtimeServices), mRenderEngine(renderEngine), mShaderBuildQueue(shaderBuildQueue), mVideoBackend(videoBackend) { mRuntimeEventDispatcher.Subscribe( RuntimeEventType::RuntimeStateBroadcastRequested, [this](const RuntimeEvent& event) { HandleRuntimeStateBroadcastRequested(event); }); mRuntimeEventDispatcher.Subscribe( RuntimeEventType::ShaderBuildRequested, [this](const RuntimeEvent& event) { HandleShaderBuildRequested(event); }); mRuntimeEventDispatcher.Subscribe( RuntimeEventType::ShaderBuildPrepared, [this](const RuntimeEvent& event) { HandleShaderBuildPrepared(event); }); mRuntimeEventDispatcher.Subscribe( RuntimeEventType::ShaderBuildFailed, [this](const RuntimeEvent& event) { HandleShaderBuildFailed(event); }); mRuntimeEventDispatcher.Subscribe( RuntimeEventType::CompileStatusChanged, [this](const RuntimeEvent& event) { HandleCompileStatusChanged(event); }); mRuntimeEventDispatcher.Subscribe( RuntimeEventType::RenderResetRequested, [this](const RuntimeEvent& event) { HandleRenderResetRequested(event); }); } bool RuntimeUpdateController::ApplyRuntimeCoordinatorResult(const RuntimeCoordinatorResult& result, std::string* error) { if (!result.accepted) { if (error) *error = result.errorMessage; return false; } if (result.compileStatusChanged) { mRuntimeStore.SetCompileStatus(result.compileStatusSucceeded, result.compileStatusMessage); ++mPendingCoordinatorCompileStatusEvents; } if (result.clearReloadRequest) mRuntimeStore.ClearReloadRequest(); mRuntimeCoordinator.ApplyCommittedStateMode(result.committedStateMode); if (result.clearTransientOscState) { mRenderEngine.ClearOscOverlayState(); mRuntimeServices.ClearOscState(); } mRenderEngine.ApplyRuntimeCoordinatorRenderReset(result.renderResetScope); if (result.renderResetScope != RuntimeCoordinatorRenderResetScope::None) ++mPendingCoordinatorRenderResetEvents; if (result.shaderBuildRequested) { RequestShaderBuild(); ++mPendingCoordinatorShaderBuildEvents; } if (result.runtimeStateBroadcastRequired) BroadcastRuntimeState(); return true; } bool RuntimeUpdateController::ProcessRuntimeWork() { bool shaderBuildRequested = false; std::vector serviceResults; mRuntimeServices.ConsumeRuntimeCoordinatorResults(serviceResults); for (const RuntimeCoordinatorServiceResult& serviceResult : serviceResults) { shaderBuildRequested = shaderBuildRequested || serviceResult.result.shaderBuildRequested; ApplyRuntimeCoordinatorResult(serviceResult.result); if (serviceResult.failed) return false; } if (shaderBuildRequested) return true; DispatchRuntimeEvents(); return ConsumeReadyShaderBuild(0, true, true); } void RuntimeUpdateController::RequestShaderBuild() { mShaderBuildQueue.RequestBuild(mVideoBackend.InputFrameWidth(), mVideoBackend.InputFrameHeight()); } void RuntimeUpdateController::BroadcastRuntimeState() { RuntimeStateBroadcastRequestedEvent event; event.reason = "runtime-state-changed"; if (!mRuntimeEventDispatcher.PublishPayload(event, "RuntimeUpdateController")) { mRuntimeServices.BroadcastState(); return; } DispatchRuntimeEvents(); } void RuntimeUpdateController::HandleRuntimeStateBroadcastRequested(const RuntimeEvent& event) { if (event.source == "ControlServices") return; mRuntimeServices.BroadcastState(); } void RuntimeUpdateController::HandleShaderBuildRequested(const RuntimeEvent& event) { const ShaderBuildEvent* payload = std::get_if(&event.payload); if (!payload || payload->phase != RuntimeEventShaderBuildPhase::Requested) return; if (ShouldSuppressCoordinatorFollowUp(event, mPendingCoordinatorShaderBuildEvents)) return; RequestShaderBuild(); } void RuntimeUpdateController::HandleShaderBuildPrepared(const RuntimeEvent& event) { const ShaderBuildEvent* payload = std::get_if(&event.payload); if (!payload || payload->phase != RuntimeEventShaderBuildPhase::Prepared) return; ConsumeReadyShaderBuild(payload->generation, false, true); } void RuntimeUpdateController::HandleShaderBuildFailed(const RuntimeEvent& event) { const ShaderBuildEvent* payload = std::get_if(&event.payload); if (!payload || payload->phase != RuntimeEventShaderBuildPhase::Failed) return; ConsumeReadyShaderBuild(payload->generation, false, false); } void RuntimeUpdateController::HandleCompileStatusChanged(const RuntimeEvent& event) { const CompileStatusChangedEvent* payload = std::get_if(&event.payload); if (!payload) return; if (ShouldSuppressCoordinatorFollowUp(event, mPendingCoordinatorCompileStatusEvents)) return; mRuntimeStore.SetCompileStatus(payload->succeeded, payload->message); } void RuntimeUpdateController::HandleRenderResetRequested(const RuntimeEvent& event) { const RenderResetEvent* payload = std::get_if(&event.payload); if (!payload || payload->applied) return; if (ShouldSuppressCoordinatorFollowUp(event, mPendingCoordinatorRenderResetEvents)) return; mRenderEngine.ApplyRuntimeCoordinatorRenderReset(ToRuntimeCoordinatorRenderResetScope(payload->scope)); } bool RuntimeUpdateController::ConsumeReadyShaderBuild(uint64_t expectedGeneration, bool publishPreparedEvent, bool publishFailureEvent) { PreparedShaderBuild readyBuild; const bool consumed = expectedGeneration == 0 ? mShaderBuildQueue.TryConsumeReadyBuild(readyBuild) : mShaderBuildQueue.TryConsumeReadyBuild(expectedGeneration, readyBuild); if (!consumed) return true; const unsigned inputWidth = mVideoBackend.InputFrameWidth(); const unsigned inputHeight = mVideoBackend.InputFrameHeight(); if (!readyBuild.succeeded) { if (publishFailureEvent) { PublishShaderBuildLifecycleEvent( RuntimeEventShaderBuildPhase::Failed, readyBuild.generation, inputWidth, inputHeight, false, readyBuild.message); DispatchRuntimeEvents(); } ApplyRuntimeCoordinatorResult(mRuntimeCoordinator.HandlePreparedShaderBuildFailure(readyBuild.message)); return false; } if (publishPreparedEvent) { PublishShaderBuildLifecycleEvent( RuntimeEventShaderBuildPhase::Prepared, readyBuild.generation, inputWidth, inputHeight, true, readyBuild.message); DispatchRuntimeEvents(); } char compilerErrorMessage[1024] = {}; if (!mRenderEngine.ApplyPreparedShaderBuild( readyBuild, inputWidth, inputHeight, mRuntimeCoordinator.PreserveFeedbackOnNextShaderBuild(), sizeof(compilerErrorMessage), compilerErrorMessage)) { const std::string errorMessage = compilerErrorMessage; if (publishFailureEvent) { PublishShaderBuildLifecycleEvent( RuntimeEventShaderBuildPhase::Failed, readyBuild.generation, inputWidth, inputHeight, false, errorMessage); DispatchRuntimeEvents(); } ApplyRuntimeCoordinatorResult(mRuntimeCoordinator.HandlePreparedShaderBuildFailure(errorMessage)); return false; } PublishShaderBuildLifecycleEvent( RuntimeEventShaderBuildPhase::Applied, readyBuild.generation, inputWidth, inputHeight, true, "Shader layers applied successfully."); ApplyRuntimeCoordinatorResult(mRuntimeCoordinator.HandlePreparedShaderBuildSuccess()); return true; } void RuntimeUpdateController::PublishShaderBuildLifecycleEvent( RuntimeEventShaderBuildPhase phase, uint64_t generation, unsigned inputWidth, unsigned inputHeight, bool succeeded, const std::string& message) { ShaderBuildEvent event; event.phase = phase; event.generation = generation; event.inputWidth = inputWidth; event.inputHeight = inputHeight; event.preserveFeedbackState = mRuntimeCoordinator.PreserveFeedbackOnNextShaderBuild(); event.succeeded = succeeded; event.message = message; mRuntimeEventDispatcher.PublishPayload(event, "RuntimeUpdateController"); } bool RuntimeUpdateController::ShouldSuppressCoordinatorFollowUp(const RuntimeEvent& event, std::size_t& pendingSuppressions) { if (event.source != "RuntimeCoordinator") return false; if (pendingSuppressions > 0) --pendingSuppressions; return true; } RuntimeEventDispatchResult RuntimeUpdateController::DispatchRuntimeEvents(std::size_t maxEvents) { RuntimeEventDispatchResult result = mRuntimeEventDispatcher.DispatchPending(maxEvents); const RuntimeEventQueueMetrics queueMetrics = mRuntimeEventDispatcher.GetQueueMetrics(); HealthTelemetry& telemetry = mRuntimeStore.GetHealthTelemetry(); telemetry.TryRecordRuntimeEventDispatchStats( result.dispatchedEvents, result.handlerInvocations, result.handlerFailures, result.dispatchDurationMilliseconds); telemetry.TryRecordRuntimeEventQueueMetrics( "runtime-events", queueMetrics.depth, queueMetrics.capacity, static_cast(queueMetrics.droppedCount), queueMetrics.oldestEventAgeMilliseconds); return result; }