Commit current work

Reworked conditions, added uber-shaders, comparison nodes, fixed Discard
This commit is contained in:
Jérôme Leclercq
2021-01-02 21:15:59 +01:00
parent ed72d668d9
commit f327932738
103 changed files with 3248 additions and 790 deletions

View File

@@ -17,30 +17,48 @@ namespace Nz
friend class MaterialPipeline;
public:
struct UniformOffsets;
BasicMaterial(Material& material);
inline void EnableAlphaTest(bool alphaTest);
inline const std::shared_ptr<Texture>& GetAlphaMap() const;
float GetAlphaThreshold() const;
inline const std::shared_ptr<TextureSampler>& GetAlphaSampler() const;
float GetAlphaTestThreshold() const;
Color GetDiffuseColor() const;
inline const std::shared_ptr<Texture>& GetDiffuseMap() const;
inline const std::shared_ptr<TextureSampler>& GetDiffuseSampler() const;
inline bool HasAlphaMap() const;
inline bool HasAlphaThreshold() const;
inline bool HasAlphaTest() const;
inline bool HasAlphaTestThreshold() const;
inline bool HasDiffuseColor() const;
inline bool HasDiffuseMap() const;
inline void SetAlphaMap(std::shared_ptr<Texture> alphaMap);
void SetAlphaThreshold(float alphaThreshold);
inline void SetAlphaSampler(std::shared_ptr<TextureSampler> alphaSampler);
void SetAlphaTestThreshold(float alphaThreshold);
void SetDiffuseColor(const Color& diffuse);
inline void SetDiffuseMap(std::shared_ptr<Texture> diffuseMap);
inline void SetDiffuseSampler(std::shared_ptr<TextureSampler> diffuseSampler);
static const std::shared_ptr<MaterialSettings>& GetSettings();
static inline const UniformOffsets& GetOffsets();
static inline const std::shared_ptr<MaterialSettings>& GetSettings();
private:
struct UniformOffsets
{
std::size_t alphaThreshold;
std::size_t diffuseColor;
std::size_t totalSize;
};
private:
struct ConditionIndexes
{
std::size_t alphaTest;
std::size_t hasAlphaMap;
std::size_t hasDiffuseMap;
};
struct TextureIndexes
@@ -54,11 +72,13 @@ namespace Nz
Material& m_material;
std::size_t m_uniformBlockIndex;
ConditionIndexes m_conditionIndexes;
TextureIndexes m_textureIndexes;
UniformOffsets m_uniformOffsets;
static std::shared_ptr<MaterialSettings> s_materialSettings;
static std::size_t s_uniformBlockIndex;
static ConditionIndexes s_conditionIndexes;
static TextureIndexes s_textureIndexes;
static UniformOffsets s_uniformOffsets;
};

View File

@@ -9,24 +9,47 @@
namespace Nz
{
inline void BasicMaterial::EnableAlphaTest(bool alphaTest)
{
NazaraAssert(HasAlphaTest(), "Material has no alpha test condition");
m_material.EnableCondition(m_conditionIndexes.alphaTest, alphaTest);
}
inline const std::shared_ptr<Texture>& BasicMaterial::GetAlphaMap() const
{
NazaraAssert(HasAlphaMap(), "Material has no alpha map slot");
NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot");
return m_material.GetTexture(m_textureIndexes.alpha);
}
inline const std::shared_ptr<TextureSampler>& BasicMaterial::GetAlphaSampler() const
{
NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot");
return m_material.GetTextureSampler(m_textureIndexes.alpha);
}
inline const std::shared_ptr<Texture>& BasicMaterial::GetDiffuseMap() const
{
NazaraAssert(HasDiffuseMap(), "Material has no alpha map slot");
NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot");
return m_material.GetTexture(m_textureIndexes.diffuse);
}
inline const std::shared_ptr<TextureSampler>& BasicMaterial::GetDiffuseSampler() const
{
NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot");
return m_material.GetTextureSampler(m_textureIndexes.diffuse);
}
inline bool BasicMaterial::HasAlphaMap() const
{
return m_textureIndexes.alpha != MaterialSettings::InvalidIndex;
}
inline bool BasicMaterial::HasAlphaThreshold() const
inline bool BasicMaterial::HasAlphaTest() const
{
return m_conditionIndexes.alphaTest != MaterialSettings::InvalidIndex;
}
inline bool BasicMaterial::HasAlphaTestThreshold() const
{
return m_uniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex;
}
@@ -44,13 +67,43 @@ namespace Nz
inline void BasicMaterial::SetAlphaMap(std::shared_ptr<Texture> alphaMap)
{
NazaraAssert(HasAlphaMap(), "Material has no alpha map slot");
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);
}
inline void BasicMaterial::SetAlphaSampler(std::shared_ptr<TextureSampler> alphaSampler)
{
NazaraAssert(HasAlphaMap(), "Material has no alpha map slot");
m_material.SetTextureSampler(m_textureIndexes.alpha, std::move(alphaSampler));
}
inline void BasicMaterial::SetDiffuseMap(std::shared_ptr<Texture> diffuseMap)
{
NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot");
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);
}
inline void BasicMaterial::SetDiffuseSampler(std::shared_ptr<TextureSampler> diffuseSampler)
{
NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot");
m_material.SetTextureSampler(m_textureIndexes.diffuse, std::move(diffuseSampler));
}
inline const std::shared_ptr<MaterialSettings>& BasicMaterial::GetSettings()
{
return s_materialSettings;
}
inline auto BasicMaterial::GetOffsets() -> const UniformOffsets&
{
return s_uniformOffsets;
}
}

