Handle shader options of any type
This commit is contained in:
@@ -26,7 +26,7 @@ namespace Nz
|
||||
inline void BasicMaterial::EnableAlphaTest(bool alphaTest)
|
||||
{
|
||||
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
|
||||
m_material.EnableOption(m_optionIndexes.alphaTest, alphaTest);
|
||||
m_material.SetOptionValue(m_optionIndexes.alphaTest, alphaTest);
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<Texture>& BasicMaterial::GetAlphaMap() const
|
||||
@@ -56,7 +56,11 @@ namespace Nz
|
||||
inline bool BasicMaterial::IsAlphaTestEnabled() const
|
||||
{
|
||||
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
|
||||
return m_material.IsOptionEnabled(m_optionIndexes.alphaTest);
|
||||
const auto& optionOpt = m_material.GetOptionValue(m_optionIndexes.alphaTest);
|
||||
if (std::holds_alternative<ShaderAst::NoValue>(optionOpt))
|
||||
return false;
|
||||
|
||||
return std::get<bool>(optionOpt);
|
||||
}
|
||||
|
||||
inline bool BasicMaterial::HasAlphaMap() const
|
||||
@@ -91,7 +95,7 @@ namespace Nz
|
||||
m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap));
|
||||
|
||||
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
|
||||
m_material.EnableOption(m_optionIndexes.hasAlphaMap, hasAlphaMap);
|
||||
m_material.SetOptionValue(m_optionIndexes.hasAlphaMap, hasAlphaMap);
|
||||
}
|
||||
|
||||
inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler)
|
||||
@@ -107,7 +111,7 @@ namespace Nz
|
||||
m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap));
|
||||
|
||||
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
|
||||
m_material.EnableOption(m_optionIndexes.hasDiffuseMap, hasDiffuseMap);
|
||||
m_material.SetOptionValue(m_optionIndexes.hasDiffuseMap, hasDiffuseMap);
|
||||
}
|
||||
|
||||
inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <Nazara/Graphics/MaterialPipeline.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <Nazara/Renderer/TextureSampler.hpp>
|
||||
#include <Nazara/Shader/Ast/ConstantValue.hpp>
|
||||
#include <Nazara/Utility/UniformBuffer.hpp>
|
||||
#include <array>
|
||||
#include <string>
|
||||
@@ -45,7 +46,6 @@ namespace Nz
|
||||
inline void EnableDepthClamp(bool depthClamp);
|
||||
inline void EnableDepthWrite(bool depthWrite);
|
||||
inline void EnableFaceCulling(bool faceCulling);
|
||||
inline void EnableOption(std::size_t optionIndex, bool enable);
|
||||
inline void EnableScissorTest(bool scissorTest);
|
||||
inline void EnableStencilTest(bool stencilTest);
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace Nz
|
||||
inline FaceSide GetFaceCulling() const;
|
||||
inline FaceFilling GetFaceFilling() const;
|
||||
inline float GetLineWidth() const;
|
||||
inline const ShaderAst::ConstantValue& GetOptionValue(std::size_t optionIndex) const;
|
||||
inline const std::shared_ptr<MaterialPipeline>& GetPipeline() const;
|
||||
inline const MaterialPipelineInfo& GetPipelineInfo() const;
|
||||
inline float GetPointSize() const;
|
||||
@@ -82,7 +83,6 @@ namespace Nz
|
||||
inline bool IsDepthClampEnabled() const;
|
||||
inline bool IsDepthWriteEnabled() const;
|
||||
inline bool IsFaceCullingEnabled() const;
|
||||
inline bool IsOptionEnabled(std::size_t optionIndex) const;
|
||||
inline bool IsScissorTestEnabled() const;
|
||||
inline bool IsStencilTestEnabled() const;
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace Nz
|
||||
inline void SetFaceCulling(FaceSide faceSide);
|
||||
inline void SetFaceFilling(FaceFilling filling);
|
||||
inline void SetLineWidth(float lineWidth);
|
||||
inline void SetOptionValue(std::size_t optionIndex, ShaderAst::ConstantValue value);
|
||||
inline void SetPointSize(float pointSize);
|
||||
inline void SetPrimitiveMode(PrimitiveMode mode);
|
||||
inline void SetTexture(std::size_t textureIndex, std::shared_ptr<Texture> texture);
|
||||
@@ -126,11 +127,11 @@ namespace Nz
|
||||
bool dataInvalidated = true;
|
||||
};
|
||||
|
||||
std::array<ShaderAst::ConstantValue, 64> m_optionValues;
|
||||
std::shared_ptr<const MaterialSettings> m_settings;
|
||||
std::vector<MaterialTexture> m_textures;
|
||||
std::vector<UniformBuffer> m_uniformBuffers;
|
||||
mutable std::shared_ptr<MaterialPipeline> m_pipeline;
|
||||
UInt64 m_enabledOptions;
|
||||
mutable MaterialPipelineInfo m_pipelineInfo;
|
||||
ShaderBindingPtr m_shaderBinding;
|
||||
bool m_forceCommandBufferRegeneration;
|
||||
|
||||
@@ -182,15 +182,6 @@ namespace Nz
|
||||
InvalidatePipeline();
|
||||
}
|
||||
|
||||
inline void MaterialPass::EnableOption(std::size_t optionIndex, bool enable)
|
||||
{
|
||||
if (TestBit<UInt64>(m_enabledOptions, optionIndex) != enable)
|
||||
{
|
||||
m_enabledOptions = ToggleBit<UInt64>(m_enabledOptions, optionIndex);
|
||||
InvalidatePipeline();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable/Disable scissor test for this material
|
||||
*
|
||||
@@ -315,6 +306,12 @@ namespace Nz
|
||||
return m_pipelineInfo.lineWidth;
|
||||
}
|
||||
|
||||
inline const ShaderAst::ConstantValue& MaterialPass::GetOptionValue(std::size_t optionIndex) const
|
||||
{
|
||||
assert(optionIndex < m_optionValues.size());
|
||||
return m_optionValues[optionIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the render states
|
||||
* \return Constant reference to the render states
|
||||
@@ -461,11 +458,6 @@ namespace Nz
|
||||
return m_pipelineInfo.faceCulling;
|
||||
}
|
||||
|
||||
inline bool MaterialPass::IsOptionEnabled(std::size_t optionIndex) const
|
||||
{
|
||||
return TestBit<UInt64>(m_enabledOptions, optionIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether this material has scissor test enabled
|
||||
* \return true If it is the case
|
||||
@@ -562,6 +554,16 @@ namespace Nz
|
||||
InvalidatePipeline();
|
||||
}
|
||||
|
||||
inline void MaterialPass::SetOptionValue(std::size_t optionIndex, ShaderAst::ConstantValue value)
|
||||
{
|
||||
assert(optionIndex < m_optionValues.size());
|
||||
if (m_optionValues[optionIndex] != value)
|
||||
{
|
||||
m_optionValues[optionIndex] = std::move(value);
|
||||
InvalidatePipeline();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the point size for this material
|
||||
*
|
||||
@@ -654,3 +656,4 @@ namespace Nz
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
#include "MaterialPass.hpp"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Graphics/MaterialSettings.hpp>
|
||||
#include <Nazara/Renderer/RenderPipeline.hpp>
|
||||
#include <Nazara/Shader/Ast/ConstantValue.hpp>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
@@ -23,8 +24,8 @@ namespace Nz
|
||||
{
|
||||
struct Shader
|
||||
{
|
||||
std::array<ShaderAst::ConstantValue, 32> optionValues;
|
||||
std::shared_ptr<UberShader> uberShader;
|
||||
Nz::UInt64 enabledOptions = 0;
|
||||
};
|
||||
|
||||
std::vector<Shader> shaders;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Nz
|
||||
|
||||
for (std::size_t i = 0; i < lhs.shaders.size(); ++i)
|
||||
{
|
||||
if (lhs.shaders[i].enabledOptions != rhs.shaders[i].enabledOptions)
|
||||
if (lhs.shaders[i].optionValues != rhs.shaders[i].optionValues)
|
||||
return false;
|
||||
|
||||
if (lhs.shaders[i].uberShader != rhs.shaders[i].uberShader)
|
||||
@@ -73,7 +73,9 @@ namespace std
|
||||
|
||||
for (const auto& shader : pipelineInfo.shaders)
|
||||
{
|
||||
Nz::HashCombine(seed, shader.enabledOptions);
|
||||
for (const auto& value : shader.optionValues)
|
||||
Nz::HashCombine(seed, value);
|
||||
|
||||
Nz::HashCombine(seed, shader.uberShader.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Nz
|
||||
|
||||
static constexpr std::size_t InvalidIndex = std::numeric_limits<std::size_t>::max();
|
||||
|
||||
static void BuildOption(std::vector<Option>& options, const std::vector<std::shared_ptr<UberShader>>& uberShaders, std::string optionName, const std::string& shaderOptionName);
|
||||
static inline void BuildOption(std::vector<Option>& options, const std::vector<std::shared_ptr<UberShader>>& uberShaders, std::string optionName, const std::string& shaderOptionName);
|
||||
|
||||
struct Builder
|
||||
{
|
||||
@@ -69,7 +69,7 @@ namespace Nz
|
||||
struct Option
|
||||
{
|
||||
std::string name;
|
||||
std::array<UInt64, ShaderStageTypeCount> enabledOptions;
|
||||
std::vector<std::optional<std::size_t>> optionIndexByShader;
|
||||
};
|
||||
|
||||
struct UniformVariable
|
||||
|
||||
@@ -168,22 +168,23 @@ namespace Nz
|
||||
|
||||
inline void MaterialSettings::BuildOption(std::vector<Option>& options, const std::vector<std::shared_ptr<UberShader>>& uberShaders, std::string optionName, const std::string& shaderOptionName)
|
||||
{
|
||||
std::array<UInt64, ShaderStageTypeCount> shaderOptions;
|
||||
shaderOptions.fill(0);
|
||||
std::vector<std::optional<std::size_t>> shaderOptions;
|
||||
|
||||
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
|
||||
for (std::size_t shaderIndex = 0; shaderIndex < uberShaders.size(); ++shaderIndex)
|
||||
{
|
||||
for (const auto& uberShader : uberShaders)
|
||||
const auto& uberShader = uberShaders[shaderIndex];
|
||||
|
||||
const UberShader::Option* optionData;
|
||||
if (uberShader->HasOption(shaderOptionName, &optionData))
|
||||
{
|
||||
if (uberShader->GetSupportedStages() & static_cast<ShaderStageType>(i))
|
||||
{
|
||||
assert(shaderOptions[i] == 0);
|
||||
shaderOptions[i] |= uberShader->GetOptionFlagByName(shaderOptionName);
|
||||
}
|
||||
if (shaderIndex >= shaderOptions.size())
|
||||
shaderOptions.resize(shaderIndex + 1);
|
||||
|
||||
shaderOptions[shaderIndex] = optionData->index;
|
||||
}
|
||||
}
|
||||
|
||||
if (std::any_of(shaderOptions.begin(), shaderOptions.end(), [&](UInt64 flags) { return flags != 0; }))
|
||||
if (std::any_of(shaderOptions.begin(), shaderOptions.end(), [&](std::optional<std::size_t> optionIndex) { return optionIndex.has_value(); }))
|
||||
{
|
||||
options.push_back({
|
||||
std::move(optionName),
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
#define NAZARA_UBER_SHADER_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Renderer/RenderPipeline.hpp>
|
||||
#include <Nazara/Shader/Ast/Nodes.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -20,21 +22,45 @@ namespace Nz
|
||||
class NAZARA_GRAPHICS_API UberShader
|
||||
{
|
||||
public:
|
||||
struct Config;
|
||||
struct Option;
|
||||
UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst);
|
||||
~UberShader() = default;
|
||||
|
||||
UInt64 GetOptionFlagByName(const std::string& optionName) const;
|
||||
|
||||
inline ShaderStageTypeFlags GetSupportedStages() const;
|
||||
|
||||
const std::shared_ptr<ShaderModule>& Get(UInt64 combination);
|
||||
const std::shared_ptr<ShaderModule>& Get(const Config& config);
|
||||
|
||||
inline bool HasOption(const std::string& optionName, Pointer<const Option>* option = nullptr) const;
|
||||
|
||||
static constexpr std::size_t MaximumOptionValue = 32;
|
||||
|
||||
struct Config
|
||||
{
|
||||
std::array<ShaderAst::ConstantValue, MaximumOptionValue> optionValues;
|
||||
};
|
||||
|
||||
struct ConfigEqual
|
||||
{
|
||||
inline bool operator()(const Config& lhs, const Config& rhs) const;
|
||||
};
|
||||
|
||||
struct ConfigHasher
|
||||
{
|
||||
inline std::size_t operator()(const Config& config) const;
|
||||
};
|
||||
|
||||
struct Option
|
||||
{
|
||||
std::size_t index;
|
||||
ShaderAst::ExpressionType type;
|
||||
};
|
||||
|
||||
private:
|
||||
std::unordered_map<UInt64 /*combination*/, std::shared_ptr<ShaderModule>> m_combinations;
|
||||
std::unordered_map<std::string, std::size_t> m_optionIndexByName;
|
||||
std::unordered_map<Config, std::shared_ptr<ShaderModule>, ConfigHasher, ConfigEqual> m_combinations;
|
||||
std::unordered_map<std::string, Option> m_optionIndexByName;
|
||||
ShaderAst::StatementPtr m_shaderAst;
|
||||
ShaderStageTypeFlags m_shaderStages;
|
||||
UInt64 m_combinationMask;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,38 @@ namespace Nz
|
||||
{
|
||||
return m_shaderStages;
|
||||
}
|
||||
|
||||
inline bool UberShader::HasOption(const std::string& optionName, Pointer<const Option>* option) const
|
||||
{
|
||||
auto it = m_optionIndexByName.find(optionName);
|
||||
if (it == m_optionIndexByName.end())
|
||||
return false;
|
||||
|
||||
if (option)
|
||||
*option = &it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool UberShader::ConfigEqual::operator()(const Config& lhs, const Config& rhs) const
|
||||
{
|
||||
for (std::size_t i = 0; i < lhs.optionValues.size(); ++i)
|
||||
{
|
||||
if (lhs.optionValues[i] != rhs.optionValues[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::size_t UberShader::ConfigHasher::operator()(const Config& config) const
|
||||
{
|
||||
std::size_t hash = 0;
|
||||
for (std::size_t i = 0; i < config.optionValues.size(); ++i)
|
||||
HashCombine(hash, config.optionValues[i]);
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <Nazara/Shader/Config.hpp>
|
||||
#include <Nazara/Shader/Ast/AstCloner.hpp>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace Nz::ShaderAst
|
||||
@@ -36,7 +37,6 @@ namespace Nz::ShaderAst
|
||||
struct Options
|
||||
{
|
||||
std::function<const ConstantValue&(std::size_t constantId)> constantQueryCallback;
|
||||
std::optional<UInt64> enabledOptions = 0;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
|
||||
namespace Nz::ShaderAst
|
||||
{
|
||||
using NoValue = std::monostate;
|
||||
|
||||
using ConstantTypes = TypeList<
|
||||
NoValue,
|
||||
bool,
|
||||
float,
|
||||
Int32,
|
||||
|
||||
@@ -302,7 +302,7 @@ namespace Nz::ShaderAst
|
||||
|
||||
std::optional<std::size_t> optIndex;
|
||||
std::string optName;
|
||||
ExpressionPtr initialValue;
|
||||
ExpressionPtr defaultValue;
|
||||
ExpressionType optType;
|
||||
};
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Nz::ShaderAst
|
||||
struct Options
|
||||
{
|
||||
std::unordered_set<std::string> reservedIdentifiers;
|
||||
UInt64 enabledOptions = 0;
|
||||
std::unordered_map<std::size_t, ConstantValue> optionValues;
|
||||
bool makeVariableNameUnique = false;
|
||||
bool removeOptionDeclaration = true;
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Nz
|
||||
};
|
||||
|
||||
static const char* GetFlipYUniformName();
|
||||
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, UInt64 enabledOptions, std::string* error = nullptr);
|
||||
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, std::unordered_map<std::size_t, ShaderAst::ConstantValue> optionValues, std::string* error = nullptr);
|
||||
|
||||
private:
|
||||
void Append(const ShaderAst::ExpressionType& type);
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace Nz::ShaderBuilder
|
||||
auto declareOptionNode = std::make_unique<ShaderAst::DeclareOptionStatement>();
|
||||
declareOptionNode->optName = std::move(name);
|
||||
declareOptionNode->optType = std::move(type);
|
||||
declareOptionNode->initialValue = std::move(initialValue);
|
||||
declareOptionNode->defaultValue = std::move(initialValue);
|
||||
|
||||
return declareOptionNode;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Shader/Config.hpp>
|
||||
#include <Nazara/Shader/Ast/ConstantValue.hpp>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
@@ -26,7 +27,7 @@ namespace Nz
|
||||
|
||||
struct States
|
||||
{
|
||||
Nz::UInt64 enabledOptions = 0;
|
||||
std::unordered_map<std::size_t, ShaderAst::ConstantValue> optionValues;
|
||||
bool optimize = false;
|
||||
bool sanitized = false;
|
||||
};
|
||||
|
||||
@@ -63,8 +63,6 @@ namespace Nz
|
||||
UInt32 GetPointerTypeId(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const;
|
||||
UInt32 GetTypeId(const ShaderAst::ExpressionType& type) const;
|
||||
|
||||
bool IsOptionEnabled(std::size_t optionIndex) const;
|
||||
|
||||
UInt32 RegisterConstant(const ShaderAst::ConstantValue& value);
|
||||
UInt32 RegisterFunctionType(const ShaderAst::DeclareFunctionStatement& functionNode);
|
||||
UInt32 RegisterPointerType(ShaderAst::ExpressionType type, SpirvStorageClass storageClass);
|
||||
|
||||
Reference in New Issue
Block a user