Runtime layer split
This commit is contained in:
@@ -5,73 +5,10 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cctype>
|
|
||||||
#include <set>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace RenderCadenceCompositor
|
namespace RenderCadenceCompositor
|
||||||
{
|
{
|
||||||
namespace
|
|
||||||
{
|
|
||||||
JsonValue ParameterValueToJson(const ShaderParameterDefinition& definition, const ShaderParameterValue& value)
|
|
||||||
{
|
|
||||||
switch (definition.type)
|
|
||||||
{
|
|
||||||
case ShaderParameterType::Float:
|
|
||||||
return JsonValue(value.numberValues.empty() ? 0.0 : value.numberValues.front());
|
|
||||||
case ShaderParameterType::Vec2:
|
|
||||||
case ShaderParameterType::Color:
|
|
||||||
{
|
|
||||||
JsonValue array = JsonValue::MakeArray();
|
|
||||||
for (double number : value.numberValues)
|
|
||||||
array.pushBack(JsonValue(number));
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
case ShaderParameterType::Boolean:
|
|
||||||
return JsonValue(value.booleanValue);
|
|
||||||
case ShaderParameterType::Enum:
|
|
||||||
return JsonValue(value.enumValue);
|
|
||||||
case ShaderParameterType::Text:
|
|
||||||
return JsonValue(value.textValue);
|
|
||||||
case ShaderParameterType::Trigger:
|
|
||||||
return JsonValue(value.numberValues.empty() ? 0.0 : value.numberValues.front());
|
|
||||||
}
|
|
||||||
return JsonValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ParseRuntimeLayerNumber(const std::string& layerId, uint64_t& number)
|
|
||||||
{
|
|
||||||
const std::string prefix = "runtime-layer-";
|
|
||||||
if (layerId.compare(0, prefix.size(), prefix) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const std::string suffix = layerId.substr(prefix.size());
|
|
||||||
if (suffix.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint64_t parsed = 0;
|
|
||||||
for (char character : suffix)
|
|
||||||
{
|
|
||||||
if (!std::isdigit(static_cast<unsigned char>(character)))
|
|
||||||
return false;
|
|
||||||
parsed = parsed * 10 + static_cast<uint64_t>(character - '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
number = parsed;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AllocateRestoredLayerId(std::set<std::string>& usedLayerIds, uint64_t& nextLayerNumber)
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
std::string candidate = "runtime-layer-" + std::to_string(nextLayerNumber++);
|
|
||||||
if (usedLayerIds.insert(candidate).second)
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeLayerModel::InitializeSingleLayer(const SupportedShaderCatalog& shaderCatalog, const std::string& shaderId, std::string& error)
|
bool RuntimeLayerModel::InitializeSingleLayer(const SupportedShaderCatalog& shaderCatalog, const std::string& shaderId, std::string& error)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
@@ -270,145 +207,6 @@ bool RuntimeLayerModel::ResetParameters(const std::string& layerId, std::string&
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeLayerModel::InitializeFromRuntimeState(const SupportedShaderCatalog& shaderCatalog, const JsonValue& runtimeState, std::string& error)
|
|
||||||
{
|
|
||||||
if (!runtimeState.isObject())
|
|
||||||
{
|
|
||||||
error = "Runtime state root must be a JSON object.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const JsonValue* layersValue = runtimeState.find("layers");
|
|
||||||
if (!layersValue || !layersValue->isArray())
|
|
||||||
{
|
|
||||||
error = "Runtime state must contain a layers array.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Layer> restoredLayers;
|
|
||||||
std::set<std::string> usedLayerIds;
|
|
||||||
uint64_t nextLayerNumber = 1;
|
|
||||||
|
|
||||||
for (const JsonValue& layerValue : layersValue->asArray())
|
|
||||||
{
|
|
||||||
if (!layerValue.isObject())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const JsonValue* shaderIdValue = layerValue.find("shaderId");
|
|
||||||
if (!shaderIdValue || !shaderIdValue->isString() || shaderIdValue->asString().empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const ShaderPackage* shaderPackage = shaderCatalog.FindPackage(shaderIdValue->asString());
|
|
||||||
if (!shaderPackage)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Layer layer;
|
|
||||||
const JsonValue* layerIdValue = layerValue.find("id");
|
|
||||||
if (layerIdValue && layerIdValue->isString() && !layerIdValue->asString().empty() && usedLayerIds.insert(layerIdValue->asString()).second)
|
|
||||||
layer.id = layerIdValue->asString();
|
|
||||||
else
|
|
||||||
layer.id = AllocateRestoredLayerId(usedLayerIds, nextLayerNumber);
|
|
||||||
|
|
||||||
uint64_t restoredLayerNumber = 0;
|
|
||||||
if (ParseRuntimeLayerNumber(layer.id, restoredLayerNumber) && restoredLayerNumber >= nextLayerNumber)
|
|
||||||
nextLayerNumber = restoredLayerNumber + 1;
|
|
||||||
|
|
||||||
layer.shaderId = shaderPackage->id;
|
|
||||||
layer.packageFingerprint = ShaderPackageFingerprint(*shaderPackage);
|
|
||||||
layer.shaderName = shaderPackage->displayName.empty() ? shaderPackage->id : shaderPackage->displayName;
|
|
||||||
const JsonValue* bypassValue = layerValue.find("bypass");
|
|
||||||
layer.bypass = bypassValue && bypassValue->isBoolean() ? bypassValue->asBoolean() : false;
|
|
||||||
layer.buildState = RuntimeLayerBuildState::Pending;
|
|
||||||
layer.message = "Runtime Slang build is waiting to start.";
|
|
||||||
InitializeDefaultParameterValues(layer, *shaderPackage);
|
|
||||||
|
|
||||||
const JsonValue* parameterValues = layerValue.find("parameterValues");
|
|
||||||
if (parameterValues && parameterValues->isObject())
|
|
||||||
{
|
|
||||||
for (const ShaderParameterDefinition& definition : layer.parameterDefinitions)
|
|
||||||
{
|
|
||||||
const JsonValue* value = parameterValues->find(definition.id);
|
|
||||||
if (!value)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ShaderParameterValue normalizedValue;
|
|
||||||
std::string normalizeError;
|
|
||||||
if (NormalizeAndValidateParameterValue(definition, *value, normalizedValue, normalizeError))
|
|
||||||
layer.parameterValues[definition.id] = normalizedValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
restoredLayers.push_back(std::move(layer));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restoredLayers.empty())
|
|
||||||
{
|
|
||||||
error = "Runtime state did not contain any supported layers.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mLayers = std::move(restoredLayers);
|
|
||||||
mNextLayerNumber = nextLayerNumber;
|
|
||||||
error.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeLayerModel::ReloadFromCatalog(const SupportedShaderCatalog& shaderCatalog, std::vector<std::pair<std::string, std::string>>& buildsToStart, std::string& error)
|
|
||||||
{
|
|
||||||
buildsToStart.clear();
|
|
||||||
for (Layer& layer : mLayers)
|
|
||||||
{
|
|
||||||
const ShaderPackage* shaderPackage = shaderCatalog.FindPackage(layer.shaderId);
|
|
||||||
if (!shaderPackage)
|
|
||||||
{
|
|
||||||
layer.buildState = RuntimeLayerBuildState::Failed;
|
|
||||||
layer.message = "Shader '" + layer.shaderId + "' is no longer available after reload.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string nextFingerprint = ShaderPackageFingerprint(*shaderPackage);
|
|
||||||
if (layer.packageFingerprint == nextFingerprint)
|
|
||||||
{
|
|
||||||
buildsToStart.push_back({ layer.id, layer.shaderId });
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, ShaderParameterDefinition> previousDefinitions;
|
|
||||||
for (const ShaderParameterDefinition& definition : layer.parameterDefinitions)
|
|
||||||
previousDefinitions[definition.id] = definition;
|
|
||||||
|
|
||||||
std::map<std::string, ShaderParameterValue> nextValues;
|
|
||||||
for (const ShaderParameterDefinition& nextDefinition : shaderPackage->parameters)
|
|
||||||
{
|
|
||||||
const auto previousDefinitionIt = previousDefinitions.find(nextDefinition.id);
|
|
||||||
const auto previousValueIt = layer.parameterValues.find(nextDefinition.id);
|
|
||||||
if (previousDefinitionIt != previousDefinitions.end()
|
|
||||||
&& previousValueIt != layer.parameterValues.end()
|
|
||||||
&& previousDefinitionIt->second.type == nextDefinition.type)
|
|
||||||
{
|
|
||||||
ShaderParameterValue preservedValue;
|
|
||||||
JsonValue valueJson = ParameterValueToJson(previousDefinitionIt->second, previousValueIt->second);
|
|
||||||
std::string normalizeError;
|
|
||||||
if (NormalizeAndValidateParameterValue(nextDefinition, valueJson, preservedValue, normalizeError))
|
|
||||||
{
|
|
||||||
nextValues[nextDefinition.id] = preservedValue;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nextValues[nextDefinition.id] = DefaultValueForDefinition(nextDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.shaderName = shaderPackage->displayName.empty() ? shaderPackage->id : shaderPackage->displayName;
|
|
||||||
layer.packageFingerprint = nextFingerprint;
|
|
||||||
layer.parameterDefinitions = shaderPackage->parameters;
|
|
||||||
layer.parameterValues = std::move(nextValues);
|
|
||||||
buildsToStart.push_back({ layer.id, layer.shaderId });
|
|
||||||
}
|
|
||||||
|
|
||||||
error.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeLayerModel::Clear()
|
void RuntimeLayerModel::Clear()
|
||||||
{
|
{
|
||||||
mLayers.clear();
|
mLayers.clear();
|
||||||
@@ -508,37 +306,6 @@ bool RuntimeLayerModel::MarkRenderCommitFailed(const std::string& layerId, const
|
|||||||
return MarkBuildFailed(layerId, message, 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.bypass = layer.bypass;
|
|
||||||
renderLayer.artifact = layer.artifact;
|
|
||||||
renderLayer.shaderId = renderLayer.artifact.shaderId.empty() ? layer.shaderId : renderLayer.artifact.shaderId;
|
|
||||||
if (layer.buildState == RuntimeLayerBuildState::Ready)
|
|
||||||
renderLayer.artifact.parameterValues = layer.parameterValues;
|
|
||||||
renderLayer.artifact.fontAtlases.clear();
|
|
||||||
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
|
std::string RuntimeLayerModel::FirstLayerId() const
|
||||||
{
|
{
|
||||||
return mLayers.empty() ? std::string() : mLayers.front().id;
|
return mLayers.empty() ? std::string() : mLayers.front().id;
|
||||||
@@ -608,21 +375,6 @@ std::string RuntimeLayerModel::AllocateLayerId()
|
|||||||
return "runtime-layer-" + std::to_string(mNextLayerNumber++);
|
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
|
double RuntimeLayerModel::RuntimeElapsedSeconds() const
|
||||||
{
|
{
|
||||||
return std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mStartTime).count();
|
return std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mStartTime).count();
|
||||||
|
|||||||
94
src/runtime/RuntimeLayerReload.cpp
Normal file
94
src/runtime/RuntimeLayerReload.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#include "RuntimeLayerModel.h"
|
||||||
|
|
||||||
|
#include "RuntimeParameterUtils.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace RenderCadenceCompositor
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
JsonValue ParameterValueToJson(const ShaderParameterDefinition& definition, const ShaderParameterValue& value)
|
||||||
|
{
|
||||||
|
switch (definition.type)
|
||||||
|
{
|
||||||
|
case ShaderParameterType::Float:
|
||||||
|
return JsonValue(value.numberValues.empty() ? 0.0 : value.numberValues.front());
|
||||||
|
case ShaderParameterType::Vec2:
|
||||||
|
case ShaderParameterType::Color:
|
||||||
|
{
|
||||||
|
JsonValue array = JsonValue::MakeArray();
|
||||||
|
for (double number : value.numberValues)
|
||||||
|
array.pushBack(JsonValue(number));
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
case ShaderParameterType::Boolean:
|
||||||
|
return JsonValue(value.booleanValue);
|
||||||
|
case ShaderParameterType::Enum:
|
||||||
|
return JsonValue(value.enumValue);
|
||||||
|
case ShaderParameterType::Text:
|
||||||
|
return JsonValue(value.textValue);
|
||||||
|
case ShaderParameterType::Trigger:
|
||||||
|
return JsonValue(value.numberValues.empty() ? 0.0 : value.numberValues.front());
|
||||||
|
}
|
||||||
|
return JsonValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeLayerModel::ReloadFromCatalog(const SupportedShaderCatalog& shaderCatalog, std::vector<std::pair<std::string, std::string>>& buildsToStart, std::string& error)
|
||||||
|
{
|
||||||
|
buildsToStart.clear();
|
||||||
|
for (Layer& layer : mLayers)
|
||||||
|
{
|
||||||
|
const ShaderPackage* shaderPackage = shaderCatalog.FindPackage(layer.shaderId);
|
||||||
|
if (!shaderPackage)
|
||||||
|
{
|
||||||
|
layer.buildState = RuntimeLayerBuildState::Failed;
|
||||||
|
layer.message = "Shader '" + layer.shaderId + "' is no longer available after reload.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string nextFingerprint = ShaderPackageFingerprint(*shaderPackage);
|
||||||
|
if (layer.packageFingerprint == nextFingerprint)
|
||||||
|
{
|
||||||
|
buildsToStart.push_back({ layer.id, layer.shaderId });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, ShaderParameterDefinition> previousDefinitions;
|
||||||
|
for (const ShaderParameterDefinition& definition : layer.parameterDefinitions)
|
||||||
|
previousDefinitions[definition.id] = definition;
|
||||||
|
|
||||||
|
std::map<std::string, ShaderParameterValue> nextValues;
|
||||||
|
for (const ShaderParameterDefinition& nextDefinition : shaderPackage->parameters)
|
||||||
|
{
|
||||||
|
const auto previousDefinitionIt = previousDefinitions.find(nextDefinition.id);
|
||||||
|
const auto previousValueIt = layer.parameterValues.find(nextDefinition.id);
|
||||||
|
if (previousDefinitionIt != previousDefinitions.end()
|
||||||
|
&& previousValueIt != layer.parameterValues.end()
|
||||||
|
&& previousDefinitionIt->second.type == nextDefinition.type)
|
||||||
|
{
|
||||||
|
ShaderParameterValue preservedValue;
|
||||||
|
JsonValue valueJson = ParameterValueToJson(previousDefinitionIt->second, previousValueIt->second);
|
||||||
|
std::string normalizeError;
|
||||||
|
if (NormalizeAndValidateParameterValue(nextDefinition, valueJson, preservedValue, normalizeError))
|
||||||
|
{
|
||||||
|
nextValues[nextDefinition.id] = preservedValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextValues[nextDefinition.id] = DefaultValueForDefinition(nextDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.shaderName = shaderPackage->displayName.empty() ? shaderPackage->id : shaderPackage->displayName;
|
||||||
|
layer.packageFingerprint = nextFingerprint;
|
||||||
|
layer.parameterDefinitions = shaderPackage->parameters;
|
||||||
|
layer.parameterValues = std::move(nextValues);
|
||||||
|
buildsToStart.push_back({ layer.id, layer.shaderId });
|
||||||
|
}
|
||||||
|
|
||||||
|
error.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/runtime/RuntimeLayerSnapshot.cpp
Normal file
52
src/runtime/RuntimeLayerSnapshot.cpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#include "RuntimeLayerModel.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace RenderCadenceCompositor
|
||||||
|
{
|
||||||
|
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.bypass = layer.bypass;
|
||||||
|
renderLayer.artifact = layer.artifact;
|
||||||
|
renderLayer.shaderId = renderLayer.artifact.shaderId.empty() ? layer.shaderId : renderLayer.artifact.shaderId;
|
||||||
|
if (layer.buildState == RuntimeLayerBuildState::Ready)
|
||||||
|
renderLayer.artifact.parameterValues = layer.parameterValues;
|
||||||
|
renderLayer.artifact.fontAtlases.clear();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
129
src/runtime/RuntimeLayerStateRestore.cpp
Normal file
129
src/runtime/RuntimeLayerStateRestore.cpp
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#include "RuntimeLayerModel.h"
|
||||||
|
|
||||||
|
#include "RuntimeParameterUtils.h"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace RenderCadenceCompositor
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool ParseRuntimeLayerNumber(const std::string& layerId, uint64_t& number)
|
||||||
|
{
|
||||||
|
const std::string prefix = "runtime-layer-";
|
||||||
|
if (layerId.compare(0, prefix.size(), prefix) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const std::string suffix = layerId.substr(prefix.size());
|
||||||
|
if (suffix.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint64_t parsed = 0;
|
||||||
|
for (char character : suffix)
|
||||||
|
{
|
||||||
|
if (!std::isdigit(static_cast<unsigned char>(character)))
|
||||||
|
return false;
|
||||||
|
parsed = parsed * 10 + static_cast<uint64_t>(character - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
number = parsed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AllocateRestoredLayerId(std::set<std::string>& usedLayerIds, uint64_t& nextLayerNumber)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
std::string candidate = "runtime-layer-" + std::to_string(nextLayerNumber++);
|
||||||
|
if (usedLayerIds.insert(candidate).second)
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeLayerModel::InitializeFromRuntimeState(const SupportedShaderCatalog& shaderCatalog, const JsonValue& runtimeState, std::string& error)
|
||||||
|
{
|
||||||
|
if (!runtimeState.isObject())
|
||||||
|
{
|
||||||
|
error = "Runtime state root must be a JSON object.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const JsonValue* layersValue = runtimeState.find("layers");
|
||||||
|
if (!layersValue || !layersValue->isArray())
|
||||||
|
{
|
||||||
|
error = "Runtime state must contain a layers array.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Layer> restoredLayers;
|
||||||
|
std::set<std::string> usedLayerIds;
|
||||||
|
uint64_t nextLayerNumber = 1;
|
||||||
|
|
||||||
|
for (const JsonValue& layerValue : layersValue->asArray())
|
||||||
|
{
|
||||||
|
if (!layerValue.isObject())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const JsonValue* shaderIdValue = layerValue.find("shaderId");
|
||||||
|
if (!shaderIdValue || !shaderIdValue->isString() || shaderIdValue->asString().empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ShaderPackage* shaderPackage = shaderCatalog.FindPackage(shaderIdValue->asString());
|
||||||
|
if (!shaderPackage)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Layer layer;
|
||||||
|
const JsonValue* layerIdValue = layerValue.find("id");
|
||||||
|
if (layerIdValue && layerIdValue->isString() && !layerIdValue->asString().empty() && usedLayerIds.insert(layerIdValue->asString()).second)
|
||||||
|
layer.id = layerIdValue->asString();
|
||||||
|
else
|
||||||
|
layer.id = AllocateRestoredLayerId(usedLayerIds, nextLayerNumber);
|
||||||
|
|
||||||
|
uint64_t restoredLayerNumber = 0;
|
||||||
|
if (ParseRuntimeLayerNumber(layer.id, restoredLayerNumber) && restoredLayerNumber >= nextLayerNumber)
|
||||||
|
nextLayerNumber = restoredLayerNumber + 1;
|
||||||
|
|
||||||
|
layer.shaderId = shaderPackage->id;
|
||||||
|
layer.packageFingerprint = ShaderPackageFingerprint(*shaderPackage);
|
||||||
|
layer.shaderName = shaderPackage->displayName.empty() ? shaderPackage->id : shaderPackage->displayName;
|
||||||
|
const JsonValue* bypassValue = layerValue.find("bypass");
|
||||||
|
layer.bypass = bypassValue && bypassValue->isBoolean() ? bypassValue->asBoolean() : false;
|
||||||
|
layer.buildState = RuntimeLayerBuildState::Pending;
|
||||||
|
layer.message = "Runtime Slang build is waiting to start.";
|
||||||
|
InitializeDefaultParameterValues(layer, *shaderPackage);
|
||||||
|
|
||||||
|
const JsonValue* parameterValues = layerValue.find("parameterValues");
|
||||||
|
if (parameterValues && parameterValues->isObject())
|
||||||
|
{
|
||||||
|
for (const ShaderParameterDefinition& definition : layer.parameterDefinitions)
|
||||||
|
{
|
||||||
|
const JsonValue* value = parameterValues->find(definition.id);
|
||||||
|
if (!value)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ShaderParameterValue normalizedValue;
|
||||||
|
std::string normalizeError;
|
||||||
|
if (NormalizeAndValidateParameterValue(definition, *value, normalizedValue, normalizeError))
|
||||||
|
layer.parameterValues[definition.id] = normalizedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restoredLayers.push_back(std::move(layer));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restoredLayers.empty())
|
||||||
|
{
|
||||||
|
error = "Runtime state did not contain any supported layers.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLayers = std::move(restoredLayers);
|
||||||
|
mNextLayerNumber = nextLayerNumber;
|
||||||
|
error.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,9 @@ add_video_shader_test(RenderCadenceCompositorRuntimeShaderParamsTests
|
|||||||
add_video_shader_test(RenderCadenceCompositorRuntimeLayerModelTests
|
add_video_shader_test(RenderCadenceCompositorRuntimeLayerModelTests
|
||||||
"${SRC_DIR}/runtime/FontAtlasBuilder.cpp"
|
"${SRC_DIR}/runtime/FontAtlasBuilder.cpp"
|
||||||
"${SRC_DIR}/runtime/RuntimeLayerModel.cpp"
|
"${SRC_DIR}/runtime/RuntimeLayerModel.cpp"
|
||||||
|
"${SRC_DIR}/runtime/RuntimeLayerReload.cpp"
|
||||||
|
"${SRC_DIR}/runtime/RuntimeLayerSnapshot.cpp"
|
||||||
|
"${SRC_DIR}/runtime/RuntimeLayerStateRestore.cpp"
|
||||||
"${SRC_DIR}/runtime/RuntimeJson.cpp"
|
"${SRC_DIR}/runtime/RuntimeJson.cpp"
|
||||||
"${SRC_DIR}/runtime/RuntimeParameterUtils.cpp"
|
"${SRC_DIR}/runtime/RuntimeParameterUtils.cpp"
|
||||||
"${SRC_DIR}/runtime/RuntimeTextTextureComposer.cpp"
|
"${SRC_DIR}/runtime/RuntimeTextTextureComposer.cpp"
|
||||||
@@ -79,6 +82,9 @@ add_video_shader_test(RenderCadenceCompositorRuntimeStateJsonTests
|
|||||||
"${SRC_DIR}/runtime/FontAtlasBuilder.cpp"
|
"${SRC_DIR}/runtime/FontAtlasBuilder.cpp"
|
||||||
"${SRC_DIR}/runtime/RuntimeJson.cpp"
|
"${SRC_DIR}/runtime/RuntimeJson.cpp"
|
||||||
"${SRC_DIR}/runtime/RuntimeLayerModel.cpp"
|
"${SRC_DIR}/runtime/RuntimeLayerModel.cpp"
|
||||||
|
"${SRC_DIR}/runtime/RuntimeLayerReload.cpp"
|
||||||
|
"${SRC_DIR}/runtime/RuntimeLayerSnapshot.cpp"
|
||||||
|
"${SRC_DIR}/runtime/RuntimeLayerStateRestore.cpp"
|
||||||
"${SRC_DIR}/runtime/RuntimeParameterUtils.cpp"
|
"${SRC_DIR}/runtime/RuntimeParameterUtils.cpp"
|
||||||
"${SRC_DIR}/runtime/RuntimeTextTextureComposer.cpp"
|
"${SRC_DIR}/runtime/RuntimeTextTextureComposer.cpp"
|
||||||
"${SRC_DIR}/runtime/SupportedShaderCatalog.cpp"
|
"${SRC_DIR}/runtime/SupportedShaderCatalog.cpp"
|
||||||
|
|||||||
Reference in New Issue
Block a user