Files
Aiden a9b08f7f27
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m28s
CI / Windows Release Package (push) Successful in 2m24s
dispatch event intergration
2026-05-11 15:42:14 +10:00

167 lines
4.2 KiB
C++

#include "ShaderBuildQueue.h"
#include "RuntimeEventDispatcher.h"
#include <chrono>
#include <utility>
namespace
{
constexpr auto kShaderBuildDebounce = std::chrono::milliseconds(400);
}
ShaderBuildQueue::ShaderBuildQueue(RuntimeSnapshotProvider& runtimeSnapshotProvider, RuntimeEventDispatcher& runtimeEventDispatcher) :
mRuntimeSnapshotProvider(runtimeSnapshotProvider),
mRuntimeEventDispatcher(runtimeEventDispatcher),
mWorkerThread([this]() { WorkerLoop(); })
{
}
ShaderBuildQueue::~ShaderBuildQueue()
{
Stop();
}
void ShaderBuildQueue::RequestBuild(unsigned outputWidth, unsigned outputHeight)
{
{
std::lock_guard<std::mutex> lock(mMutex);
mHasRequest = true;
++mRequestedGeneration;
mRequestedOutputWidth = outputWidth;
mRequestedOutputHeight = outputHeight;
mHasReadyBuild = false;
}
mCondition.notify_one();
}
bool ShaderBuildQueue::TryConsumeReadyBuild(PreparedShaderBuild& build)
{
std::lock_guard<std::mutex> lock(mMutex);
if (!mHasReadyBuild)
return false;
build = std::move(mReadyBuild);
mReadyBuild = PreparedShaderBuild();
mHasReadyBuild = false;
return true;
}
bool ShaderBuildQueue::TryConsumeReadyBuild(uint64_t expectedGeneration, PreparedShaderBuild& build)
{
std::lock_guard<std::mutex> lock(mMutex);
if (!mHasReadyBuild || mReadyBuild.generation != expectedGeneration)
return false;
build = std::move(mReadyBuild);
mReadyBuild = PreparedShaderBuild();
mHasReadyBuild = false;
return true;
}
void ShaderBuildQueue::Stop()
{
{
std::lock_guard<std::mutex> lock(mMutex);
if (mStopping)
return;
mStopping = true;
}
mCondition.notify_one();
if (mWorkerThread.joinable())
mWorkerThread.join();
}
void ShaderBuildQueue::WorkerLoop()
{
for (;;)
{
uint64_t generation = 0;
unsigned outputWidth = 0;
unsigned outputHeight = 0;
{
std::unique_lock<std::mutex> lock(mMutex);
mCondition.wait(lock, [this]() { return mStopping || mHasRequest; });
if (mStopping)
return;
generation = mRequestedGeneration;
outputWidth = mRequestedOutputWidth;
outputHeight = mRequestedOutputHeight;
mHasRequest = false;
}
for (;;)
{
std::unique_lock<std::mutex> lock(mMutex);
if (mCondition.wait_for(lock, kShaderBuildDebounce, [this, generation]() {
return mStopping || (mHasRequest && mRequestedGeneration != generation);
}))
{
if (mStopping)
return;
generation = mRequestedGeneration;
outputWidth = mRequestedOutputWidth;
outputHeight = mRequestedOutputHeight;
mHasRequest = false;
continue;
}
break;
}
PreparedShaderBuild build = Build(generation, outputWidth, outputHeight);
bool shouldPublish = false;
{
std::lock_guard<std::mutex> lock(mMutex);
if (mStopping)
return;
if (generation != mRequestedGeneration)
continue;
mReadyBuild = build;
mHasReadyBuild = true;
shouldPublish = true;
}
if (shouldPublish)
PublishBuildLifecycleEvent(build, outputWidth, outputHeight);
}
}
PreparedShaderBuild ShaderBuildQueue::Build(uint64_t generation, unsigned outputWidth, unsigned outputHeight)
{
PreparedShaderBuild build;
build.generation = generation;
build.renderSnapshot = mRuntimeSnapshotProvider.PublishRenderStateSnapshot(outputWidth, outputHeight);
build.layers.reserve(build.renderSnapshot.states.size());
for (const RuntimeRenderState& state : build.renderSnapshot.states)
{
PreparedLayerShader layer;
layer.state = state;
if (!mRuntimeSnapshotProvider.BuildLayerPassFragmentShaderSources(state.layerId, layer.passes, build.message))
{
build.succeeded = false;
return build;
}
build.layers.push_back(std::move(layer));
}
build.succeeded = true;
build.message = "Shader layers prepared successfully.";
return build;
}
void ShaderBuildQueue::PublishBuildLifecycleEvent(const PreparedShaderBuild& build, unsigned outputWidth, unsigned outputHeight) const
{
ShaderBuildEvent event;
event.phase = build.succeeded ? RuntimeEventShaderBuildPhase::Prepared : RuntimeEventShaderBuildPhase::Failed;
event.generation = build.generation;
event.inputWidth = outputWidth;
event.inputHeight = outputHeight;
event.succeeded = build.succeeded;
event.message = build.message;
mRuntimeEventDispatcher.PublishPayload(event, "ShaderBuildQueue");
}