View File

@@ -41,6 +41,7 @@ namespace Nz
inline void EnableAlphaTest(bool alphaTest);
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);
@@ -53,7 +54,7 @@ namespace Nz
inline void EnableVertexColor(bool vertexColor);
inline void EnsurePipelineUpdate() const;
inline RendererComparison GetDepthCompareFunc() const;
inline BlendFunc GetDstBlend() const;
inline FaceSide GetFaceCulling() const;
@@ -63,7 +64,7 @@ namespace Nz
inline const MaterialPipelineInfo& GetPipelineInfo() const;
inline float GetPointSize() const;
inline const std::shared_ptr<const MaterialSettings>& GetSettings() const;
inline const std::shared_ptr<ShaderStage>& GetShader(ShaderStageType shaderStage) const;
inline const std::shared_ptr<UberShader>& GetShader(ShaderStageType shaderStage) const;
inline BlendFunc GetSrcBlend() const;
inline const std::shared_ptr<Texture>& GetTexture(std::size_t textureIndex) const;
inline const std::shared_ptr<TextureSampler>& GetTextureSampler(std::size_t textureIndex) const;
@@ -76,6 +77,7 @@ namespace Nz
inline bool IsAlphaTestEnabled() const;
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;
@@ -92,7 +94,6 @@ namespace Nz
inline void SetFaceFilling(FaceFilling filling);
inline void SetLineWidth(float lineWidth);
inline void SetPointSize(float pointSize);
inline void SetShader(ShaderStageType shaderStage, std::shared_ptr<ShaderStage> shader);
inline void SetUniformBuffer(std::size_t bufferIndex, UniformBufferRef uniformBuffer);
inline void SetSrcBlend(BlendFunc func);
inline void SetTexture(std::size_t textureIndex, std::shared_ptr<Texture> texture);
@@ -115,7 +116,8 @@ namespace Nz
std::vector<MaterialTexture> m_textures;
std::vector<UniformBufferRef> m_uniformBuffers;
mutable std::shared_ptr<MaterialPipeline> m_pipeline;
MaterialPipelineInfo m_pipelineInfo;
UInt32 m_enabledConditions;
mutable MaterialPipelineInfo m_pipelineInfo;
mutable bool m_pipelineUpdated;
bool m_shadowCastingEnabled;
};

View File

