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>
|
||||
|
||||
Reference in New Issue
Block a user