Graphics: rework ubershaders to prevent duplicate shaders modules
Also rename all remaining conditions to options
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline ShaderStageTypeFlags UberShader::GetSupportedStages() const
|
||||
{
|
||||
return m_shaderStages;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
||||
Reference in New Issue
Block a user