Fixes
This commit is contained in:
127
src/render/thread/RenderThread.cpp
Normal file
127
src/render/thread/RenderThread.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "RenderThread.h"
|
||||
|
||||
#include "../frames/InputFrameMailbox.h"
|
||||
#include "../frames/SystemFrameExchange.h"
|
||||
#include "../frames/SystemFrameTypes.h"
|
||||
#include "../logging/Logger.h"
|
||||
#include "../platform/HiddenGlWindow.h"
|
||||
#include "InputFrameTexture.h"
|
||||
#include "readback/Bgra8ReadbackPipeline.h"
|
||||
#include "GLExtensions.h"
|
||||
#include "RuntimeRenderScene.h"
|
||||
#include "SimpleMotionRenderer.h"
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
void RenderThread::ThreadMain()
|
||||
{
|
||||
RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread starting.");
|
||||
HiddenGlWindow window;
|
||||
std::string error;
|
||||
if (!window.Create(mConfig.width, mConfig.height, error))
|
||||
{
|
||||
SignalStartupFailure(error.empty() ? "OpenGL context creation failed." : error);
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<HiddenGlWindow> prepareWindow = std::make_unique<HiddenGlWindow>();
|
||||
if (!prepareWindow->CreateShared(mConfig.width, mConfig.height, window.DeviceContext(), window.Context(), error))
|
||||
{
|
||||
SignalStartupFailure(error.empty() ? "Runtime shader prepare shared context creation failed." : error);
|
||||
return;
|
||||
}
|
||||
if (!window.MakeCurrent())
|
||||
{
|
||||
SignalStartupFailure("OpenGL context creation failed.");
|
||||
return;
|
||||
}
|
||||
if (!ResolveGLExtensions())
|
||||
{
|
||||
SignalStartupFailure("OpenGL extension resolution failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleMotionRenderer renderer;
|
||||
RuntimeRenderScene runtimeRenderScene;
|
||||
Bgra8ReadbackPipeline readback;
|
||||
InputFrameTexture inputTexture;
|
||||
if (!runtimeRenderScene.StartPrepareWorker(std::move(prepareWindow), error))
|
||||
{
|
||||
SignalStartupFailure(error.empty() ? "Runtime shader prepare worker initialization failed." : error);
|
||||
return;
|
||||
}
|
||||
if (!renderer.InitializeGl(mConfig.width, mConfig.height) || !readback.Initialize(mConfig.width, mConfig.height, mConfig.pboDepth))
|
||||
{
|
||||
SignalStartupFailure("Render pipeline initialization failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
RenderCadenceClock clock(mConfig.frameDurationMilliseconds);
|
||||
uint64_t frameIndex = 0;
|
||||
mRunning.store(true, std::memory_order_release);
|
||||
SignalStarted();
|
||||
|
||||
while (!mStopping.load(std::memory_order_acquire))
|
||||
{
|
||||
readback.ConsumeCompleted(
|
||||
[this](SystemFrame& frame) { return mFrameExchange.AcquireForRender(frame); },
|
||||
[this](const SystemFrame& frame) { return mFrameExchange.PublishCompleted(frame); },
|
||||
[this]() {
|
||||
CountAcquireMiss();
|
||||
},
|
||||
[this]() { CountCompleted(); });
|
||||
PublishReadbackMetrics(readback);
|
||||
|
||||
const auto now = RenderCadenceClock::Clock::now();
|
||||
const RenderCadenceClock::Tick tick = clock.Poll(now);
|
||||
if (!tick.due)
|
||||
{
|
||||
if (tick.sleepFor > RenderCadenceClock::Duration::zero())
|
||||
std::this_thread::sleep_for(tick.sleepFor);
|
||||
continue;
|
||||
}
|
||||
|
||||
TryCommitReadyRuntimeShader(runtimeRenderScene);
|
||||
const GLuint videoInputTexture = inputTexture.PollAndUpload(mInputMailbox);
|
||||
PublishInputMetrics(inputTexture);
|
||||
if (!readback.RenderAndQueue(frameIndex, [this, &renderer, &runtimeRenderScene, videoInputTexture](uint64_t index) {
|
||||
if (runtimeRenderScene.HasLayers())
|
||||
runtimeRenderScene.RenderFrame(index, mConfig.width, mConfig.height, videoInputTexture);
|
||||
else if (videoInputTexture != 0)
|
||||
renderer.RenderTexture(videoInputTexture);
|
||||
else
|
||||
renderer.RenderFrame(index);
|
||||
}))
|
||||
{
|
||||
mPboQueueMisses.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
PublishReadbackMetrics(readback);
|
||||
|
||||
CountRendered();
|
||||
++frameIndex;
|
||||
clock.MarkRendered(RenderCadenceClock::Clock::now());
|
||||
|
||||
mClockOverruns.store(clock.OverrunCount(), std::memory_order_relaxed);
|
||||
mSkippedFrames.store(clock.SkippedFrameCount(), std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < mConfig.pboDepth * 2; ++i)
|
||||
{
|
||||
readback.ConsumeCompleted(
|
||||
[this](SystemFrame& frame) { return mFrameExchange.AcquireForRender(frame); },
|
||||
[this](const SystemFrame& frame) { return mFrameExchange.PublishCompleted(frame); },
|
||||
[this]() {
|
||||
CountAcquireMiss();
|
||||
},
|
||||
[this]() { CountCompleted(); });
|
||||
PublishReadbackMetrics(readback);
|
||||
}
|
||||
|
||||
readback.Shutdown();
|
||||
inputTexture.ShutdownGl();
|
||||
runtimeRenderScene.ShutdownGl();
|
||||
renderer.ShutdownGl();
|
||||
window.ClearCurrent();
|
||||
mRunning.store(false, std::memory_order_release);
|
||||
RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread stopped.");
|
||||
}
|
||||
129
src/render/thread/RenderThread.h
Normal file
129
src/render/thread/RenderThread.h
Normal file
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#include "RenderCadenceClock.h"
|
||||
#include "RuntimeLayerModel.h"
|
||||
#include "RuntimeShaderArtifact.h"
|
||||
#include "RuntimeRenderScene.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
class SystemFrameExchange;
|
||||
class InputFrameMailbox;
|
||||
class InputFrameTexture;
|
||||
class Bgra8ReadbackPipeline;
|
||||
|
||||
class RenderThread
|
||||
{
|
||||
public:
|
||||
struct Config
|
||||
{
|
||||
unsigned width = 1920;
|
||||
unsigned height = 1080;
|
||||
double frameDurationMilliseconds = 1000.0 / 59.94;
|
||||
std::size_t pboDepth = 6;
|
||||
};
|
||||
|
||||
struct Metrics
|
||||
{
|
||||
uint64_t renderedFrames = 0;
|
||||
uint64_t completedReadbacks = 0;
|
||||
uint64_t acquireMisses = 0;
|
||||
uint64_t pboQueueMisses = 0;
|
||||
uint64_t clockOverruns = 0;
|
||||
uint64_t skippedFrames = 0;
|
||||
uint64_t shaderBuildsCommitted = 0;
|
||||
uint64_t shaderBuildFailures = 0;
|
||||
double renderFrameMilliseconds = 0.0;
|
||||
double renderFrameBudgetUsedPercent = 0.0;
|
||||
double renderFrameMaxMilliseconds = 0.0;
|
||||
double readbackQueueMilliseconds = 0.0;
|
||||
double completedReadbackCopyMilliseconds = 0.0;
|
||||
uint64_t inputFramesReceived = 0;
|
||||
uint64_t inputFramesDropped = 0;
|
||||
uint64_t inputConsumeMisses = 0;
|
||||
uint64_t inputUploadMisses = 0;
|
||||
std::size_t inputReadyFrames = 0;
|
||||
std::size_t inputReadingFrames = 0;
|
||||
double inputLatestAgeMilliseconds = 0.0;
|
||||
double inputUploadMilliseconds = 0.0;
|
||||
bool inputFormatSupported = true;
|
||||
bool inputSignalPresent = false;
|
||||
};
|
||||
|
||||
RenderThread(SystemFrameExchange& frameExchange, Config config);
|
||||
RenderThread(SystemFrameExchange& frameExchange, InputFrameMailbox* inputMailbox, Config config);
|
||||
RenderThread(const RenderThread&) = delete;
|
||||
RenderThread& operator=(const RenderThread&) = delete;
|
||||
~RenderThread();
|
||||
|
||||
bool Start(std::string& error);
|
||||
void Stop();
|
||||
void SubmitRuntimeShaderArtifact(const RuntimeShaderArtifact& artifact);
|
||||
void SubmitRuntimeRenderLayers(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers);
|
||||
|
||||
Metrics GetMetrics() const;
|
||||
bool IsRunning() const { return mRunning.load(std::memory_order_acquire); }
|
||||
|
||||
private:
|
||||
void ThreadMain();
|
||||
void SignalStarted();
|
||||
void SignalStartupFailure(const std::string& error);
|
||||
void CountRendered();
|
||||
void CountCompleted();
|
||||
void CountAcquireMiss();
|
||||
void PublishReadbackMetrics(const Bgra8ReadbackPipeline& readback);
|
||||
void PublishInputMetrics(const InputFrameTexture& inputTexture);
|
||||
void TryCommitReadyRuntimeShader(RuntimeRenderScene& runtimeRenderScene);
|
||||
bool TryTakePendingRuntimeShaderArtifact(RuntimeShaderArtifact& artifact);
|
||||
bool TryTakePendingRenderLayers(std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers);
|
||||
|
||||
SystemFrameExchange& mFrameExchange;
|
||||
InputFrameMailbox* mInputMailbox = nullptr;
|
||||
Config mConfig;
|
||||
std::thread mThread;
|
||||
std::atomic<bool> mStopping{ false };
|
||||
std::atomic<bool> mRunning{ false };
|
||||
|
||||
mutable std::mutex mStartupMutex;
|
||||
std::condition_variable mStartupCondition;
|
||||
bool mStarted = false;
|
||||
std::string mStartupError;
|
||||
|
||||
std::atomic<uint64_t> mRenderedFrames{ 0 };
|
||||
std::atomic<uint64_t> mCompletedReadbacks{ 0 };
|
||||
std::atomic<uint64_t> mAcquireMisses{ 0 };
|
||||
std::atomic<uint64_t> mPboQueueMisses{ 0 };
|
||||
std::atomic<uint64_t> mClockOverruns{ 0 };
|
||||
std::atomic<uint64_t> mSkippedFrames{ 0 };
|
||||
std::atomic<uint64_t> mShaderBuildsCommitted{ 0 };
|
||||
std::atomic<uint64_t> mShaderBuildFailures{ 0 };
|
||||
std::atomic<double> mRenderFrameMilliseconds{ 0.0 };
|
||||
std::atomic<double> mRenderFrameBudgetUsedPercent{ 0.0 };
|
||||
std::atomic<double> mRenderFrameMaxMilliseconds{ 0.0 };
|
||||
std::atomic<double> mReadbackQueueMilliseconds{ 0.0 };
|
||||
std::atomic<double> mCompletedReadbackCopyMilliseconds{ 0.0 };
|
||||
std::atomic<uint64_t> mInputFramesReceived{ 0 };
|
||||
std::atomic<uint64_t> mInputFramesDropped{ 0 };
|
||||
std::atomic<uint64_t> mInputConsumeMisses{ 0 };
|
||||
std::atomic<uint64_t> mInputUploadMisses{ 0 };
|
||||
std::atomic<std::size_t> mInputReadyFrames{ 0 };
|
||||
std::atomic<std::size_t> mInputReadingFrames{ 0 };
|
||||
std::atomic<double> mInputLatestAgeMilliseconds{ 0.0 };
|
||||
std::atomic<double> mInputUploadMilliseconds{ 0.0 };
|
||||
std::atomic<bool> mInputFormatSupported{ true };
|
||||
std::atomic<bool> mInputSignalPresent{ false };
|
||||
|
||||
std::mutex mShaderArtifactMutex;
|
||||
bool mHasPendingShaderArtifact = false;
|
||||
RuntimeShaderArtifact mPendingShaderArtifact;
|
||||
|
||||
std::mutex mRenderLayersMutex;
|
||||
bool mHasPendingRenderLayers = false;
|
||||
std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel> mPendingRenderLayers;
|
||||
};
|
||||
80
src/render/thread/RenderThreadLifecycle.cpp
Normal file
80
src/render/thread/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/thread/RenderThreadMetrics.cpp
Normal file
101
src/render/thread/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/thread/RenderThreadRuntimeShaders.cpp
Normal file
102
src/render/thread/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