Shader: Replace indices-based option keys by CRC32
This commit is contained in:
@@ -174,26 +174,8 @@ namespace Nz
|
||||
|
||||
settings.shaders = options.shaders;
|
||||
|
||||
for (std::shared_ptr<UberShader> uberShader : settings.shaders)
|
||||
for (const std::shared_ptr<UberShader>& uberShader : settings.shaders)
|
||||
{
|
||||
constexpr std::size_t InvalidOption = std::numeric_limits<std::size_t>::max();
|
||||
|
||||
auto FetchLocationOption = [&](const std::string& optionName)
|
||||
{
|
||||
const UberShader::Option* optionPtr;
|
||||
if (!uberShader->HasOption(optionName, &optionPtr))
|
||||
return InvalidOption;
|
||||
|
||||
//if (optionPtr->type != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::Int32 })
|
||||
// throw std::runtime_error("Location options must be of type i32");
|
||||
|
||||
return optionPtr->index;
|
||||
};
|
||||
|
||||
std::size_t positionLocationIndex = FetchLocationOption("PosLocation");
|
||||
std::size_t colorLocationIndex = FetchLocationOption("ColorLocation");
|
||||
std::size_t uvLocationIndex = FetchLocationOption("UvLocation");
|
||||
|
||||
uberShader->UpdateConfigCallback([=](UberShader::Config& config, const std::vector<RenderPipelineInfo::VertexBufferData>& vertexBuffers)
|
||||
{
|
||||
if (vertexBuffers.empty())
|
||||
@@ -202,27 +184,21 @@ namespace Nz
|
||||
const VertexDeclaration& vertexDeclaration = *vertexBuffers.front().declaration;
|
||||
const auto& components = vertexDeclaration.GetComponents();
|
||||
|
||||
std::size_t locationIndex = 0;
|
||||
Int32 locationIndex = 0;
|
||||
for (const auto& component : components)
|
||||
{
|
||||
switch (component.component)
|
||||
{
|
||||
case VertexComponent::Position:
|
||||
if (positionLocationIndex != InvalidOption)
|
||||
config.optionValues[positionLocationIndex] = static_cast<Int32>(locationIndex);
|
||||
|
||||
config.optionValues[CRC32("PosLocation")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Color:
|
||||
if (colorLocationIndex != InvalidOption)
|
||||
config.optionValues[colorLocationIndex] = static_cast<Int32>(locationIndex);
|
||||
|
||||
config.optionValues[CRC32("ColorLocation")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::TexCoord:
|
||||
if (uvLocationIndex != InvalidOption)
|
||||
config.optionValues[uvLocationIndex] = static_cast<Int32>(locationIndex);
|
||||
|
||||
config.optionValues[CRC32("UvLocation")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Unused:
|
||||
@@ -241,19 +217,19 @@ namespace Nz
|
||||
if (options.basicOptionIndexes)
|
||||
options.basicOptionIndexes->hasDiffuseMap = settings.options.size();
|
||||
|
||||
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasDiffuseMap", "HasDiffuseTexture");
|
||||
MaterialSettings::BuildOption(settings.options, "HasDiffuseMap", "HasDiffuseTexture");
|
||||
|
||||
// HasAlphaMap
|
||||
if (options.basicOptionIndexes)
|
||||
options.basicOptionIndexes->hasAlphaMap = settings.options.size();
|
||||
|
||||
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasAlphaMap", "HasAlphaTexture");
|
||||
MaterialSettings::BuildOption(settings.options, "HasAlphaMap", "HasAlphaTexture");
|
||||
|
||||
// AlphaTest
|
||||
if (options.basicOptionIndexes)
|
||||
options.basicOptionIndexes->alphaTest = settings.options.size();
|
||||
|
||||
MaterialSettings::BuildOption(settings.options, settings.shaders, "AlphaTest", "AlphaTest");
|
||||
MaterialSettings::BuildOption(settings.options, "AlphaTest", "AlphaTest");
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -128,25 +128,24 @@ namespace Nz
|
||||
|
||||
void MaterialPass::UpdatePipeline() const
|
||||
{
|
||||
for (auto& shader : m_pipelineInfo.shaders)
|
||||
shader.optionValues.fill(ShaderAst::NoValue{});
|
||||
m_pipelineInfo.optionCount = 0;
|
||||
|
||||
const auto& options = m_settings->GetOptions();
|
||||
for (std::size_t optionIndex = 0; optionIndex < options.size(); ++optionIndex)
|
||||
{
|
||||
const auto& option = options[optionIndex];
|
||||
assert(option.optionIndexByShader.size() <= m_pipelineInfo.shaders.size());
|
||||
|
||||
for (std::size_t shaderIndex = 0; shaderIndex < option.optionIndexByShader.size(); ++shaderIndex)
|
||||
if (!std::holds_alternative<ShaderAst::NoValue>(m_optionValues[optionIndex]))
|
||||
{
|
||||
if (!option.optionIndexByShader[shaderIndex].has_value())
|
||||
continue;
|
||||
auto& optionValue = m_pipelineInfo.optionValues[m_pipelineInfo.optionCount];
|
||||
optionValue.hash = options[optionIndex].hash;
|
||||
optionValue.value = m_optionValues[optionIndex];
|
||||
|
||||
std::size_t shaderOptionIndex = *option.optionIndexByShader[shaderIndex];
|
||||
m_pipelineInfo.shaders[shaderIndex].optionValues[shaderOptionIndex] = m_optionValues[optionIndex];
|
||||
m_pipelineInfo.optionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// make option values consistent (required for hash/equality)
|
||||
std::sort(m_pipelineInfo.optionValues.begin(), m_pipelineInfo.optionValues.end(), [](const auto& lhs, const auto& rhs) { return lhs.hash < rhs.hash; });
|
||||
|
||||
m_pipeline = MaterialPipeline::Get(m_pipelineInfo);
|
||||
m_pipelineUpdated = true;
|
||||
}
|
||||
|
||||
@@ -49,11 +49,18 @@ namespace Nz
|
||||
|
||||
renderPipelineInfo.pipelineLayout = m_pipelineInfo.settings->GetRenderPipelineLayout();
|
||||
|
||||
std::unordered_map<UInt32, ShaderAst::ConstantValue> optionValues;
|
||||
for (std::size_t i = 0; i < m_pipelineInfo.optionCount; ++i)
|
||||
{
|
||||
const auto& option = m_pipelineInfo.optionValues[i];
|
||||
optionValues[option.hash] = option.value;
|
||||
}
|
||||
|
||||
for (const auto& shader : m_pipelineInfo.shaders)
|
||||
{
|
||||
if (shader.uberShader)
|
||||
{
|
||||
UberShader::Config config{ shader.optionValues };
|
||||
UberShader::Config config{ optionValues };
|
||||
shader.uberShader->UpdateConfig(config, vertexBuffers);
|
||||
|
||||
renderPipelineInfo.shaderModules.push_back(shader.uberShader->Get(config));
|
||||
|
||||
@@ -241,28 +241,8 @@ namespace Nz
|
||||
|
||||
settings.shaders = options.shaders;
|
||||
|
||||
for (std::shared_ptr<UberShader> uberShader : settings.shaders)
|
||||
for (const std::shared_ptr<UberShader>& uberShader : settings.shaders)
|
||||
{
|
||||
constexpr std::size_t InvalidOption = std::numeric_limits<std::size_t>::max();
|
||||
|
||||
auto FetchLocationOption = [&](const std::string& optionName)
|
||||
{
|
||||
const UberShader::Option* optionPtr;
|
||||
if (!uberShader->HasOption(optionName, &optionPtr))
|
||||
return InvalidOption;
|
||||
|
||||
//if (optionPtr->type != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::Int32 })
|
||||
// throw std::runtime_error("Location options must be of type i32");
|
||||
|
||||
return optionPtr->index;
|
||||
};
|
||||
|
||||
std::size_t positionLocationIndex = FetchLocationOption("PosLocation");
|
||||
std::size_t colorLocationIndex = FetchLocationOption("ColorLocation");
|
||||
std::size_t normalLocationIndex = FetchLocationOption("NormalLocation");
|
||||
std::size_t tangentLocationIndex = FetchLocationOption("TangentLocation");
|
||||
std::size_t uvLocationIndex = FetchLocationOption("UvLocation");
|
||||
|
||||
uberShader->UpdateConfigCallback([=](UberShader::Config& config, const std::vector<RenderPipelineInfo::VertexBufferData>& vertexBuffers)
|
||||
{
|
||||
if (vertexBuffers.empty())
|
||||
@@ -271,39 +251,29 @@ namespace Nz
|
||||
const VertexDeclaration& vertexDeclaration = *vertexBuffers.front().declaration;
|
||||
const auto& components = vertexDeclaration.GetComponents();
|
||||
|
||||
std::size_t locationIndex = 0;
|
||||
Int32 locationIndex = 0;
|
||||
for (const auto& component : components)
|
||||
{
|
||||
switch (component.component)
|
||||
{
|
||||
case VertexComponent::Position:
|
||||
if (positionLocationIndex != InvalidOption)
|
||||
config.optionValues[positionLocationIndex] = static_cast<Int32>(locationIndex);
|
||||
|
||||
config.optionValues[CRC32("PosLocation")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Color:
|
||||
if (colorLocationIndex != InvalidOption)
|
||||
config.optionValues[colorLocationIndex] = static_cast<Int32>(locationIndex);
|
||||
|
||||
config.optionValues[CRC32("ColorLocation")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Normal:
|
||||
if (normalLocationIndex != InvalidOption)
|
||||
config.optionValues[normalLocationIndex] = static_cast<Int32>(locationIndex);
|
||||
|
||||
config.optionValues[CRC32("NormalLocation")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Tangent:
|
||||
if (tangentLocationIndex != InvalidOption)
|
||||
config.optionValues[tangentLocationIndex] = static_cast<Int32>(locationIndex);
|
||||
|
||||
config.optionValues[CRC32("TangentLocation")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::TexCoord:
|
||||
if (uvLocationIndex != InvalidOption)
|
||||
config.optionValues[uvLocationIndex] = static_cast<Int32>(locationIndex);
|
||||
|
||||
config.optionValues[CRC32("UvLocation")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Unused:
|
||||
@@ -322,25 +292,25 @@ namespace Nz
|
||||
if (options.phongOptionIndexes)
|
||||
options.phongOptionIndexes->hasEmissiveMap = settings.options.size();
|
||||
|
||||
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasEmissiveMap", "HasEmissiveTexture");
|
||||
MaterialSettings::BuildOption(settings.options, "HasEmissiveMap", "HasEmissiveTexture");
|
||||
|
||||
// HasHeightMap
|
||||
if (options.phongOptionIndexes)
|
||||
options.phongOptionIndexes->hasHeightMap = settings.options.size();
|
||||
|
||||
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasHeightMap", "HasHeightTexture");
|
||||
MaterialSettings::BuildOption(settings.options, "HasHeightMap", "HasHeightTexture");
|
||||
|
||||
// HasNormalMap
|
||||
if (options.phongOptionIndexes)
|
||||
options.phongOptionIndexes->hasNormalMap = settings.options.size();
|
||||
|
||||
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasNormalMap", "HasNormalTexture");
|
||||
MaterialSettings::BuildOption(settings.options, "HasNormalMap", "HasNormalTexture");
|
||||
|
||||
// HasSpecularMap
|
||||
if (options.phongOptionIndexes)
|
||||
options.phongOptionIndexes->hasSpecularMap = settings.options.size();
|
||||
|
||||
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasSpecularMap", "HasSpecularTexture");
|
||||
MaterialSettings::BuildOption(settings.options, "HasSpecularMap", "HasSpecularTexture");
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Nz
|
||||
//TODO: Check optionType
|
||||
|
||||
m_optionIndexByName[optionName] = Option{
|
||||
optionCount
|
||||
CRC32(optionName)
|
||||
};
|
||||
|
||||
optionCount++;
|
||||
@@ -48,9 +48,6 @@ namespace Nz
|
||||
|
||||
if ((m_shaderStages & supportedStageType) != m_shaderStages)
|
||||
throw std::runtime_error("shader doesn't support all required shader stages");
|
||||
|
||||
if (optionCount >= MaximumOptionValue)
|
||||
throw std::runtime_error("Too many shader options (at most " + std::to_string(MaximumOptionValue) + " are supported)");
|
||||
}
|
||||
|
||||
const std::shared_ptr<ShaderModule>& UberShader::Get(const Config& config)
|
||||
@@ -59,12 +56,7 @@ namespace Nz
|
||||
if (it == m_combinations.end())
|
||||
{
|
||||
ShaderWriter::States states;
|
||||
|
||||
for (std::size_t i = 0; i < MaximumOptionValue; ++i)
|
||||
{
|
||||
if (!std::holds_alternative<ShaderAst::NoValue>(config.optionValues[i]))
|
||||
states.optionValues[i] = config.optionValues[i];
|
||||
}
|
||||
states.optionValues = config.optionValues;
|
||||
|
||||
std::shared_ptr<ShaderModule> stage = Graphics::Instance()->GetRenderDevice()->InstantiateShaderModule(m_shaderStages, *m_shaderModule, std::move(states));
|
||||
|
||||
|
||||
@@ -122,7 +122,6 @@ namespace Nz::ShaderAst
|
||||
|
||||
std::array<DeclareFunctionStatement*, ShaderStageTypeCount> entryFunctions = {};
|
||||
std::optional<DependencyCheckerVisitor::UsageSet> importUsage;
|
||||
std::size_t nextOptionIndex = 0;
|
||||
std::vector<Identifier> identifiersInScope;
|
||||
std::vector<PendingFunction> pendingFunctions;
|
||||
std::vector<Scope> scopes;
|
||||
@@ -951,6 +950,8 @@ namespace Nz::ShaderAst
|
||||
throw AstError{ "options must be declared outside of functions" };
|
||||
|
||||
auto clone = static_unique_pointer_cast<DeclareOptionStatement>(AstCloner::Clone(node));
|
||||
if (clone->optName.empty())
|
||||
throw AstError{ "empty option name" };
|
||||
|
||||
ExpressionType resolvedType = ResolveType(clone->optType);
|
||||
|
||||
@@ -959,12 +960,12 @@ namespace Nz::ShaderAst
|
||||
|
||||
clone->optType = std::move(resolvedType);
|
||||
|
||||
std::size_t optionIndex = m_context->nextOptionIndex++;
|
||||
UInt32 optionHash = CRC32(reinterpret_cast<const UInt8*>(clone->optName.data()), clone->optName.size());
|
||||
|
||||
if (m_context->importUsage.has_value())
|
||||
clone->hidden = true;
|
||||
|
||||
if (auto optionValueIt = m_context->options.optionValues.find(optionIndex); optionValueIt != m_context->options.optionValues.end())
|
||||
if (auto optionValueIt = m_context->options.optionValues.find(optionHash); optionValueIt != m_context->options.optionValues.end())
|
||||
clone->optIndex = RegisterConstant(clone->optName, optionValueIt->second, clone->hidden.value_or(false), clone->optIndex);
|
||||
else if (clone->defaultValue)
|
||||
clone->optIndex = RegisterConstant(clone->optName, ComputeConstantValue(*clone->defaultValue), clone->hidden.value_or(false), clone->optIndex);
|
||||
|
||||
@@ -139,7 +139,6 @@ namespace Nz
|
||||
|
||||
std::optional<ShaderStageType> stage;
|
||||
std::stringstream stream;
|
||||
std::unordered_map<std::size_t, ShaderAst::ConstantValue> optionValues;
|
||||
std::unordered_map<std::size_t, ShaderAst::StructDescription*> structs;
|
||||
std::unordered_map<std::size_t, std::string> variableNames;
|
||||
std::vector<InOutField> inputFields;
|
||||
@@ -155,7 +154,6 @@ namespace Nz
|
||||
std::string GlslWriter::Generate(std::optional<ShaderStageType> shaderStage, const ShaderAst::Module& module, const BindingMapping& bindingMapping, const States& states)
|
||||
{
|
||||
State state(bindingMapping);
|
||||
state.optionValues = states.optionValues;
|
||||
state.stage = shaderStage;
|
||||
|
||||
m_currentState = &state;
|
||||
@@ -210,7 +208,7 @@ namespace Nz
|
||||
return s_flipYUniformName;
|
||||
}
|
||||
|
||||
ShaderAst::ModulePtr GlslWriter::Sanitize(const ShaderAst::Module& module, std::unordered_map<std::size_t, ShaderAst::ConstantValue> optionValues, std::string* error)
|
||||
ShaderAst::ModulePtr GlslWriter::Sanitize(const ShaderAst::Module& module, std::unordered_map<UInt32, ShaderAst::ConstantValue> optionValues, std::string* error)
|
||||
{
|
||||
// Always sanitize for reserved identifiers
|
||||
ShaderAst::SanitizeVisitor::Options options;
|
||||
|
||||
@@ -59,7 +59,10 @@ void CodeOutputWidget::Refresh()
|
||||
Nz::ShaderWriter::States states;
|
||||
|
||||
for (std::size_t i = 0; i < m_shaderGraph.GetOptionCount(); ++i)
|
||||
states.optionValues[i] = m_shaderGraph.IsOptionEnabled(i);
|
||||
{
|
||||
const auto& option = m_shaderGraph.GetOption(i);
|
||||
states.optionValues[Nz::CRC32(option.name)] = m_shaderGraph.IsOptionEnabled(i);
|
||||
}
|
||||
|
||||
Nz::ShaderAst::ModulePtr shaderModule = m_shaderGraph.ToModule();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user