Clean up
This commit is contained in:
@@ -1,379 +0,0 @@
|
||||
#include "RuntimeLayerModel.h"
|
||||
|
||||
#include "RuntimeParameterUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
namespace RenderCadenceCompositor
|
||||
{
|
||||
bool RuntimeLayerModel::InitializeSingleLayer(const SupportedShaderCatalog& shaderCatalog, const std::string& shaderId, std::string& error)
|
||||
{
|
||||
Clear();
|
||||
if (shaderId.empty())
|
||||
{
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
const ShaderPackage* shaderPackage = shaderCatalog.FindPackage(shaderId);
|
||||
if (!shaderPackage)
|
||||
{
|
||||
error = "Shader '" + shaderId + "' is not in the supported shader catalog.";
|
||||
return false;
|
||||
}
|
||||
|
||||
Layer layer;
|
||||
layer.id = AllocateLayerId();
|
||||
layer.shaderId = shaderPackage->id;
|
||||
layer.shaderName = shaderPackage->displayName.empty() ? shaderPackage->id : shaderPackage->displayName;
|
||||
layer.buildState = RuntimeLayerBuildState::Pending;
|
||||
layer.message = "Runtime Slang build is waiting to start.";
|
||||
InitializeDefaultParameterValues(layer, *shaderPackage);
|
||||
mLayers.push_back(std::move(layer));
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::AddLayer(const SupportedShaderCatalog& shaderCatalog, const std::string& shaderId, std::string& layerId, std::string& error)
|
||||
{
|
||||
const ShaderPackage* shaderPackage = shaderCatalog.FindPackage(shaderId);
|
||||
if (!shaderPackage)
|
||||
{
|
||||
error = "Shader '" + shaderId + "' is not in the supported shader catalog.";
|
||||
return false;
|
||||
}
|
||||
|
||||
Layer layer;
|
||||
layer.id = AllocateLayerId();
|
||||
layer.shaderId = shaderPackage->id;
|
||||
layer.shaderName = shaderPackage->displayName.empty() ? shaderPackage->id : shaderPackage->displayName;
|
||||
layer.buildState = RuntimeLayerBuildState::Pending;
|
||||
layer.message = "Runtime Slang build is waiting to start.";
|
||||
InitializeDefaultParameterValues(layer, *shaderPackage);
|
||||
layerId = layer.id;
|
||||
mLayers.push_back(std::move(layer));
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::RemoveLayer(const std::string& layerId, std::string& error)
|
||||
{
|
||||
for (auto layerIt = mLayers.begin(); layerIt != mLayers.end(); ++layerIt)
|
||||
{
|
||||
if (layerIt->id != layerId)
|
||||
continue;
|
||||
|
||||
mLayers.erase(layerIt);
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
error = "Unknown runtime layer id: " + layerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::ReorderLayer(const std::string& layerId, int targetIndex, std::string& error)
|
||||
{
|
||||
auto layerIt = std::find_if(mLayers.begin(), mLayers.end(), [&layerId](const Layer& layer) {
|
||||
return layer.id == layerId;
|
||||
});
|
||||
if (layerIt == mLayers.end())
|
||||
{
|
||||
error = "Unknown runtime layer id: " + layerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetIndex < 0)
|
||||
targetIndex = 0;
|
||||
if (targetIndex >= static_cast<int>(mLayers.size()))
|
||||
targetIndex = static_cast<int>(mLayers.size()) - 1;
|
||||
|
||||
Layer layer = std::move(*layerIt);
|
||||
mLayers.erase(layerIt);
|
||||
std::size_t destinationIndex = static_cast<std::size_t>(targetIndex);
|
||||
if (destinationIndex > mLayers.size())
|
||||
destinationIndex = mLayers.size();
|
||||
mLayers.insert(mLayers.begin() + static_cast<std::ptrdiff_t>(destinationIndex), std::move(layer));
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::SetLayerBypass(const std::string& layerId, bool bypass, std::string& error)
|
||||
{
|
||||
Layer* layer = FindLayer(layerId);
|
||||
if (!layer)
|
||||
{
|
||||
error = "Unknown runtime layer id: " + layerId;
|
||||
return false;
|
||||
}
|
||||
layer->bypass = bypass;
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::SetLayerShader(const SupportedShaderCatalog& shaderCatalog, const std::string& layerId, const std::string& shaderId, std::string& error)
|
||||
{
|
||||
Layer* layer = FindLayer(layerId);
|
||||
if (!layer)
|
||||
{
|
||||
error = "Unknown runtime layer id: " + layerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
const ShaderPackage* shaderPackage = shaderCatalog.FindPackage(shaderId);
|
||||
if (!shaderPackage)
|
||||
{
|
||||
error = "Shader '" + shaderId + "' is not in the supported shader catalog.";
|
||||
return false;
|
||||
}
|
||||
|
||||
layer->shaderId = shaderPackage->id;
|
||||
layer->shaderName = shaderPackage->displayName.empty() ? shaderPackage->id : shaderPackage->displayName;
|
||||
layer->buildState = RuntimeLayerBuildState::Pending;
|
||||
layer->message = "Runtime Slang build is waiting to start.";
|
||||
layer->renderReady = false;
|
||||
layer->artifact = RuntimeShaderArtifact();
|
||||
InitializeDefaultParameterValues(*layer, *shaderPackage);
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::UpdateParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& value, std::string& error)
|
||||
{
|
||||
Layer* layer = FindLayer(layerId);
|
||||
if (!layer)
|
||||
{
|
||||
error = "Unknown runtime layer id: " + layerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
const ShaderParameterDefinition* definition = FindParameterDefinition(*layer, parameterId);
|
||||
if (!definition)
|
||||
{
|
||||
error = "Unknown parameter id '" + parameterId + "' for layer " + layerId + ".";
|
||||
return false;
|
||||
}
|
||||
|
||||
ShaderParameterValue normalizedValue;
|
||||
if (definition->type == ShaderParameterType::Trigger)
|
||||
{
|
||||
const auto currentIt = layer->parameterValues.find(parameterId);
|
||||
const double previousCount = currentIt == layer->parameterValues.end() || currentIt->second.numberValues.empty()
|
||||
? 0.0
|
||||
: currentIt->second.numberValues.front();
|
||||
normalizedValue.numberValues = { previousCount + 1.0, RuntimeElapsedSeconds() };
|
||||
}
|
||||
else if (!NormalizeAndValidateParameterValue(*definition, value, normalizedValue, error))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
layer->parameterValues[parameterId] = normalizedValue;
|
||||
if (layer->renderReady)
|
||||
layer->artifact.parameterValues = layer->parameterValues;
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::ResetParameters(const std::string& layerId, std::string& error)
|
||||
{
|
||||
Layer* layer = FindLayer(layerId);
|
||||
if (!layer)
|
||||
{
|
||||
error = "Unknown runtime layer id: " + layerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
layer->parameterValues.clear();
|
||||
for (const ShaderParameterDefinition& definition : layer->parameterDefinitions)
|
||||
layer->parameterValues[definition.id] = DefaultValueForDefinition(definition);
|
||||
if (layer->renderReady)
|
||||
layer->artifact.parameterValues = layer->parameterValues;
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuntimeLayerModel::Clear()
|
||||
{
|
||||
mLayers.clear();
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::MarkBuildStarted(const std::string& layerId, const std::string& message, std::string& error)
|
||||
{
|
||||
Layer* layer = FindLayer(layerId);
|
||||
if (!layer)
|
||||
{
|
||||
error = "Unknown runtime layer id: " + layerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
layer->buildState = RuntimeLayerBuildState::Pending;
|
||||
layer->message = message;
|
||||
layer->renderReady = false;
|
||||
layer->artifact = RuntimeShaderArtifact();
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::MarkBuildReady(const RuntimeShaderArtifact& artifact, std::string& error)
|
||||
{
|
||||
Layer* layer = artifact.layerId.empty() ? FindFirstLayerForShader(artifact.shaderId) : FindLayer(artifact.layerId);
|
||||
if (!layer)
|
||||
{
|
||||
error = artifact.layerId.empty()
|
||||
? "No runtime layer is waiting for shader artifact: " + artifact.shaderId
|
||||
: "No runtime layer is waiting for shader artifact on layer: " + artifact.layerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
layer->shaderName = artifact.displayName.empty() ? artifact.shaderId : artifact.displayName;
|
||||
layer->buildState = RuntimeLayerBuildState::Ready;
|
||||
layer->message = artifact.message;
|
||||
layer->renderReady = true;
|
||||
layer->artifact = artifact;
|
||||
layer->artifact.parameterValues = layer->parameterValues;
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::MarkBuildFailedForShader(const std::string& shaderId, const std::string& message)
|
||||
{
|
||||
Layer* layer = FindFirstLayerForShader(shaderId);
|
||||
if (!layer)
|
||||
return false;
|
||||
|
||||
std::string error;
|
||||
return MarkBuildFailed(layer->id, message, error);
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::MarkBuildFailed(const std::string& layerId, const std::string& message, std::string& error)
|
||||
{
|
||||
Layer* layer = FindLayer(layerId);
|
||||
if (!layer)
|
||||
{
|
||||
error = "Unknown runtime layer id: " + layerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
layer->buildState = RuntimeLayerBuildState::Failed;
|
||||
layer->message = message;
|
||||
layer->renderReady = false;
|
||||
layer->artifact = RuntimeShaderArtifact();
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeLayerModel::MarkRenderCommitFailed(const std::string& layerId, const std::string& message, std::string& error)
|
||||
{
|
||||
return MarkBuildFailed(layerId, message, error);
|
||||
}
|
||||
|
||||
RuntimeLayerModelSnapshot RuntimeLayerModel::Snapshot() const
|
||||
{
|
||||
RuntimeLayerModelSnapshot snapshot;
|
||||
snapshot.compileSucceeded = true;
|
||||
|
||||
for (const Layer& layer : mLayers)
|
||||
{
|
||||
snapshot.displayLayers.push_back(ToReadModel(layer));
|
||||
if (!layer.message.empty() && snapshot.compileMessage.empty())
|
||||
snapshot.compileMessage = layer.message;
|
||||
if (layer.buildState == RuntimeLayerBuildState::Failed)
|
||||
snapshot.compileSucceeded = false;
|
||||
if (layer.renderReady)
|
||||
{
|
||||
RuntimeRenderLayerModel renderLayer;
|
||||
renderLayer.id = layer.id;
|
||||
renderLayer.shaderId = layer.shaderId;
|
||||
renderLayer.bypass = layer.bypass;
|
||||
renderLayer.artifact = layer.artifact;
|
||||
renderLayer.artifact.parameterValues = layer.parameterValues;
|
||||
snapshot.renderLayers.push_back(std::move(renderLayer));
|
||||
}
|
||||
}
|
||||
|
||||
if (snapshot.compileMessage.empty())
|
||||
snapshot.compileMessage = mLayers.empty() ? "Runtime shader build disabled." : "Runtime shader build has not completed yet.";
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
std::string RuntimeLayerModel::FirstLayerId() const
|
||||
{
|
||||
return mLayers.empty() ? std::string() : mLayers.front().id;
|
||||
}
|
||||
|
||||
RuntimeLayerModel::Layer* RuntimeLayerModel::FindLayer(const std::string& layerId)
|
||||
{
|
||||
for (Layer& layer : mLayers)
|
||||
{
|
||||
if (layer.id == layerId)
|
||||
return &layer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const RuntimeLayerModel::Layer* RuntimeLayerModel::FindLayer(const std::string& layerId) const
|
||||
{
|
||||
for (const Layer& layer : mLayers)
|
||||
{
|
||||
if (layer.id == layerId)
|
||||
return &layer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RuntimeLayerModel::Layer* RuntimeLayerModel::FindFirstLayerForShader(const std::string& shaderId)
|
||||
{
|
||||
for (Layer& layer : mLayers)
|
||||
{
|
||||
if (layer.shaderId == shaderId)
|
||||
return &layer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RuntimeLayerModel::InitializeDefaultParameterValues(Layer& layer, const ShaderPackage& shaderPackage)
|
||||
{
|
||||
layer.parameterDefinitions = shaderPackage.parameters;
|
||||
layer.parameterValues.clear();
|
||||
for (const ShaderParameterDefinition& definition : layer.parameterDefinitions)
|
||||
layer.parameterValues[definition.id] = DefaultValueForDefinition(definition);
|
||||
}
|
||||
|
||||
const ShaderParameterDefinition* RuntimeLayerModel::FindParameterDefinition(const Layer& layer, const std::string& parameterId)
|
||||
{
|
||||
for (const ShaderParameterDefinition& definition : layer.parameterDefinitions)
|
||||
{
|
||||
if (definition.id == parameterId)
|
||||
return &definition;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string RuntimeLayerModel::AllocateLayerId()
|
||||
{
|
||||
return "runtime-layer-" + std::to_string(mNextLayerNumber++);
|
||||
}
|
||||
|
||||
RuntimeLayerReadModel RuntimeLayerModel::ToReadModel(const Layer& layer)
|
||||
{
|
||||
RuntimeLayerReadModel readModel;
|
||||
readModel.id = layer.id;
|
||||
readModel.shaderId = layer.shaderId;
|
||||
readModel.shaderName = layer.shaderName;
|
||||
readModel.bypass = layer.bypass;
|
||||
readModel.buildState = layer.buildState;
|
||||
readModel.message = layer.message;
|
||||
readModel.renderReady = layer.renderReady;
|
||||
readModel.parameterDefinitions = layer.parameterDefinitions;
|
||||
readModel.parameterValues = layer.parameterValues;
|
||||
return readModel;
|
||||
}
|
||||
|
||||
double RuntimeLayerModel::RuntimeElapsedSeconds() const
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mStartTime).count();
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RuntimeJson.h"
|
||||
#include "RuntimeShaderArtifact.h"
|
||||
#include "SupportedShaderCatalog.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace RenderCadenceCompositor
|
||||
{
|
||||
enum class RuntimeLayerBuildState
|
||||
{
|
||||
Pending,
|
||||
Ready,
|
||||
Failed
|
||||
};
|
||||
|
||||
struct RuntimeLayerReadModel
|
||||
{
|
||||
std::string id;
|
||||
std::string shaderId;
|
||||
std::string shaderName;
|
||||
bool bypass = false;
|
||||
RuntimeLayerBuildState buildState = RuntimeLayerBuildState::Pending;
|
||||
std::string message;
|
||||
bool renderReady = false;
|
||||
std::vector<ShaderParameterDefinition> parameterDefinitions;
|
||||
std::map<std::string, ShaderParameterValue> parameterValues;
|
||||
};
|
||||
|
||||
struct RuntimeRenderLayerModel
|
||||
{
|
||||
std::string id;
|
||||
std::string shaderId;
|
||||
bool bypass = false;
|
||||
RuntimeShaderArtifact artifact;
|
||||
};
|
||||
|
||||
struct RuntimeLayerModelSnapshot
|
||||
{
|
||||
bool compileSucceeded = true;
|
||||
std::string compileMessage;
|
||||
std::vector<RuntimeLayerReadModel> displayLayers;
|
||||
std::vector<RuntimeRenderLayerModel> renderLayers;
|
||||
};
|
||||
|
||||
class RuntimeLayerModel
|
||||
{
|
||||
public:
|
||||
bool InitializeSingleLayer(const SupportedShaderCatalog& shaderCatalog, const std::string& shaderId, std::string& error);
|
||||
void Clear();
|
||||
|
||||
bool AddLayer(const SupportedShaderCatalog& shaderCatalog, const std::string& shaderId, std::string& layerId, std::string& error);
|
||||
bool RemoveLayer(const std::string& layerId, std::string& error);
|
||||
bool ReorderLayer(const std::string& layerId, int targetIndex, std::string& error);
|
||||
bool SetLayerBypass(const std::string& layerId, bool bypass, std::string& error);
|
||||
bool SetLayerShader(const SupportedShaderCatalog& shaderCatalog, const std::string& layerId, const std::string& shaderId, std::string& error);
|
||||
bool UpdateParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& value, std::string& error);
|
||||
bool ResetParameters(const std::string& layerId, std::string& error);
|
||||
bool MarkBuildStarted(const std::string& layerId, const std::string& message, std::string& error);
|
||||
bool MarkBuildReady(const RuntimeShaderArtifact& artifact, std::string& error);
|
||||
bool MarkBuildFailedForShader(const std::string& shaderId, const std::string& message);
|
||||
bool MarkBuildFailed(const std::string& layerId, const std::string& message, std::string& error);
|
||||
bool MarkRenderCommitFailed(const std::string& layerId, const std::string& message, std::string& error);
|
||||
|
||||
RuntimeLayerModelSnapshot Snapshot() const;
|
||||
std::string FirstLayerId() const;
|
||||
|
||||
private:
|
||||
struct Layer
|
||||
{
|
||||
std::string id;
|
||||
std::string shaderId;
|
||||
std::string shaderName;
|
||||
bool bypass = false;
|
||||
RuntimeLayerBuildState buildState = RuntimeLayerBuildState::Pending;
|
||||
std::string message;
|
||||
bool renderReady = false;
|
||||
std::vector<ShaderParameterDefinition> parameterDefinitions;
|
||||
std::map<std::string, ShaderParameterValue> parameterValues;
|
||||
RuntimeShaderArtifact artifact;
|
||||
};
|
||||
|
||||
Layer* FindLayer(const std::string& layerId);
|
||||
const Layer* FindLayer(const std::string& layerId) const;
|
||||
Layer* FindFirstLayerForShader(const std::string& shaderId);
|
||||
static void InitializeDefaultParameterValues(Layer& layer, const ShaderPackage& shaderPackage);
|
||||
static const ShaderParameterDefinition* FindParameterDefinition(const Layer& layer, const std::string& parameterId);
|
||||
std::string AllocateLayerId();
|
||||
static RuntimeLayerReadModel ToReadModel(const Layer& layer);
|
||||
double RuntimeElapsedSeconds() const;
|
||||
|
||||
std::vector<Layer> mLayers;
|
||||
uint64_t mNextLayerNumber = 1;
|
||||
std::chrono::steady_clock::time_point mStartTime = std::chrono::steady_clock::now();
|
||||
};
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ShaderTypes.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct RuntimeShaderPassArtifact
|
||||
{
|
||||
std::string passId;
|
||||
std::string fragmentShaderSource;
|
||||
std::vector<std::string> inputNames;
|
||||
std::string outputName;
|
||||
};
|
||||
|
||||
struct RuntimeShaderArtifact
|
||||
{
|
||||
std::string layerId;
|
||||
std::string shaderId;
|
||||
std::string displayName;
|
||||
std::string fragmentShaderSource;
|
||||
std::vector<RuntimeShaderPassArtifact> passes;
|
||||
std::string message;
|
||||
std::vector<ShaderParameterDefinition> parameterDefinitions;
|
||||
std::map<std::string, ShaderParameterValue> parameterValues;
|
||||
};
|
||||
@@ -1,75 +0,0 @@
|
||||
#include "RuntimeShaderBridge.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
RuntimeShaderBridge::~RuntimeShaderBridge()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void RuntimeShaderBridge::Start(const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError)
|
||||
{
|
||||
Start(std::string(), shaderId, std::move(onArtifactReady), std::move(onError));
|
||||
}
|
||||
|
||||
void RuntimeShaderBridge::Start(const std::string& layerId, const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError)
|
||||
{
|
||||
Stop();
|
||||
if (shaderId.empty())
|
||||
return;
|
||||
|
||||
mLayerId = layerId;
|
||||
mOnArtifactReady = std::move(onArtifactReady);
|
||||
mOnError = std::move(onError);
|
||||
mStopping.store(false, std::memory_order_release);
|
||||
mFinished.store(false, std::memory_order_release);
|
||||
mCompiler.StartShaderBuild(shaderId);
|
||||
mThread = std::thread([this]() { ThreadMain(); });
|
||||
}
|
||||
|
||||
void RuntimeShaderBridge::RequestStop()
|
||||
{
|
||||
mStopping.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
void RuntimeShaderBridge::Stop()
|
||||
{
|
||||
RequestStop();
|
||||
if (mThread.joinable())
|
||||
mThread.join();
|
||||
mCompiler.Stop();
|
||||
mLayerId.clear();
|
||||
mOnArtifactReady = ArtifactCallback();
|
||||
mOnError = ErrorCallback();
|
||||
mFinished.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool RuntimeShaderBridge::CanStopWithoutWaiting() const
|
||||
{
|
||||
return mFinished.load(std::memory_order_acquire) && !mCompiler.Running();
|
||||
}
|
||||
|
||||
void RuntimeShaderBridge::ThreadMain()
|
||||
{
|
||||
while (!mStopping.load(std::memory_order_acquire))
|
||||
{
|
||||
RuntimeSlangShaderBuild build;
|
||||
if (mCompiler.TryConsume(build))
|
||||
{
|
||||
if (build.succeeded)
|
||||
{
|
||||
build.artifact.layerId = mLayerId;
|
||||
if (mOnArtifactReady)
|
||||
mOnArtifactReady(build.artifact);
|
||||
}
|
||||
else if (mOnError)
|
||||
{
|
||||
mOnError(build.message);
|
||||
}
|
||||
mFinished.store(true, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
mFinished.store(true, std::memory_order_release);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RuntimeShaderArtifact.h"
|
||||
#include "RuntimeSlangShaderCompiler.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
class RuntimeShaderBridge
|
||||
{
|
||||
public:
|
||||
using ArtifactCallback = std::function<void(const RuntimeShaderArtifact&)>;
|
||||
using ErrorCallback = std::function<void(const std::string&)>;
|
||||
|
||||
RuntimeShaderBridge() = default;
|
||||
RuntimeShaderBridge(const RuntimeShaderBridge&) = delete;
|
||||
RuntimeShaderBridge& operator=(const RuntimeShaderBridge&) = delete;
|
||||
~RuntimeShaderBridge();
|
||||
|
||||
void Start(const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError);
|
||||
void Start(const std::string& layerId, const std::string& shaderId, ArtifactCallback onArtifactReady, ErrorCallback onError);
|
||||
void RequestStop();
|
||||
void Stop();
|
||||
bool CanStopWithoutWaiting() const;
|
||||
|
||||
private:
|
||||
void ThreadMain();
|
||||
|
||||
RuntimeSlangShaderCompiler mCompiler;
|
||||
std::thread mThread;
|
||||
std::atomic<bool> mStopping{ false };
|
||||
std::atomic<bool> mFinished{ true };
|
||||
std::string mLayerId;
|
||||
ArtifactCallback mOnArtifactReady;
|
||||
ErrorCallback mOnError;
|
||||
};
|
||||
@@ -1,159 +0,0 @@
|
||||
#include "RuntimeSlangShaderCompiler.h"
|
||||
|
||||
#include "ShaderCompiler.h"
|
||||
#include "ShaderPackageRegistry.h"
|
||||
#include "ShaderTypes.h"
|
||||
#include "SupportedShaderCatalog.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::filesystem::path FindRepoRoot()
|
||||
{
|
||||
std::filesystem::path current = std::filesystem::current_path();
|
||||
for (;;)
|
||||
{
|
||||
if (std::filesystem::exists(current / "shaders" / "happy-accident" / "shader.slang") &&
|
||||
std::filesystem::exists(current / "runtime" / "templates" / "shader_wrapper.slang.in"))
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
const std::filesystem::path parent = current.parent_path();
|
||||
if (parent.empty() || parent == current)
|
||||
return std::filesystem::current_path();
|
||||
current = parent;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RuntimeSlangShaderCompiler::~RuntimeSlangShaderCompiler()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void RuntimeSlangShaderCompiler::StartHappyAccidentBuild()
|
||||
{
|
||||
StartShaderBuild("happy-accident");
|
||||
}
|
||||
|
||||
void RuntimeSlangShaderCompiler::StartShaderBuild(const std::string& shaderId)
|
||||
{
|
||||
if (mRunning.load(std::memory_order_acquire))
|
||||
return;
|
||||
|
||||
if (mThread.joinable())
|
||||
mThread.join();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mReadyBuild = RuntimeSlangShaderBuild();
|
||||
}
|
||||
|
||||
mRunning.store(true, std::memory_order_release);
|
||||
mThread = std::thread([this, shaderId]() {
|
||||
RuntimeSlangShaderBuild build = BuildShader(shaderId);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
mReadyBuild = std::move(build);
|
||||
mReadyBuild.available = true;
|
||||
}
|
||||
mRunning.store(false, std::memory_order_release);
|
||||
});
|
||||
}
|
||||
|
||||
void RuntimeSlangShaderCompiler::Stop()
|
||||
{
|
||||
if (mThread.joinable())
|
||||
mThread.join();
|
||||
mRunning.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool RuntimeSlangShaderCompiler::TryConsume(RuntimeSlangShaderBuild& build)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
if (!mReadyBuild.available)
|
||||
return false;
|
||||
|
||||
build = std::move(mReadyBuild);
|
||||
mReadyBuild = RuntimeSlangShaderBuild();
|
||||
return true;
|
||||
}
|
||||
|
||||
RuntimeSlangShaderBuild RuntimeSlangShaderCompiler::BuildShader(const std::string& shaderId) const
|
||||
{
|
||||
RuntimeSlangShaderBuild build;
|
||||
build.artifact.shaderId = shaderId;
|
||||
|
||||
try
|
||||
{
|
||||
const std::filesystem::path repoRoot = FindRepoRoot();
|
||||
const std::filesystem::path shaderDir = repoRoot / "shaders" / shaderId;
|
||||
const std::filesystem::path runtimeBuildDir = repoRoot / "runtime" / "generated" / "render-cadence-compositor";
|
||||
|
||||
ShaderPackageRegistry registry(0);
|
||||
ShaderPackage shaderPackage;
|
||||
std::string error;
|
||||
if (!registry.ParseManifest(shaderDir / "shader.json", shaderPackage, error))
|
||||
{
|
||||
build.succeeded = false;
|
||||
build.message = error.empty() ? "Shader manifest parse failed." : error;
|
||||
return build;
|
||||
}
|
||||
const RenderCadenceCompositor::ShaderSupportResult support =
|
||||
RenderCadenceCompositor::CheckStatelessSinglePassShaderSupport(shaderPackage);
|
||||
if (!support.supported)
|
||||
{
|
||||
build.succeeded = false;
|
||||
build.message = support.reason;
|
||||
return build;
|
||||
}
|
||||
|
||||
ShaderCompiler compiler(
|
||||
repoRoot,
|
||||
runtimeBuildDir / (shaderId + ".wrapper.slang"),
|
||||
runtimeBuildDir / (shaderId + ".generated.glsl"),
|
||||
runtimeBuildDir / (shaderId + ".patched.glsl"),
|
||||
0);
|
||||
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
for (const ShaderPassDefinition& pass : shaderPackage.passes)
|
||||
{
|
||||
std::string fragmentShaderSource;
|
||||
if (!compiler.BuildPassFragmentShaderSource(shaderPackage, pass, fragmentShaderSource, error))
|
||||
{
|
||||
build.succeeded = false;
|
||||
build.message = error.empty() ? "Slang compile failed." : error;
|
||||
return build;
|
||||
}
|
||||
|
||||
RuntimeShaderPassArtifact passArtifact;
|
||||
passArtifact.passId = pass.id;
|
||||
passArtifact.fragmentShaderSource = std::move(fragmentShaderSource);
|
||||
passArtifact.inputNames = pass.inputNames;
|
||||
passArtifact.outputName = pass.outputName;
|
||||
build.artifact.passes.push_back(std::move(passArtifact));
|
||||
}
|
||||
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
const double milliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(end - start).count();
|
||||
build.succeeded = true;
|
||||
build.artifact.shaderId = shaderPackage.id;
|
||||
build.artifact.displayName = shaderPackage.displayName;
|
||||
build.artifact.parameterDefinitions = shaderPackage.parameters;
|
||||
if (!build.artifact.passes.empty())
|
||||
build.artifact.fragmentShaderSource = build.artifact.passes.front().fragmentShaderSource;
|
||||
build.artifact.message = shaderPackage.displayName + " Slang compile completed in " + std::to_string(milliseconds) + " ms.";
|
||||
build.message = build.artifact.message;
|
||||
return build;
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
build.succeeded = false;
|
||||
build.message = exception.what();
|
||||
return build;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RuntimeShaderArtifact.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
struct RuntimeSlangShaderBuild
|
||||
{
|
||||
bool available = false;
|
||||
bool succeeded = false;
|
||||
RuntimeShaderArtifact artifact;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
class RuntimeSlangShaderCompiler
|
||||
{
|
||||
public:
|
||||
RuntimeSlangShaderCompiler() = default;
|
||||
RuntimeSlangShaderCompiler(const RuntimeSlangShaderCompiler&) = delete;
|
||||
RuntimeSlangShaderCompiler& operator=(const RuntimeSlangShaderCompiler&) = delete;
|
||||
~RuntimeSlangShaderCompiler();
|
||||
|
||||
void StartHappyAccidentBuild();
|
||||
void StartShaderBuild(const std::string& shaderId);
|
||||
void Stop();
|
||||
bool TryConsume(RuntimeSlangShaderBuild& build);
|
||||
bool Running() const { return mRunning.load(std::memory_order_acquire); }
|
||||
|
||||
private:
|
||||
RuntimeSlangShaderBuild BuildShader(const std::string& shaderId) const;
|
||||
|
||||
std::thread mThread;
|
||||
std::atomic<bool> mRunning{ false };
|
||||
std::mutex mMutex;
|
||||
RuntimeSlangShaderBuild mReadyBuild;
|
||||
};
|
||||
@@ -1,112 +0,0 @@
|
||||
#include "SupportedShaderCatalog.h"
|
||||
|
||||
#include "ShaderPackageRegistry.h"
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace RenderCadenceCompositor
|
||||
{
|
||||
ShaderSupportResult CheckStatelessSinglePassShaderSupport(const ShaderPackage& shaderPackage)
|
||||
{
|
||||
if (shaderPackage.passes.empty())
|
||||
return { false, "Shader package has no render passes." };
|
||||
|
||||
if (shaderPackage.temporal.enabled)
|
||||
return { false, "RenderCadenceCompositor currently supports only stateless shaders; temporal history is not enabled in this app." };
|
||||
|
||||
if (shaderPackage.feedback.enabled)
|
||||
return { false, "RenderCadenceCompositor currently supports only stateless shaders; feedback storage is not enabled in this app." };
|
||||
|
||||
if (!shaderPackage.textureAssets.empty())
|
||||
return { false, "RenderCadenceCompositor does not load shader texture assets yet; texture-backed shaders need a CPU-prepared asset handoff first." };
|
||||
|
||||
if (!shaderPackage.fontAssets.empty())
|
||||
return { false, "RenderCadenceCompositor does not load shader font assets yet; text shaders need a CPU-prepared asset handoff first." };
|
||||
|
||||
for (const ShaderParameterDefinition& parameter : shaderPackage.parameters)
|
||||
{
|
||||
if (parameter.type == ShaderParameterType::Text)
|
||||
return { false, "RenderCadenceCompositor currently skips text parameters because they require per-shader text texture storage." };
|
||||
}
|
||||
|
||||
bool writesLayerOutput = false;
|
||||
for (const ShaderPassDefinition& pass : shaderPackage.passes)
|
||||
{
|
||||
if (pass.sourcePath.empty())
|
||||
{
|
||||
return { false, "Shader pass '" + pass.id + "' has no source." };
|
||||
}
|
||||
if (pass.outputName == "layerOutput")
|
||||
writesLayerOutput = true;
|
||||
for (const std::string& inputName : pass.inputNames)
|
||||
{
|
||||
if (inputName == "videoInput" || inputName == "layerInput")
|
||||
continue;
|
||||
bool matchesNamedOutput = false;
|
||||
for (const ShaderPassDefinition& outputPass : shaderPackage.passes)
|
||||
{
|
||||
if (outputPass.outputName == inputName)
|
||||
{
|
||||
matchesNamedOutput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matchesNamedOutput)
|
||||
return { false, "Shader pass '" + pass.id + "' references unknown input '" + inputName + "'." };
|
||||
}
|
||||
}
|
||||
if (!writesLayerOutput)
|
||||
return { false, "Shader package must write a pass output named 'layerOutput'." };
|
||||
|
||||
return { true, std::string() };
|
||||
}
|
||||
|
||||
bool SupportedShaderCatalog::Load(const std::filesystem::path& shaderRoot, unsigned maxTemporalHistoryFrames, std::string& error)
|
||||
{
|
||||
mShaders.clear();
|
||||
mPackagesById.clear();
|
||||
|
||||
if (shaderRoot.empty())
|
||||
{
|
||||
error = "Shader library path is empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
ShaderPackageRegistry registry(maxTemporalHistoryFrames);
|
||||
std::map<std::string, ShaderPackage> packagesById;
|
||||
std::vector<std::string> packageOrder;
|
||||
std::vector<ShaderPackageStatus> packageStatuses;
|
||||
if (!registry.Scan(shaderRoot, packagesById, packageOrder, packageStatuses, error))
|
||||
return false;
|
||||
|
||||
for (const std::string& packageId : packageOrder)
|
||||
{
|
||||
const auto packageIt = packagesById.find(packageId);
|
||||
if (packageIt == packagesById.end())
|
||||
continue;
|
||||
|
||||
const ShaderPackage& shaderPackage = packageIt->second;
|
||||
const ShaderSupportResult support = CheckStatelessSinglePassShaderSupport(shaderPackage);
|
||||
if (!support.supported)
|
||||
continue;
|
||||
|
||||
SupportedShaderSummary summary;
|
||||
summary.id = shaderPackage.id;
|
||||
summary.name = shaderPackage.displayName.empty() ? shaderPackage.id : shaderPackage.displayName;
|
||||
summary.description = shaderPackage.description;
|
||||
summary.category = shaderPackage.category;
|
||||
mShaders.push_back(std::move(summary));
|
||||
mPackagesById[shaderPackage.id] = shaderPackage;
|
||||
}
|
||||
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
const ShaderPackage* SupportedShaderCatalog::FindPackage(const std::string& shaderId) const
|
||||
{
|
||||
const auto packageIt = mPackagesById.find(shaderId);
|
||||
return packageIt == mPackagesById.end() ? nullptr : &packageIt->second;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ShaderTypes.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace RenderCadenceCompositor
|
||||
{
|
||||
struct SupportedShaderSummary
|
||||
{
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string category;
|
||||
};
|
||||
|
||||
struct ShaderSupportResult
|
||||
{
|
||||
bool supported = false;
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
ShaderSupportResult CheckStatelessSinglePassShaderSupport(const ShaderPackage& shaderPackage);
|
||||
|
||||
class SupportedShaderCatalog
|
||||
{
|
||||
public:
|
||||
bool Load(const std::filesystem::path& shaderRoot, unsigned maxTemporalHistoryFrames, std::string& error);
|
||||
const std::vector<SupportedShaderSummary>& Shaders() const { return mShaders; }
|
||||
const ShaderPackage* FindPackage(const std::string& shaderId) const;
|
||||
|
||||
private:
|
||||
std::vector<SupportedShaderSummary> mShaders;
|
||||
std::map<std::string, ShaderPackage> mPackagesById;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user