render thread split
This commit is contained in:
@@ -9,100 +9,11 @@
|
|||||||
#include "readback/Bgra8ReadbackPipeline.h"
|
#include "readback/Bgra8ReadbackPipeline.h"
|
||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
#include "runtime/RuntimeRenderScene.h"
|
#include "runtime/RuntimeRenderScene.h"
|
||||||
#include "runtime/RuntimeShaderRenderer.h"
|
|
||||||
#include "SimpleMotionRenderer.h"
|
#include "SimpleMotionRenderer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
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<std::mutex> lock(mStartupMutex);
|
|
||||||
mStarted = false;
|
|
||||||
mStartupError.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
mStopping.store(false, std::memory_order_release);
|
|
||||||
mThread = std::thread([this]() { ThreadMain(); });
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> 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()
|
void RenderThread::ThreadMain()
|
||||||
{
|
{
|
||||||
RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread starting.");
|
RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread starting.");
|
||||||
@@ -214,180 +125,3 @@ void RenderThread::ThreadMain()
|
|||||||
mRunning.store(false, std::memory_order_release);
|
mRunning.store(false, std::memory_order_release);
|
||||||
RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread stopped.");
|
RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread stopped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderThread::SignalStarted()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lock(mShaderArtifactMutex);
|
|
||||||
mPendingShaderArtifact = artifact;
|
|
||||||
mHasPendingShaderArtifact = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderThread::SubmitRuntimeRenderLayers(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mRenderLayersMutex);
|
|
||||||
mPendingRenderLayers = layers;
|
|
||||||
mHasPendingRenderLayers = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RenderThread::TryTakePendingRuntimeShaderArtifact(RuntimeShaderArtifact& artifact)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mShaderArtifactMutex);
|
|
||||||
if (!mHasPendingShaderArtifact)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
artifact = std::move(mPendingShaderArtifact);
|
|
||||||
mPendingShaderArtifact = RuntimeShaderArtifact();
|
|
||||||
mHasPendingShaderArtifact = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RenderThread::TryTakePendingRenderLayers(std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mRenderLayersMutex);
|
|
||||||
if (!mHasPendingRenderLayers)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
layers = std::move(mPendingRenderLayers);
|
|
||||||
mPendingRenderLayers.clear();
|
|
||||||
mHasPendingRenderLayers = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderThread::TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRenderScene)
|
|
||||||
{
|
|
||||||
std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel> 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);
|
|
||||||
}
|
|
||||||
|
|||||||
80
src/render/RenderThreadLifecycle.cpp
Normal file
80
src/render/RenderThreadLifecycle.cpp
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#include "RenderThread.h"
|
||||||
|
|
||||||
|
#include "../logging/Logger.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
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<std::mutex> lock(mStartupMutex);
|
||||||
|
mStarted = false;
|
||||||
|
mStartupError.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
mStopping.store(false, std::memory_order_release);
|
||||||
|
mThread = std::thread([this]() { ThreadMain(); });
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> lock(mStartupMutex);
|
||||||
|
mStartupError = error;
|
||||||
|
mStartupCondition.notify_all();
|
||||||
|
}
|
||||||
101
src/render/RenderThreadMetrics.cpp
Normal file
101
src/render/RenderThreadMetrics.cpp
Normal file
@@ -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);
|
||||||
|
}
|
||||||
102
src/render/RenderThreadRuntimeShaders.cpp
Normal file
102
src/render/RenderThreadRuntimeShaders.cpp
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#include "RenderThread.h"
|
||||||
|
|
||||||
|
#include "../logging/Logger.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
void RenderThread::SubmitRuntimeShaderArtifact(const RuntimeShaderArtifact& artifact)
|
||||||
|
{
|
||||||
|
if (artifact.fragmentShaderSource.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(mShaderArtifactMutex);
|
||||||
|
mPendingShaderArtifact = artifact;
|
||||||
|
mHasPendingShaderArtifact = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderThread::SubmitRuntimeRenderLayers(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRenderLayersMutex);
|
||||||
|
mPendingRenderLayers = layers;
|
||||||
|
mHasPendingRenderLayers = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderThread::TryTakePendingRuntimeShaderArtifact(RuntimeShaderArtifact& artifact)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mShaderArtifactMutex);
|
||||||
|
if (!mHasPendingShaderArtifact)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
artifact = std::move(mPendingShaderArtifact);
|
||||||
|
mPendingShaderArtifact = RuntimeShaderArtifact();
|
||||||
|
mHasPendingShaderArtifact = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderThread::TryTakePendingRenderLayers(std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mRenderLayersMutex);
|
||||||
|
if (!mHasPendingRenderLayers)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
layers = std::move(mPendingRenderLayers);
|
||||||
|
mPendingRenderLayers.clear();
|
||||||
|
mHasPendingRenderLayers = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderThread::TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRenderScene)
|
||||||
|
{
|
||||||
|
std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel> 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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user