Graphics: rework ubershaders to prevent duplicate shaders modules

Also rename all remaining conditions to options
This commit is contained in:
Jérôme Leclercq
2021-07-08 14:52:39 +02:00
parent 9ab47edd11
commit a895e553d4
38 changed files with 524 additions and 485 deletions

View File

@@ -56,7 +56,7 @@ namespace Nz
};
private:
struct ConditionIndexes
struct OptionIndexes
{
std::size_t alphaTest;
std::size_t hasAlphaMap;
@@ -74,13 +74,13 @@ namespace Nz
Material& m_material;
std::size_t m_uniformBlockIndex;
ConditionIndexes m_conditionIndexes;
OptionIndexes m_optionIndexes;
TextureIndexes m_textureIndexes;
UniformOffsets m_uniformOffsets;
static std::shared_ptr<MaterialSettings> s_materialSettings;
static std::size_t s_uniformBlockIndex;
static ConditionIndexes s_conditionIndexes;
static OptionIndexes s_optionIndexes;
static TextureIndexes s_textureIndexes;
static UniformOffsets s_uniformOffsets;
};

View File

@@ -25,8 +25,8 @@ namespace Nz
*/
inline void BasicMaterial::EnableAlphaTest(bool alphaTest)
{
NazaraAssert(HasAlphaTest(), "Material has no alpha test condition");
m_material.EnableCondition(m_conditionIndexes.alphaTest, alphaTest);
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
m_material.EnableOption(m_optionIndexes.alphaTest, alphaTest);
}
inline const std::shared_ptr<Texture>& BasicMaterial::GetAlphaMap() const
@@ -55,8 +55,8 @@ namespace Nz
inline bool BasicMaterial::IsAlphaTestEnabled() const
{
NazaraAssert(HasAlphaTest(), "Material has no alpha test condition");
return m_material.IsConditionEnabled(m_conditionIndexes.alphaTest);
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
return m_material.IsOptionEnabled(m_optionIndexes.alphaTest);
}
inline bool BasicMaterial::HasAlphaMap() const
@@ -66,7 +66,7 @@ namespace Nz
inline bool BasicMaterial::HasAlphaTest() const
{
return m_conditionIndexes.alphaTest != MaterialSettings::InvalidIndex;
return m_optionIndexes.alphaTest != MaterialSettings::InvalidIndex;
}
inline bool BasicMaterial::HasAlphaTestThreshold() const
@@ -90,8 +90,8 @@ namespace Nz
bool hasAlphaMap = (alphaMap != nullptr);
m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap));
if (m_conditionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.EnableCondition(m_conditionIndexes.hasAlphaMap, hasAlphaMap);
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.EnableOption(m_optionIndexes.hasAlphaMap, hasAlphaMap);
}
inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler)
@@ -106,8 +106,8 @@ namespace Nz
bool hasDiffuseMap = (diffuseMap != nullptr);
m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap));
if (m_conditionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.EnableCondition(m_conditionIndexes.hasDiffuseMap, hasDiffuseMap);
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.EnableOption(m_optionIndexes.hasDiffuseMap, hasDiffuseMap);
}
inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler)

View File

@@ -41,11 +41,11 @@ namespace Nz
inline void EnableBlending(bool blending);
inline void EnableColorWrite(bool colorWrite);
inline void EnableCondition(std::size_t conditionIndex, bool enable);
inline void EnableDepthBuffer(bool depthBuffer);
inline void EnableDepthSorting(bool depthSorting);
inline void EnableDepthWrite(bool depthWrite);
inline void EnableFaceCulling(bool faceCulling);
inline void EnableOption(std::size_t optionIndex, bool enable);
inline void EnableReflectionMapping(bool reflection);
inline void EnableScissorTest(bool scissorTest);
inline void EnableShadowCasting(bool castShadows);
@@ -83,11 +83,11 @@ namespace Nz
inline bool IsBlendingEnabled() const;
inline bool IsColorWriteEnabled() const;
inline bool IsConditionEnabled(std::size_t conditionIndex) const;
inline bool IsDepthBufferEnabled() const;
inline bool IsDepthSortingEnabled() const;
inline bool IsDepthWriteEnabled() const;
inline bool IsFaceCullingEnabled() const;
inline bool IsOptionEnabled(std::size_t optionIndex) const;
inline bool IsReflectionMappingEnabled() const;
inline bool IsScissorTestEnabled() const;
inline bool IsStencilTestEnabled() const;
@@ -117,7 +117,7 @@ namespace Nz
inline void InvalidateShaderBinding();
inline void InvalidateTextureSampler(std::size_t textureIndex);
inline void InvalidateUniformData(std::size_t uniformBufferIndex);
inline void UpdatePipeline() const;
void UpdatePipeline() const;
void UpdateShaderBinding();
struct MaterialTexture
@@ -138,7 +138,7 @@ namespace Nz
std::vector<MaterialTexture> m_textures;
std::vector<UniformBuffer> m_uniformBuffers;
mutable std::shared_ptr<MaterialPipeline> m_pipeline;
UInt64 m_enabledConditions;
UInt64 m_enabledOptions;
mutable MaterialPipelineInfo m_pipelineInfo;
ShaderBindingPtr m_shaderBinding;
mutable bool m_pipelineUpdated;

