restructure
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
#include "RuntimeShaderPrepareWorker.h"
|
||||
|
||||
#include "../../platform/HiddenGlWindow.h"
|
||||
#include "RuntimeShaderRenderer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
RuntimeShaderPrepareWorker::~RuntimeShaderPrepareWorker()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool RuntimeShaderPrepareWorker::Start(std::unique_ptr<HiddenGlWindow> sharedWindow, std::string& error)
|
||||
{
|
||||
if (mThread.joinable())
|
||||
return true;
|
||||
if (!sharedWindow || sharedWindow->DeviceContext() == nullptr || sharedWindow->Context() == nullptr)
|
||||
{
|
||||
error = "Runtime shader prepare worker needs an existing shared GL context.";
|
||||
return false;
|
||||
}
|
||||
|
||||
mWindow = std::move(sharedWindow);
|
||||
mStopping.store(false, std::memory_order_release);
|
||||
mStarted.store(false, std::memory_order_release);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mStartupReady = false;
|
||||
mStartupError.clear();
|
||||
}
|
||||
mThread = std::thread([this]() { ThreadMain(); });
|
||||
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
if (!mStartupCondition.wait_for(lock, std::chrono::seconds(3), [this]() {
|
||||
return mStartupReady || !mStartupError.empty();
|
||||
}))
|
||||
{
|
||||
error = "Timed out starting runtime shader prepare worker.";
|
||||
lock.unlock();
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
if (!mStartupError.empty())
|
||||
{
|
||||
error = mStartupError;
|
||||
lock.unlock();
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuntimeShaderPrepareWorker::Stop()
|
||||
{
|
||||
mStopping.store(true, std::memory_order_release);
|
||||
mCondition.notify_all();
|
||||
if (mThread.joinable())
|
||||
mThread.join();
|
||||
|
||||
std::deque<RuntimePreparedShaderProgram> completed;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mRequests.clear();
|
||||
completed.swap(mCompleted);
|
||||
}
|
||||
for (RuntimePreparedShaderProgram& program : completed)
|
||||
program.ReleaseGl();
|
||||
mWindow.reset();
|
||||
mStarted.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
void RuntimeShaderPrepareWorker::Submit(const std::vector<RenderCadenceCompositor::RuntimeRenderLayerModel>& layers)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
for (const RenderCadenceCompositor::RuntimeRenderLayerModel& layer : layers)
|
||||
{
|
||||
if (layer.artifact.fragmentShaderSource.empty())
|
||||
continue;
|
||||
|
||||
PrepareRequest request;
|
||||
request.layerId = layer.id;
|
||||
request.shaderId = layer.shaderId;
|
||||
request.sourceFingerprint = Fingerprint(layer.artifact);
|
||||
request.artifact = layer.artifact;
|
||||
|
||||
auto sameLayer = [&request](const PrepareRequest& existing) {
|
||||
return existing.layerId == request.layerId;
|
||||
};
|
||||
mRequests.erase(std::remove_if(mRequests.begin(), mRequests.end(), sameLayer), mRequests.end());
|
||||
mRequests.push_back(std::move(request));
|
||||
}
|
||||
mCondition.notify_one();
|
||||
}
|
||||
|
||||
bool RuntimeShaderPrepareWorker::TryConsume(RuntimePreparedShaderProgram& preparedProgram)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
if (mCompleted.empty())
|
||||
return false;
|
||||
|
||||
preparedProgram = std::move(mCompleted.front());
|
||||
mCompleted.pop_front();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuntimeShaderPrepareWorker::ThreadMain()
|
||||
{
|
||||
if (!mWindow || !mWindow->MakeCurrent())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mStartupError = "Runtime shader prepare worker could not make shared GL context current.";
|
||||
mStartupCondition.notify_all();
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mStartupReady = true;
|
||||
}
|
||||
mStarted.store(true, std::memory_order_release);
|
||||
mStartupCondition.notify_all();
|
||||
|
||||
while (!mStopping.load(std::memory_order_acquire))
|
||||
{
|
||||
PrepareRequest request;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
mCondition.wait(lock, [this]() {
|
||||
return mStopping.load(std::memory_order_acquire) || !mRequests.empty();
|
||||
});
|
||||
if (mStopping.load(std::memory_order_acquire))
|
||||
break;
|
||||
request = std::move(mRequests.front());
|
||||
mRequests.pop_front();
|
||||
}
|
||||
|
||||
RuntimePreparedShaderProgram preparedProgram;
|
||||
RuntimeShaderRenderer::BuildPreparedProgram(
|
||||
request.layerId,
|
||||
request.sourceFingerprint,
|
||||
request.artifact,
|
||||
preparedProgram);
|
||||
glFlush();
|
||||
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mCompleted.push_back(std::move(preparedProgram));
|
||||
}
|
||||
|
||||
mWindow->ClearCurrent();
|
||||
}
|
||||
|
||||
std::string RuntimeShaderPrepareWorker::Fingerprint(const RuntimeShaderArtifact& artifact)
|
||||
{
|
||||
const std::hash<std::string> hasher;
|
||||
return artifact.shaderId + ":" + std::to_string(artifact.fragmentShaderSource.size()) + ":" + std::to_string(hasher(artifact.fragmentShaderSource));
|
||||
}
|
||||
Reference in New Issue
Block a user