@@ -111,6 +111,15 @@ namespace Nz
InvalidatePipeline();
}
inline void Material::EnableCondition(std::size_t conditionIndex, bool enable)
{
if (TestBit<UInt64>(m_enabledConditions, conditionIndex) != enable)
{
m_enabledConditions = SetBit<UInt64>(m_enabledConditions, conditionIndex);
InvalidatePipeline();
}
}
/*!
* \brief Enable/Disable depth buffer for this material
*
@@ -428,9 +437,9 @@ namespace Nz
* \brief Gets the über-shader used by this material
* \return Constant pointer to the über-shader used
*/
inline const std::shared_ptr<ShaderStage>& Material::GetShader(ShaderStageType shaderStage) const
inline const std::shared_ptr<UberShader>& Material::GetShader(ShaderStageType shaderStage) const
{
return m_pipelineInfo.shaders[UnderlyingCast(shaderStage)];
return m_pipelineInfo.shaders[UnderlyingCast(shaderStage)].uberShader;
}
/*!
@@ -507,6 +516,11 @@ 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
@@ -682,22 +696,6 @@ namespace Nz
InvalidatePipeline();
}
/*!
* \brief Sets the shader with a constant reference to a ubershader
*
* \param uberShader Uber shader to apply
*
* \remark Invalidates the pipeline
*
* \see GetShader
*/
inline void Material::SetShader(ShaderStageType shaderStage, std::shared_ptr<ShaderStage> shader)
{
m_pipelineInfo.shaders[UnderlyingCast(shaderStage)] = std::move(shader);
InvalidatePipeline();
}
inline void Material::SetUniformBuffer(std::size_t bufferIndex, UniformBufferRef uniformBuffer)
{
NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid shared uniform buffer index");
@@ -739,6 +737,19 @@ namespace Nz
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;
}

View File