View File

@@ -90,15 +90,6 @@ namespace Nz
InvalidatePipeline();
}
inline void Material::EnableCondition(std::size_t conditionIndex, bool enable)
{
if (TestBit<UInt64>(m_enabledConditions, conditionIndex) != enable)
{
m_enabledConditions = ToggleBit<UInt64>(m_enabledConditions, conditionIndex);
InvalidatePipeline();
}
}
/*!
* \brief Enable/Disable depth buffer for this material
*
@@ -189,6 +180,15 @@ namespace Nz
InvalidatePipeline();
}
inline void Material::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 reflection mapping for this material
*
@@ -515,11 +515,6 @@ namespace Nz
return m_pipelineInfo.colorWrite;
}
inline bool Material::IsConditionEnabled(std::size_t conditionIndex) const
{
return TestBit<UInt64>(m_enabledConditions, conditionIndex);
}
/*!
* \brief Checks whether this material has depth buffer enabled
* \return true If it is the case
@@ -556,6 +551,11 @@ namespace Nz
return m_pipelineInfo.faceCulling;
}
inline bool Material::IsOptionEnabled(std::size_t optionIndex) const
{
return TestBit<UInt64>(m_enabledOptions, optionIndex);
}
/*!
* \brief Checks whether this material has reflection mapping enabled
* \return true If it is the case
@@ -766,25 +766,6 @@ namespace Nz
OnMaterialInvalidated(this);
}
inline void Material::UpdatePipeline() const
{
for (auto& shader : m_pipelineInfo.shaders)
shader.enabledConditions = 0;
const auto& conditions = m_settings->GetConditions();
for (std::size_t conditionIndex = 0; conditionIndex < conditions.size(); ++conditionIndex)
{
if (TestBit<UInt64>(m_enabledConditions, conditionIndex))
{
for (std::size_t shaderStage = 0; shaderStage < ShaderStageTypeCount; ++shaderStage)
m_pipelineInfo.shaders[shaderStage].enabledConditions |= conditions[conditionIndex].enabledConditions[shaderStage];
}
}
m_pipeline = MaterialPipeline::Get(m_pipelineInfo);
m_pipelineUpdated = true;
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@@ -21,10 +21,10 @@ namespace Nz
struct MaterialPipelineInfo : RenderStates
{
struct ShaderStage
struct Shader
{
std::shared_ptr<UberShader> uberShader;
Nz::UInt64 enabledConditions = 0;
Nz::UInt64 enabledOptions = 0;
};
bool depthSorting = false;
@@ -32,7 +32,7 @@ namespace Nz
bool reflectionMapping = false;
bool shadowReceive = true;
std::array<ShaderStage, ShaderStageTypeCount> shaders;
std::vector<Shader> shaders;
std::shared_ptr<const MaterialSettings> settings;
};

View File

@@ -40,7 +40,7 @@ namespace Nz
for (std::size_t i = 0; i < lhs.shaders.size(); ++i)
{
if (lhs.shaders[i].enabledConditions != rhs.shaders[i].enabledConditions)
if (lhs.shaders[i].enabledOptions != rhs.shaders[i].enabledOptions)
return false;
if (lhs.shaders[i].uberShader != rhs.shaders[i].uberShader)
@@ -85,7 +85,7 @@ namespace std
for (const auto& shader : pipelineInfo.shaders)
{
Nz::HashCombine(seed, shader.enabledConditions);
Nz::HashCombine(seed, shader.enabledOptions);
Nz::HashCombine(seed, shader.uberShader.get());
}

View File

@@ -24,10 +24,8 @@ namespace Nz
class MaterialSettings
{
public:
using Shaders = std::array<std::shared_ptr<UberShader>, ShaderStageTypeCount>;
struct Builder;
struct Condition;
struct Option;
struct SharedUniformBlock;
struct Texture;
struct UniformBlock;
@@ -39,11 +37,11 @@ namespace Nz
~MaterialSettings() = default;
inline const Builder& GetBuilderData() const;
inline const std::vector<Condition>& GetConditions() const;
inline std::size_t GetConditionIndex(const std::string_view& name) const;
inline const std::vector<Option>& GetOptions() const;
inline std::size_t GetOptionIndex(const std::string_view& name) const;
inline const std::shared_ptr<RenderPipelineLayout>& GetRenderPipelineLayout() const;
inline const std::shared_ptr<UberShader>& GetShader(ShaderStageType stage) const;
inline const Shaders& GetShaders() const;
inline const std::vector<std::shared_ptr<UberShader>>& GetShaders() const;
inline const std::vector<SharedUniformBlock>& GetSharedUniformBlocks() const;
inline std::size_t GetSharedUniformBlockIndex(const std::string_view& name) const;
inline std::size_t GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const;
@@ -60,17 +58,17 @@ namespace Nz
struct Builder
{
Shaders shaders;
std::vector<Condition> conditions;
std::vector<std::shared_ptr<UberShader>> shaders;
std::vector<Option> options;
std::vector<Texture> textures;
std::vector<UniformBlock> uniformBlocks;
std::vector<SharedUniformBlock> sharedUniformBlocks;
};
struct Condition
struct Option
{
std::string name;
std::array<UInt64, ShaderStageTypeCount> enabledConditions;
std::array<UInt64, ShaderStageTypeCount> enabledOptions;
};
struct UniformVariable

View File

@@ -59,16 +59,16 @@ namespace Nz
return m_data;
}
inline auto MaterialSettings::GetConditions() const -> const std::vector<Condition>&
inline auto MaterialSettings::GetOptions() const -> const std::vector<Option>&
{
return m_data.conditions;
return m_data.options;
}
inline std::size_t MaterialSettings::GetConditionIndex(const std::string_view& name) const
inline std::size_t MaterialSettings::GetOptionIndex(const std::string_view& name) const
{
for (std::size_t i = 0; i < m_data.conditions.size(); ++i)
for (std::size_t i = 0; i < m_data.options.size(); ++i)
{
if (m_data.conditions[i].name == name)
if (m_data.options[i].name == name)
return i;
}
@@ -85,7 +85,7 @@ namespace Nz
return m_data.shaders[UnderlyingCast(stage)];
}
inline auto MaterialSettings::GetShaders() const -> const Shaders&
inline const std::vector<std::shared_ptr<UberShader>>& MaterialSettings::GetShaders() const
{
return m_data.shaders;
}

View File

@@ -20,18 +20,20 @@ namespace Nz
class NAZARA_GRAPHICS_API UberShader
{
public:
UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst);
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);
private:
std::unordered_map<UInt64 /*combination*/, std::shared_ptr<ShaderModule>> m_combinations;
std::unordered_map<std::string, std::size_t> m_optionIndexByName;
ShaderAst::StatementPtr m_shaderAst;
ShaderStageType m_shaderStage;
ShaderStageTypeFlags m_shaderStages;
UInt64 m_combinationMask;
};
}

View File

@@ -7,6 +7,10 @@
namespace Nz
{
inline ShaderStageTypeFlags UberShader::GetSupportedStages() const
{
return m_shaderStages;
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@@ -31,10 +31,12 @@ namespace Nz::ShaderAst
struct Callbacks
{
std::function<void(ShaderStageType stageType, const std::string& functionName)> onEntryPointDeclaration;
std::function<void(const std::string& optionName, const ExpressionType& optionType)> onOptionDeclaration;
};
private:
void Visit(DeclareFunctionStatement& node) override;
void Visit(DeclareOptionStatement& node) override;
const Callbacks* m_callbacks;

View File

@@ -46,7 +46,7 @@ namespace Nz
};
static const char* GetFlipYUniformName();
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, UInt64 enabledConditions, std::string* error = nullptr);
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, UInt64 enabledOptions, std::string* error = nullptr);
private:
void Append(const ShaderAst::ExpressionType& type);