Refactor material system (#382)

This commit is contained in:
Jérôme Leclercq
2022-10-31 19:53:41 +01:00
committed by GitHub
parent 0a8048809c
commit dc6ce8427c
156 changed files with 3633 additions and 4569 deletions

View File

@@ -3,186 +3,327 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/MaterialSettings.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <cassert>
#include <Nazara/Utils/Algorithm.hpp>
#include <stdexcept>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline MaterialSettings::MaterialSettings() :
MaterialSettings(Builder{})
template<typename T> class Vector2;
template<typename T> class Vector3;
template<typename T> class Vector4;
template<typename T>
struct TypeToMaterialPropertyType
{
static_assert(AlwaysFalse<T>(), "T is not a valid type for material property");
};
template<> struct TypeToMaterialPropertyType<bool> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Bool; };
template<> struct TypeToMaterialPropertyType<Vector2<bool>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Bool2; };
template<> struct TypeToMaterialPropertyType<Vector3<bool>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Bool3; };
template<> struct TypeToMaterialPropertyType<Vector4<bool>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Bool4; };
template<> struct TypeToMaterialPropertyType<Color> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Color; };
template<> struct TypeToMaterialPropertyType<float> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Float; };
template<> struct TypeToMaterialPropertyType<Vector2<float>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Float2; };
template<> struct TypeToMaterialPropertyType<Vector3<float>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Float3; };
template<> struct TypeToMaterialPropertyType<Vector4<float>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Float4; };
template<> struct TypeToMaterialPropertyType<Int32> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Int; };
template<> struct TypeToMaterialPropertyType<Vector2<Int32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Int2; };
template<> struct TypeToMaterialPropertyType<Vector3<Int32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Int3; };
template<> struct TypeToMaterialPropertyType<Vector4<Int32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::Int4; };
template<> struct TypeToMaterialPropertyType<UInt32> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::UInt; };
template<> struct TypeToMaterialPropertyType<Vector2<UInt32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::UInt2; };
template<> struct TypeToMaterialPropertyType<Vector3<UInt32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::UInt3; };
template<> struct TypeToMaterialPropertyType<Vector4<UInt32>> { static constexpr MaterialPropertyType PropertyType = MaterialPropertyType::UInt4; };
template<MaterialPropertyType P>
struct MaterialPropertyTypeInfo
{
};
template<typename T>
struct MaterialPropertyTypeInfoPrimitive
{
using Type = T;
using BufferType = T;
using OptionType = T;
static Type DecodeFromBuffer(BufferType value) { return value; }
static Type DecodeFromOption(OptionType value) { return value; }
static BufferType EncodeToBuffer(Type value) { return value; }
static OptionType EncodeToOption(Type value) { return value; }
};
template<typename T, std::size_t N>
struct MaterialPropertyTypeInfoVector;
template<typename T>
struct MaterialPropertyTypeInfoVector<T, 2>
{
using Type = Vector2<T>;
using BufferType = nzsl::Vector2<T>;
using OptionType = nzsl::Vector2<T>;
static Type DecodeFromBuffer(BufferType value) { return { value.x(), value.y() }; }
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y() }; }
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y }; }
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y }; }
};
template<typename T>
struct MaterialPropertyTypeInfoVector<T, 3>
{
using Type = Vector3<T>;
using BufferType = nzsl::Vector3<T>;
using OptionType = nzsl::Vector3<T>;
static Type DecodeFromBuffer(BufferType value) { return { value.x(), value.y(), value.z() }; }
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z() }; }
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y, value.z }; }
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y, value.z }; }
};
template<typename T>
struct MaterialPropertyTypeInfoVector<T, 4>
{
using Type = Vector4<T>;
using BufferType = nzsl::Vector4<T>;
using OptionType = nzsl::Vector4<T>;
static Type DecodeFromBuffer(BufferType value) { return { value.x(), value.y(), value.z(), value.w() }; }
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z(), value.w() }; }
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y, value.z, value.w }; }
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y, value.z, value.w }; }
};
template<>
struct MaterialPropertyTypeInfo<MaterialPropertyType::Bool>
{
using Type = bool;
using BufferType = UInt32;
using OptionType = bool;
static Type DecodeFromBuffer(BufferType value) { return value != 0; }
static Type DecodeFromOption(OptionType value) { return value; }
static BufferType EncodeToBuffer(Type value) { return value; }
static OptionType EncodeToOption(Type value) { return value; }
};
template<>
struct MaterialPropertyTypeInfo<MaterialPropertyType::Bool2>
{
using Type = Vector2<bool>;
using BufferType = nzsl::Vector2u32;
using OptionType = nzsl::Vector2<bool>;
static Type DecodeFromBuffer(BufferType value) { return { value.x() != 0, value.y() != 0 }; }
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y() }; }
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y }; }
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y }; }
};
template<>
struct MaterialPropertyTypeInfo<MaterialPropertyType::Bool3>
{
using Type = Vector3<bool>;
using BufferType = nzsl::Vector3u32;
using OptionType = nzsl::Vector3<bool>;
static Type DecodeFromBuffer(BufferType value) { return { value.x() != 0, value.y() != 0, value.z() != 0 }; }
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z() }; }
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y, value.z }; }
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y, value.z }; }
};
template<>
struct MaterialPropertyTypeInfo<MaterialPropertyType::Bool4>
{
using Type = Vector4<bool>;
using BufferType = nzsl::Vector4u32;
using OptionType = nzsl::Vector4<bool>;
static Type DecodeFromBuffer(BufferType value) { return { value.x() != 0, value.y() != 0, value.z() != 0, value.w() != 0}; }
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z(), value.w() }; }
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.x, value.y, value.z, value.w }; }
static OptionType EncodeToOption(Type value) { return OptionType{ value.x, value.y, value.z, value.w }; }
};
template<>
struct MaterialPropertyTypeInfo<MaterialPropertyType::Color>
{
using Type = Color;
using BufferType = nzsl::Vector4f32;
using OptionType = nzsl::Vector4f32;
static Type DecodeFromBuffer(BufferType value) { return { value.x(), value.y(), value.z(), value.w() }; }
static Type DecodeFromOption(OptionType value) { return { value.x(), value.y(), value.z(), value.w() }; }
static BufferType EncodeToBuffer(Type value) { return BufferType{ value.r, value.g, value.b, value.a }; }
static OptionType EncodeToOption(Type value) { return BufferType{ value.r, value.g, value.b, value.a }; }
};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Float> : MaterialPropertyTypeInfoPrimitive<float> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Float2> : MaterialPropertyTypeInfoVector<float, 2> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Float3> : MaterialPropertyTypeInfoVector<float, 3> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Float4> : MaterialPropertyTypeInfoVector<float, 4> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Int> : MaterialPropertyTypeInfoPrimitive<Int32> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Int2> : MaterialPropertyTypeInfoVector<Int32, 2> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Int3> : MaterialPropertyTypeInfoVector<Int32, 3> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::Int4> : MaterialPropertyTypeInfoVector<Int32, 4> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::UInt> : MaterialPropertyTypeInfoPrimitive<UInt32> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::UInt2> : MaterialPropertyTypeInfoVector<UInt32, 2> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::UInt3> : MaterialPropertyTypeInfoVector<UInt32, 3> {};
template<> struct MaterialPropertyTypeInfo<MaterialPropertyType::UInt4> : MaterialPropertyTypeInfoVector<UInt32, 4> {};
inline void MaterialSettings::AddPass(std::size_t passIndex, MaterialPass materialPass)
{
if (passIndex >= m_materialPasses.size())
m_materialPasses.resize(passIndex + 1);
m_materialPasses[passIndex] = std::move(materialPass);
}
inline MaterialSettings::MaterialSettings(Builder data) :
m_data(std::move(data))
inline void MaterialSettings::AddPropertyHandler(std::unique_ptr<PropertyHandler> propertyHandler)
{
RenderPipelineLayoutInfo info;
for (const Texture& textureInfo : m_data.textures)
{
info.bindings.push_back({
0,
textureInfo.bindingIndex,
ShaderBindingType::Texture,
textureInfo.shaderStages
});
}
for (const UniformBlock& ubo : m_data.uniformBlocks)
{
info.bindings.push_back({
0,
ubo.bindingIndex,
ShaderBindingType::UniformBuffer,
ubo.shaderStages
});
}
for (const SharedUniformBlock& ubo : m_data.sharedUniformBlocks)
{
info.bindings.push_back({
0,
ubo.bindingIndex,
ShaderBindingType::UniformBuffer,
ubo.shaderStages
});
}
m_pipelineLayout = Graphics::Instance()->GetRenderDevice()->InstantiateRenderPipelineLayout(std::move(info));
m_propertyHandlers.emplace_back(std::move(propertyHandler));
}
inline auto MaterialSettings::GetBuilderData() const -> const Builder&
inline void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType)
{
return m_data;
auto& textureProperty = m_textureProperties.emplace_back();
textureProperty.name = std::move(propertyName);
textureProperty.type = propertyType;
}
inline auto MaterialSettings::GetOptions() const -> const std::vector<Option>&
inline void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType, std::shared_ptr<Texture> defaultTexture)
{
return m_data.options;
if (defaultTexture && defaultTexture->GetType() != propertyType)
throw std::runtime_error("default texture type doesn't match property image type");
auto& textureProperty = m_textureProperties.emplace_back();
textureProperty.name = std::move(propertyName);
textureProperty.type = propertyType;
textureProperty.defaultTexture = std::move(defaultTexture);
}
inline std::size_t MaterialSettings::GetOptionIndex(const std::string_view& name) const
inline void MaterialSettings::AddTextureProperty(std::string propertyName, ImageType propertyType, std::shared_ptr<Texture> defaultTexture, const TextureSamplerInfo& defaultSamplerInfo)
{
for (std::size_t i = 0; i < m_data.options.size(); ++i)
if (defaultTexture && defaultTexture->GetType() != propertyType)
throw std::runtime_error("default texture type doesn't match property image type");
auto& textureProperty = m_textureProperties.emplace_back();
textureProperty.name = std::move(propertyName);
textureProperty.type = propertyType;
textureProperty.defaultTexture = std::move(defaultTexture);
textureProperty.defaultSamplerInfo = defaultSamplerInfo;
}
inline void MaterialSettings::AddValueProperty(std::string propertyName, MaterialPropertyType propertyType, Value defaultValue)
{
std::visit([&](auto&& arg)
{
if (m_data.options[i].name == name)
using T = std::decay_t<decltype(arg)>;
if constexpr (!std::is_same_v<T, MaterialPropertyNoValue>)
{
constexpr MaterialPropertyType valueType = TypeToMaterialPropertyType_v<T>;
if (propertyType != valueType)
throw std::runtime_error("default value type doesn't match property type");
}
else
throw std::runtime_error("value properties must have a default value");
}, defaultValue);
auto& valueProperty = m_valueProperties.emplace_back();
valueProperty.name = std::move(propertyName);
valueProperty.type = propertyType;
valueProperty.defaultValue = std::move(defaultValue);
}
inline std::size_t MaterialSettings::FindTextureProperty(std::string_view propertyName) const
{
for (std::size_t i = 0; i < m_textureProperties.size(); ++i)
{
if (m_textureProperties[i].name == propertyName)
return i;
}
return InvalidIndex;
return InvalidPropertyIndex;
}
inline std::size_t MaterialSettings::GetPredefinedBinding(PredefinedShaderBinding shaderBinding) const
inline std::size_t MaterialSettings::FindValueProperty(std::string_view propertyName) const
{
return m_data.predefinedBindings[UnderlyingCast(shaderBinding)];
}
inline const std::shared_ptr<RenderPipelineLayout>& MaterialSettings::GetRenderPipelineLayout() const
{
return m_pipelineLayout;
}
inline const std::shared_ptr<UberShader>& MaterialSettings::GetShader(nzsl::ShaderStageType stage) const
{
return m_data.shaders[UnderlyingCast(stage)];
}
inline const std::vector<std::shared_ptr<UberShader>>& MaterialSettings::GetShaders() const
{
return m_data.shaders;
}
inline auto MaterialSettings::GetSharedUniformBlocks() const -> const std::vector<SharedUniformBlock>&
{
return m_data.sharedUniformBlocks;
}
inline std::size_t MaterialSettings::GetSharedUniformBlockIndex(const std::string_view& name) const
{
for (std::size_t i = 0; i < m_data.sharedUniformBlocks.size(); ++i)
for (std::size_t i = 0; i < m_valueProperties.size(); ++i)
{
if (m_data.sharedUniformBlocks[i].name == name)
if (m_valueProperties[i].name == propertyName)
return i;
}
return InvalidIndex;
return InvalidPropertyIndex;
}
inline std::size_t MaterialSettings::GetSharedUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const
inline const MaterialPass* MaterialSettings::GetPass(std::size_t passIndex) const
{
assert(uniformBlockIndex < m_data.sharedUniformBlocks.size());
if (passIndex > m_materialPasses.size() || !m_materialPasses[passIndex].has_value())
return nullptr;
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)
return i;
}
return InvalidIndex;
return &m_materialPasses[passIndex].value();
}
inline auto MaterialSettings::GetTextures() const -> const std::vector<Texture>&
inline const std::vector<std::optional<MaterialPass>>& MaterialSettings::GetPasses() const
{
return m_data.textures;
return m_materialPasses;
}
inline std::size_t MaterialSettings::GetTextureIndex(const std::string_view& name) const
inline const std::vector<std::unique_ptr<PropertyHandler>>& MaterialSettings::GetPropertyHandlers() const
{
for (std::size_t i = 0; i < m_data.textures.size(); ++i)
{
if (m_data.textures[i].name == name)
return i;
}
return InvalidIndex;
return m_propertyHandlers;
}
inline auto MaterialSettings::GetUniformBlocks() const -> const std::vector<UniformBlock>&
inline auto MaterialSettings::GetTextureProperty(std::size_t texturePropertyIndex) const -> const TextureProperty&
{
return m_data.uniformBlocks;
assert(texturePropertyIndex < m_textureProperties.size());
return m_textureProperties[texturePropertyIndex];
}
inline std::size_t MaterialSettings::GetUniformBlockIndex(const std::string_view& name) const
inline std::size_t MaterialSettings::GetTexturePropertyCount() const
{
for (std::size_t i = 0; i < m_data.uniformBlocks.size(); ++i)
{
if (m_data.uniformBlocks[i].name == name)
return i;
}
return InvalidIndex;
return m_textureProperties.size();
}
inline std::size_t MaterialSettings::GetUniformBlockVariableOffset(std::size_t uniformBlockIndex, const std::string_view& name) const
inline auto MaterialSettings::GetValueProperty(std::size_t valuePropertyIndex) const -> const ValueProperty&
{
assert(uniformBlockIndex < m_data.uniformBlocks.size());
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)
return i;
}
return InvalidIndex;
assert(valuePropertyIndex < m_valueProperties.size());
return m_valueProperties[valuePropertyIndex];
}
inline void MaterialSettings::BuildOption(std::vector<Option>& options, std::string optionName, const std::string& shaderOptionName)
inline std::size_t MaterialSettings::GetValuePropertyCount() const
{
UInt32 optionHash = CRC32(shaderOptionName);
options.push_back({
std::move(optionName),
optionHash
});
return m_valueProperties.size();
}
inline MaterialSettings::Builder::Builder()
template<typename T>
void MaterialSettings::AddValueProperty(std::string propertyName)
{
predefinedBindings.fill(InvalidIndex);
return AddValueProperty(std::move(propertyName), TypeToMaterialPropertyType_v<T>);
}
template<typename T, typename U>
void MaterialSettings::AddValueProperty(std::string propertyName, U&& defaultValue)
{
constexpr std::size_t TypeIndex = TypeListFind<MaterialPropertyTypeList, T>;
auto& valueProperty = m_valueProperties.emplace_back();
valueProperty.name = std::move(propertyName);
valueProperty.type = TypeToMaterialPropertyType_v<T>;
valueProperty.defaultValue.emplace<TypeIndex>(std::forward<U>(defaultValue));
}
}