@@ -17,18 +17,24 @@
namespace Nz
{
class ShaderStage;
class UberShader;
struct MaterialPipelineInfo : RenderStates
{
struct ShaderStage
{
std::shared_ptr<UberShader> uberShader;
Nz::UInt64 enabledConditions = 0;
};
bool alphaTest = false;
bool depthSorting = false;
bool hasVertexColor = false;
bool reflectionMapping = false;
bool shadowReceive = true;
std::array<ShaderStage, ShaderStageTypeCount> shaders;
std::shared_ptr<const MaterialSettings> settings;
std::array<std::shared_ptr<ShaderStage>, ShaderStageTypeCount> shaders;
};
inline bool operator==(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs);

View File

@@ -40,7 +40,10 @@ namespace Nz
for (std::size_t i = 0; i < lhs.shaders.size(); ++i)
{
if (lhs.shaders[i] != rhs.shaders[i])
if (lhs.shaders[i].enabledConditions != rhs.shaders[i].enabledConditions)
return false;
if (lhs.shaders[i].uberShader != rhs.shaders[i].uberShader)
return false;
}
@@ -82,7 +85,10 @@ namespace std
NazaraPipelineMember(settings.get()); //< Hash pointer
for (const auto& shader : pipelineInfo.shaders)
Nz::HashCombine(seed, shader.get());
{
Nz::HashCombine(seed, shader.enabledConditions);
Nz::HashCombine(seed, shader.uberShader.get());
}
#undef NazaraPipelineMember
#undef NazaraPipelineBoolMember

View File

@@ -19,29 +19,35 @@
namespace Nz
{
class UberShader;
class MaterialSettings
{
public:
using DefaultShaders = std::array<std::shared_ptr<ShaderStage>, ShaderStageTypeCount>;
using PredefinedBinding = std::array<std::size_t, PredefinedShaderBindingCount>;
using Shaders = std::array<std::shared_ptr<UberShader>, ShaderStageTypeCount>;
struct Builder;
struct Condition;
struct SharedUniformBlock;
struct Texture;
struct UniformBlock;
inline MaterialSettings();
inline MaterialSettings(std::vector<Texture> textures, std::vector<UniformBlock> uniformBlocks, std::vector<SharedUniformBlock> sharedUniformBlocks, const PredefinedBinding& predefinedBinding, DefaultShaders defaultShaders);
inline MaterialSettings(Builder builder);
MaterialSettings(const MaterialSettings&) = default;
MaterialSettings(MaterialSettings&&) = delete;
~MaterialSettings() = default;
inline const std::shared_ptr<ShaderStage>& GetDefaultShader(ShaderStageType stage) const;
inline const DefaultShaders& GetDefaultShaders() const;
inline const std::vector<Condition>& GetConditions() const;
inline std::size_t GetConditionIndex(const std::string_view& name) const;
inline std::size_t GetPredefinedBindingIndex(PredefinedShaderBinding binding) 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<SharedUniformBlock>& GetSharedUniformBlocks() const;
inline std::size_t GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) 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;
inline const std::vector<Texture>& GetTextures() const;
inline std::size_t GetTextureIndex(const std::string_view& name) const;
inline const std::vector<UniformBlock>& GetUniformBlocks() const;
@@ -53,6 +59,22 @@ namespace Nz
static constexpr std::size_t InvalidIndex = std::numeric_limits<std::size_t>::max();
struct Builder
{
PredefinedBinding predefinedBinding;
Shaders shaders;
std::vector<Condition> conditions;
std::vector<Texture> textures;
std::vector<UniformBlock> uniformBlocks;
std::vector<SharedUniformBlock> sharedUniformBlocks;
};
struct Condition
{
std::string name;
std::array<UInt64, ShaderStageTypeCount> enabledConditions;
};
struct UniformVariable
{
std::string name;
@@ -84,11 +106,7 @@ namespace Nz
private:
std::shared_ptr<RenderPipelineLayout> m_pipelineLayout;
std::vector<SharedUniformBlock> m_sharedUniformBlocks;
std::vector<Texture> m_textures;
std::vector<UniformBlock> m_uniformBlocks;
DefaultShaders m_defaultShaders;
PredefinedBinding m_predefinedBinding;
Builder m_data;
};
}

View File

@@ -10,22 +10,18 @@
namespace Nz
{
inline MaterialSettings::MaterialSettings() :
MaterialSettings({}, {}, {}, { InvalidIndex }, {})
MaterialSettings(Builder{})
{
}
inline MaterialSettings::MaterialSettings(std::vector<Texture> textures, std::vector<UniformBlock> uniformBlocks, std::vector<SharedUniformBlock> sharedUniformBlocks, const PredefinedBinding& predefinedBindings, DefaultShaders defaultShaders) :
m_sharedUniformBlocks(std::move(sharedUniformBlocks)),
m_textures(std::move(textures)),
m_uniformBlocks(std::move(uniformBlocks)),
m_defaultShaders(std::move(defaultShaders)),
m_predefinedBinding(predefinedBindings)
inline MaterialSettings::MaterialSettings(Builder data) :
m_data(std::move(data))
{
RenderPipelineLayoutInfo info;
unsigned int bindingIndex = 0;
for (const Texture& textureInfo : m_textures)
for (const Texture& textureInfo : m_data.textures)
{
info.bindings.push_back({
//textureInfo.bindingPoint,
@@ -35,7 +31,7 @@ namespace Nz
});
}
for (const UniformBlock& ubo : m_uniformBlocks)
for (const UniformBlock& ubo : m_data.uniformBlocks)
{
info.bindings.push_back({
//ubo.bindingPoint,
@@ -45,7 +41,7 @@ namespace Nz
});
}
for (const SharedUniformBlock& ubo : m_sharedUniformBlocks)
for (const SharedUniformBlock& ubo : m_data.sharedUniformBlocks)
{
info.bindings.push_back({
//ubo.bindingPoint,
@@ -58,19 +54,25 @@ namespace Nz
m_pipelineLayout = Graphics::Instance()->GetRenderDevice().InstantiateRenderPipelineLayout(std::move(info));
}
inline const std::shared_ptr<ShaderStage>& MaterialSettings::GetDefaultShader(ShaderStageType stage) const
inline auto MaterialSettings::GetConditions() const -> const std::vector<Condition>&
{
return m_defaultShaders[UnderlyingCast(stage)];
return m_data.conditions;
}
inline auto MaterialSettings::GetDefaultShaders() const -> const DefaultShaders&
inline std::size_t MaterialSettings::GetConditionIndex(const std::string_view& name) const
{
return m_defaultShaders;
for (std::size_t i = 0; i < m_data.conditions.size(); ++i)
{
if (m_data.conditions[i].name == name)
return i;
}
return InvalidIndex;
}
inline std::size_t MaterialSettings::GetPredefinedBindingIndex(PredefinedShaderBinding binding) const
{
return m_predefinedBinding[UnderlyingCast(binding)];
return m_data.predefinedBinding[UnderlyingCast(binding)];
}
inline const std::shared_ptr<RenderPipelineLayout>& MaterialSettings::GetRenderPipelineLayout() const
@@ -78,32 +80,37 @@ namespace Nz
return m_pipelineLayout;
}
inline const std::shared_ptr<UberShader>& MaterialSettings::GetShader(ShaderStageType stage) const
{
return m_data.shaders[UnderlyingCast(stage)];
}
inline auto MaterialSettings::GetShaders() const -> const Shaders&
{
return m_data.shaders;
}
inline auto MaterialSettings::GetSharedUniformBlocks() const -> const std::vector<SharedUniformBlock>&
{
return m_sharedUniformBlocks;
return m_data.sharedUniformBlocks;
}
inline std::size_t MaterialSettings::GetSharedUniformBlockIndex(const std::string_view& name) const
{
for (std::size_t i = 0; i < m_sharedUniformBlocks.size(); ++i)
for (std::size_t i = 0; i < m_data.sharedUniformBlocks.size(); ++i)
{
if (m_sharedUniformBlocks[i].name == name)
if (m_data.sharedUniformBlocks[i].name == name)
return i;
}
return InvalidIndex;
}
inline auto MaterialSettings::GetTextures() const -> const std::vector<Texture>&
{
return m_textures;
}
inline std::size_t MaterialSettings::GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const
{
assert(uniformBlockIndex < m_sharedUniformBlocks.size());
assert(uniformBlockIndex < m_data.sharedUniformBlocks.size());
const std::vector<UniformVariable>& variables = m_sharedUniformBlocks[uniformBlockIndex].uniforms;
const std::vector<UniformVariable>& variables = m_data.sharedUniformBlocks[uniformBlockIndex].uniforms;
for (std::size_t i = 0; i < variables.size(); ++i)
{
if (variables[i].name == name)
@@ -113,11 +120,16 @@ namespace Nz
return InvalidIndex;
}
inline auto MaterialSettings::GetTextures() const -> const std::vector<Texture>&
{
return m_data.textures;
}
inline std::size_t MaterialSettings::GetTextureIndex(const std::string_view& name) const
{
for (std::size_t i = 0; i < m_textures.size(); ++i)
for (std::size_t i = 0; i < m_data.textures.size(); ++i)
{
if (m_textures[i].name == name)
if (m_data.textures[i].name == name)
return i;
}
@@ -126,14 +138,14 @@ namespace Nz
inline auto MaterialSettings::GetUniformBlocks() const -> const std::vector<UniformBlock>&
{
return m_uniformBlocks;
return m_data.uniformBlocks;
}
inline std::size_t MaterialSettings::GetUniformBlockIndex(const std::string_view& name) const
{
for (std::size_t i = 0; i < m_uniformBlocks.size(); ++i)
for (std::size_t i = 0; i < m_data.uniformBlocks.size(); ++i)
{
if (m_uniformBlocks[i].name == name)
if (m_data.uniformBlocks[i].name == name)
return i;
}
@@ -142,9 +154,9 @@ namespace Nz
inline std::size_t MaterialSettings::GetUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const
{
assert(uniformBlockIndex < m_uniformBlocks.size());
assert(uniformBlockIndex < m_data.uniformBlocks.size());
const std::vector<UniformVariable>& variables = m_uniformBlocks[uniformBlockIndex].uniforms;
const std::vector<UniformVariable>& variables = m_data.uniformBlocks[uniformBlockIndex].uniforms;
for (std::size_t i = 0; i < variables.size(); ++i)
{
if (variables[i].name == name)

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_UBER_SHADER_HPP
#define NAZARA_UBER_SHADER_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Bitset.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Shader/ShaderAst.hpp>
#include <unordered_map>
namespace Nz
{
class ShaderStage;
class NAZARA_GRAPHICS_API UberShader
{
public:
inline UberShader(ShaderAst shaderAst);
~UberShader() = default;
UInt64 GetConditionFlagByName(const std::string_view& condition) const;
const std::shared_ptr<ShaderStage>& Get(UInt64 combination);
private:
std::unordered_map<UInt64 /*combination*/, std::shared_ptr<ShaderStage>> m_combinations;
ShaderAst m_shaderAst;
UInt64 m_combinationMask;
};
}
#include <Nazara/Graphics/UberShader.inl>
#endif // NAZARA_UBER_SHADER_HPP

View File

@@ -0,0 +1,12 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/UberShader.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
}
#include <Nazara/Graphics/DebugOff.hpp>