diff --git a/src/render/RenderThread.cpp b/src/render/RenderThread.cpp index 6cbbebd..f45641b 100644 --- a/src/render/RenderThread.cpp +++ b/src/render/RenderThread.cpp @@ -9,100 +9,11 @@ #include "readback/Bgra8ReadbackPipeline.h" #include "GLExtensions.h" #include "runtime/RuntimeRenderScene.h" -#include "runtime/RuntimeShaderRenderer.h" #include "SimpleMotionRenderer.h" -#include #include #include -RenderThread::RenderThread(SystemFrameExchange& frameExchange, Config config) : - mFrameExchange(frameExchange), - mConfig(config) -{ -} - -RenderThread::RenderThread(SystemFrameExchange& frameExchange, InputFrameMailbox* inputMailbox, Config config) : - mFrameExchange(frameExchange), - mInputMailbox(inputMailbox), - mConfig(config) -{ -} - -RenderThread::~RenderThread() -{ - Stop(); -} - -bool RenderThread::Start(std::string& error) -{ - if (mThread.joinable()) - return true; - - { - std::lock_guard lock(mStartupMutex); - mStarted = false; - mStartupError.clear(); - } - - mStopping.store(false, std::memory_order_release); - mThread = std::thread([this]() { ThreadMain(); }); - - std::unique_lock lock(mStartupMutex); - if (!mStartupCondition.wait_for(lock, std::chrono::seconds(3), [this]() { - return mStarted || !mStartupError.empty(); - })) - { - error = "Timed out starting render thread."; - return false; - } - if (!mStartupError.empty()) - { - error = mStartupError; - lock.unlock(); - if (mThread.joinable()) - mThread.join(); - return false; - } - return true; -} - -void RenderThread::Stop() -{ - mStopping.store(true, std::memory_order_release); - if (mThread.joinable()) - mThread.join(); -} - -RenderThread::Metrics RenderThread::GetMetrics() const -{ - Metrics metrics; - metrics.renderedFrames = mRenderedFrames.load(std::memory_order_relaxed); - metrics.completedReadbacks = mCompletedReadbacks.load(std::memory_order_relaxed); - metrics.acquireMisses = mAcquireMisses.load(std::memory_order_relaxed); - metrics.pboQueueMisses = mPboQueueMisses.load(std::memory_order_relaxed); - metrics.clockOverruns = mClockOverruns.load(std::memory_order_relaxed); - metrics.skippedFrames = mSkippedFrames.load(std::memory_order_relaxed); - metrics.shaderBuildsCommitted = mShaderBuildsCommitted.load(std::memory_order_relaxed); - metrics.shaderBuildFailures = mShaderBuildFailures.load(std::memory_order_relaxed); - metrics.renderFrameMilliseconds = mRenderFrameMilliseconds.load(std::memory_order_relaxed); - metrics.renderFrameBudgetUsedPercent = mRenderFrameBudgetUsedPercent.load(std::memory_order_relaxed); - metrics.renderFrameMaxMilliseconds = mRenderFrameMaxMilliseconds.load(std::memory_order_relaxed); - metrics.readbackQueueMilliseconds = mReadbackQueueMilliseconds.load(std::memory_order_relaxed); - metrics.completedReadbackCopyMilliseconds = mCompletedReadbackCopyMilliseconds.load(std::memory_order_relaxed); - metrics.inputFramesReceived = mInputFramesReceived.load(std::memory_order_relaxed); - metrics.inputFramesDropped = mInputFramesDropped.load(std::memory_order_relaxed); - metrics.inputConsumeMisses = mInputConsumeMisses.load(std::memory_order_relaxed); - metrics.inputUploadMisses = mInputUploadMisses.load(std::memory_order_relaxed); - metrics.inputReadyFrames = mInputReadyFrames.load(std::memory_order_relaxed); - metrics.inputReadingFrames = mInputReadingFrames.load(std::memory_order_relaxed); - metrics.inputLatestAgeMilliseconds = mInputLatestAgeMilliseconds.load(std::memory_order_relaxed); - metrics.inputUploadMilliseconds = mInputUploadMilliseconds.load(std::memory_order_relaxed); - metrics.inputFormatSupported = mInputFormatSupported.load(std::memory_order_relaxed); - metrics.inputSignalPresent = mInputSignalPresent.load(std::memory_order_relaxed); - return metrics; -} - void RenderThread::ThreadMain() { RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread starting."); @@ -214,180 +125,3 @@ void RenderThread::ThreadMain() mRunning.store(false, std::memory_order_release); RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread stopped."); } - -void RenderThread::SignalStarted() -{ - std::lock_guard lock(mStartupMutex); - mStarted = true; - mStartupCondition.notify_all(); -} - -void RenderThread::SignalStartupFailure(const std::string& error) -{ - RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Error, "render-thread", error); - std::lock_guard lock(mStartupMutex); - mStartupError = error; - mStartupCondition.notify_all(); -} - -void RenderThread::CountRendered() -{ - mRenderedFrames.fetch_add(1, std::memory_order_relaxed); -} - -void RenderThread::CountCompleted() -{ - mCompletedReadbacks.fetch_add(1, std::memory_order_relaxed); -} - -void RenderThread::CountAcquireMiss() -{ - mAcquireMisses.fetch_add(1, std::memory_order_relaxed); -} - -void RenderThread::PublishReadbackMetrics(const Bgra8ReadbackPipeline& readback) -{ - const double renderMilliseconds = readback.LastRenderFrameMilliseconds(); - mRenderFrameMilliseconds.store(renderMilliseconds, std::memory_order_relaxed); - if (mConfig.frameDurationMilliseconds > 0.0) - { - mRenderFrameBudgetUsedPercent.store( - (renderMilliseconds / mConfig.frameDurationMilliseconds) * 100.0, - std::memory_order_relaxed); - } - else - { - mRenderFrameBudgetUsedPercent.store(0.0, std::memory_order_relaxed); - } - - const double previousMax = mRenderFrameMaxMilliseconds.load(std::memory_order_relaxed); - if (renderMilliseconds > previousMax) - mRenderFrameMaxMilliseconds.store(renderMilliseconds, std::memory_order_relaxed); - - mReadbackQueueMilliseconds.store(readback.LastReadbackQueueMilliseconds(), std::memory_order_relaxed); - mCompletedReadbackCopyMilliseconds.store(readback.LastCompletedReadbackCopyMilliseconds(), std::memory_order_relaxed); -} - -void RenderThread::PublishInputMetrics(const InputFrameTexture& inputTexture) -{ - if (mInputMailbox != nullptr) - { - const InputFrameMailboxMetrics mailboxMetrics = mInputMailbox->Metrics(); - mInputFramesReceived.store(mailboxMetrics.submittedFrames, std::memory_order_relaxed); - mInputFramesDropped.store(mailboxMetrics.droppedReadyFrames + mailboxMetrics.submitMisses, std::memory_order_relaxed); - mInputConsumeMisses.store(mailboxMetrics.consumeMisses, std::memory_order_relaxed); - mInputReadyFrames.store(mailboxMetrics.readyCount, std::memory_order_relaxed); - mInputReadingFrames.store(mailboxMetrics.readingCount, std::memory_order_relaxed); - mInputLatestAgeMilliseconds.store(mailboxMetrics.latestFrameAgeMilliseconds, std::memory_order_relaxed); - mInputSignalPresent.store(mailboxMetrics.hasSubmittedFrame, std::memory_order_relaxed); - } - else - { - mInputFramesReceived.store(0, std::memory_order_relaxed); - mInputFramesDropped.store(0, std::memory_order_relaxed); - mInputConsumeMisses.store(0, std::memory_order_relaxed); - mInputReadyFrames.store(0, std::memory_order_relaxed); - mInputReadingFrames.store(0, std::memory_order_relaxed); - mInputLatestAgeMilliseconds.store(0.0, std::memory_order_relaxed); - mInputSignalPresent.store(false, std::memory_order_relaxed); - } - - mInputUploadMisses.store(inputTexture.UploadMisses(), std::memory_order_relaxed); - mInputUploadMilliseconds.store(inputTexture.LastUploadMilliseconds(), std::memory_order_relaxed); - mInputFormatSupported.store(inputTexture.LastFrameFormatSupported(), std::memory_order_relaxed); -} - -void RenderThread::SubmitRuntimeShaderArtifact(const RuntimeShaderArtifact& artifact) -{ - if (artifact.fragmentShaderSource.empty()) - return; - - std::lock_guard lock(mShaderArtifactMutex); - mPendingShaderArtifact = artifact; - mHasPendingShaderArtifact = true; -} - -void RenderThread::SubmitRuntimeRenderLayers(const std::vector& layers) -{ - std::lock_guard lock(mRenderLayersMutex); - mPendingRenderLayers = layers; - mHasPendingRenderLayers = true; -} - -bool RenderThread::TryTakePendingRuntimeShaderArtifact(RuntimeShaderArtifact& artifact) -{ - std::lock_guard lock(mShaderArtifactMutex); - if (!mHasPendingShaderArtifact) - return false; - - artifact = std::move(mPendingShaderArtifact); - mPendingShaderArtifact = RuntimeShaderArtifact(); - mHasPendingShaderArtifact = false; - return true; -} - -bool RenderThread::TryTakePendingRenderLayers(std::vector& layers) -{ - std::lock_guard lock(mRenderLayersMutex); - if (!mHasPendingRenderLayers) - return false; - - layers = std::move(mPendingRenderLayers); - mPendingRenderLayers.clear(); - mHasPendingRenderLayers = false; - return true; -} - -void RenderThread::TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRenderScene) -{ - std::vector layers; - std::string commitError; - if (TryTakePendingRenderLayers(layers)) - { - bool structuralChange = false; - if (!runtimeRenderScene.CommitRenderLayers(layers, commitError, &structuralChange)) - { - RenderCadenceCompositor::TryLog( - RenderCadenceCompositor::LogLevel::Error, - "render-thread", - "Runtime render-layer commit failed: " + commitError); - mShaderBuildFailures.fetch_add(1, std::memory_order_relaxed); - return; - } - - if (structuralChange) - { - RenderCadenceCompositor::TryLog( - RenderCadenceCompositor::LogLevel::Log, - "render-thread", - "Runtime render layer snapshot committed."); - mShaderBuildsCommitted.fetch_add(1, std::memory_order_relaxed); - } - return; - } - - RuntimeShaderArtifact artifact; - if (!TryTakePendingRuntimeShaderArtifact(artifact)) - return; - - RenderCadenceCompositor::RuntimeRenderLayerModel layer; - layer.id = artifact.layerId.empty() ? "runtime-layer-1" : artifact.layerId; - layer.shaderId = artifact.shaderId; - layer.artifact = artifact; - layers.push_back(std::move(layer)); - if (!runtimeRenderScene.CommitRenderLayers(layers, commitError)) - { - RenderCadenceCompositor::TryLog( - RenderCadenceCompositor::LogLevel::Error, - "render-thread", - "Runtime shader GL commit failed: " + commitError); - mShaderBuildFailures.fetch_add(1, std::memory_order_relaxed); - return; - } - - RenderCadenceCompositor::TryLog( - RenderCadenceCompositor::LogLevel::Log, - "render-thread", - "Runtime shader committed: " + artifact.shaderId + ". " + artifact.message); - mShaderBuildsCommitted.fetch_add(1, std::memory_order_relaxed); -} diff --git a/src/render/RenderThreadLifecycle.cpp b/src/render/RenderThreadLifecycle.cpp new file mode 100644 index 0000000..3da6115 --- /dev/null +++ b/src/render/RenderThreadLifecycle.cpp @@ -0,0 +1,80 @@ +#include "RenderThread.h" + +#include "../logging/Logger.h" + +#include +#include +#include + +RenderThread::RenderThread(SystemFrameExchange& frameExchange, Config config) : + mFrameExchange(frameExchange), + mConfig(config) +{ +} + +RenderThread::RenderThread(SystemFrameExchange& frameExchange, InputFrameMailbox* inputMailbox, Config config) : + mFrameExchange(frameExchange), + mInputMailbox(inputMailbox), + mConfig(config) +{ +} + +RenderThread::~RenderThread() +{ + Stop(); +} + +bool RenderThread::Start(std::string& error) +{ + if (mThread.joinable()) + return true; + + { + std::lock_guard lock(mStartupMutex); + mStarted = false; + mStartupError.clear(); + } + + mStopping.store(false, std::memory_order_release); + mThread = std::thread([this]() { ThreadMain(); }); + + std::unique_lock lock(mStartupMutex); + if (!mStartupCondition.wait_for(lock, std::chrono::seconds(3), [this]() { + return mStarted || !mStartupError.empty(); + })) + { + error = "Timed out starting render thread."; + return false; + } + if (!mStartupError.empty()) + { + error = mStartupError; + lock.unlock(); + if (mThread.joinable()) + mThread.join(); + return false; + } + return true; +} + +void RenderThread::Stop() +{ + mStopping.store(true, std::memory_order_release); + if (mThread.joinable()) + mThread.join(); +} + +void RenderThread::SignalStarted() +{ + std::lock_guard lock(mStartupMutex); + mStarted = true; + mStartupCondition.notify_all(); +} + +void RenderThread::SignalStartupFailure(const std::string& error) +{ + RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Error, "render-thread", error); + std::lock_guard lock(mStartupMutex); + mStartupError = error; + mStartupCondition.notify_all(); +} diff --git a/src/render/RenderThreadMetrics.cpp b/src/render/RenderThreadMetrics.cpp new file mode 100644 index 0000000..d1d6261 --- /dev/null +++ b/src/render/RenderThreadMetrics.cpp @@ -0,0 +1,101 @@ +#include "RenderThread.h" + +#include "../frames/InputFrameMailbox.h" +#include "InputFrameTexture.h" +#include "readback/Bgra8ReadbackPipeline.h" + +RenderThread::Metrics RenderThread::GetMetrics() const +{ + Metrics metrics; + metrics.renderedFrames = mRenderedFrames.load(std::memory_order_relaxed); + metrics.completedReadbacks = mCompletedReadbacks.load(std::memory_order_relaxed); + metrics.acquireMisses = mAcquireMisses.load(std::memory_order_relaxed); + metrics.pboQueueMisses = mPboQueueMisses.load(std::memory_order_relaxed); + metrics.clockOverruns = mClockOverruns.load(std::memory_order_relaxed); + metrics.skippedFrames = mSkippedFrames.load(std::memory_order_relaxed); + metrics.shaderBuildsCommitted = mShaderBuildsCommitted.load(std::memory_order_relaxed); + metrics.shaderBuildFailures = mShaderBuildFailures.load(std::memory_order_relaxed); + metrics.renderFrameMilliseconds = mRenderFrameMilliseconds.load(std::memory_order_relaxed); + metrics.renderFrameBudgetUsedPercent = mRenderFrameBudgetUsedPercent.load(std::memory_order_relaxed); + metrics.renderFrameMaxMilliseconds = mRenderFrameMaxMilliseconds.load(std::memory_order_relaxed); + metrics.readbackQueueMilliseconds = mReadbackQueueMilliseconds.load(std::memory_order_relaxed); + metrics.completedReadbackCopyMilliseconds = mCompletedReadbackCopyMilliseconds.load(std::memory_order_relaxed); + metrics.inputFramesReceived = mInputFramesReceived.load(std::memory_order_relaxed); + metrics.inputFramesDropped = mInputFramesDropped.load(std::memory_order_relaxed); + metrics.inputConsumeMisses = mInputConsumeMisses.load(std::memory_order_relaxed); + metrics.inputUploadMisses = mInputUploadMisses.load(std::memory_order_relaxed); + metrics.inputReadyFrames = mInputReadyFrames.load(std::memory_order_relaxed); + metrics.inputReadingFrames = mInputReadingFrames.load(std::memory_order_relaxed); + metrics.inputLatestAgeMilliseconds = mInputLatestAgeMilliseconds.load(std::memory_order_relaxed); + metrics.inputUploadMilliseconds = mInputUploadMilliseconds.load(std::memory_order_relaxed); + metrics.inputFormatSupported = mInputFormatSupported.load(std::memory_order_relaxed); + metrics.inputSignalPresent = mInputSignalPresent.load(std::memory_order_relaxed); + return metrics; +} + +void RenderThread::CountRendered() +{ + mRenderedFrames.fetch_add(1, std::memory_order_relaxed); +} + +void RenderThread::CountCompleted() +{ + mCompletedReadbacks.fetch_add(1, std::memory_order_relaxed); +} + +void RenderThread::CountAcquireMiss() +{ + mAcquireMisses.fetch_add(1, std::memory_order_relaxed); +} + +void RenderThread::PublishReadbackMetrics(const Bgra8ReadbackPipeline& readback) +{ + const double renderMilliseconds = readback.LastRenderFrameMilliseconds(); + mRenderFrameMilliseconds.store(renderMilliseconds, std::memory_order_relaxed); + if (mConfig.frameDurationMilliseconds > 0.0) + { + mRenderFrameBudgetUsedPercent.store( + (renderMilliseconds / mConfig.frameDurationMilliseconds) * 100.0, + std::memory_order_relaxed); + } + else + { + mRenderFrameBudgetUsedPercent.store(0.0, std::memory_order_relaxed); + } + + const double previousMax = mRenderFrameMaxMilliseconds.load(std::memory_order_relaxed); + if (renderMilliseconds > previousMax) + mRenderFrameMaxMilliseconds.store(renderMilliseconds, std::memory_order_relaxed); + + mReadbackQueueMilliseconds.store(readback.LastReadbackQueueMilliseconds(), std::memory_order_relaxed); + mCompletedReadbackCopyMilliseconds.store(readback.LastCompletedReadbackCopyMilliseconds(), std::memory_order_relaxed); +} + +void RenderThread::PublishInputMetrics(const InputFrameTexture& inputTexture) +{ + if (mInputMailbox != nullptr) + { + const InputFrameMailboxMetrics mailboxMetrics = mInputMailbox->Metrics(); + mInputFramesReceived.store(mailboxMetrics.submittedFrames, std::memory_order_relaxed); + mInputFramesDropped.store(mailboxMetrics.droppedReadyFrames + mailboxMetrics.submitMisses, std::memory_order_relaxed); + mInputConsumeMisses.store(mailboxMetrics.consumeMisses, std::memory_order_relaxed); + mInputReadyFrames.store(mailboxMetrics.readyCount, std::memory_order_relaxed); + mInputReadingFrames.store(mailboxMetrics.readingCount, std::memory_order_relaxed); + mInputLatestAgeMilliseconds.store(mailboxMetrics.latestFrameAgeMilliseconds, std::memory_order_relaxed); + mInputSignalPresent.store(mailboxMetrics.hasSubmittedFrame, std::memory_order_relaxed); + } + else + { + mInputFramesReceived.store(0, std::memory_order_relaxed); + mInputFramesDropped.store(0, std::memory_order_relaxed); + mInputConsumeMisses.store(0, std::memory_order_relaxed); + mInputReadyFrames.store(0, std::memory_order_relaxed); + mInputReadingFrames.store(0, std::memory_order_relaxed); + mInputLatestAgeMilliseconds.store(0.0, std::memory_order_relaxed); + mInputSignalPresent.store(false, std::memory_order_relaxed); + } + + mInputUploadMisses.store(inputTexture.UploadMisses(), std::memory_order_relaxed); + mInputUploadMilliseconds.store(inputTexture.LastUploadMilliseconds(), std::memory_order_relaxed); + mInputFormatSupported.store(inputTexture.LastFrameFormatSupported(), std::memory_order_relaxed); +} diff --git a/src/render/RenderThreadRuntimeShaders.cpp b/src/render/RenderThreadRuntimeShaders.cpp new file mode 100644 index 0000000..ded8d3d --- /dev/null +++ b/src/render/RenderThreadRuntimeShaders.cpp @@ -0,0 +1,102 @@ +#include "RenderThread.h" + +#include "../logging/Logger.h" + +#include +#include +#include + +void RenderThread::SubmitRuntimeShaderArtifact(const RuntimeShaderArtifact& artifact) +{ + if (artifact.fragmentShaderSource.empty()) + return; + + std::lock_guard lock(mShaderArtifactMutex); + mPendingShaderArtifact = artifact; + mHasPendingShaderArtifact = true; +} + +void RenderThread::SubmitRuntimeRenderLayers(const std::vector& layers) +{ + std::lock_guard lock(mRenderLayersMutex); + mPendingRenderLayers = layers; + mHasPendingRenderLayers = true; +} + +bool RenderThread::TryTakePendingRuntimeShaderArtifact(RuntimeShaderArtifact& artifact) +{ + std::lock_guard lock(mShaderArtifactMutex); + if (!mHasPendingShaderArtifact) + return false; + + artifact = std::move(mPendingShaderArtifact); + mPendingShaderArtifact = RuntimeShaderArtifact(); + mHasPendingShaderArtifact = false; + return true; +} + +bool RenderThread::TryTakePendingRenderLayers(std::vector& layers) +{ + std::lock_guard lock(mRenderLayersMutex); + if (!mHasPendingRenderLayers) + return false; + + layers = std::move(mPendingRenderLayers); + mPendingRenderLayers.clear(); + mHasPendingRenderLayers = false; + return true; +} + +void RenderThread::TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRenderScene) +{ + std::vector layers; + std::string commitError; + if (TryTakePendingRenderLayers(layers)) + { + bool structuralChange = false; + if (!runtimeRenderScene.CommitRenderLayers(layers, commitError, &structuralChange)) + { + RenderCadenceCompositor::TryLog( + RenderCadenceCompositor::LogLevel::Error, + "render-thread", + "Runtime render-layer commit failed: " + commitError); + mShaderBuildFailures.fetch_add(1, std::memory_order_relaxed); + return; + } + + if (structuralChange) + { + RenderCadenceCompositor::TryLog( + RenderCadenceCompositor::LogLevel::Log, + "render-thread", + "Runtime render layer snapshot committed."); + mShaderBuildsCommitted.fetch_add(1, std::memory_order_relaxed); + } + return; + } + + RuntimeShaderArtifact artifact; + if (!TryTakePendingRuntimeShaderArtifact(artifact)) + return; + + RenderCadenceCompositor::RuntimeRenderLayerModel layer; + layer.id = artifact.layerId.empty() ? "runtime-layer-1" : artifact.layerId; + layer.shaderId = artifact.shaderId; + layer.artifact = artifact; + layers.push_back(std::move(layer)); + if (!runtimeRenderScene.CommitRenderLayers(layers, commitError)) + { + RenderCadenceCompositor::TryLog( + RenderCadenceCompositor::LogLevel::Error, + "render-thread", + "Runtime shader GL commit failed: " + commitError); + mShaderBuildFailures.fetch_add(1, std::memory_order_relaxed); + return; + } + + RenderCadenceCompositor::TryLog( + RenderCadenceCompositor::LogLevel::Log, + "render-thread", + "Runtime shader committed: " + artifact.shaderId + ". " + artifact.message); + mShaderBuildsCommitted.fetch_add(1, std::memory_order_relaxed); +}